c-next 0.1.61 → 0.1.63

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.
Files changed (104) hide show
  1. package/README.md +86 -63
  2. package/grammar/CNext.g4 +3 -17
  3. package/package.json +1 -1
  4. package/src/cli/serve/ServeCommand.ts +57 -45
  5. package/src/lib/__tests__/parseCHeader.mocked.test.ts +145 -0
  6. package/src/transpiler/Transpiler.ts +603 -613
  7. package/src/transpiler/__tests__/DualCodePaths.test.ts +5 -1
  8. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +2 -99
  9. package/src/transpiler/__tests__/Transpiler.test.ts +3 -26
  10. package/src/transpiler/data/IncludeTreeWalker.ts +1 -1
  11. package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +23 -52
  12. package/src/transpiler/logic/parser/grammar/CNext.interp +1 -3
  13. package/src/transpiler/logic/parser/grammar/CNextListener.ts +0 -22
  14. package/src/transpiler/logic/parser/grammar/CNextParser.ts +665 -1084
  15. package/src/transpiler/logic/parser/grammar/CNextVisitor.ts +0 -14
  16. package/src/transpiler/logic/symbols/CppSymbolCollector.ts +67 -43
  17. package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
  18. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
  19. package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
  20. package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
  21. package/src/transpiler/output/codegen/CodeGenerator.ts +1410 -2587
  22. package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
  23. package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
  24. package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
  25. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +2082 -52
  26. package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
  27. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
  28. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
  29. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
  30. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +227 -66
  31. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +55 -58
  32. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +288 -275
  33. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
  34. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +195 -133
  35. package/src/transpiler/output/codegen/assignment/AssignmentContextBuilder.ts +24 -74
  36. package/src/transpiler/output/codegen/assignment/AssignmentKind.ts +3 -0
  37. package/src/transpiler/output/codegen/assignment/IAssignmentContext.ts +3 -0
  38. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +290 -320
  39. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +42 -0
  40. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +76 -2
  41. package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
  42. package/src/transpiler/output/codegen/generators/IOrchestrator.ts +5 -1
  43. package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
  44. package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
  45. package/src/transpiler/output/codegen/generators/declarationGenerators/RegisterGenerator.ts +11 -24
  46. package/src/transpiler/output/codegen/generators/declarationGenerators/RegisterMacroGenerator.ts +64 -0
  47. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +137 -61
  48. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopedRegisterGenerator.ts +18 -27
  49. package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
  50. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
  51. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
  52. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +5 -1
  53. package/src/transpiler/output/codegen/generators/statements/ControlFlowGenerator.ts +1 -17
  54. package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
  55. package/src/transpiler/output/codegen/helpers/ArrayAccessHelper.ts +129 -0
  56. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
  57. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +40 -44
  58. package/src/transpiler/output/codegen/helpers/AssignmentTargetExtractor.ts +17 -45
  59. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +83 -78
  60. package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
  61. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
  62. package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
  63. package/src/transpiler/output/codegen/helpers/MemberSeparatorResolver.ts +10 -3
  64. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
  65. package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +44 -0
  66. package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
  67. package/src/transpiler/output/codegen/helpers/__tests__/ArrayAccessHelper.test.ts +479 -0
  68. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
  69. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
  70. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
  71. package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
  72. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
  73. package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
  74. package/src/transpiler/output/codegen/helpers/__tests__/MemberSeparatorResolver.test.ts +1 -0
  75. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
  76. package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +201 -0
  77. package/src/transpiler/output/codegen/helpers/__tests__/TypeGenerationHelper.test.ts +50 -0
  78. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
  79. package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
  80. package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
  81. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
  82. package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
  83. package/src/transpiler/output/codegen/types/IArrayAccessDeps.ts +23 -0
  84. package/src/transpiler/output/codegen/types/IArrayAccessInfo.ts +26 -0
  85. package/src/transpiler/output/codegen/types/IMemberSeparatorDeps.ts +7 -0
  86. package/src/transpiler/output/codegen/utils/CodegenParserUtils.ts +98 -0
  87. package/src/transpiler/output/codegen/utils/ExpressionUnwrapper.ts +22 -22
  88. package/src/transpiler/output/codegen/utils/__tests__/CodegenParserUtils.test.ts +228 -0
  89. package/src/transpiler/types/IFileResult.ts +0 -4
  90. package/src/transpiler/types/IPipelineFile.ts +27 -0
  91. package/src/transpiler/types/IPipelineInput.ts +23 -0
  92. package/src/transpiler/types/TranspilerState.ts +1 -1
  93. package/src/utils/FormatUtils.ts +28 -2
  94. package/src/utils/MapUtils.ts +25 -0
  95. package/src/utils/PostfixAnalysisUtils.ts +48 -0
  96. package/src/utils/__tests__/FormatUtils.test.ts +42 -0
  97. package/src/utils/__tests__/MapUtils.test.ts +85 -0
  98. package/src/utils/constants/OperatorMappings.ts +19 -0
  99. package/src/transpiler/logic/StandaloneContextBuilder.ts +0 -150
  100. package/src/transpiler/logic/__tests__/StandaloneContextBuilder.test.ts +0 -647
  101. package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
  102. package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
  103. package/src/transpiler/types/ITranspileContext.ts +0 -49
  104. package/src/transpiler/types/ITranspileContribution.ts +0 -32
@@ -77,8 +77,6 @@ import { FieldInitializerListContext } from "./CNextParser.js";
77
77
  import { FieldInitializerContext } from "./CNextParser.js";
78
78
  import { ArrayInitializerContext } from "./CNextParser.js";
79
79
  import { ArrayInitializerElementContext } from "./CNextParser.js";
80
- import { MemberAccessContext } from "./CNextParser.js";
81
- import { ArrayAccessContext } from "./CNextParser.js";
82
80
  import { ArgumentListContext } from "./CNextParser.js";
83
81
  import { TypeContext } from "./CNextParser.js";
84
82
  import { ScopedTypeContext } from "./CNextParser.js";
@@ -546,18 +544,6 @@ export class CNextVisitor<Result> extends AbstractParseTreeVisitor<Result> {
546
544
  * @return the visitor result
547
545
  */
548
546
  visitArrayInitializerElement?: (ctx: ArrayInitializerElementContext) => Result;
549
- /**
550
- * Visit a parse tree produced by `CNextParser.memberAccess`.
551
- * @param ctx the parse tree
552
- * @return the visitor result
553
- */
554
- visitMemberAccess?: (ctx: MemberAccessContext) => Result;
555
- /**
556
- * Visit a parse tree produced by `CNextParser.arrayAccess`.
557
- * @param ctx the parse tree
558
- * @return the visitor result
559
- */
560
- visitArrayAccess?: (ctx: ArrayAccessContext) => Result;
561
547
  /**
562
548
  * Visit a parse tree produced by `CNextParser.argumentList`.
563
549
  * @param ctx the parse tree
@@ -39,6 +39,55 @@ class CppSymbolCollector {
39
39
  return SymbolCollectorContext.getWarnings(this.ctx);
40
40
  }
41
41
 
42
+ // ========================================================================
43
+ // Symbol Creation Helpers (Issue #707: Reduce code duplication)
44
+ // ========================================================================
45
+
46
+ /**
47
+ * Add a class/struct symbol to the symbol table.
48
+ */
49
+ private _addClassSymbol(fullName: string, line: number): void {
50
+ SymbolCollectorContext.addSymbol(this.ctx, {
51
+ name: fullName,
52
+ kind: ESymbolKind.Class,
53
+ sourceFile: this.ctx.sourceFile,
54
+ sourceLine: line,
55
+ sourceLanguage: ESourceLanguage.Cpp,
56
+ isExported: true,
57
+ parent: this.currentNamespace,
58
+ });
59
+ }
60
+
61
+ /**
62
+ * Add a member function symbol to the symbol table.
63
+ */
64
+ private _addMemberFunctionSymbol(
65
+ className: string,
66
+ funcName: string,
67
+ returnType: string,
68
+ params: Array<{
69
+ name: string;
70
+ type: string;
71
+ isConst: boolean;
72
+ isArray: boolean;
73
+ }>,
74
+ line: number,
75
+ isDeclaration: boolean,
76
+ ): void {
77
+ SymbolCollectorContext.addSymbol(this.ctx, {
78
+ name: `${className}::${funcName}`,
79
+ kind: ESymbolKind.Function,
80
+ type: returnType,
81
+ sourceFile: this.ctx.sourceFile,
82
+ sourceLine: line,
83
+ sourceLanguage: ESourceLanguage.Cpp,
84
+ isExported: true,
85
+ isDeclaration: isDeclaration || undefined,
86
+ parent: className,
87
+ parameters: params.length > 0 ? params : undefined,
88
+ });
89
+ }
90
+
42
91
  /**
43
92
  * Collect all symbols from a C++ translation unit
44
93
  */
@@ -257,15 +306,7 @@ class CppSymbolCollector {
257
306
  const memberSpec = anonymousClassSpec.memberSpecification?.();
258
307
  if (!memberSpec) return false;
259
308
 
260
- SymbolCollectorContext.addSymbol(this.ctx, {
261
- name: fullName,
262
- kind: ESymbolKind.Class,
263
- sourceFile: this.ctx.sourceFile,
264
- sourceLine: line,
265
- sourceLanguage: ESourceLanguage.Cpp,
266
- isExported: true,
267
- parent: this.currentNamespace,
268
- });
309
+ this._addClassSymbol(fullName, line);
269
310
  this.collectClassMembers(fullName, memberSpec);
270
311
  return true;
271
312
  }
@@ -348,15 +389,7 @@ class CppSymbolCollector {
348
389
  ? `${this.currentNamespace}::${name}`
349
390
  : name;
350
391
 
351
- SymbolCollectorContext.addSymbol(this.ctx, {
352
- name: fullName,
353
- kind: ESymbolKind.Class,
354
- sourceFile: this.ctx.sourceFile,
355
- sourceLine: line,
356
- sourceLanguage: ESourceLanguage.Cpp,
357
- isExported: true,
358
- parent: this.currentNamespace,
359
- });
392
+ this._addClassSymbol(fullName, line);
360
393
 
361
394
  // Extract struct/class field information if SymbolTable is available
362
395
  if (this.ctx.symbolTable) {
@@ -429,18 +462,14 @@ class CppSymbolCollector {
429
462
  ? this.extractTypeFromDeclSpecSeq(declSpecSeq)
430
463
  : "void";
431
464
  const params = this.extractFunctionParameters(declarator);
432
-
433
- SymbolCollectorContext.addSymbol(this.ctx, {
434
- name: `${className}::${funcName}`,
435
- kind: ESymbolKind.Function,
436
- type: returnType,
437
- sourceFile: this.ctx.sourceFile,
438
- sourceLine: line,
439
- sourceLanguage: ESourceLanguage.Cpp,
440
- isExported: true,
441
- parent: className,
442
- parameters: params.length > 0 ? params : undefined,
443
- });
465
+ this._addMemberFunctionSymbol(
466
+ className,
467
+ funcName,
468
+ returnType,
469
+ params,
470
+ line,
471
+ false,
472
+ );
444
473
  }
445
474
 
446
475
  /**
@@ -484,19 +513,14 @@ class CppSymbolCollector {
484
513
  line: number,
485
514
  ): void {
486
515
  const params = this.extractFunctionParameters(declarator);
487
-
488
- SymbolCollectorContext.addSymbol(this.ctx, {
489
- name: `${className}::${funcName}`,
490
- kind: ESymbolKind.Function,
491
- type: returnType,
492
- sourceFile: this.ctx.sourceFile,
493
- sourceLine: line,
494
- sourceLanguage: ESourceLanguage.Cpp,
495
- isExported: true,
496
- isDeclaration: true,
497
- parent: className,
498
- parameters: params.length > 0 ? params : undefined,
499
- });
516
+ this._addMemberFunctionSymbol(
517
+ className,
518
+ funcName,
519
+ returnType,
520
+ params,
521
+ line,
522
+ true,
523
+ );
500
524
  }
501
525
 
502
526
  /**
@@ -11,29 +11,98 @@ import IFieldInfo from "../../types/IFieldInfo";
11
11
  import TypeUtils from "../utils/TypeUtils";
12
12
  import LiteralUtils from "../../../../../utils/LiteralUtils";
13
13
 
14
- class StructCollector {
15
- /**
16
- * Parse array dimension expressions and append resolved sizes to dimensions array.
17
- */
18
- private static parseArrayDimensions(
19
- arrayDims: Parser.ArrayDimensionContext[],
20
- dimensions: number[],
21
- constValues?: Map<string, number>,
22
- ): void {
23
- for (const dim of arrayDims) {
24
- const sizeExpr = dim.expression();
25
- if (sizeExpr) {
26
- const dimText = sizeExpr.getText();
27
- const literalSize = LiteralUtils.parseIntegerLiteral(dimText);
28
- if (literalSize !== undefined) {
29
- dimensions.push(literalSize);
30
- } else if (constValues?.has(dimText)) {
31
- dimensions.push(constValues.get(dimText)!);
32
- }
14
+ /**
15
+ * Result of processing an arrayType syntax context.
16
+ */
17
+ interface IArrayTypeResult {
18
+ isArray: boolean;
19
+ dimension: number | undefined;
20
+ }
21
+
22
+ /**
23
+ * Process arrayType syntax (e.g., Item[3] items) and return array info.
24
+ */
25
+ function processArrayTypeSyntax(
26
+ arrayTypeCtx: Parser.ArrayTypeContext | null | undefined,
27
+ constValues?: Map<string, number>,
28
+ ): IArrayTypeResult {
29
+ if (!arrayTypeCtx) {
30
+ return { isArray: false, dimension: undefined };
31
+ }
32
+
33
+ const sizeExpr = arrayTypeCtx.expression();
34
+ if (!sizeExpr) {
35
+ return { isArray: true, dimension: undefined };
36
+ }
37
+
38
+ const resolved = tryResolveExpressionDimension(sizeExpr, constValues);
39
+ return { isArray: true, dimension: resolved };
40
+ }
41
+
42
+ /**
43
+ * Process string type fields and update dimensions array.
44
+ */
45
+ function processStringField(
46
+ stringCtx: Parser.StringTypeContext,
47
+ arrayDims: Parser.ArrayDimensionContext[],
48
+ dimensions: number[],
49
+ constValues?: Map<string, number>,
50
+ ): boolean {
51
+ const intLiteral = stringCtx.INTEGER_LITERAL();
52
+ if (!intLiteral) {
53
+ return false;
54
+ }
55
+
56
+ const capacity = Number.parseInt(intLiteral.getText(), 10);
57
+
58
+ // If there are array dimensions, they come BEFORE string capacity
59
+ if (arrayDims.length > 0) {
60
+ parseArrayDimensions(arrayDims, dimensions, constValues);
61
+ }
62
+ // String capacity becomes final dimension (+1 for null terminator)
63
+ dimensions.push(capacity + 1);
64
+ return true;
65
+ }
66
+
67
+ /**
68
+ * Try to resolve a single expression as a numeric dimension.
69
+ * Handles integer literals and const references.
70
+ */
71
+ function tryResolveExpressionDimension(
72
+ sizeExpr: Parser.ExpressionContext,
73
+ constValues?: Map<string, number>,
74
+ ): number | undefined {
75
+ const dimText = sizeExpr.getText();
76
+ const literalSize = LiteralUtils.parseIntegerLiteral(dimText);
77
+ if (literalSize !== undefined) {
78
+ return literalSize;
79
+ }
80
+ if (constValues?.has(dimText)) {
81
+ return constValues.get(dimText);
82
+ }
83
+ return undefined;
84
+ }
85
+
86
+ /**
87
+ * Parse array dimension expressions and append resolved sizes to dimensions array.
88
+ */
89
+ function parseArrayDimensions(
90
+ arrayDims: Parser.ArrayDimensionContext[],
91
+ dimensions: number[],
92
+ constValues?: Map<string, number>,
93
+ ): void {
94
+ for (const dim of arrayDims) {
95
+ const sizeExpr = dim.expression();
96
+ if (sizeExpr) {
97
+ const resolved = tryResolveExpressionDimension(sizeExpr, constValues);
98
+ if (resolved !== undefined) {
99
+ dimensions.push(resolved);
33
100
  }
34
101
  }
35
102
  }
103
+ }
36
104
 
105
+ class StructCollector {
37
106
  /**
38
107
  * Collect a struct declaration and return an IStructSymbol.
39
108
  *
@@ -56,57 +125,12 @@ class StructCollector {
56
125
  const fields = new Map<string, IFieldInfo>();
57
126
 
58
127
  for (const member of ctx.structMember()) {
59
- const fieldName = member.IDENTIFIER().getText();
60
- const typeCtx = member.type();
61
- const fieldType = TypeUtils.getTypeName(typeCtx, scopeName);
62
- // Note: C-Next struct members don't have const modifier in grammar
63
- const isConst = false;
64
-
65
- const arrayDims = member.arrayDimension();
66
- const dimensions: number[] = [];
67
- let isArray = false;
68
-
69
- // Handle string types specially
70
- if (typeCtx.stringType()) {
71
- const stringCtx = typeCtx.stringType()!;
72
- const intLiteral = stringCtx.INTEGER_LITERAL();
73
-
74
- if (intLiteral) {
75
- const capacity = Number.parseInt(intLiteral.getText(), 10);
76
-
77
- // If there are array dimensions, they come BEFORE string capacity
78
- if (arrayDims.length > 0) {
79
- StructCollector.parseArrayDimensions(
80
- arrayDims,
81
- dimensions,
82
- constValues,
83
- );
84
- }
85
- // String capacity becomes final dimension (+1 for null terminator)
86
- dimensions.push(capacity + 1);
87
- isArray = true;
88
- }
89
- } else if (arrayDims.length > 0) {
90
- // Non-string array
91
- isArray = true;
92
- StructCollector.parseArrayDimensions(
93
- arrayDims,
94
- dimensions,
95
- constValues,
96
- );
97
- }
98
-
99
- const fieldInfo: IFieldInfo = {
100
- type: fieldType,
101
- isArray,
102
- isConst,
103
- };
104
-
105
- if (dimensions.length > 0) {
106
- fieldInfo.dimensions = dimensions;
107
- }
108
-
109
- fields.set(fieldName, fieldInfo);
128
+ const fieldInfo = StructCollector.collectField(
129
+ member,
130
+ scopeName,
131
+ constValues,
132
+ );
133
+ fields.set(member.IDENTIFIER().getText(), fieldInfo);
110
134
  }
111
135
 
112
136
  return {
@@ -120,6 +144,68 @@ class StructCollector {
120
144
  fields,
121
145
  };
122
146
  }
147
+
148
+ /**
149
+ * Collect a single struct field and return its IFieldInfo.
150
+ */
151
+ private static collectField(
152
+ member: Parser.StructMemberContext,
153
+ scopeName?: string,
154
+ constValues?: Map<string, number>,
155
+ ): IFieldInfo {
156
+ const typeCtx = member.type();
157
+ const fieldType = TypeUtils.getTypeName(typeCtx, scopeName);
158
+ // Note: C-Next struct members don't have const modifier in grammar
159
+ const isConst = false;
160
+
161
+ const arrayDims = member.arrayDimension();
162
+ const dimensions: number[] = [];
163
+ let isArray = false;
164
+
165
+ // Check for C-Next style arrayType syntax: Item[3] items -> typeCtx.arrayType()
166
+ const arrayTypeResult = processArrayTypeSyntax(
167
+ typeCtx.arrayType(),
168
+ constValues,
169
+ );
170
+ if (arrayTypeResult.isArray) {
171
+ isArray = true;
172
+ if (arrayTypeResult.dimension !== undefined) {
173
+ dimensions.push(arrayTypeResult.dimension);
174
+ }
175
+ // Note: non-literal, non-const expressions (like global.EnumName.COUNT)
176
+ // won't be resolvable at symbol collection time - dimensions stays empty
177
+ // but isArray is still true so the field is tracked as an array
178
+ }
179
+
180
+ // Handle string types specially
181
+ if (typeCtx.stringType()) {
182
+ const stringHandled = processStringField(
183
+ typeCtx.stringType()!,
184
+ arrayDims,
185
+ dimensions,
186
+ constValues,
187
+ );
188
+ if (stringHandled) {
189
+ isArray = true;
190
+ }
191
+ } else if (arrayDims.length > 0) {
192
+ // Non-string array
193
+ isArray = true;
194
+ parseArrayDimensions(arrayDims, dimensions, constValues);
195
+ }
196
+
197
+ const fieldInfo: IFieldInfo = {
198
+ type: fieldType,
199
+ isArray,
200
+ isConst,
201
+ };
202
+
203
+ if (dimensions.length > 0) {
204
+ fieldInfo.dimensions = dimensions;
205
+ }
206
+
207
+ return fieldInfo;
208
+ }
123
209
  }
124
210
 
125
211
  export default StructCollector;
@@ -9,6 +9,7 @@ import ESymbolKind from "../../../../../utils/types/ESymbolKind";
9
9
  import IVariableSymbol from "../../types/IVariableSymbol";
10
10
  import ArrayInitializerUtils from "../utils/ArrayInitializerUtils";
11
11
  import TypeUtils from "../utils/TypeUtils";
12
+ import LiteralUtils from "../../../../../utils/LiteralUtils";
12
13
 
13
14
  class VariableCollector {
14
15
  /**
@@ -101,17 +102,41 @@ class VariableCollector {
101
102
  // Issue #468: Check for atomic modifier
102
103
  const isAtomic = ctx.atomicModifier() !== null;
103
104
 
104
- // Check for array dimensions
105
+ // Check for array dimensions - both C-style (arrayDimension) and C-Next style (arrayType)
105
106
  const arrayDims = ctx.arrayDimension();
106
- const isArray = arrayDims.length > 0;
107
+ const arrayTypeCtx = typeCtx.arrayType();
108
+ const hasArrayTypeSyntax = arrayTypeCtx !== null;
109
+ const isArray = arrayDims.length > 0 || hasArrayTypeSyntax;
107
110
  const initExpr = ctx.expression();
108
- const arrayDimensions = isArray
109
- ? VariableCollector.collectArrayDimensions(
111
+ const arrayDimensions: (number | string)[] = [];
112
+
113
+ // Collect dimension from arrayType syntax (u16[8] arr)
114
+ if (hasArrayTypeSyntax) {
115
+ const sizeExpr = arrayTypeCtx.expression();
116
+ if (sizeExpr) {
117
+ const dimText = sizeExpr.getText();
118
+ const literalSize = LiteralUtils.parseIntegerLiteral(dimText);
119
+ if (literalSize !== undefined) {
120
+ arrayDimensions.push(literalSize);
121
+ } else if (constValues?.has(dimText)) {
122
+ arrayDimensions.push(constValues.get(dimText)!);
123
+ } else {
124
+ // Keep as string for macro/enum references
125
+ arrayDimensions.push(dimText);
126
+ }
127
+ }
128
+ }
129
+
130
+ // Collect additional dimensions from arrayDimension syntax
131
+ if (arrayDims.length > 0) {
132
+ arrayDimensions.push(
133
+ ...VariableCollector.collectArrayDimensions(
110
134
  arrayDims,
111
135
  constValues,
112
136
  initExpr,
113
- )
114
- : [];
137
+ ),
138
+ );
139
+ }
115
140
 
116
141
  // Issue #282: Capture initial value for const inlining
117
142
  const initialValue = initExpr?.getText();
@@ -5,6 +5,41 @@
5
5
  import * as Parser from "../../../parser/grammar/CNextParser";
6
6
  import CNEXT_TO_C_TYPE_MAP from "../../../../../utils/constants/TypeMappings";
7
7
 
8
+ /**
9
+ * Resolve scoped type (this.Type) to full name.
10
+ */
11
+ function resolveScopedType(
12
+ scopedTypeCtx: Parser.ScopedTypeContext,
13
+ scopeName?: string,
14
+ ): string {
15
+ const typeName = scopedTypeCtx.IDENTIFIER().getText();
16
+ return scopeName ? `${scopeName}_${typeName}` : typeName;
17
+ }
18
+
19
+ /**
20
+ * Resolve string type with optional capacity.
21
+ */
22
+ function resolveStringType(stringCtx: Parser.StringTypeContext): string {
23
+ const intLiteral = stringCtx.INTEGER_LITERAL();
24
+ return intLiteral ? `string<${intLiteral.getText()}>` : "string";
25
+ }
26
+
27
+ /**
28
+ * Extract inner type from arrayType context.
29
+ */
30
+ function resolveArrayInnerType(arrayTypeCtx: Parser.ArrayTypeContext): string {
31
+ if (arrayTypeCtx.primitiveType()) {
32
+ return arrayTypeCtx.primitiveType()!.getText();
33
+ }
34
+ if (arrayTypeCtx.userType()) {
35
+ return arrayTypeCtx.userType()!.getText();
36
+ }
37
+ // Fallback for other nested types - strip the dimension part
38
+ const text = arrayTypeCtx.getText();
39
+ const bracketIdx = text.indexOf("[");
40
+ return bracketIdx > 0 ? text.substring(0, bracketIdx) : text;
41
+ }
42
+
8
43
  class TypeUtils {
9
44
  /**
10
45
  * Extract the type name from a type context.
@@ -23,11 +58,7 @@ class TypeUtils {
23
58
 
24
59
  // Handle this.Type for scoped types (e.g., this.State -> Motor_State)
25
60
  if (ctx.scopedType()) {
26
- const typeName = ctx.scopedType()!.IDENTIFIER().getText();
27
- if (scopeName) {
28
- return `${scopeName}_${typeName}`;
29
- }
30
- return typeName;
61
+ return resolveScopedType(ctx.scopedType()!, scopeName);
31
62
  }
32
63
 
33
64
  // Issue #478: Handle global.Type for global types inside scope
@@ -54,12 +85,13 @@ class TypeUtils {
54
85
 
55
86
  // Handle string types - preserve capacity for validation (Issue #139)
56
87
  if (ctx.stringType()) {
57
- const stringCtx = ctx.stringType()!;
58
- const intLiteral = stringCtx.INTEGER_LITERAL();
59
- if (intLiteral) {
60
- return `string<${intLiteral.getText()}>`;
61
- }
62
- return "string";
88
+ return resolveStringType(ctx.stringType()!);
89
+ }
90
+
91
+ // Handle arrayType: Type[size] - extract the inner type without dimension
92
+ // The dimension is tracked separately in arrayDimensions
93
+ if (ctx.arrayType()) {
94
+ return resolveArrayInnerType(ctx.arrayType()!);
63
95
  }
64
96
 
65
97
  // Fallback