c-next 0.1.65 → 0.1.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -1
- package/src/transpiler/Transpiler.ts +49 -42
- package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +129 -0
- package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +27 -3
- package/src/transpiler/output/codegen/CodeGenerator.ts +131 -186
- package/src/transpiler/output/codegen/TypeResolver.ts +2 -2
- package/src/transpiler/output/codegen/TypeValidator.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +1087 -0
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +665 -1315
- package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +1 -1
- package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +1 -1
- package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +1 -1
- package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +1 -1
- package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +1 -1
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +1 -1
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +1 -1
- package/src/transpiler/output/codegen/assignment/handlers/AccessPatternHandlers.ts +24 -27
- package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +25 -18
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +27 -33
- package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +39 -42
- package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +39 -97
- package/src/transpiler/output/codegen/assignment/handlers/RegisterUtils.ts +75 -0
- package/src/transpiler/output/codegen/assignment/handlers/SimpleHandler.ts +9 -6
- package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +30 -22
- package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +42 -50
- package/src/transpiler/output/codegen/assignment/handlers/TAssignmentHandler.ts +6 -5
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +81 -134
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +85 -124
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +82 -124
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +135 -297
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +105 -227
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterUtils.test.ts +214 -1
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +66 -127
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/StringHandlers.test.ts +37 -83
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +162 -0
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +618 -12
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +819 -0
- package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +1 -1
- package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +1 -1
- package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
- package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +337 -0
- package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +135 -0
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/VariableDeclarationFormatter.ts +118 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +426 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +315 -0
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclarationFormatter.test.ts +333 -0
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/types/ICodeGenApi.ts +57 -0
- package/src/transpiler/output/codegen/types/IParameterInput.ts +58 -0
- package/src/transpiler/output/codegen/types/IVariableFormatInput.ts +51 -0
- package/src/transpiler/output/headers/BaseHeaderGenerator.ts +20 -35
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +21 -48
- package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +0 -64
- package/src/transpiler/{output/codegen → state}/CodeGenState.ts +46 -26
- package/src/transpiler/{output/codegen → state}/__tests__/CodeGenState.test.ts +12 -2
- package/src/transpiler/output/codegen/assignment/handlers/IHandlerDeps.ts +0 -161
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import * as Parser from "../../../logic/parser/grammar/CNextParser.js";
|
|
13
13
|
import TOverflowBehavior from "../types/TOverflowBehavior.js";
|
|
14
14
|
import analyzePostfixOps from "../../../../utils/PostfixAnalysisUtils.js";
|
|
15
|
-
import CodeGenState from "
|
|
15
|
+
import CodeGenState from "../../../state/CodeGenState.js";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Result of resolving expected type for an assignment target.
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import * as Parser from "../../../logic/parser/grammar/CNextParser.js";
|
|
18
18
|
import TypeValidator from "../TypeValidator.js";
|
|
19
19
|
import EnumAssignmentValidator from "./EnumAssignmentValidator.js";
|
|
20
|
-
import CodeGenState from "
|
|
20
|
+
import CodeGenState from "../../../state/CodeGenState.js";
|
|
21
21
|
import TypeCheckUtils from "../../../../utils/TypeCheckUtils.js";
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import * as Parser from "../../../logic/parser/grammar/CNextParser.js";
|
|
15
|
-
import CodeGenState from "
|
|
15
|
+
import CodeGenState from "../../../state/CodeGenState.js";
|
|
16
16
|
import EnumTypeResolver from "../resolution/EnumTypeResolver.js";
|
|
17
17
|
import TypeCheckUtils from "../../../../utils/TypeCheckUtils.js";
|
|
18
18
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
import TTypeInfo from "../types/TTypeInfo.js";
|
|
17
17
|
import TIncludeHeader from "../generators/TIncludeHeader.js";
|
|
18
|
-
import CodeGenState from "
|
|
18
|
+
import CodeGenState from "../../../state/CodeGenState.js";
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Callback types for code generation operations.
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ParameterInputAdapter - Adapts different input formats to IParameterInput
|
|
3
|
+
*
|
|
4
|
+
* Provides two conversion methods:
|
|
5
|
+
* - fromAST(): For CodeGenerator, converts Parser.ParameterContext + CodeGenState
|
|
6
|
+
* - fromSymbol(): For HeaderGenerator, converts IParameterSymbol
|
|
7
|
+
*
|
|
8
|
+
* Both produce normalized IParameterInput for use with ParameterSignatureBuilder.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import * as Parser from "../../../logic/parser/grammar/CNextParser";
|
|
12
|
+
import IParameterInput from "../types/IParameterInput";
|
|
13
|
+
import IParameterSymbol from "../../../../utils/types/IParameterSymbol";
|
|
14
|
+
import ICallbackTypeInfo from "../types/ICallbackTypeInfo";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Dependencies required by fromAST() to resolve types and state.
|
|
18
|
+
* These are passed in to avoid direct dependency on CodeGenState,
|
|
19
|
+
* making the adapter more testable.
|
|
20
|
+
*/
|
|
21
|
+
interface IFromASTDeps {
|
|
22
|
+
/** Get C-Next type name from type context (e.g., 'u32', 'Point') */
|
|
23
|
+
getTypeName: (type: Parser.TypeContext) => string;
|
|
24
|
+
|
|
25
|
+
/** Generate C type from type context (e.g., 'uint32_t', 'Point') */
|
|
26
|
+
generateType: (type: Parser.TypeContext) => string;
|
|
27
|
+
|
|
28
|
+
/** Generate expression string (for array dimension expressions) */
|
|
29
|
+
generateExpression: (expr: Parser.ExpressionContext) => string;
|
|
30
|
+
|
|
31
|
+
/** Map of callback type names to their info */
|
|
32
|
+
callbackTypes: ReadonlyMap<string, ICallbackTypeInfo>;
|
|
33
|
+
|
|
34
|
+
/** Check if type is a known struct (C-Next or C header) */
|
|
35
|
+
isKnownStruct: (typeName: string) => boolean;
|
|
36
|
+
|
|
37
|
+
/** TYPE_MAP for primitive detection */
|
|
38
|
+
typeMap: Record<string, string>;
|
|
39
|
+
|
|
40
|
+
/** Whether the parameter is modified in the current function */
|
|
41
|
+
isModified: boolean;
|
|
42
|
+
|
|
43
|
+
/** Whether the parameter should use pass-by-value (pre-computed) */
|
|
44
|
+
isPassByValue: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Dependencies required by fromSymbol() to resolve types.
|
|
49
|
+
* Simpler than AST deps since IParameterSymbol already contains most info.
|
|
50
|
+
*
|
|
51
|
+
* The caller (BaseHeaderGenerator) pre-computes isPassByValue including
|
|
52
|
+
* ISR/float/enum/passByValueSet checks. The adapter trusts this decision.
|
|
53
|
+
*/
|
|
54
|
+
interface IFromSymbolDeps {
|
|
55
|
+
/** Map C-Next type to C type */
|
|
56
|
+
mapType: (type: string) => string;
|
|
57
|
+
|
|
58
|
+
/** Whether the parameter should use pass-by-value (pre-computed by caller) */
|
|
59
|
+
isPassByValue: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Static adapter class for converting different input formats to IParameterInput.
|
|
64
|
+
*/
|
|
65
|
+
class ParameterInputAdapter {
|
|
66
|
+
/**
|
|
67
|
+
* Convert AST ParameterContext to normalized IParameterInput.
|
|
68
|
+
* Used by CodeGenerator.generateParameter().
|
|
69
|
+
*
|
|
70
|
+
* Note: Validation (C-style array rejection, unbounded dimension rejection)
|
|
71
|
+
* should be done BEFORE calling this method.
|
|
72
|
+
*
|
|
73
|
+
* @param ctx - The parser context for the parameter
|
|
74
|
+
* @param deps - Dependencies for type resolution and state lookup
|
|
75
|
+
* @returns Normalized IParameterInput
|
|
76
|
+
*/
|
|
77
|
+
static fromAST(
|
|
78
|
+
ctx: Parser.ParameterContext,
|
|
79
|
+
deps: IFromASTDeps,
|
|
80
|
+
): IParameterInput {
|
|
81
|
+
const isConst = ctx.constModifier() !== null;
|
|
82
|
+
const typeName = deps.getTypeName(ctx.type());
|
|
83
|
+
const name = ctx.IDENTIFIER().getText();
|
|
84
|
+
const mappedType = deps.generateType(ctx.type());
|
|
85
|
+
|
|
86
|
+
// Check for callback type
|
|
87
|
+
const callbackInfo = deps.callbackTypes.get(typeName);
|
|
88
|
+
if (callbackInfo) {
|
|
89
|
+
return this._buildCallbackInput(
|
|
90
|
+
name,
|
|
91
|
+
typeName,
|
|
92
|
+
mappedType,
|
|
93
|
+
callbackInfo.typedefName,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Check for array type
|
|
98
|
+
const arrayTypeCtx = ctx.type().arrayType();
|
|
99
|
+
if (arrayTypeCtx) {
|
|
100
|
+
return this._buildArrayInputFromAST(
|
|
101
|
+
arrayTypeCtx,
|
|
102
|
+
name,
|
|
103
|
+
typeName,
|
|
104
|
+
mappedType,
|
|
105
|
+
isConst,
|
|
106
|
+
deps,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Check for string type (non-array)
|
|
111
|
+
const stringTypeCtx = ctx.type().stringType();
|
|
112
|
+
if (stringTypeCtx) {
|
|
113
|
+
return this._buildStringInput(
|
|
114
|
+
name,
|
|
115
|
+
typeName,
|
|
116
|
+
isConst,
|
|
117
|
+
deps,
|
|
118
|
+
stringTypeCtx,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Determine classification for non-array, non-string types
|
|
123
|
+
const isKnownStruct = deps.isKnownStruct(typeName);
|
|
124
|
+
const isKnownPrimitive = !!deps.typeMap[typeName];
|
|
125
|
+
const isAutoConst = !deps.isModified && !isConst;
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
name,
|
|
129
|
+
baseType: typeName,
|
|
130
|
+
mappedType,
|
|
131
|
+
isConst,
|
|
132
|
+
isAutoConst,
|
|
133
|
+
isArray: false,
|
|
134
|
+
isCallback: false,
|
|
135
|
+
isString: false,
|
|
136
|
+
isPassByValue: deps.isPassByValue,
|
|
137
|
+
isPassByReference: isKnownStruct || isKnownPrimitive,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Convert IParameterSymbol to normalized IParameterInput.
|
|
143
|
+
* Used by BaseHeaderGenerator.generateParameter().
|
|
144
|
+
*
|
|
145
|
+
* The caller pre-computes isPassByValue (ISR, float, enum, passByValueSet).
|
|
146
|
+
* Non-PBV, non-array, non-string types use pass-by-reference.
|
|
147
|
+
*
|
|
148
|
+
* @param param - The parameter symbol
|
|
149
|
+
* @param deps - Dependencies for type mapping
|
|
150
|
+
* @returns Normalized IParameterInput
|
|
151
|
+
*/
|
|
152
|
+
static fromSymbol(
|
|
153
|
+
param: IParameterSymbol,
|
|
154
|
+
deps: IFromSymbolDeps,
|
|
155
|
+
): IParameterInput {
|
|
156
|
+
const mappedType = deps.mapType(param.type);
|
|
157
|
+
|
|
158
|
+
// Array parameters
|
|
159
|
+
if (
|
|
160
|
+
param.isArray &&
|
|
161
|
+
param.arrayDimensions &&
|
|
162
|
+
param.arrayDimensions.length > 0
|
|
163
|
+
) {
|
|
164
|
+
return this._buildArrayInputFromSymbol(param, mappedType);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// String type detection
|
|
168
|
+
const isString =
|
|
169
|
+
param.type === "string" || param.type.startsWith("string<");
|
|
170
|
+
|
|
171
|
+
// Non-array string
|
|
172
|
+
if (isString && !param.isArray) {
|
|
173
|
+
return {
|
|
174
|
+
name: param.name,
|
|
175
|
+
baseType: param.type,
|
|
176
|
+
mappedType: "char",
|
|
177
|
+
isConst: param.isConst,
|
|
178
|
+
isAutoConst: param.isAutoConst ?? false,
|
|
179
|
+
isArray: false,
|
|
180
|
+
isCallback: false,
|
|
181
|
+
isString: true,
|
|
182
|
+
isPassByValue: false,
|
|
183
|
+
isPassByReference: false,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
name: param.name,
|
|
189
|
+
baseType: param.type,
|
|
190
|
+
mappedType,
|
|
191
|
+
isConst: param.isConst,
|
|
192
|
+
isAutoConst: param.isAutoConst ?? false,
|
|
193
|
+
isArray: false,
|
|
194
|
+
isCallback: false,
|
|
195
|
+
isString: false,
|
|
196
|
+
isPassByValue: deps.isPassByValue,
|
|
197
|
+
isPassByReference: !deps.isPassByValue,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Build IParameterInput for a callback parameter.
|
|
203
|
+
*/
|
|
204
|
+
private static _buildCallbackInput(
|
|
205
|
+
name: string,
|
|
206
|
+
typeName: string,
|
|
207
|
+
mappedType: string,
|
|
208
|
+
typedefName: string,
|
|
209
|
+
): IParameterInput {
|
|
210
|
+
return {
|
|
211
|
+
name,
|
|
212
|
+
baseType: typeName,
|
|
213
|
+
mappedType,
|
|
214
|
+
isConst: false,
|
|
215
|
+
isAutoConst: false,
|
|
216
|
+
isArray: false,
|
|
217
|
+
isCallback: true,
|
|
218
|
+
callbackTypedefName: typedefName,
|
|
219
|
+
isString: false,
|
|
220
|
+
isPassByValue: true, // Callbacks are function pointers, pass by value
|
|
221
|
+
isPassByReference: false,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Build IParameterInput for an array parameter from AST.
|
|
227
|
+
*/
|
|
228
|
+
private static _buildArrayInputFromAST(
|
|
229
|
+
arrayTypeCtx: Parser.ArrayTypeContext,
|
|
230
|
+
name: string,
|
|
231
|
+
typeName: string,
|
|
232
|
+
mappedType: string,
|
|
233
|
+
isConst: boolean,
|
|
234
|
+
deps: IFromASTDeps,
|
|
235
|
+
): IParameterInput {
|
|
236
|
+
const allDims = arrayTypeCtx.arrayTypeDimension();
|
|
237
|
+
|
|
238
|
+
// Build dimension strings
|
|
239
|
+
const dims: string[] = allDims.map(
|
|
240
|
+
(d: Parser.ArrayTypeDimensionContext) => {
|
|
241
|
+
const expr = d.expression();
|
|
242
|
+
return expr ? deps.generateExpression(expr) : "";
|
|
243
|
+
},
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
// Check for string array (string<N>[M])
|
|
247
|
+
const stringTypeCtx = arrayTypeCtx.stringType();
|
|
248
|
+
const isString = stringTypeCtx !== null;
|
|
249
|
+
|
|
250
|
+
if (isString && stringTypeCtx) {
|
|
251
|
+
const intLiteral = stringTypeCtx.INTEGER_LITERAL();
|
|
252
|
+
if (intLiteral) {
|
|
253
|
+
const capacity = Number.parseInt(intLiteral.getText(), 10);
|
|
254
|
+
dims.push(String(capacity + 1));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const isAutoConst = !deps.isModified && !isConst;
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
name,
|
|
262
|
+
baseType: typeName,
|
|
263
|
+
mappedType,
|
|
264
|
+
isConst,
|
|
265
|
+
isAutoConst,
|
|
266
|
+
isArray: true,
|
|
267
|
+
arrayDimensions: dims,
|
|
268
|
+
isCallback: false,
|
|
269
|
+
isString,
|
|
270
|
+
isPassByValue: false, // Arrays are always passed by pointer
|
|
271
|
+
isPassByReference: false,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Build IParameterInput for an array parameter from symbol.
|
|
277
|
+
*/
|
|
278
|
+
private static _buildArrayInputFromSymbol(
|
|
279
|
+
param: IParameterSymbol,
|
|
280
|
+
mappedType: string,
|
|
281
|
+
): IParameterInput {
|
|
282
|
+
const isString =
|
|
283
|
+
param.type === "string" || param.type.startsWith("string<");
|
|
284
|
+
const isUnboundedString = param.type === "string"; // No capacity specified
|
|
285
|
+
|
|
286
|
+
// For header generator, we need to use char for string arrays
|
|
287
|
+
const actualMappedType = isString ? "char" : mappedType;
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
name: param.name,
|
|
291
|
+
baseType: param.type,
|
|
292
|
+
mappedType: actualMappedType,
|
|
293
|
+
isConst: param.isConst,
|
|
294
|
+
isAutoConst: param.isAutoConst ?? false,
|
|
295
|
+
isArray: true,
|
|
296
|
+
arrayDimensions: param.arrayDimensions,
|
|
297
|
+
isCallback: false,
|
|
298
|
+
isString,
|
|
299
|
+
isUnboundedString,
|
|
300
|
+
isPassByValue: false,
|
|
301
|
+
isPassByReference: false,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Build IParameterInput for a non-array string parameter.
|
|
307
|
+
*/
|
|
308
|
+
private static _buildStringInput(
|
|
309
|
+
name: string,
|
|
310
|
+
typeName: string,
|
|
311
|
+
isConst: boolean,
|
|
312
|
+
deps: IFromASTDeps,
|
|
313
|
+
stringTypeCtx: Parser.StringTypeContext,
|
|
314
|
+
): IParameterInput {
|
|
315
|
+
const intLiteral = stringTypeCtx.INTEGER_LITERAL();
|
|
316
|
+
const capacity = intLiteral
|
|
317
|
+
? Number.parseInt(intLiteral.getText(), 10)
|
|
318
|
+
: undefined;
|
|
319
|
+
const isAutoConst = !deps.isModified && !isConst;
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
name,
|
|
323
|
+
baseType: typeName,
|
|
324
|
+
mappedType: "char",
|
|
325
|
+
isConst,
|
|
326
|
+
isAutoConst,
|
|
327
|
+
isArray: false,
|
|
328
|
+
isCallback: false,
|
|
329
|
+
isString: true,
|
|
330
|
+
stringCapacity: capacity,
|
|
331
|
+
isPassByValue: false,
|
|
332
|
+
isPassByReference: false,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export default ParameterInputAdapter;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ParameterSignatureBuilder - Stateless builder for C/C++ parameter signatures
|
|
3
|
+
*
|
|
4
|
+
* Takes a normalized IParameterInput and produces the final parameter string.
|
|
5
|
+
* All decisions (const, pass-by-value, etc.) are pre-computed in the input.
|
|
6
|
+
*
|
|
7
|
+
* This is the single source of truth for parameter formatting, used by both:
|
|
8
|
+
* - CodeGenerator (via ParameterInputAdapter.fromAST)
|
|
9
|
+
* - BaseHeaderGenerator (via ParameterInputAdapter.fromSymbol)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import IParameterInput from "../types/IParameterInput";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Static helper class for building C/C++ parameter signature strings.
|
|
16
|
+
*/
|
|
17
|
+
class ParameterSignatureBuilder {
|
|
18
|
+
/**
|
|
19
|
+
* Build a parameter signature string from normalized input.
|
|
20
|
+
*
|
|
21
|
+
* @param param - Normalized parameter input (all decisions pre-computed)
|
|
22
|
+
* @param refSuffix - '*' for C mode (pointer), '&' for C++ mode (reference)
|
|
23
|
+
* @returns The formatted parameter string (e.g., "const uint32_t* value")
|
|
24
|
+
*/
|
|
25
|
+
static build(param: IParameterInput, refSuffix: string): string {
|
|
26
|
+
// Callback parameters: just typedef name and param name
|
|
27
|
+
if (param.isCallback && param.callbackTypedefName) {
|
|
28
|
+
return `${param.callbackTypedefName} ${param.name}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Array parameters with dimensions
|
|
32
|
+
if (
|
|
33
|
+
param.isArray &&
|
|
34
|
+
param.arrayDimensions &&
|
|
35
|
+
param.arrayDimensions.length > 0
|
|
36
|
+
) {
|
|
37
|
+
return this._buildArrayParam(param);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Pass-by-value parameters (ISR, float, enum, small primitives)
|
|
41
|
+
if (param.isPassByValue) {
|
|
42
|
+
return this._buildPassByValueParam(param);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Non-array string: string<N> -> const char* name
|
|
46
|
+
if (param.isString && !param.isArray) {
|
|
47
|
+
return this._buildStringParam(param);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Known struct or known primitive: pass by reference
|
|
51
|
+
if (param.isPassByReference) {
|
|
52
|
+
return this._buildRefParam(param, refSuffix);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Unknown types: pass by value (standard C semantics)
|
|
56
|
+
return this._buildUnknownParam(param);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Build array parameter signature.
|
|
61
|
+
* Examples:
|
|
62
|
+
* - u32[10] arr -> const uint32_t arr[10]
|
|
63
|
+
* - u8[4][4] matrix -> const uint8_t matrix[4][4]
|
|
64
|
+
* - string<32>[5] names -> const char names[5][33]
|
|
65
|
+
* - string[5] names -> char* names[5] (unbounded string array)
|
|
66
|
+
*/
|
|
67
|
+
private static _buildArrayParam(param: IParameterInput): string {
|
|
68
|
+
const constPrefix = this._getConstPrefix(param);
|
|
69
|
+
const dims = param.arrayDimensions!.map((d) => `[${d}]`).join("");
|
|
70
|
+
|
|
71
|
+
// Unbounded string arrays use char* (array of char pointers)
|
|
72
|
+
if (param.isUnboundedString) {
|
|
73
|
+
return `${constPrefix}char* ${param.name}${dims}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Bounded string arrays use char (dimensions include capacity)
|
|
77
|
+
if (param.isString) {
|
|
78
|
+
return `${constPrefix}char ${param.name}${dims}`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return `${constPrefix}${param.mappedType} ${param.name}${dims}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Build pass-by-value parameter signature.
|
|
86
|
+
* Used for: ISR, f32, f64, enums, small unmodified primitives.
|
|
87
|
+
* Example: float value, ISR handler, Status s
|
|
88
|
+
*/
|
|
89
|
+
private static _buildPassByValueParam(param: IParameterInput): string {
|
|
90
|
+
const constMod = param.isConst ? "const " : "";
|
|
91
|
+
return `${constMod}${param.mappedType} ${param.name}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Build non-array string parameter signature.
|
|
96
|
+
* string<N> -> const char* name (with auto-const if unmodified)
|
|
97
|
+
*/
|
|
98
|
+
private static _buildStringParam(param: IParameterInput): string {
|
|
99
|
+
const constPrefix = this._getConstPrefix(param);
|
|
100
|
+
return `${constPrefix}char* ${param.name}`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Build pass-by-reference parameter signature.
|
|
105
|
+
* C mode: const Point* p
|
|
106
|
+
* C++ mode: const Point& p
|
|
107
|
+
*/
|
|
108
|
+
private static _buildRefParam(
|
|
109
|
+
param: IParameterInput,
|
|
110
|
+
refSuffix: string,
|
|
111
|
+
): string {
|
|
112
|
+
const constPrefix = this._getConstPrefix(param);
|
|
113
|
+
return `${constPrefix}${param.mappedType}${refSuffix} ${param.name}`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Build unknown type parameter (pass by value, standard C semantics).
|
|
118
|
+
*/
|
|
119
|
+
private static _buildUnknownParam(param: IParameterInput): string {
|
|
120
|
+
const constMod = param.isConst ? "const " : "";
|
|
121
|
+
return `${constMod}${param.mappedType} ${param.name}`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Get const prefix combining explicit const and auto-const.
|
|
126
|
+
* Auto-const is applied to unmodified parameters.
|
|
127
|
+
*/
|
|
128
|
+
private static _getConstPrefix(param: IParameterInput): string {
|
|
129
|
+
const autoConst = param.isAutoConst && !param.isConst ? "const " : "";
|
|
130
|
+
const explicitConst = param.isConst ? "const " : "";
|
|
131
|
+
return `${autoConst}${explicitConst}`;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export default ParameterSignatureBuilder;
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import * as Parser from "../../../logic/parser/grammar/CNextParser.js";
|
|
16
16
|
import FormatUtils from "../../../../utils/FormatUtils.js";
|
|
17
17
|
import StringUtils from "../../../../utils/StringUtils.js";
|
|
18
|
-
import CodeGenState from "
|
|
18
|
+
import CodeGenState from "../../../state/CodeGenState.js";
|
|
19
19
|
|
|
20
20
|
/** C null terminator character literal for generated code */
|
|
21
21
|
const C_NULL_CHAR = String.raw`'\0'`;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VariableDeclarationFormatter - Unified variable declaration string generation.
|
|
3
|
+
*
|
|
4
|
+
* Phase 2 of unified code generation: Provides a single source of truth for
|
|
5
|
+
* variable declaration formatting, eliminating sync issues between
|
|
6
|
+
* CodeGenerator and HeaderGeneratorUtils.
|
|
7
|
+
*
|
|
8
|
+
* Handles:
|
|
9
|
+
* - Modifier ordering (extern const volatile)
|
|
10
|
+
* - Type formatting with embedded dimensions (string<N> → char[N+1])
|
|
11
|
+
* - Array dimension placement after variable name
|
|
12
|
+
*
|
|
13
|
+
* This class is STATELESS - all decisions are pre-computed in IVariableFormatInput.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type IVariableFormatInput from "../types/IVariableFormatInput";
|
|
17
|
+
|
|
18
|
+
/** Modifier flags for variable declarations */
|
|
19
|
+
type IVariableModifiers = IVariableFormatInput["modifiers"];
|
|
20
|
+
|
|
21
|
+
class VariableDeclarationFormatter {
|
|
22
|
+
/**
|
|
23
|
+
* Format a variable declaration string.
|
|
24
|
+
*
|
|
25
|
+
* @param input - Normalized variable declaration input (all decisions pre-computed)
|
|
26
|
+
* @returns Formatted declaration string (e.g., "extern const uint32_t count")
|
|
27
|
+
*/
|
|
28
|
+
static format(input: IVariableFormatInput): string {
|
|
29
|
+
const modifierPrefix = VariableDeclarationFormatter.buildModifierPrefix(
|
|
30
|
+
input.modifiers,
|
|
31
|
+
);
|
|
32
|
+
const arrayDimsStr = VariableDeclarationFormatter.buildArrayDimensions(
|
|
33
|
+
input.arrayDimensions,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
// Handle types with embedded dimensions (e.g., char[33] from string<32>)
|
|
37
|
+
// In C, array dimensions follow the variable name, not the type
|
|
38
|
+
return VariableDeclarationFormatter.formatWithEmbeddedDimensions(
|
|
39
|
+
modifierPrefix,
|
|
40
|
+
input.mappedType,
|
|
41
|
+
input.name,
|
|
42
|
+
arrayDimsStr,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Build the modifier prefix string with consistent ordering.
|
|
48
|
+
*
|
|
49
|
+
* Order: extern volatile const
|
|
50
|
+
* - Matches the established C-Next output format
|
|
51
|
+
* - atomic maps to volatile, so atomic and volatile are mutually exclusive
|
|
52
|
+
* - The caller should validate this before calling
|
|
53
|
+
*/
|
|
54
|
+
static buildModifierPrefix(modifiers: IVariableModifiers): string {
|
|
55
|
+
const parts: string[] = [];
|
|
56
|
+
|
|
57
|
+
if (modifiers.isExtern) {
|
|
58
|
+
parts.push("extern");
|
|
59
|
+
}
|
|
60
|
+
// atomic and volatile both map to volatile in C
|
|
61
|
+
// volatile comes before const to match established format
|
|
62
|
+
if (modifiers.isAtomic || modifiers.isVolatile) {
|
|
63
|
+
parts.push("volatile");
|
|
64
|
+
}
|
|
65
|
+
if (modifiers.isConst) {
|
|
66
|
+
parts.push("const");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return parts.length > 0 ? parts.join(" ") + " " : "";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Build array dimension string from dimensions array.
|
|
74
|
+
*
|
|
75
|
+
* @param dimensions - Array of dimension strings (e.g., ['10', '20'])
|
|
76
|
+
* @returns Formatted dimensions (e.g., '[10][20]')
|
|
77
|
+
*/
|
|
78
|
+
static buildArrayDimensions(dimensions?: string[]): string {
|
|
79
|
+
if (!dimensions || dimensions.length === 0) {
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
return dimensions.map((d) => `[${d}]`).join("");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Format declaration handling types with embedded array dimensions.
|
|
87
|
+
*
|
|
88
|
+
* Handles types like char[33] from string<32> where the dimension is
|
|
89
|
+
* embedded in the mapped type. In C, array dimensions must follow the
|
|
90
|
+
* variable name:
|
|
91
|
+
* char greeting[33]; // Correct
|
|
92
|
+
* char[33] greeting; // Wrong
|
|
93
|
+
*
|
|
94
|
+
* For string arrays (string<32>[5] names), produces:
|
|
95
|
+
* char names[5][33]; // Additional dims first, embedded dim last
|
|
96
|
+
*/
|
|
97
|
+
private static formatWithEmbeddedDimensions(
|
|
98
|
+
modifierPrefix: string,
|
|
99
|
+
mappedType: string,
|
|
100
|
+
name: string,
|
|
101
|
+
additionalDims: string,
|
|
102
|
+
): string {
|
|
103
|
+
// Check if the mapped type has embedded array dimensions (e.g., char[33])
|
|
104
|
+
// This happens for string<N> types which map to char[N+1]
|
|
105
|
+
const embeddedMatch = /^(\w+)\[(\d+)\]$/.exec(mappedType);
|
|
106
|
+
if (embeddedMatch) {
|
|
107
|
+
const baseType = embeddedMatch[1];
|
|
108
|
+
const embeddedDim = embeddedMatch[2];
|
|
109
|
+
// Format: modifiers baseType name[additionalDims][embeddedDim]
|
|
110
|
+
return `${modifierPrefix}${baseType} ${name}${additionalDims}[${embeddedDim}]`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// No embedded dimensions - standard format
|
|
114
|
+
return `${modifierPrefix}${mappedType} ${name}${additionalDims}`;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export default VariableDeclarationFormatter;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
9
9
|
import ArrayInitHelper from "../ArrayInitHelper.js";
|
|
10
|
-
import CodeGenState from "
|
|
10
|
+
import CodeGenState from "../../../../state/CodeGenState.js";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Default callbacks for testing.
|
package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
2
|
import AssignmentExpectedTypeResolver from "../AssignmentExpectedTypeResolver.js";
|
|
3
3
|
import CNextSourceParser from "../../../../logic/parser/CNextSourceParser.js";
|
|
4
|
-
import CodeGenState from "
|
|
4
|
+
import CodeGenState from "../../../../state/CodeGenState.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Create a mock assignment target context by parsing a minimal assignment statement.
|
|
@@ -3,7 +3,7 @@ import AssignmentValidator from "../AssignmentValidator.js";
|
|
|
3
3
|
import TypeValidator from "../../TypeValidator.js";
|
|
4
4
|
import EnumAssignmentValidator from "../EnumAssignmentValidator.js";
|
|
5
5
|
import CNextSourceParser from "../../../../logic/parser/CNextSourceParser.js";
|
|
6
|
-
import CodeGenState from "
|
|
6
|
+
import CodeGenState from "../../../../state/CodeGenState.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Create a mock assignment target context by parsing a minimal assignment statement.
|