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
@@ -42,10 +42,35 @@ function createMockConstModifier(
42
42
  return isConst ? ({} as Parser.ConstModifierContext) : null;
43
43
  }
44
44
 
45
+ /**
46
+ * Create a mock array type context.
47
+ */
48
+ function createMockArrayType(sizeExpr?: string | null) {
49
+ if (sizeExpr === null) {
50
+ // Empty brackets - no expression
51
+ return {
52
+ expression: () => null,
53
+ };
54
+ }
55
+ return {
56
+ expression: () =>
57
+ sizeExpr
58
+ ? {
59
+ getText: () => sizeExpr,
60
+ __mockValue: sizeExpr,
61
+ }
62
+ : null,
63
+ };
64
+ }
65
+
45
66
  /**
46
67
  * Create a mock type context.
47
68
  */
48
- function createMockType(typeName: string, hasStringType = false) {
69
+ function createMockType(
70
+ typeName: string,
71
+ hasStringType = false,
72
+ arrayTypeSize?: string | null,
73
+ ) {
49
74
  return {
50
75
  getText: () => typeName,
51
76
  stringType: () =>
@@ -54,6 +79,8 @@ function createMockType(typeName: string, hasStringType = false) {
54
79
  INTEGER_LITERAL: () => ({ getText: () => "32" }),
55
80
  }
56
81
  : null,
82
+ arrayType: () =>
83
+ arrayTypeSize !== undefined ? createMockArrayType(arrayTypeSize) : null,
57
84
  };
58
85
  }
59
86
 
@@ -99,10 +126,16 @@ function createMockVariableDecl(options: {
99
126
  hasStringType?: boolean;
100
127
  constructorArgs?: string[];
101
128
  startLine?: number;
129
+ arrayTypeSize?: string | null; // C-Next style: u16[8] name
102
130
  }) {
103
131
  return {
104
132
  IDENTIFIER: () => ({ getText: () => options.name }),
105
- type: () => createMockType(options.type, options.hasStringType),
133
+ type: () =>
134
+ createMockType(
135
+ options.type,
136
+ options.hasStringType,
137
+ options.arrayTypeSize,
138
+ ),
106
139
  constModifier: () => createMockConstModifier(options.isConst ?? false),
107
140
  expression: () =>
108
141
  options.initialValue ? createMockExpression(options.initialValue) : null,
@@ -207,10 +240,11 @@ function createMockStructMember(
207
240
  type: string,
208
241
  arrayDims?: string[],
209
242
  hasStringType = false,
243
+ arrayTypeSize?: string | null,
210
244
  ) {
211
245
  return {
212
246
  IDENTIFIER: () => ({ getText: () => name }),
213
- type: () => createMockType(type, hasStringType),
247
+ type: () => createMockType(type, hasStringType, arrayTypeSize),
214
248
  arrayDimension: () => (arrayDims ?? []).map(createMockArrayDimension),
215
249
  };
216
250
  }
@@ -225,13 +259,20 @@ function createMockStructDecl(
225
259
  type: string;
226
260
  arrayDims?: string[];
227
261
  hasStringType?: boolean;
262
+ arrayTypeSize?: string | null;
228
263
  }>,
229
264
  ) {
230
265
  return {
231
266
  IDENTIFIER: () => ({ getText: () => name }),
232
267
  structMember: () =>
233
268
  members.map((m) =>
234
- createMockStructMember(m.name, m.type, m.arrayDims, m.hasStringType),
269
+ createMockStructMember(
270
+ m.name,
271
+ m.type,
272
+ m.arrayDims,
273
+ m.hasStringType,
274
+ m.arrayTypeSize,
275
+ ),
235
276
  ),
236
277
  };
237
278
  }
@@ -579,6 +620,66 @@ describe("ScopeGenerator", () => {
579
620
  expect(result.code).toContain("static uint8_t Serial_buffer[256] = {0};");
580
621
  });
581
622
 
623
+ it("generates C-Next style array variable with constant size", () => {
624
+ const varDecl = createMockVariableDecl({
625
+ name: "data",
626
+ type: "u16[8]",
627
+ arrayTypeSize: "8",
628
+ });
629
+ const member = createMockScopeMember({ variableDecl: varDecl });
630
+ const ctx = createMockScopeContext("Buffer", [member]);
631
+ const input = createMockInput();
632
+ const state = createMockState();
633
+ const orchestrator = createMockOrchestrator({
634
+ ...createMockOrchestrator(),
635
+ tryEvaluateConstant: vi.fn(() => 8),
636
+ });
637
+
638
+ const result = generateScope(ctx, input, state, orchestrator);
639
+
640
+ expect(result.code).toContain("static u16[8] Buffer_data[8] = {0};");
641
+ });
642
+
643
+ it("generates C-Next style array variable with non-constant expression (fallback)", () => {
644
+ const varDecl = createMockVariableDecl({
645
+ name: "items",
646
+ type: "u16[BUFFER_SIZE]",
647
+ arrayTypeSize: "BUFFER_SIZE",
648
+ });
649
+ const member = createMockScopeMember({ variableDecl: varDecl });
650
+ const ctx = createMockScopeContext("Storage", [member]);
651
+ const input = createMockInput();
652
+ const state = createMockState();
653
+ const orchestrator = createMockOrchestrator({
654
+ ...createMockOrchestrator(),
655
+ tryEvaluateConstant: vi.fn(() => undefined), // Can't resolve macro
656
+ generateExpression: vi.fn(() => "BUFFER_SIZE"),
657
+ });
658
+
659
+ const result = generateScope(ctx, input, state, orchestrator);
660
+
661
+ expect(result.code).toContain(
662
+ "static u16[BUFFER_SIZE] Storage_items[BUFFER_SIZE] = {0};",
663
+ );
664
+ });
665
+
666
+ it("generates C-Next style array variable with no size (empty brackets)", () => {
667
+ const varDecl = createMockVariableDecl({
668
+ name: "flexible",
669
+ type: "u8[]",
670
+ arrayTypeSize: null, // No size expression
671
+ });
672
+ const member = createMockScopeMember({ variableDecl: varDecl });
673
+ const ctx = createMockScopeContext("Dynamic", [member]);
674
+ const input = createMockInput();
675
+ const state = createMockState();
676
+ const orchestrator = createMockOrchestrator();
677
+
678
+ const result = generateScope(ctx, input, state, orchestrator);
679
+
680
+ expect(result.code).toContain("static u8[] Dynamic_flexible[] = {0};");
681
+ });
682
+
582
683
  it("generates string variable with capacity dimension (ADR-045)", () => {
583
684
  const varDecl = createMockVariableDecl({
584
685
  name: "message",
@@ -1036,6 +1137,58 @@ describe("ScopeGenerator", () => {
1036
1137
  expect(result.code).toContain("uint8_t data[256];");
1037
1138
  });
1038
1139
 
1140
+ it("generates struct field with C-Next array type constant size", () => {
1141
+ const structDecl = createMockStructDecl("Container", [
1142
+ { name: "items", type: "u16[4]", arrayTypeSize: "4" },
1143
+ ]);
1144
+ const member = createMockScopeMember({ structDecl: structDecl });
1145
+ const ctx = createMockScopeContext("Data", [member]);
1146
+ const input = createMockInput();
1147
+ const state = createMockState();
1148
+ const orchestrator = createMockOrchestrator({
1149
+ ...createMockOrchestrator(),
1150
+ tryEvaluateConstant: vi.fn(() => 4),
1151
+ });
1152
+
1153
+ const result = generateScope(ctx, input, state, orchestrator);
1154
+
1155
+ expect(result.code).toContain("u16[4] items[4];");
1156
+ });
1157
+
1158
+ it("generates struct field with C-Next array type non-constant (fallback)", () => {
1159
+ const structDecl = createMockStructDecl("FlexContainer", [
1160
+ { name: "buffer", type: "u8[MAX_SIZE]", arrayTypeSize: "MAX_SIZE" },
1161
+ ]);
1162
+ const member = createMockScopeMember({ structDecl: structDecl });
1163
+ const ctx = createMockScopeContext("Flex", [member]);
1164
+ const input = createMockInput();
1165
+ const state = createMockState();
1166
+ const orchestrator = createMockOrchestrator({
1167
+ ...createMockOrchestrator(),
1168
+ tryEvaluateConstant: vi.fn(() => undefined), // Can't resolve macro
1169
+ generateExpression: vi.fn(() => "MAX_SIZE"),
1170
+ });
1171
+
1172
+ const result = generateScope(ctx, input, state, orchestrator);
1173
+
1174
+ expect(result.code).toContain("u8[MAX_SIZE] buffer[MAX_SIZE];");
1175
+ });
1176
+
1177
+ it("generates struct field with C-Next array type no size (empty brackets)", () => {
1178
+ const structDecl = createMockStructDecl("DynamicContainer", [
1179
+ { name: "data", type: "u8[]", arrayTypeSize: null },
1180
+ ]);
1181
+ const member = createMockScopeMember({ structDecl: structDecl });
1182
+ const ctx = createMockScopeContext("Dyn", [member]);
1183
+ const input = createMockInput();
1184
+ const state = createMockState();
1185
+ const orchestrator = createMockOrchestrator();
1186
+
1187
+ const result = generateScope(ctx, input, state, orchestrator);
1188
+
1189
+ expect(result.code).toContain("u8[] data[];");
1190
+ });
1191
+
1039
1192
  it("generates struct field with string capacity", () => {
1040
1193
  const structDecl = createMockStructDecl("Message", [
1041
1194
  { name: "text", type: "string<64>", hasStringType: true },
@@ -11,6 +11,27 @@
11
11
  import TYPE_MAP from "../../types/TYPE_MAP";
12
12
  import OverflowHelperTemplates from "./OverflowHelperTemplates";
13
13
 
14
+ /**
15
+ * Generate a safe arithmetic helper function (div or mod).
16
+ * Extracted to eliminate duplication between safe_div and safe_mod generation.
17
+ */
18
+ const generateSafeArithmeticHelper = (
19
+ opName: string,
20
+ opSymbol: string,
21
+ cnxType: string,
22
+ cType: string,
23
+ ): string[] => [
24
+ `static inline bool cnx_safe_${opName}_${cnxType}(${cType}* output, ${cType} numerator, ${cType} divisor, ${cType} defaultValue) {`,
25
+ ` if (divisor == 0) {`,
26
+ ` *output = defaultValue;`,
27
+ ` return true; // Error occurred`,
28
+ ` }`,
29
+ ` *output = numerator ${opSymbol} divisor;`,
30
+ ` return false; // Success`,
31
+ `}`,
32
+ "",
33
+ ];
34
+
14
35
  /**
15
36
  * Generate all needed overflow helper functions
16
37
  * ADR-044: Overflow helper functions with clamping or panic behavior
@@ -90,32 +111,12 @@ const generateSafeDivHelpers = (
90
111
 
91
112
  // Generate safe_div helper if needed
92
113
  if (needsDiv) {
93
- lines.push(
94
- `static inline bool cnx_safe_div_${cnxType}(${cType}* output, ${cType} numerator, ${cType} divisor, ${cType} defaultValue) {`,
95
- ` if (divisor == 0) {`,
96
- ` *output = defaultValue;`,
97
- ` return true; // Error occurred`,
98
- ` }`,
99
- ` *output = numerator / divisor;`,
100
- ` return false; // Success`,
101
- `}`,
102
- "",
103
- );
114
+ lines.push(...generateSafeArithmeticHelper("div", "/", cnxType, cType));
104
115
  }
105
116
 
106
117
  // Generate safe_mod helper if needed
107
118
  if (needsMod) {
108
- lines.push(
109
- `static inline bool cnx_safe_mod_${cnxType}(${cType}* output, ${cType} numerator, ${cType} divisor, ${cType} defaultValue) {`,
110
- ` if (divisor == 0) {`,
111
- ` *output = defaultValue;`,
112
- ` return true; // Error occurred`,
113
- ` }`,
114
- ` *output = numerator % divisor;`,
115
- ` return false; // Success`,
116
- `}`,
117
- "",
118
- );
119
+ lines.push(...generateSafeArithmeticHelper("mod", "%", cnxType, cType));
119
120
  }
120
121
  }
121
122
 
@@ -7,18 +7,12 @@
7
7
  * - Array initializers with size inference: u8 data[] <- [1, 2, 3]
8
8
  * - Fill-all syntax: u8 data[10] <- [0*]
9
9
  * - Array size validation
10
+ *
11
+ * Migrated to use CodeGenState instead of constructor DI.
10
12
  */
11
13
 
12
14
  import * as Parser from "../../../logic/parser/grammar/CNextParser.js";
13
- import TTypeInfo from "../types/TTypeInfo.js";
14
-
15
- /**
16
- * Array initialization tracking state.
17
- */
18
- interface IArrayInitState {
19
- lastArrayInitCount: number;
20
- lastArrayFillValue: string | undefined;
21
- }
15
+ import CodeGenState from "../CodeGenState.js";
22
16
 
23
17
  /**
24
18
  * Result from processing array initialization.
@@ -33,18 +27,10 @@ interface IArrayInitResult {
33
27
  }
34
28
 
35
29
  /**
36
- * Dependencies required for array initialization.
30
+ * Callbacks required for array initialization.
31
+ * These need CodeGenerator context and cannot be replaced with static state.
37
32
  */
38
- interface IArrayInitHelperDeps {
39
- /** Type registry for updating inferred dimensions */
40
- typeRegistry: Map<string, TTypeInfo>;
41
- /** Local arrays set for tracking */
42
- localArrays: Set<string>;
43
- /** Array initialization tracking state */
44
- arrayInitState: IArrayInitState;
45
- /** Get/set expected type context */
46
- getExpectedType: () => string | null;
47
- setExpectedType: (type: string | null) => void;
33
+ interface IArrayInitCallbacks {
48
34
  /** Generate expression code */
49
35
  generateExpression: (ctx: Parser.ExpressionContext) => string;
50
36
  /** Get type name from type context */
@@ -57,12 +43,6 @@ interface IArrayInitHelperDeps {
57
43
  * Handles array initialization with size inference and fill-all syntax.
58
44
  */
59
45
  class ArrayInitHelper {
60
- private readonly deps: IArrayInitHelperDeps;
61
-
62
- constructor(deps: IArrayInitHelperDeps) {
63
- this.deps = deps;
64
- }
65
-
66
46
  /**
67
47
  * Process array initialization expression.
68
48
  * Returns null if not an array initializer pattern.
@@ -73,33 +53,46 @@ class ArrayInitHelper {
73
53
  * @param arrayDims - Array dimension contexts
74
54
  * @param hasEmptyArrayDim - Whether any dimension is empty (for inference)
75
55
  * @param declaredSize - First dimension size if explicit, null otherwise
56
+ * @param callbacks - Callbacks to CodeGenerator methods
76
57
  */
77
- processArrayInit(
58
+ static processArrayInit(
78
59
  name: string,
79
60
  typeCtx: Parser.TypeContext,
80
61
  expression: Parser.ExpressionContext,
81
62
  arrayDims: Parser.ArrayDimensionContext[],
82
63
  hasEmptyArrayDim: boolean,
83
64
  declaredSize: number | null,
65
+ callbacks: IArrayInitCallbacks,
84
66
  ): IArrayInitResult | null {
85
67
  // Reset and generate initializer
86
- this.deps.arrayInitState.lastArrayInitCount = 0;
87
- this.deps.arrayInitState.lastArrayFillValue = undefined;
68
+ CodeGenState.lastArrayInitCount = 0;
69
+ CodeGenState.lastArrayFillValue = undefined;
88
70
 
89
- const initValue = this._generateArrayInitValue(typeCtx, expression);
71
+ const initValue = ArrayInitHelper._generateArrayInitValue(
72
+ typeCtx,
73
+ expression,
74
+ callbacks,
75
+ );
90
76
 
91
77
  // Check if it was an array initializer
92
- if (!this._isArrayInitializer()) {
78
+ if (!ArrayInitHelper._isArrayInitializer()) {
93
79
  return null;
94
80
  }
95
81
 
96
- this.deps.localArrays.add(name);
82
+ CodeGenState.localArrays.add(name);
97
83
 
98
84
  const dimensionSuffix = hasEmptyArrayDim
99
- ? this._processSizeInference(name)
100
- : this._processExplicitSize(arrayDims, declaredSize);
101
-
102
- const finalInitValue = this._expandFillAllSyntax(initValue, declaredSize);
85
+ ? ArrayInitHelper._processSizeInference(name)
86
+ : ArrayInitHelper._processExplicitSize(
87
+ arrayDims,
88
+ declaredSize,
89
+ callbacks,
90
+ );
91
+
92
+ const finalInitValue = ArrayInitHelper._expandFillAllSyntax(
93
+ initValue,
94
+ declaredSize,
95
+ );
103
96
 
104
97
  return { isArrayInit: true, dimensionSuffix, initValue: finalInitValue };
105
98
  }
@@ -107,66 +100,66 @@ class ArrayInitHelper {
107
100
  /**
108
101
  * Generate the array initializer value with proper expected type
109
102
  */
110
- private _generateArrayInitValue(
103
+ private static _generateArrayInitValue(
111
104
  typeCtx: Parser.TypeContext,
112
105
  expression: Parser.ExpressionContext,
106
+ callbacks: IArrayInitCallbacks,
113
107
  ): string {
114
- const typeName = this.deps.getTypeName(typeCtx);
115
- const savedExpectedType = this.deps.getExpectedType();
116
- this.deps.setExpectedType(typeName);
117
- const initValue = this.deps.generateExpression(expression);
118
- this.deps.setExpectedType(savedExpectedType);
108
+ const typeName = callbacks.getTypeName(typeCtx);
109
+ const savedExpectedType = CodeGenState.expectedType;
110
+ CodeGenState.expectedType = typeName;
111
+ const initValue = callbacks.generateExpression(expression);
112
+ CodeGenState.expectedType = savedExpectedType;
119
113
  return initValue;
120
114
  }
121
115
 
122
116
  /**
123
117
  * Check if the last expression was an array initializer
124
118
  */
125
- private _isArrayInitializer(): boolean {
119
+ private static _isArrayInitializer(): boolean {
126
120
  return (
127
- this.deps.arrayInitState.lastArrayInitCount > 0 ||
128
- this.deps.arrayInitState.lastArrayFillValue !== undefined
121
+ CodeGenState.lastArrayInitCount > 0 ||
122
+ CodeGenState.lastArrayFillValue !== undefined
129
123
  );
130
124
  }
131
125
 
132
126
  /**
133
127
  * Process size inference for empty array dimension (u8 data[] <- [1, 2, 3])
134
128
  */
135
- private _processSizeInference(name: string): string {
136
- if (this.deps.arrayInitState.lastArrayFillValue !== undefined) {
129
+ private static _processSizeInference(name: string): string {
130
+ if (CodeGenState.lastArrayFillValue !== undefined) {
137
131
  throw new Error(
138
- `Error: Fill-all syntax [${this.deps.arrayInitState.lastArrayFillValue}*] requires explicit array size`,
132
+ `Error: Fill-all syntax [${CodeGenState.lastArrayFillValue}*] requires explicit array size`,
139
133
  );
140
134
  }
141
135
 
142
136
  // Update type registry with inferred size for .length support
143
- const existingType = this.deps.typeRegistry.get(name);
137
+ const existingType = CodeGenState.typeRegistry.get(name);
144
138
  if (existingType) {
145
- existingType.arrayDimensions = [
146
- this.deps.arrayInitState.lastArrayInitCount,
147
- ];
139
+ existingType.arrayDimensions = [CodeGenState.lastArrayInitCount];
148
140
  }
149
141
 
150
- return `[${this.deps.arrayInitState.lastArrayInitCount}]`;
142
+ return `[${CodeGenState.lastArrayInitCount}]`;
151
143
  }
152
144
 
153
145
  /**
154
146
  * Process explicit array size with validation
155
147
  */
156
- private _processExplicitSize(
148
+ private static _processExplicitSize(
157
149
  arrayDims: Parser.ArrayDimensionContext[],
158
150
  declaredSize: number | null,
151
+ callbacks: IArrayInitCallbacks,
159
152
  ): string {
160
- const dimensionSuffix = this.deps.generateArrayDimensions(arrayDims);
153
+ const dimensionSuffix = callbacks.generateArrayDimensions(arrayDims);
161
154
 
162
155
  // Validate size matches if not using fill-all
163
156
  if (
164
157
  declaredSize !== null &&
165
- this.deps.arrayInitState.lastArrayFillValue === undefined &&
166
- this.deps.arrayInitState.lastArrayInitCount !== declaredSize
158
+ CodeGenState.lastArrayFillValue === undefined &&
159
+ CodeGenState.lastArrayInitCount !== declaredSize
167
160
  ) {
168
161
  throw new Error(
169
- `Error: Array size mismatch - declared [${declaredSize}] but got ${this.deps.arrayInitState.lastArrayInitCount} elements`,
162
+ `Error: Array size mismatch - declared [${declaredSize}] but got ${CodeGenState.lastArrayInitCount} elements`,
170
163
  );
171
164
  }
172
165
 
@@ -176,18 +169,18 @@ class ArrayInitHelper {
176
169
  /**
177
170
  * Expand fill-all syntax (e.g., [0*] with size 5 -> {0, 0, 0, 0, 0})
178
171
  */
179
- private _expandFillAllSyntax(
172
+ private static _expandFillAllSyntax(
180
173
  initValue: string,
181
174
  declaredSize: number | null,
182
175
  ): string {
183
176
  if (
184
- this.deps.arrayInitState.lastArrayFillValue === undefined ||
177
+ CodeGenState.lastArrayFillValue === undefined ||
185
178
  declaredSize === null
186
179
  ) {
187
180
  return initValue;
188
181
  }
189
182
 
190
- const fillVal = this.deps.arrayInitState.lastArrayFillValue;
183
+ const fillVal = CodeGenState.lastArrayFillValue;
191
184
  // C handles {0} correctly, no need to expand
192
185
  if (fillVal === "0") {
193
186
  return initValue;
@@ -5,12 +5,14 @@
5
5
  *
6
6
  * Sets up expectedType and assignmentContext for expression generation,
7
7
  * enabling type-aware resolution of unqualified enum members and overflow behavior.
8
+ *
9
+ * Migrated to use CodeGenState instead of constructor DI.
8
10
  */
9
11
 
10
12
  import * as Parser from "../../../logic/parser/grammar/CNextParser.js";
11
- import TTypeInfo from "../types/TTypeInfo.js";
12
13
  import TOverflowBehavior from "../types/TOverflowBehavior.js";
13
14
  import analyzePostfixOps from "../../../../utils/PostfixAnalysisUtils.js";
15
+ import CodeGenState from "../CodeGenState.js";
14
16
 
15
17
  /**
16
18
  * Result of resolving expected type for an assignment target.
@@ -31,41 +33,25 @@ interface IAssignmentContext {
31
33
  overflowBehavior: TOverflowBehavior;
32
34
  }
33
35
 
34
- /**
35
- * Dependencies required for expected type resolution.
36
- */
37
- interface IExpectedTypeResolverDeps {
38
- /** Type registry for looking up variable types */
39
- readonly typeRegistry: ReadonlyMap<string, TTypeInfo>;
40
- /** Struct field types: structName -> (fieldName -> fieldType) */
41
- readonly structFields: ReadonlyMap<string, ReadonlyMap<string, string>>;
42
- /** Check if a type is a known struct */
43
- isKnownStruct: (typeName: string) => boolean;
44
- }
45
-
46
36
  /**
47
37
  * Resolves expected type for assignment targets.
48
38
  */
49
39
  class AssignmentExpectedTypeResolver {
50
- private readonly deps: IExpectedTypeResolverDeps;
51
-
52
- constructor(deps: IExpectedTypeResolverDeps) {
53
- this.deps = deps;
54
- }
55
-
56
40
  /**
57
41
  * Resolve expected type for an assignment target.
58
42
  *
59
43
  * @param targetCtx - The assignment target context
60
44
  * @returns The resolved expected type and assignment context
61
45
  */
62
- resolve(targetCtx: Parser.AssignmentTargetContext): IExpectedTypeResult {
46
+ static resolve(
47
+ targetCtx: Parser.AssignmentTargetContext,
48
+ ): IExpectedTypeResult {
63
49
  const postfixOps = targetCtx.postfixTargetOp();
64
50
  const baseId = targetCtx.IDENTIFIER()?.getText();
65
51
 
66
52
  // Case 1: Simple identifier (x <- value) - no postfix ops
67
53
  if (baseId && postfixOps.length === 0) {
68
- return this.resolveForSimpleIdentifier(baseId);
54
+ return AssignmentExpectedTypeResolver.resolveForSimpleIdentifier(baseId);
69
55
  }
70
56
 
71
57
  // Case 2: Has member access - extract identifiers from postfix chain
@@ -77,7 +63,9 @@ class AssignmentExpectedTypeResolver {
77
63
 
78
64
  // If we have member access (multiple identifiers), resolve for member chain
79
65
  if (identifiers.length >= 2 && !hasSubscript) {
80
- return this.resolveForMemberChain(identifiers);
66
+ return AssignmentExpectedTypeResolver.resolveForMemberChain(
67
+ identifiers,
68
+ );
81
69
  }
82
70
  }
83
71
 
@@ -88,8 +76,8 @@ class AssignmentExpectedTypeResolver {
88
76
  /**
89
77
  * Resolve expected type for a simple identifier target.
90
78
  */
91
- private resolveForSimpleIdentifier(id: string): IExpectedTypeResult {
92
- const typeInfo = this.deps.typeRegistry.get(id);
79
+ private static resolveForSimpleIdentifier(id: string): IExpectedTypeResult {
80
+ const typeInfo = CodeGenState.typeRegistry.get(id);
93
81
  if (!typeInfo) {
94
82
  return { expectedType: null, assignmentContext: null };
95
83
  }
@@ -111,15 +99,17 @@ class AssignmentExpectedTypeResolver {
111
99
  * Issue #452: Enables type-aware resolution of unqualified enum members
112
100
  * for nested access (e.g., config.nested.field).
113
101
  */
114
- private resolveForMemberChain(identifiers: string[]): IExpectedTypeResult {
102
+ private static resolveForMemberChain(
103
+ identifiers: string[],
104
+ ): IExpectedTypeResult {
115
105
  if (identifiers.length < 2) {
116
106
  return { expectedType: null, assignmentContext: null };
117
107
  }
118
108
 
119
109
  const rootName = identifiers[0];
120
- const rootTypeInfo = this.deps.typeRegistry.get(rootName);
110
+ const rootTypeInfo = CodeGenState.typeRegistry.get(rootName);
121
111
 
122
- if (!rootTypeInfo || !this.deps.isKnownStruct(rootTypeInfo.baseType)) {
112
+ if (!rootTypeInfo || !CodeGenState.isKnownStruct(rootTypeInfo.baseType)) {
123
113
  return { expectedType: null, assignmentContext: null };
124
114
  }
125
115
 
@@ -128,18 +118,19 @@ class AssignmentExpectedTypeResolver {
128
118
  // Walk through each member in the chain to find the final field's type
129
119
  for (let i = 1; i < identifiers.length && currentStructType; i++) {
130
120
  const memberName = identifiers[i];
131
- const structFieldTypes = this.deps.structFields.get(currentStructType);
121
+ const structFieldTypes: ReadonlyMap<string, string> | undefined =
122
+ CodeGenState.symbols?.structFields.get(currentStructType);
132
123
 
133
124
  if (!structFieldTypes?.has(memberName)) {
134
125
  break;
135
126
  }
136
127
 
137
- const memberType = structFieldTypes.get(memberName)!;
128
+ const memberType: string = structFieldTypes.get(memberName)!;
138
129
 
139
130
  if (i === identifiers.length - 1) {
140
131
  // Last field in chain - this is the assignment target's type
141
132
  return { expectedType: memberType, assignmentContext: null };
142
- } else if (this.deps.isKnownStruct(memberType)) {
133
+ } else if (CodeGenState.isKnownStruct(memberType)) {
143
134
  // Intermediate field - continue walking if it's a struct
144
135
  currentStructType = memberType;
145
136
  } else {