c-next 0.1.62 → 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 (55) hide show
  1. package/README.md +86 -63
  2. package/package.json +1 -1
  3. package/src/transpiler/Transpiler.ts +3 -2
  4. package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
  5. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +1 -1
  6. package/src/transpiler/__tests__/Transpiler.test.ts +0 -23
  7. package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
  8. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
  9. package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
  10. package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
  11. package/src/transpiler/output/codegen/CodeGenerator.ts +817 -1377
  12. package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
  13. package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
  14. package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
  15. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +326 -60
  16. package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
  17. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
  18. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
  19. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
  20. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +39 -43
  21. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +52 -55
  22. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +122 -62
  23. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
  24. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +143 -126
  25. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +287 -320
  26. package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
  27. package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
  28. package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
  29. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +121 -51
  30. package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
  31. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
  32. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
  33. package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
  34. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
  35. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +21 -30
  36. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +56 -53
  37. package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
  38. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
  39. package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
  40. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
  41. package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
  42. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
  43. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
  44. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
  45. package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
  46. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
  47. package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
  48. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
  49. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
  50. package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
  51. package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
  52. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
  53. package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
  54. package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
  55. package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
@@ -9,29 +9,18 @@
9
9
  * 2. memcpy float → shadow (if not already current)
10
10
  * 3. Modify shadow bits
11
11
  * 4. memcpy shadow → float
12
+ *
13
+ * Migrated to use CodeGenState instead of constructor DI.
12
14
  */
13
15
 
14
16
  import TTypeInfo from "../types/TTypeInfo.js";
15
17
  import TIncludeHeader from "../generators/TIncludeHeader.js";
18
+ import CodeGenState from "../CodeGenState.js";
16
19
 
17
20
  /**
18
- * State tracking for float bit shadows.
19
- */
20
- interface IFloatBitState {
21
- /** Shadow variables already declared in current scope */
22
- floatBitShadows: Set<string>;
23
- /** Shadows that currently hold the float's value (skip redundant memcpy read) */
24
- floatShadowCurrent: Set<string>;
25
- }
26
-
27
- /**
28
- * Dependencies required for float bit write generation.
21
+ * Callback types for code generation operations.
29
22
  */
30
- interface IFloatBitHelperDeps {
31
- /** Whether we're generating C++ code */
32
- cppMode: boolean;
33
- /** Float bit shadow tracking state */
34
- state: IFloatBitState;
23
+ interface IFloatBitCallbacks {
35
24
  /** Generate a bit mask expression */
36
25
  generateBitMask: (width: string, is64Bit?: boolean) => string;
37
26
  /** Fold boolean expressions to 0/1 integer */
@@ -47,12 +36,6 @@ interface IFloatBitHelperDeps {
47
36
  * For bit range: width is provided, uses bitIndex as start position
48
37
  */
49
38
  class FloatBitHelper {
50
- private readonly deps: IFloatBitHelperDeps;
51
-
52
- constructor(deps: IFloatBitHelperDeps) {
53
- this.deps = deps;
54
- }
55
-
56
39
  /**
57
40
  * Generate float bit write using shadow variable + memcpy.
58
41
  * Returns null if typeInfo is not a float type.
@@ -62,14 +45,16 @@ class FloatBitHelper {
62
45
  * @param bitIndex - Bit index expression (start position)
63
46
  * @param width - Bit width expression (null for single bit)
64
47
  * @param value - Value to write
48
+ * @param callbacks - Code generation callbacks
65
49
  * @returns Generated C code, or null if not a float type
66
50
  */
67
- generateFloatBitWrite(
51
+ static generateFloatBitWrite(
68
52
  name: string,
69
53
  typeInfo: TTypeInfo,
70
54
  bitIndex: string,
71
55
  width: string | null,
72
56
  value: string,
57
+ callbacks: IFloatBitCallbacks,
73
58
  ): string | null {
74
59
  const isFloatType =
75
60
  typeInfo.baseType === "f32" || typeInfo.baseType === "f64";
@@ -77,8 +62,8 @@ class FloatBitHelper {
77
62
  return null;
78
63
  }
79
64
 
80
- this.deps.requireInclude("string"); // For memcpy
81
- this.deps.requireInclude("float_static_assert"); // For size verification
65
+ callbacks.requireInclude("string"); // For memcpy
66
+ callbacks.requireInclude("float_static_assert"); // For size verification
82
67
 
83
68
  const isF64 = typeInfo.baseType === "f64";
84
69
  const shadowType = isF64 ? "uint64_t" : "uint32_t";
@@ -86,13 +71,13 @@ class FloatBitHelper {
86
71
  const maskSuffix = isF64 ? "ULL" : "U";
87
72
 
88
73
  // Check if shadow variable needs declaration
89
- const needsDeclaration = !this.deps.state.floatBitShadows.has(shadowName);
74
+ const needsDeclaration = !CodeGenState.floatBitShadows.has(shadowName);
90
75
  if (needsDeclaration) {
91
- this.deps.state.floatBitShadows.add(shadowName);
76
+ CodeGenState.floatBitShadows.add(shadowName);
92
77
  }
93
78
 
94
79
  // Check if shadow already has current value (skip redundant memcpy read)
95
- const shadowIsCurrent = this.deps.state.floatShadowCurrent.has(shadowName);
80
+ const shadowIsCurrent = CodeGenState.floatShadowCurrent.has(shadowName);
96
81
 
97
82
  const decl = needsDeclaration ? `${shadowType} ${shadowName}; ` : "";
98
83
  const readMemcpy = shadowIsCurrent
@@ -100,18 +85,18 @@ class FloatBitHelper {
100
85
  : `memcpy(&${shadowName}, &${name}, sizeof(${name})); `;
101
86
 
102
87
  // Mark shadow as current after this write
103
- this.deps.state.floatShadowCurrent.add(shadowName);
88
+ CodeGenState.floatShadowCurrent.add(shadowName);
104
89
 
105
90
  if (width === null) {
106
91
  // Single bit assignment: floatVar[3] <- true
107
92
  return (
108
93
  `${decl}${readMemcpy}` +
109
- `${shadowName} = (${shadowName} & ~(1${maskSuffix} << ${bitIndex})) | ((${shadowType})${this.deps.foldBooleanToInt(value)} << ${bitIndex}); ` +
94
+ `${shadowName} = (${shadowName} & ~(1${maskSuffix} << ${bitIndex})) | ((${shadowType})${callbacks.foldBooleanToInt(value)} << ${bitIndex}); ` +
110
95
  `memcpy(&${name}, &${shadowName}, sizeof(${name}));`
111
96
  );
112
97
  } else {
113
98
  // Bit range assignment: floatVar[0, 8] <- b0
114
- const mask = this.deps.generateBitMask(width, isF64);
99
+ const mask = callbacks.generateBitMask(width, isF64);
115
100
  return (
116
101
  `${decl}${readMemcpy}` +
117
102
  `${shadowName} = (${shadowName} & ~(${mask} << ${bitIndex})) | (((${shadowType})${value} & ${mask}) << ${bitIndex}); ` +
@@ -2,6 +2,7 @@
2
2
  * StringDeclHelper - Generates string variable declarations
3
3
  *
4
4
  * Issue #644: Extracted from CodeGenerator to reduce file size.
5
+ * Migrated to use CodeGenState instead of constructor DI.
5
6
  *
6
7
  * Handles all string-related declaration patterns:
7
8
  * - Bounded strings: string<64> name
@@ -13,7 +14,8 @@
13
14
 
14
15
  import * as Parser from "../../../logic/parser/grammar/CNextParser.js";
15
16
  import FormatUtils from "../../../../utils/FormatUtils.js";
16
- import TTypeInfo from "../types/TTypeInfo.js";
17
+ import StringUtils from "../../../../utils/StringUtils.js";
18
+ import CodeGenState from "../CodeGenState.js";
17
19
 
18
20
  /** C null terminator character literal for generated code */
19
21
  const C_NULL_CHAR = String.raw`'\0'`;
@@ -39,27 +41,30 @@ interface ISubstringOps {
39
41
  }
40
42
 
41
43
  /**
42
- * Array initialization tracking state.
44
+ * Declaration modifiers for string variable declarations.
43
45
  */
44
- interface IArrayInitState {
45
- lastArrayInitCount: number;
46
- lastArrayFillValue: string | undefined;
46
+ interface IStringDeclModifiers {
47
+ extern: string;
48
+ const: string;
49
+ atomic: string;
50
+ volatile: string;
47
51
  }
48
52
 
49
53
  /**
50
- * Dependencies required for string declaration generation.
54
+ * Result from generating a string declaration.
51
55
  */
52
- interface IStringDeclHelperDeps {
53
- /** Type registry for looking up variable types */
54
- typeRegistry: Map<string, TTypeInfo>;
55
- /** Get whether currently inside a function body */
56
- getInFunctionBody: () => boolean;
57
- /** Get current indentation level */
58
- getIndentLevel: () => number;
59
- /** Array initialization tracking */
60
- arrayInitState: IArrayInitState;
61
- /** Local arrays set */
62
- localArrays: Set<string>;
56
+ interface IStringDeclResult {
57
+ /** The generated C code */
58
+ code: string;
59
+ /** Whether the declaration was handled (false = not a string type) */
60
+ handled: boolean;
61
+ }
62
+
63
+ /**
64
+ * Callbacks required for string declaration generation.
65
+ * These need CodeGenerator context and cannot be replaced with static state.
66
+ */
67
+ interface IStringDeclCallbacks {
63
68
  /** Generate expression code */
64
69
  generateExpression: (ctx: Parser.ExpressionContext) => string;
65
70
  /** Generate array dimensions */
@@ -70,55 +75,28 @@ interface IStringDeclHelperDeps {
70
75
  ) => IStringConcatOps | null;
71
76
  /** Get substring extraction operands */
72
77
  getSubstringOperands: (ctx: Parser.ExpressionContext) => ISubstringOps | null;
73
- /** Get string literal length */
74
- getStringLiteralLength: (literal: string) => number;
75
78
  /** Get string expression capacity */
76
79
  getStringExprCapacity: (exprCode: string) => number | null;
77
80
  /** Request string include */
78
81
  requireStringInclude: () => void;
79
82
  }
80
83
 
81
- /**
82
- * Declaration modifiers for string variable declarations.
83
- */
84
- interface IStringDeclModifiers {
85
- extern: string;
86
- const: string;
87
- atomic: string;
88
- volatile: string;
89
- }
90
-
91
- /**
92
- * Result from generating a string declaration.
93
- */
94
- interface IStringDeclResult {
95
- /** The generated C code */
96
- code: string;
97
- /** Whether the declaration was handled (false = not a string type) */
98
- handled: boolean;
99
- }
100
-
101
84
  /**
102
85
  * Generates string variable declarations in C.
103
86
  */
104
87
  class StringDeclHelper {
105
- private readonly deps: IStringDeclHelperDeps;
106
-
107
- constructor(deps: IStringDeclHelperDeps) {
108
- this.deps = deps;
109
- }
110
-
111
88
  /**
112
89
  * Generate string declaration if the type is a string type.
113
90
  * Returns { handled: false } if not a string type.
114
91
  */
115
- generateStringDecl(
92
+ static generateStringDecl(
116
93
  typeCtx: Parser.TypeContext,
117
94
  name: string,
118
95
  expression: Parser.ExpressionContext | null,
119
96
  arrayDims: Parser.ArrayDimensionContext[],
120
97
  modifiers: IStringDeclModifiers,
121
98
  isConst: boolean,
99
+ callbacks: IStringDeclCallbacks,
122
100
  ): IStringDeclResult {
123
101
  const stringCtx = typeCtx.stringType();
124
102
  if (!stringCtx) {
@@ -130,21 +108,23 @@ class StringDeclHelper {
130
108
  if (intLiteral) {
131
109
  // Bounded string with explicit capacity
132
110
  const capacity = Number.parseInt(intLiteral.getText(), 10);
133
- return this.generateBoundedStringDecl(
111
+ return StringDeclHelper._generateBoundedStringDecl(
134
112
  name,
135
113
  capacity,
136
114
  expression,
137
115
  arrayDims,
138
116
  modifiers,
139
117
  isConst,
118
+ callbacks,
140
119
  );
141
120
  } else {
142
121
  // Unsized string - requires const and literal
143
- return this.generateUnsizedStringDecl(
122
+ return StringDeclHelper._generateUnsizedStringDecl(
144
123
  name,
145
124
  expression,
146
125
  modifiers,
147
126
  isConst,
127
+ callbacks,
148
128
  );
149
129
  }
150
130
  }
@@ -152,25 +132,27 @@ class StringDeclHelper {
152
132
  /**
153
133
  * Generate bounded string declaration (string<N>).
154
134
  */
155
- private generateBoundedStringDecl(
135
+ private static _generateBoundedStringDecl(
156
136
  name: string,
157
137
  capacity: number,
158
138
  expression: Parser.ExpressionContext | null,
159
139
  arrayDims: Parser.ArrayDimensionContext[],
160
140
  modifiers: IStringDeclModifiers,
161
141
  isConst: boolean,
142
+ callbacks: IStringDeclCallbacks,
162
143
  ): IStringDeclResult {
163
144
  const { extern, const: constMod } = modifiers;
164
145
 
165
146
  // String arrays: string<64> arr[4] -> char arr[4][65] = {0};
166
147
  if (arrayDims.length > 0) {
167
- return this.generateStringArrayDecl(
148
+ return StringDeclHelper._generateStringArrayDecl(
168
149
  name,
169
150
  capacity,
170
151
  expression,
171
152
  arrayDims,
172
153
  modifiers,
173
154
  isConst,
155
+ callbacks,
174
156
  );
175
157
  }
176
158
 
@@ -182,50 +164,70 @@ class StringDeclHelper {
182
164
  };
183
165
  }
184
166
 
185
- return this._generateBoundedStringWithInit(
167
+ return StringDeclHelper._generateBoundedStringWithInit(
186
168
  name,
187
169
  capacity,
188
170
  expression,
189
171
  extern,
190
172
  constMod,
173
+ callbacks,
191
174
  );
192
175
  }
193
176
 
194
177
  /**
195
178
  * Generate bounded string with initializer expression
196
179
  */
197
- private _generateBoundedStringWithInit(
180
+ private static _generateBoundedStringWithInit(
198
181
  name: string,
199
182
  capacity: number,
200
183
  expression: Parser.ExpressionContext,
201
184
  extern: string,
202
185
  constMod: string,
186
+ callbacks: IStringDeclCallbacks,
203
187
  ): IStringDeclResult {
204
188
  // Check for string concatenation
205
- const concatOps = this.deps.getStringConcatOperands(expression);
189
+ const concatOps = callbacks.getStringConcatOperands(expression);
206
190
  if (concatOps) {
207
- return this.generateConcatDecl(name, capacity, concatOps, constMod);
191
+ return StringDeclHelper._generateConcatDecl(
192
+ name,
193
+ capacity,
194
+ concatOps,
195
+ constMod,
196
+ );
208
197
  }
209
198
 
210
199
  // Check for substring extraction
211
- const substringOps = this.deps.getSubstringOperands(expression);
200
+ const substringOps = callbacks.getSubstringOperands(expression);
212
201
  if (substringOps) {
213
- return this.generateSubstringDecl(name, capacity, substringOps, constMod);
202
+ return StringDeclHelper._generateSubstringDecl(
203
+ name,
204
+ capacity,
205
+ substringOps,
206
+ constMod,
207
+ );
214
208
  }
215
209
 
216
210
  // Validate and generate simple assignment
217
- this._validateStringInit(expression.getText(), capacity);
218
- const code = `${extern}${constMod}char ${name}[${capacity + 1}] = ${this.deps.generateExpression(expression)};`;
211
+ StringDeclHelper._validateStringInit(
212
+ expression.getText(),
213
+ capacity,
214
+ callbacks,
215
+ );
216
+ const code = `${extern}${constMod}char ${name}[${capacity + 1}] = ${callbacks.generateExpression(expression)};`;
219
217
  return { code, handled: true };
220
218
  }
221
219
 
222
220
  /**
223
221
  * Validate string initialization (literal length and variable capacity)
224
222
  */
225
- private _validateStringInit(exprText: string, capacity: number): void {
223
+ private static _validateStringInit(
224
+ exprText: string,
225
+ capacity: number,
226
+ callbacks: IStringDeclCallbacks,
227
+ ): void {
226
228
  // Validate string literal fits capacity
227
229
  if (exprText.startsWith('"') && exprText.endsWith('"')) {
228
- const content = this.deps.getStringLiteralLength(exprText);
230
+ const content = StringUtils.literalLength(exprText);
229
231
  if (content > capacity) {
230
232
  throw new Error(
231
233
  `Error: String literal (${content} chars) exceeds string<${capacity}> capacity`,
@@ -234,7 +236,7 @@ class StringDeclHelper {
234
236
  }
235
237
 
236
238
  // Check for string variable assignment
237
- const srcCapacity = this.deps.getStringExprCapacity(exprText);
239
+ const srcCapacity = callbacks.getStringExprCapacity(exprText);
238
240
  if (srcCapacity !== null && srcCapacity > capacity) {
239
241
  throw new Error(
240
242
  `Error: Cannot assign string<${srcCapacity}> to string<${capacity}> (potential truncation)`,
@@ -245,13 +247,14 @@ class StringDeclHelper {
245
247
  /**
246
248
  * Generate string array declaration.
247
249
  */
248
- private generateStringArrayDecl(
250
+ private static _generateStringArrayDecl(
249
251
  name: string,
250
252
  capacity: number,
251
253
  expression: Parser.ExpressionContext | null,
252
254
  arrayDims: Parser.ArrayDimensionContext[],
253
255
  modifiers: IStringDeclModifiers,
254
256
  isConst: boolean,
257
+ callbacks: IStringDeclCallbacks,
255
258
  ): IStringDeclResult {
256
259
  const {
257
260
  extern,
@@ -263,20 +266,20 @@ class StringDeclHelper {
263
266
 
264
267
  // No initializer - zero-initialize
265
268
  if (!expression) {
266
- decl += this.deps.generateArrayDimensions(arrayDims);
269
+ decl += callbacks.generateArrayDimensions(arrayDims);
267
270
  decl += `[${capacity + 1}]`;
268
271
  return { code: `${decl} = {0};`, handled: true };
269
272
  }
270
273
 
271
274
  // Reset array init tracking and generate initializer
272
- this.deps.arrayInitState.lastArrayInitCount = 0;
273
- this.deps.arrayInitState.lastArrayFillValue = undefined;
274
- const initValue = this.deps.generateExpression(expression);
275
+ CodeGenState.lastArrayInitCount = 0;
276
+ CodeGenState.lastArrayFillValue = undefined;
277
+ const initValue = callbacks.generateExpression(expression);
275
278
 
276
279
  // Check if it was an array initializer
277
280
  const isArrayInit =
278
- this.deps.arrayInitState.lastArrayInitCount > 0 ||
279
- this.deps.arrayInitState.lastArrayFillValue !== undefined;
281
+ CodeGenState.lastArrayInitCount > 0 ||
282
+ CodeGenState.lastArrayFillValue !== undefined;
280
283
 
281
284
  if (!isArrayInit) {
282
285
  throw new Error(
@@ -285,18 +288,21 @@ class StringDeclHelper {
285
288
  }
286
289
 
287
290
  // Track as local array
288
- this.deps.localArrays.add(name);
291
+ CodeGenState.localArrays.add(name);
289
292
 
290
293
  const hasEmptyArrayDim = arrayDims.some((dim) => !dim.expression());
291
294
  if (hasEmptyArrayDim) {
292
- decl += this._handleSizeInference(name, capacity, isConst);
295
+ decl += StringDeclHelper._handleSizeInference(name, capacity, isConst);
293
296
  } else {
294
- decl += this._handleExplicitSize(arrayDims);
297
+ decl += StringDeclHelper._handleExplicitSize(arrayDims, callbacks);
295
298
  }
296
299
 
297
300
  decl += `[${capacity + 1}]`; // String capacity + null terminator
298
301
 
299
- const finalInitValue = this._expandFillAllIfNeeded(initValue, arrayDims);
302
+ const finalInitValue = StringDeclHelper._expandFillAllIfNeeded(
303
+ initValue,
304
+ arrayDims,
305
+ );
300
306
  return { code: `${decl} = ${finalInitValue};`, handled: true };
301
307
  }
302
308
 
@@ -304,22 +310,22 @@ class StringDeclHelper {
304
310
  * Handle size inference for empty array dimension.
305
311
  * Returns the dimension string to append to declaration.
306
312
  */
307
- private _handleSizeInference(
313
+ private static _handleSizeInference(
308
314
  name: string,
309
315
  capacity: number,
310
316
  isConst: boolean,
311
317
  ): string {
312
- const fillValue = this.deps.arrayInitState.lastArrayFillValue;
318
+ const fillValue = CodeGenState.lastArrayFillValue;
313
319
  if (fillValue !== undefined) {
314
320
  throw new Error(
315
321
  `Error: Fill-all syntax [${fillValue}*] requires explicit array size`,
316
322
  );
317
323
  }
318
324
 
319
- const arraySize = this.deps.arrayInitState.lastArrayInitCount;
325
+ const arraySize = CodeGenState.lastArrayInitCount;
320
326
 
321
327
  // Update type registry with inferred size
322
- this.deps.typeRegistry.set(name, {
328
+ CodeGenState.typeRegistry.set(name, {
323
329
  baseType: "char",
324
330
  bitWidth: 8,
325
331
  isArray: true,
@@ -336,16 +342,16 @@ class StringDeclHelper {
336
342
  * Handle explicit array size with validation.
337
343
  * Returns the dimension string to append to declaration.
338
344
  */
339
- private _handleExplicitSize(
345
+ private static _handleExplicitSize(
340
346
  arrayDims: Parser.ArrayDimensionContext[],
347
+ callbacks: IStringDeclCallbacks,
341
348
  ): string {
342
- const declaredSize = this._getFirstDimNumericSize(arrayDims);
349
+ const declaredSize = StringDeclHelper._getFirstDimNumericSize(arrayDims);
343
350
 
344
351
  // Validate element count matches declared size (only for non-fill-all)
345
352
  if (declaredSize !== null) {
346
- const isFillAll =
347
- this.deps.arrayInitState.lastArrayFillValue !== undefined;
348
- const elementCount = this.deps.arrayInitState.lastArrayInitCount;
353
+ const isFillAll = CodeGenState.lastArrayFillValue !== undefined;
354
+ const elementCount = CodeGenState.lastArrayInitCount;
349
355
 
350
356
  if (!isFillAll && elementCount !== declaredSize) {
351
357
  throw new Error(
@@ -354,18 +360,18 @@ class StringDeclHelper {
354
360
  }
355
361
  }
356
362
 
357
- return this.deps.generateArrayDimensions(arrayDims);
363
+ return callbacks.generateArrayDimensions(arrayDims);
358
364
  }
359
365
 
360
366
  /**
361
367
  * Expand fill-all syntax if needed.
362
368
  * ["Hello"*] with size 3 -> {"Hello", "Hello", "Hello"}
363
369
  */
364
- private _expandFillAllIfNeeded(
370
+ private static _expandFillAllIfNeeded(
365
371
  initValue: string,
366
372
  arrayDims: Parser.ArrayDimensionContext[],
367
373
  ): string {
368
- const fillVal = this.deps.arrayInitState.lastArrayFillValue;
374
+ const fillVal = CodeGenState.lastArrayFillValue;
369
375
  if (fillVal === undefined) {
370
376
  return initValue;
371
377
  }
@@ -375,7 +381,7 @@ class StringDeclHelper {
375
381
  return initValue;
376
382
  }
377
383
 
378
- const declaredSize = this._getFirstDimNumericSize(arrayDims);
384
+ const declaredSize = StringDeclHelper._getFirstDimNumericSize(arrayDims);
379
385
  if (declaredSize === null) {
380
386
  return initValue;
381
387
  }
@@ -387,7 +393,7 @@ class StringDeclHelper {
387
393
  /**
388
394
  * Get the numeric size from the first array dimension, or null if not numeric.
389
395
  */
390
- private _getFirstDimNumericSize(
396
+ private static _getFirstDimNumericSize(
391
397
  arrayDims: Parser.ArrayDimensionContext[],
392
398
  ): number | null {
393
399
  const firstDimExpr = arrayDims[0]?.expression();
@@ -406,7 +412,7 @@ class StringDeclHelper {
406
412
  /**
407
413
  * Generate string concatenation declaration.
408
414
  */
409
- private generateConcatDecl(
415
+ private static _generateConcatDecl(
410
416
  name: string,
411
417
  capacity: number,
412
418
  concatOps: IStringConcatOps,
@@ -414,7 +420,7 @@ class StringDeclHelper {
414
420
  ): IStringDeclResult {
415
421
  // String concatenation requires runtime function calls (strncpy, strncat)
416
422
  // which cannot exist at global scope in C
417
- if (!this.deps.getInFunctionBody()) {
423
+ if (!CodeGenState.inFunctionBody) {
418
424
  throw new Error(
419
425
  `Error: String concatenation cannot be used at global scope. ` +
420
426
  `Move the declaration inside a function.`,
@@ -430,7 +436,7 @@ class StringDeclHelper {
430
436
  }
431
437
 
432
438
  // Generate safe concatenation code
433
- const indent = FormatUtils.indent(this.deps.getIndentLevel());
439
+ const indent = FormatUtils.indent(CodeGenState.indentLevel);
434
440
  const lines: string[] = [];
435
441
  lines.push(
436
442
  `${constMod}char ${name}[${capacity + 1}] = "";`,
@@ -444,7 +450,7 @@ class StringDeclHelper {
444
450
  /**
445
451
  * Generate substring extraction declaration.
446
452
  */
447
- private generateSubstringDecl(
453
+ private static _generateSubstringDecl(
448
454
  name: string,
449
455
  capacity: number,
450
456
  substringOps: ISubstringOps,
@@ -452,7 +458,7 @@ class StringDeclHelper {
452
458
  ): IStringDeclResult {
453
459
  // Substring extraction requires runtime function calls (strncpy)
454
460
  // which cannot exist at global scope in C
455
- if (!this.deps.getInFunctionBody()) {
461
+ if (!CodeGenState.inFunctionBody) {
456
462
  throw new Error(
457
463
  `Error: Substring extraction cannot be used at global scope. ` +
458
464
  `Move the declaration inside a function.`,
@@ -481,7 +487,7 @@ class StringDeclHelper {
481
487
  }
482
488
 
483
489
  // Generate safe substring extraction code
484
- const indent = FormatUtils.indent(this.deps.getIndentLevel());
490
+ const indent = FormatUtils.indent(CodeGenState.indentLevel);
485
491
  const lines: string[] = [];
486
492
  lines.push(
487
493
  `${constMod}char ${name}[${capacity + 1}] = "";`,
@@ -494,11 +500,12 @@ class StringDeclHelper {
494
500
  /**
495
501
  * Generate unsized const string declaration.
496
502
  */
497
- private generateUnsizedStringDecl(
503
+ private static _generateUnsizedStringDecl(
498
504
  name: string,
499
505
  expression: Parser.ExpressionContext | null,
500
506
  modifiers: IStringDeclModifiers,
501
507
  isConst: boolean,
508
+ callbacks: IStringDeclCallbacks,
502
509
  ): IStringDeclResult {
503
510
  if (!isConst) {
504
511
  throw new Error(
@@ -520,11 +527,11 @@ class StringDeclHelper {
520
527
  }
521
528
 
522
529
  // Infer capacity from literal length
523
- const inferredCapacity = this.deps.getStringLiteralLength(exprText);
524
- this.deps.requireStringInclude();
530
+ const inferredCapacity = StringUtils.literalLength(exprText);
531
+ callbacks.requireStringInclude();
525
532
 
526
533
  // Register in type registry with inferred capacity
527
- this.deps.typeRegistry.set(name, {
534
+ CodeGenState.typeRegistry.set(name, {
528
535
  baseType: "char",
529
536
  bitWidth: 8,
530
537
  isArray: true,
@@ -242,6 +242,15 @@ class TypeGenerationHelper {
242
242
  return "string";
243
243
  }
244
244
 
245
+ // Bug fix: Handle arrayType syntax (u16[8] myArray) - check inner primitive type
246
+ if (ctx.arrayType()) {
247
+ const arrCtx = ctx.arrayType()!;
248
+ if (arrCtx.primitiveType()) {
249
+ const type = arrCtx.primitiveType()!.getText();
250
+ return TypeGenerationHelper.generatePrimitiveType(type).include;
251
+ }
252
+ }
253
+
245
254
  return null;
246
255
  }
247
256
  }