c-next 0.2.15 → 0.2.17
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/README.md +16 -0
- package/dist/index.js +1403 -427
- package/dist/index.js.map +3 -3
- package/grammar/CNext.g4 +4 -0
- package/package.json +5 -1
- package/src/transpiler/Transpiler.ts +90 -22
- package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
- package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +57 -10
- package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +186 -14
- package/src/transpiler/logic/analysis/SignedShiftAnalyzer.ts +124 -12
- package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +200 -0
- package/src/transpiler/logic/analysis/__tests__/InitializationAnalyzer.test.ts +386 -1
- package/src/transpiler/logic/analysis/__tests__/SignedShiftAnalyzer.test.ts +211 -0
- package/src/transpiler/logic/parser/grammar/CNext.interp +1 -1
- package/src/transpiler/logic/parser/grammar/CNextParser.ts +154 -86
- package/src/transpiler/logic/symbols/SymbolTable.ts +54 -12
- package/src/transpiler/logic/symbols/SymbolUtils.ts +21 -8
- package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +39 -4
- package/src/transpiler/logic/symbols/__tests__/SymbolUtils.test.ts +2 -1
- package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +2 -1
- package/src/transpiler/logic/symbols/cnext/__tests__/CNextResolver.integration.test.ts +5 -2
- package/src/transpiler/logic/symbols/cnext/__tests__/ScopeCollector.test.ts +5 -2
- package/src/transpiler/logic/symbols/cnext/collectors/ScopeCollector.ts +7 -2
- package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +15 -2
- package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +64 -50
- package/src/transpiler/logic/symbols/cpp/utils/DeclaratorUtils.ts +4 -2
- package/src/transpiler/output/codegen/CodeGenerator.ts +151 -94
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +167 -18
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +150 -34
- package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +2 -2
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +11 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +32 -8
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +91 -1
- package/src/transpiler/output/codegen/generators/expressions/BinaryExprGenerator.ts +43 -24
- package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +48 -43
- package/src/transpiler/output/codegen/generators/expressions/ExpressionGenerator.ts +9 -2
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +44 -0
- package/src/transpiler/output/codegen/generators/expressions/__tests__/ExpressionGenerator.test.ts +82 -1
- package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +17 -3
- package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +17 -4
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +227 -32
- package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +0 -21
- package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +60 -39
- package/src/transpiler/output/codegen/helpers/TypeRegistrationEngine.ts +170 -36
- package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +37 -39
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +117 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +94 -2
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +268 -1
- package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +0 -64
- package/src/transpiler/output/codegen/helpers/__tests__/TypeRegistrationEngine.test.ts +101 -0
- package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclHelper.test.ts +29 -5
- package/src/transpiler/output/codegen/types/ICallbackTypeInfo.ts +2 -1
- package/src/transpiler/output/codegen/types/IParameterInput.ts +7 -0
- package/src/transpiler/output/headers/BaseHeaderGenerator.ts +8 -0
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +75 -0
- package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +280 -0
- package/src/transpiler/output/headers/generators/IHeaderTypeInput.ts +13 -0
- package/src/transpiler/output/headers/generators/generateStructHeader.ts +48 -28
- package/src/transpiler/state/CodeGenState.ts +71 -6
- package/src/transpiler/state/__tests__/CodeGenState.test.ts +253 -11
- package/src/transpiler/types/symbols/c/ICFieldInfo.ts +6 -2
- package/src/transpiler/types/symbols/cpp/ICppFieldInfo.ts +5 -2
- package/src/utils/LiteralUtils.ts +23 -0
- package/src/utils/ScopeUtils.ts +19 -0
- package/src/utils/__tests__/LiteralUtils.test.ts +101 -0
- package/src/utils/__tests__/ScopeUtils.test.ts +10 -0
- package/src/utils/types/IParameterSymbol.ts +1 -0
|
@@ -98,6 +98,21 @@ class StringDeclHelper {
|
|
|
98
98
|
isConst: boolean,
|
|
99
99
|
callbacks: IStringDeclCallbacks,
|
|
100
100
|
): IStringDeclResult {
|
|
101
|
+
// Issue #1029: Check for string array in arrayType syntax first
|
|
102
|
+
// For `string<32>[4] items`, the structure is: arrayType -> stringType arrayTypeDimension+
|
|
103
|
+
const arrayTypeCtx = typeCtx.arrayType?.();
|
|
104
|
+
if (arrayTypeCtx?.stringType?.()) {
|
|
105
|
+
return StringDeclHelper._generateStringArrayFromArrayType(
|
|
106
|
+
name,
|
|
107
|
+
arrayTypeCtx,
|
|
108
|
+
expression,
|
|
109
|
+
arrayDims,
|
|
110
|
+
modifiers,
|
|
111
|
+
isConst,
|
|
112
|
+
callbacks,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
101
116
|
const stringCtx = typeCtx.stringType();
|
|
102
117
|
if (!stringCtx) {
|
|
103
118
|
return { code: "", handled: false };
|
|
@@ -129,6 +144,182 @@ class StringDeclHelper {
|
|
|
129
144
|
}
|
|
130
145
|
}
|
|
131
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Issue #1029: Generate string array declaration from arrayType syntax.
|
|
149
|
+
* Handles: string<32>[4] items -> char items[4][33] = {0};
|
|
150
|
+
*/
|
|
151
|
+
private static _generateStringArrayFromArrayType(
|
|
152
|
+
name: string,
|
|
153
|
+
arrayTypeCtx: Parser.ArrayTypeContext,
|
|
154
|
+
expression: Parser.ExpressionContext | null,
|
|
155
|
+
trailingArrayDims: Parser.ArrayDimensionContext[],
|
|
156
|
+
modifiers: IStringDeclModifiers,
|
|
157
|
+
isConst: boolean,
|
|
158
|
+
callbacks: IStringDeclCallbacks,
|
|
159
|
+
): IStringDeclResult {
|
|
160
|
+
const stringCtx = arrayTypeCtx.stringType()!;
|
|
161
|
+
const intLiteral = stringCtx.INTEGER_LITERAL();
|
|
162
|
+
if (!intLiteral) {
|
|
163
|
+
// Unsized string array - not supported
|
|
164
|
+
throw new Error(
|
|
165
|
+
"Error: String arrays require explicit capacity, e.g., string<64>[4]",
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const capacity = Number.parseInt(intLiteral.getText(), 10);
|
|
170
|
+
// Ensure string.h is included for strncpy operations
|
|
171
|
+
callbacks.requireStringInclude();
|
|
172
|
+
|
|
173
|
+
const {
|
|
174
|
+
extern,
|
|
175
|
+
const: constMod,
|
|
176
|
+
atomic,
|
|
177
|
+
volatile: volatileMod,
|
|
178
|
+
} = modifiers;
|
|
179
|
+
|
|
180
|
+
// Build array dimensions from arrayType (e.g., [4] from string<32>[4])
|
|
181
|
+
let arrayDimStr = "";
|
|
182
|
+
for (const dim of arrayTypeCtx.arrayTypeDimension()) {
|
|
183
|
+
const sizeExpr = dim.expression();
|
|
184
|
+
if (sizeExpr) {
|
|
185
|
+
arrayDimStr += `[${sizeExpr.getText()}]`;
|
|
186
|
+
} else {
|
|
187
|
+
arrayDimStr += "[]";
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Add any trailing dimensions from variable declaration
|
|
192
|
+
arrayDimStr += callbacks.generateArrayDimensions(trailingArrayDims);
|
|
193
|
+
|
|
194
|
+
// Add string capacity dimension
|
|
195
|
+
arrayDimStr += `[${capacity + 1}]`;
|
|
196
|
+
|
|
197
|
+
let decl = `${extern}${constMod}${atomic}${volatileMod}char ${name}${arrayDimStr}`;
|
|
198
|
+
|
|
199
|
+
// Track as local array
|
|
200
|
+
CodeGenState.localArrays.add(name);
|
|
201
|
+
|
|
202
|
+
// No initializer - zero-initialize
|
|
203
|
+
if (!expression) {
|
|
204
|
+
return { code: `${decl} = {0};`, handled: true };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Reset array init tracking and generate initializer
|
|
208
|
+
CodeGenState.lastArrayInitCount = 0;
|
|
209
|
+
CodeGenState.lastArrayFillValue = undefined;
|
|
210
|
+
const initValue = callbacks.generateExpression(expression);
|
|
211
|
+
|
|
212
|
+
// Check if it was an array initializer
|
|
213
|
+
const isArrayInit =
|
|
214
|
+
CodeGenState.lastArrayInitCount > 0 ||
|
|
215
|
+
CodeGenState.lastArrayFillValue !== undefined;
|
|
216
|
+
|
|
217
|
+
if (!isArrayInit) {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`Error: String array initialization from variables not supported`,
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Validate element count if declared size is available
|
|
224
|
+
const declaredSize =
|
|
225
|
+
StringDeclHelper._getArrayTypeDeclaredSize(arrayTypeCtx);
|
|
226
|
+
if (declaredSize !== null) {
|
|
227
|
+
const isFillAll = CodeGenState.lastArrayFillValue !== undefined;
|
|
228
|
+
const elementCount = CodeGenState.lastArrayInitCount;
|
|
229
|
+
|
|
230
|
+
if (!isFillAll && elementCount !== declaredSize) {
|
|
231
|
+
throw new Error(
|
|
232
|
+
`Error: Array size mismatch - declared [${declaredSize}] but got ${elementCount} elements`,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Handle fill-all expansion if needed
|
|
238
|
+
const finalInitValue = StringDeclHelper._expandFillAllForArrayType(
|
|
239
|
+
initValue,
|
|
240
|
+
arrayTypeCtx,
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
// MISRA C:2012 Rules 9.3/9.4 - String literals don't fill all inner array bytes,
|
|
244
|
+
// but C standard guarantees zero-initialization of remaining elements
|
|
245
|
+
const suppression =
|
|
246
|
+
"// cppcheck-suppress misra-c2012-9.3\n// cppcheck-suppress misra-c2012-9.4\n";
|
|
247
|
+
return {
|
|
248
|
+
code: `${suppression}${decl} = ${finalInitValue};`,
|
|
249
|
+
handled: true,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Get the numeric size from the first arrayTypeDimension, or null if not numeric.
|
|
255
|
+
* Used by arrayType-based string arrays (string<N>[M]).
|
|
256
|
+
*/
|
|
257
|
+
private static _getArrayTypeDeclaredSize(
|
|
258
|
+
arrayTypeCtx: Parser.ArrayTypeContext,
|
|
259
|
+
): number | null {
|
|
260
|
+
const dims = arrayTypeCtx.arrayTypeDimension();
|
|
261
|
+
if (dims.length === 0) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
const firstDimExpr = dims[0].expression();
|
|
265
|
+
return StringDeclHelper._parseNumericSize(firstDimExpr);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Expand fill-all syntax for arrayType-based string arrays.
|
|
270
|
+
* Delegates to the common fill-all expansion logic with size from arrayType.
|
|
271
|
+
*/
|
|
272
|
+
private static _expandFillAllForArrayType(
|
|
273
|
+
initValue: string,
|
|
274
|
+
arrayTypeCtx: Parser.ArrayTypeContext,
|
|
275
|
+
): string {
|
|
276
|
+
const declaredSize =
|
|
277
|
+
StringDeclHelper._getArrayTypeDeclaredSize(arrayTypeCtx);
|
|
278
|
+
return StringDeclHelper._expandFillAll(initValue, declaredSize);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Common fill-all expansion logic shared between arrayType and arrayDimension paths.
|
|
283
|
+
*/
|
|
284
|
+
private static _expandFillAll(
|
|
285
|
+
initValue: string,
|
|
286
|
+
declaredSize: number | null,
|
|
287
|
+
): string {
|
|
288
|
+
const fillVal = CodeGenState.lastArrayFillValue;
|
|
289
|
+
if (fillVal === undefined) {
|
|
290
|
+
return initValue;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Empty string fill doesn't need expansion (C handles {""} correctly)
|
|
294
|
+
if (fillVal === '""') {
|
|
295
|
+
return initValue;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (declaredSize === null) {
|
|
299
|
+
return initValue;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const elements = new Array<string>(declaredSize).fill(fillVal);
|
|
303
|
+
return `{${elements.join(", ")}}`;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Parse a numeric size from an expression, or return null if not numeric.
|
|
308
|
+
* Shared helper to eliminate duplicate parsing logic.
|
|
309
|
+
*/
|
|
310
|
+
private static _parseNumericSize(
|
|
311
|
+
expr: Parser.ExpressionContext | null | undefined,
|
|
312
|
+
): number | null {
|
|
313
|
+
if (!expr) {
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
const sizeText = expr.getText();
|
|
317
|
+
if (!/^\d+$/.exec(sizeText)) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
return Number.parseInt(sizeText, 10);
|
|
321
|
+
}
|
|
322
|
+
|
|
132
323
|
/**
|
|
133
324
|
* Generate bounded string declaration (string<N>).
|
|
134
325
|
*/
|
|
@@ -207,24 +398,48 @@ class StringDeclHelper {
|
|
|
207
398
|
);
|
|
208
399
|
}
|
|
209
400
|
|
|
210
|
-
// Validate and
|
|
211
|
-
|
|
212
|
-
|
|
401
|
+
// Validate and check if it's a literal or variable
|
|
402
|
+
const exprText = expression.getText();
|
|
403
|
+
const isLiteral = StringDeclHelper._validateStringInit(
|
|
404
|
+
exprText,
|
|
213
405
|
capacity,
|
|
214
406
|
callbacks,
|
|
215
407
|
);
|
|
216
|
-
|
|
217
|
-
|
|
408
|
+
|
|
409
|
+
if (isLiteral) {
|
|
410
|
+
// String literal: can use direct initialization
|
|
411
|
+
const code = `${extern}${constMod}char ${name}[${capacity + 1}] = ${callbacks.generateExpression(expression)};`;
|
|
412
|
+
return { code, handled: true };
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// String variable: need strcpy (cannot use array initialization in C)
|
|
416
|
+
// Issue #1030: string-to-string initialization
|
|
417
|
+
if (!CodeGenState.inFunctionBody) {
|
|
418
|
+
throw new Error(
|
|
419
|
+
`Error: String initialization from variable cannot be used at global scope. ` +
|
|
420
|
+
`Move the declaration inside a function, or use an empty initializer and assign later.`,
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const srcExpr = callbacks.generateExpression(expression);
|
|
425
|
+
const indent = FormatUtils.indent(CodeGenState.indentLevel);
|
|
426
|
+
const lines: string[] = [];
|
|
427
|
+
lines.push(
|
|
428
|
+
`${constMod}char ${name}[${capacity + 1}] = "";`,
|
|
429
|
+
`${indent}strcpy(${name}, ${srcExpr});`,
|
|
430
|
+
);
|
|
431
|
+
return { code: lines.join("\n"), handled: true };
|
|
218
432
|
}
|
|
219
433
|
|
|
220
434
|
/**
|
|
221
435
|
* Validate string initialization (literal length and variable capacity)
|
|
436
|
+
* Returns true if the expression is a string literal, false if it's a variable.
|
|
222
437
|
*/
|
|
223
438
|
private static _validateStringInit(
|
|
224
439
|
exprText: string,
|
|
225
440
|
capacity: number,
|
|
226
441
|
callbacks: IStringDeclCallbacks,
|
|
227
|
-
):
|
|
442
|
+
): boolean {
|
|
228
443
|
// Validate string literal fits capacity
|
|
229
444
|
if (exprText.startsWith('"') && exprText.endsWith('"')) {
|
|
230
445
|
const content = StringUtils.literalLength(exprText);
|
|
@@ -233,6 +448,7 @@ class StringDeclHelper {
|
|
|
233
448
|
`Error: String literal (${content} chars) exceeds string<${capacity}> capacity`,
|
|
234
449
|
);
|
|
235
450
|
}
|
|
451
|
+
return true; // Is a literal
|
|
236
452
|
}
|
|
237
453
|
|
|
238
454
|
// Check for string variable assignment
|
|
@@ -242,6 +458,7 @@ class StringDeclHelper {
|
|
|
242
458
|
`Error: Cannot assign string<${srcCapacity}> to string<${capacity}> (potential truncation)`,
|
|
243
459
|
);
|
|
244
460
|
}
|
|
461
|
+
return false; // Is a variable (not a literal)
|
|
245
462
|
}
|
|
246
463
|
|
|
247
464
|
/**
|
|
@@ -373,47 +590,25 @@ class StringDeclHelper {
|
|
|
373
590
|
/**
|
|
374
591
|
* Expand fill-all syntax if needed.
|
|
375
592
|
* ["Hello"*] with size 3 -> {"Hello", "Hello", "Hello"}
|
|
593
|
+
* Delegates to the common fill-all expansion logic with size from arrayDimension.
|
|
376
594
|
*/
|
|
377
595
|
private static _expandFillAllIfNeeded(
|
|
378
596
|
initValue: string,
|
|
379
597
|
arrayDims: Parser.ArrayDimensionContext[],
|
|
380
598
|
): string {
|
|
381
|
-
const fillVal = CodeGenState.lastArrayFillValue;
|
|
382
|
-
if (fillVal === undefined) {
|
|
383
|
-
return initValue;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// Empty string fill doesn't need expansion (C handles {""} correctly)
|
|
387
|
-
if (fillVal === '""') {
|
|
388
|
-
return initValue;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
599
|
const declaredSize = StringDeclHelper._getFirstDimNumericSize(arrayDims);
|
|
392
|
-
|
|
393
|
-
return initValue;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
const elements = new Array<string>(declaredSize).fill(fillVal);
|
|
397
|
-
return `{${elements.join(", ")}}`;
|
|
600
|
+
return StringDeclHelper._expandFillAll(initValue, declaredSize);
|
|
398
601
|
}
|
|
399
602
|
|
|
400
603
|
/**
|
|
401
604
|
* Get the numeric size from the first array dimension, or null if not numeric.
|
|
605
|
+
* Used by arrayDimension-based string arrays (string<N> arr[M]).
|
|
402
606
|
*/
|
|
403
607
|
private static _getFirstDimNumericSize(
|
|
404
608
|
arrayDims: Parser.ArrayDimensionContext[],
|
|
405
609
|
): number | null {
|
|
406
610
|
const firstDimExpr = arrayDims[0]?.expression();
|
|
407
|
-
|
|
408
|
-
return null;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
const sizeText = firstDimExpr.getText();
|
|
412
|
-
if (!/^\d+$/.exec(sizeText)) {
|
|
413
|
-
return null;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
return Number.parseInt(sizeText, 10);
|
|
611
|
+
return StringDeclHelper._parseNumericSize(firstDimExpr);
|
|
417
612
|
}
|
|
418
613
|
|
|
419
614
|
/**
|
|
@@ -87,27 +87,6 @@ class SymbolLookupHelper {
|
|
|
87
87
|
return symbols.some((sym) => sym.kind === "namespace");
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
/**
|
|
91
|
-
* Check if a type name is from a C++ header.
|
|
92
|
-
* Issue #304: Used to determine whether to use {} or {0} for initialization.
|
|
93
|
-
* C++ types with constructors may fail with {0} but work with {}.
|
|
94
|
-
*/
|
|
95
|
-
static isCppType(
|
|
96
|
-
symbolTable: ISymbolTable | null | undefined,
|
|
97
|
-
typeName: string,
|
|
98
|
-
): boolean {
|
|
99
|
-
if (!symbolTable) return false;
|
|
100
|
-
|
|
101
|
-
const symbols = symbolTable.getOverloads(typeName);
|
|
102
|
-
const cppTypeKinds = new Set<TSymbolKind>(["struct", "class", "type"]);
|
|
103
|
-
|
|
104
|
-
return symbols.some(
|
|
105
|
-
(sym) =>
|
|
106
|
-
sym.sourceLanguage === ESourceLanguage.Cpp &&
|
|
107
|
-
cppTypeKinds.has(sym.kind),
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
90
|
/**
|
|
112
91
|
* Check if a function is a C-Next function (uses pass-by-reference semantics).
|
|
113
92
|
* Returns true if the function is found in symbol table as C-Next.
|
|
@@ -29,6 +29,19 @@ interface ITypeGenerationDeps {
|
|
|
29
29
|
validateCrossScopeVisibility: (scope: string, member: string) => void;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Common interface for type contexts that share the same type accessors.
|
|
34
|
+
* Both TypeContext and ArrayTypeContext have these methods.
|
|
35
|
+
*/
|
|
36
|
+
interface ITypeAccessors {
|
|
37
|
+
primitiveType(): Parser.PrimitiveTypeContext | null;
|
|
38
|
+
userType(): Parser.UserTypeContext | null;
|
|
39
|
+
stringType(): Parser.StringTypeContext | null;
|
|
40
|
+
scopedType(): Parser.ScopedTypeContext | null;
|
|
41
|
+
qualifiedType(): Parser.QualifiedTypeContext | null;
|
|
42
|
+
globalType(): Parser.GlobalTypeContext | null;
|
|
43
|
+
}
|
|
44
|
+
|
|
32
45
|
class TypeGenerationHelper {
|
|
33
46
|
/**
|
|
34
47
|
* Generate C type for a primitive type.
|
|
@@ -154,41 +167,35 @@ class TypeGenerationHelper {
|
|
|
154
167
|
}
|
|
155
168
|
|
|
156
169
|
/**
|
|
157
|
-
*
|
|
158
|
-
*
|
|
170
|
+
* Dispatch type generation for contexts that share common type accessors.
|
|
171
|
+
* Handles scoped, qualified, global, primitive, string, and user types.
|
|
172
|
+
* Used by both bare type contexts and array element type contexts.
|
|
173
|
+
*
|
|
174
|
+
* @returns The resolved C type string, or null if no matching type accessor found
|
|
159
175
|
*/
|
|
160
|
-
static
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
// Note: caller is responsible for handling the include
|
|
166
|
-
return result.cType;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Bounded string type
|
|
170
|
-
if (ctx.stringType()) {
|
|
176
|
+
private static dispatchTypeGeneration(
|
|
177
|
+
accessors: ITypeAccessors,
|
|
178
|
+
deps: ITypeGenerationDeps,
|
|
179
|
+
): string | null {
|
|
180
|
+
if (accessors.stringType()) {
|
|
171
181
|
return TypeGenerationHelper.generateStringType();
|
|
172
182
|
}
|
|
173
183
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const typeName = ctx.scopedType()!.IDENTIFIER().getText();
|
|
184
|
+
if (accessors.scopedType()) {
|
|
185
|
+
const typeName = accessors.scopedType()!.IDENTIFIER().getText();
|
|
177
186
|
return TypeGenerationHelper.generateScopedType(
|
|
178
187
|
typeName,
|
|
179
188
|
deps.currentScope,
|
|
180
189
|
);
|
|
181
190
|
}
|
|
182
191
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const typeName = ctx.globalType()!.IDENTIFIER().getText();
|
|
192
|
+
if (accessors.globalType()) {
|
|
193
|
+
const typeName = accessors.globalType()!.IDENTIFIER().getText();
|
|
186
194
|
return TypeGenerationHelper.generateGlobalType(typeName);
|
|
187
195
|
}
|
|
188
196
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const identifiers = ctx.qualifiedType()!.IDENTIFIER();
|
|
197
|
+
if (accessors.qualifiedType()) {
|
|
198
|
+
const identifiers = accessors.qualifiedType()!.IDENTIFIER();
|
|
192
199
|
const identifierNames = identifiers.map((id) => id.getText());
|
|
193
200
|
const isCpp = deps.isCppScopeSymbol(identifierNames[0]);
|
|
194
201
|
return TypeGenerationHelper.generateQualifiedType(
|
|
@@ -198,30 +205,44 @@ class TypeGenerationHelper {
|
|
|
198
205
|
);
|
|
199
206
|
}
|
|
200
207
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
208
|
+
if (accessors.primitiveType()) {
|
|
209
|
+
const type = accessors.primitiveType()!.getText();
|
|
210
|
+
return TYPE_MAP[type] || type;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (accessors.userType()) {
|
|
214
|
+
const typeName = accessors.userType()!.getText();
|
|
215
|
+
// ADR-046: cstring maps to char* for C library interop
|
|
216
|
+
if (typeName === "cstring") {
|
|
217
|
+
return "char*";
|
|
218
|
+
}
|
|
204
219
|
const needsStruct = deps.checkNeedsStructKeyword(typeName);
|
|
205
220
|
return TypeGenerationHelper.generateUserType(typeName, needsStruct);
|
|
206
221
|
}
|
|
207
222
|
|
|
208
|
-
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Full type generation using all dependencies.
|
|
228
|
+
* This is the main entry point that handles all type contexts.
|
|
229
|
+
*/
|
|
230
|
+
static generate(ctx: Parser.TypeContext, deps: ITypeGenerationDeps): string {
|
|
231
|
+
// Array type - dispatch on the element type
|
|
209
232
|
if (ctx.arrayType()) {
|
|
210
233
|
const arrCtx = ctx.arrayType()!;
|
|
211
|
-
|
|
212
|
-
if (
|
|
213
|
-
return
|
|
234
|
+
const result = TypeGenerationHelper.dispatchTypeGeneration(arrCtx, deps);
|
|
235
|
+
if (result !== null) {
|
|
236
|
+
return result;
|
|
214
237
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
needsStruct,
|
|
224
|
-
);
|
|
238
|
+
// Fallback for array types without recognized element type
|
|
239
|
+
return ctx.getText();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Non-array types - dispatch directly
|
|
243
|
+
const result = TypeGenerationHelper.dispatchTypeGeneration(ctx, deps);
|
|
244
|
+
if (result !== null) {
|
|
245
|
+
return result;
|
|
225
246
|
}
|
|
226
247
|
|
|
227
248
|
// Void or fallback
|