c-next 0.1.68 → 0.1.70

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 (62) hide show
  1. package/package.json +1 -1
  2. package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +240 -204
  3. package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +693 -0
  4. package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +86 -5
  5. package/src/transpiler/{output/codegen → logic/analysis}/helpers/AssignmentTargetExtractor.ts +1 -1
  6. package/src/transpiler/{output/codegen → logic/analysis}/helpers/ChildStatementCollector.ts +1 -1
  7. package/src/transpiler/{output/codegen → logic/analysis}/helpers/StatementExpressionCollector.ts +1 -1
  8. package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/AssignmentTargetExtractor.test.ts +2 -2
  9. package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/ChildStatementCollector.test.ts +2 -2
  10. package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/StatementExpressionCollector.test.ts +2 -2
  11. package/src/transpiler/output/codegen/CodeGenerator.ts +160 -742
  12. package/src/transpiler/output/codegen/TypeRegistrationUtils.ts +4 -6
  13. package/src/transpiler/output/codegen/TypeResolver.ts +2 -2
  14. package/src/transpiler/output/codegen/TypeValidator.ts +7 -7
  15. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +2 -2
  16. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +29 -1
  17. package/src/transpiler/output/codegen/__tests__/TypeRegistrationUtils.test.ts +36 -51
  18. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +20 -17
  19. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +4 -6
  20. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +4 -2
  21. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +1 -1
  22. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +1 -1
  23. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +9 -9
  24. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +12 -12
  25. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +11 -11
  26. package/src/transpiler/output/codegen/assignment/AssignmentContextBuilder.ts +49 -0
  27. package/src/transpiler/output/codegen/assignment/IAssignmentContext.ts +15 -0
  28. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +30 -17
  29. package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +25 -18
  30. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +19 -8
  31. package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +3 -3
  32. package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +4 -4
  33. package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +5 -5
  34. package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +9 -1
  35. package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +41 -26
  36. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +29 -37
  37. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +27 -19
  38. package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +10 -1
  39. package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +51 -33
  40. package/src/transpiler/output/codegen/assignment/handlers/__tests__/StringHandlers.test.ts +9 -1
  41. package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +5 -4
  42. package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +14 -6
  43. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +19 -16
  44. package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +21 -4
  45. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +15 -2
  46. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +2 -1
  47. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +2 -2
  48. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +3 -3
  49. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
  50. package/src/transpiler/output/codegen/helpers/MemberSeparatorResolver.ts +6 -1
  51. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +2 -2
  52. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +1 -1
  53. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +7 -7
  54. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +7 -7
  55. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +2 -2
  56. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +4 -4
  57. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +2 -2
  58. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +5 -5
  59. package/src/transpiler/state/CodeGenState.ts +157 -5
  60. package/src/transpiler/state/__tests__/CodeGenState.test.ts +274 -6
  61. /package/src/transpiler/{output/codegen → logic/analysis}/helpers/TransitiveModificationPropagator.ts +0 -0
  62. /package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/TransitiveModificationPropagator.test.ts +0 -0
@@ -139,7 +139,7 @@ describe("MemberChainAnalyzer", () => {
139
139
 
140
140
  it("returns isBitAccess false when last op is member access", () => {
141
141
  // point.flags (no subscript at end)
142
- CodeGenState.typeRegistry.set("point", {
142
+ CodeGenState.setVariableTypeInfo("point", {
143
143
  baseType: "Point",
144
144
  bitWidth: 0,
145
145
  isArray: false,
@@ -159,7 +159,7 @@ describe("MemberChainAnalyzer", () => {
159
159
 
160
160
  it("returns isBitAccess false when last subscript has 2 expressions (bit range)", () => {
161
161
  // flags[0, 8] - bit range, not single bit access
162
- CodeGenState.typeRegistry.set("flags", {
162
+ CodeGenState.setVariableTypeInfo("flags", {
163
163
  baseType: "u32",
164
164
  bitWidth: 32,
165
165
  isArray: false,
@@ -180,7 +180,7 @@ describe("MemberChainAnalyzer", () => {
180
180
  pointFields.set("flags", "u8");
181
181
  setupStructFields("Point", pointFields);
182
182
 
183
- CodeGenState.typeRegistry.set("point", {
183
+ CodeGenState.setVariableTypeInfo("point", {
184
184
  baseType: "Point",
185
185
  bitWidth: 0,
186
186
  isArray: false,
@@ -209,7 +209,7 @@ describe("MemberChainAnalyzer", () => {
209
209
  gridFields.set("items", "u8");
210
210
  setupStructFields("Grid", gridFields, new Set(["items"]));
211
211
 
212
- CodeGenState.typeRegistry.set("grid", {
212
+ CodeGenState.setVariableTypeInfo("grid", {
213
213
  baseType: "Grid",
214
214
  bitWidth: 0,
215
215
  isArray: false,
@@ -236,7 +236,7 @@ describe("MemberChainAnalyzer", () => {
236
236
  pointFields.set("name", "string");
237
237
  setupStructFields("Point", pointFields);
238
238
 
239
- CodeGenState.typeRegistry.set("point", {
239
+ CodeGenState.setVariableTypeInfo("point", {
240
240
  baseType: "Point",
241
241
  bitWidth: 0,
242
242
  isArray: false,
@@ -263,7 +263,7 @@ describe("MemberChainAnalyzer", () => {
263
263
  deviceFields.set("flags", "u8");
264
264
  setupStructFields("Device", deviceFields);
265
265
 
266
- CodeGenState.typeRegistry.set("devices", {
266
+ CodeGenState.setVariableTypeInfo("devices", {
267
267
  baseType: "Device",
268
268
  bitWidth: 0,
269
269
  isArray: true,
@@ -290,7 +290,7 @@ describe("MemberChainAnalyzer", () => {
290
290
 
291
291
  it("returns false for 2D array element: matrix[0][1]", () => {
292
292
  // matrix[0][1] is array access, not bit access
293
- CodeGenState.typeRegistry.set("matrix", {
293
+ CodeGenState.setVariableTypeInfo("matrix", {
294
294
  baseType: "u8",
295
295
  bitWidth: 8,
296
296
  isArray: true,
@@ -315,7 +315,7 @@ describe("MemberChainAnalyzer", () => {
315
315
  it("detects bit access on 2D array element: matrix[0][1][3]", () => {
316
316
  // matrix[0][1][3] where matrix is u8[4][4]
317
317
  // The third subscript [3] is bit access on the u8 element
318
- CodeGenState.typeRegistry.set("matrix", {
318
+ CodeGenState.setVariableTypeInfo("matrix", {
319
319
  baseType: "u8",
320
320
  bitWidth: 8,
321
321
  isArray: true,
@@ -357,7 +357,7 @@ describe("MemberChainAnalyzer", () => {
357
357
 
358
358
  it("returns false for member access on non-struct", () => {
359
359
  // x.field[0] where x is a primitive
360
- CodeGenState.typeRegistry.set("x", {
360
+ CodeGenState.setVariableTypeInfo("x", {
361
361
  baseType: "u32",
362
362
  bitWidth: 32,
363
363
  isArray: false,
@@ -38,7 +38,7 @@ describe("StringLengthCounter", () => {
38
38
 
39
39
  describe("countExpression", () => {
40
40
  it("counts single .length access on string variable", () => {
41
- CodeGenState.typeRegistry.set("myStr", {
41
+ CodeGenState.setVariableTypeInfo("myStr", {
42
42
  baseType: "char",
43
43
  bitWidth: 8,
44
44
  isArray: false,
@@ -54,7 +54,7 @@ describe("StringLengthCounter", () => {
54
54
  });
55
55
 
56
56
  it("counts multiple .length accesses on same variable", () => {
57
- CodeGenState.typeRegistry.set("str", {
57
+ CodeGenState.setVariableTypeInfo("str", {
58
58
  baseType: "char",
59
59
  bitWidth: 8,
60
60
  isArray: false,
@@ -71,7 +71,7 @@ describe("StringLengthCounter", () => {
71
71
  });
72
72
 
73
73
  it("counts .length accesses on different string variables", () => {
74
- CodeGenState.typeRegistry.set("a", {
74
+ CodeGenState.setVariableTypeInfo("a", {
75
75
  baseType: "char",
76
76
  bitWidth: 8,
77
77
  isArray: false,
@@ -79,7 +79,7 @@ describe("StringLengthCounter", () => {
79
79
  isString: true,
80
80
  stringCapacity: 16,
81
81
  });
82
- CodeGenState.typeRegistry.set("b", {
82
+ CodeGenState.setVariableTypeInfo("b", {
83
83
  baseType: "char",
84
84
  bitWidth: 8,
85
85
  isArray: false,
@@ -96,7 +96,7 @@ describe("StringLengthCounter", () => {
96
96
  });
97
97
 
98
98
  it("ignores .length on non-string variables", () => {
99
- CodeGenState.typeRegistry.set("arr", {
99
+ CodeGenState.setVariableTypeInfo("arr", {
100
100
  baseType: "u8",
101
101
  bitWidth: 8,
102
102
  isArray: true,
@@ -111,7 +111,7 @@ describe("StringLengthCounter", () => {
111
111
  });
112
112
 
113
113
  it("ignores other member accesses", () => {
114
- CodeGenState.typeRegistry.set("obj", {
114
+ CodeGenState.setVariableTypeInfo("obj", {
115
115
  baseType: "MyStruct",
116
116
  bitWidth: 32,
117
117
  isArray: false,
@@ -135,7 +135,7 @@ describe("StringLengthCounter", () => {
135
135
 
136
136
  describe("countBlock", () => {
137
137
  it("counts .length accesses across multiple statements", () => {
138
- CodeGenState.typeRegistry.set("msg", {
138
+ CodeGenState.setVariableTypeInfo("msg", {
139
139
  baseType: "char",
140
140
  bitWidth: 8,
141
141
  isArray: false,
@@ -154,7 +154,7 @@ describe("StringLengthCounter", () => {
154
154
  });
155
155
 
156
156
  it("counts .length in assignment statements", () => {
157
- CodeGenState.typeRegistry.set("text", {
157
+ CodeGenState.setVariableTypeInfo("text", {
158
158
  baseType: "char",
159
159
  bitWidth: 8,
160
160
  isArray: false,
@@ -175,7 +175,7 @@ describe("StringLengthCounter", () => {
175
175
 
176
176
  describe("countBlockInto", () => {
177
177
  it("adds counts to existing map", () => {
178
- CodeGenState.typeRegistry.set("s1", {
178
+ CodeGenState.setVariableTypeInfo("s1", {
179
179
  baseType: "char",
180
180
  bitWidth: 8,
181
181
  isArray: false,
@@ -183,7 +183,7 @@ describe("StringLengthCounter", () => {
183
183
  isString: true,
184
184
  stringCapacity: 32,
185
185
  });
186
- CodeGenState.typeRegistry.set("s2", {
186
+ CodeGenState.setVariableTypeInfo("s2", {
187
187
  baseType: "char",
188
188
  bitWidth: 8,
189
189
  isArray: false,
@@ -209,7 +209,7 @@ describe("StringLengthCounter", () => {
209
209
 
210
210
  describe("nested expressions", () => {
211
211
  it("counts .length in ternary expressions", () => {
212
- CodeGenState.typeRegistry.set("str", {
212
+ CodeGenState.setVariableTypeInfo("str", {
213
213
  baseType: "char",
214
214
  bitWidth: 8,
215
215
  isArray: false,
@@ -225,7 +225,7 @@ describe("StringLengthCounter", () => {
225
225
  });
226
226
 
227
227
  it("counts .length in comparison expressions", () => {
228
- CodeGenState.typeRegistry.set("name", {
228
+ CodeGenState.setVariableTypeInfo("name", {
229
229
  baseType: "char",
230
230
  bitWidth: 8,
231
231
  isArray: false,
@@ -144,7 +144,7 @@ class AssignmentClassifier {
144
144
  varName: string,
145
145
  fieldName: string,
146
146
  ): AssignmentKind | null {
147
- const typeInfo = CodeGenState.typeRegistry.get(varName);
147
+ const typeInfo = CodeGenState.getVariableTypeInfo(varName);
148
148
  if (!typeInfo?.isBitmap || !typeInfo.bitmapTypeName) {
149
149
  return null;
150
150
  }
@@ -189,7 +189,7 @@ class AssignmentClassifier {
189
189
  }
190
190
 
191
191
  // Check if struct member bitmap field: struct.bitmapMember.field
192
- const structTypeInfo = CodeGenState.typeRegistry.get(firstName);
192
+ const structTypeInfo = CodeGenState.getVariableTypeInfo(firstName);
193
193
  if (
194
194
  !structTypeInfo ||
195
195
  !CodeGenState.isKnownStruct(structTypeInfo.baseType)
@@ -270,7 +270,7 @@ class AssignmentClassifier {
270
270
 
271
271
  const ids = ctx.identifiers;
272
272
  const firstId = ids[0];
273
- const typeInfo = CodeGenState.typeRegistry.get(firstId);
273
+ const typeInfo = CodeGenState.getVariableTypeInfo(firstId);
274
274
 
275
275
  // Check for bit range through struct chain: devices[0].control[0, 4]
276
276
  // Detected by last subscript having 2 expressions (start, width)
@@ -494,7 +494,7 @@ class AssignmentClassifier {
494
494
  }
495
495
 
496
496
  const name = ctx.identifiers[0];
497
- const typeInfo = CodeGenState.typeRegistry.get(name) ?? null;
497
+ const typeInfo = CodeGenState.getVariableTypeInfo(name) ?? null;
498
498
 
499
499
  // Use shared classifier for array vs bit access decision
500
500
  // Use lastSubscriptExprCount to distinguish [0][0] (two ops, each 1 expr)
@@ -558,16 +558,16 @@ class AssignmentClassifier {
558
558
  let typeInfo;
559
559
  if (ctx.isSimpleIdentifier) {
560
560
  const id = ctx.identifiers[0];
561
- typeInfo = CodeGenState.typeRegistry.get(id);
561
+ typeInfo = CodeGenState.getVariableTypeInfo(id);
562
562
  } else if (ctx.isSimpleThisAccess && CodeGenState.currentScope) {
563
563
  // this.member pattern: lookup using scoped name
564
564
  const memberName = ctx.identifiers[0];
565
565
  const scopedName = `${CodeGenState.currentScope}_${memberName}`;
566
- typeInfo = CodeGenState.typeRegistry.get(scopedName);
566
+ typeInfo = CodeGenState.getVariableTypeInfo(scopedName);
567
567
  } else if (ctx.isSimpleGlobalAccess) {
568
568
  // global.member pattern: lookup using direct name
569
569
  const memberName = ctx.identifiers[0];
570
- typeInfo = CodeGenState.typeRegistry.get(memberName);
570
+ typeInfo = CodeGenState.getVariableTypeInfo(memberName);
571
571
  } else {
572
572
  return null;
573
573
  }
@@ -604,7 +604,7 @@ class AssignmentClassifier {
604
604
  ): AssignmentKind | null {
605
605
  if (!ctx.isSimpleIdentifier) return null;
606
606
  const id = ctx.identifiers[0];
607
- const typeInfo = CodeGenState.typeRegistry.get(id);
607
+ const typeInfo = CodeGenState.getVariableTypeInfo(id);
608
608
  return AssignmentClassifier.isSimpleStringType(typeInfo)
609
609
  ? AssignmentKind.STRING_SIMPLE
610
610
  : null;
@@ -619,7 +619,7 @@ class AssignmentClassifier {
619
619
  if (!ctx.isSimpleThisAccess || !CodeGenState.currentScope) return null;
620
620
  const memberName = ctx.identifiers[0];
621
621
  const scopedName = `${CodeGenState.currentScope}_${memberName}`;
622
- const typeInfo = CodeGenState.typeRegistry.get(scopedName);
622
+ const typeInfo = CodeGenState.getVariableTypeInfo(scopedName);
623
623
  return AssignmentClassifier.isSimpleStringType(typeInfo)
624
624
  ? AssignmentKind.STRING_THIS_MEMBER
625
625
  : null;
@@ -633,7 +633,7 @@ class AssignmentClassifier {
633
633
  ): AssignmentKind | null {
634
634
  if (!ctx.isSimpleGlobalAccess) return null;
635
635
  const id = ctx.identifiers[0];
636
- const typeInfo = CodeGenState.typeRegistry.get(id);
636
+ const typeInfo = CodeGenState.getVariableTypeInfo(id);
637
637
  return AssignmentClassifier.isSimpleStringType(typeInfo)
638
638
  ? AssignmentKind.STRING_GLOBAL
639
639
  : null;
@@ -644,7 +644,7 @@ class AssignmentClassifier {
644
644
  * Returns the base struct type if valid, null if not a known struct.
645
645
  */
646
646
  private static _resolveStructType(structName: string): string | null {
647
- const structTypeInfo = CodeGenState.typeRegistry.get(structName);
647
+ const structTypeInfo = CodeGenState.getVariableTypeInfo(structName);
648
648
  if (
649
649
  !structTypeInfo ||
650
650
  !CodeGenState.isKnownStruct(structTypeInfo.baseType)
@@ -18,6 +18,15 @@ interface IContextBuilderDeps {
18
18
 
19
19
  /** Generate C expression for a value */
20
20
  generateExpression(ctx: Parser.ExpressionContext): string;
21
+
22
+ /** Generate fully-resolved assignment target with scope prefixes */
23
+ generateAssignmentTarget(ctx: Parser.AssignmentTargetContext): string;
24
+
25
+ /** Check if an identifier is a known register (for skipping resolution) */
26
+ isKnownRegister(name: string): boolean;
27
+
28
+ /** Current scope name (for scoped register detection) */
29
+ currentScope: string | null;
21
30
  }
22
31
 
23
32
  /**
@@ -32,6 +41,37 @@ interface ITargetExtraction {
32
41
  lastSubscriptExprCount: number;
33
42
  }
34
43
 
44
+ /**
45
+ * Extract the base identifier from a resolved target string.
46
+ * Removes subscripts ([...]) from the resolved target.
47
+ * Examples:
48
+ * "ArrayBug_data[0]" -> "ArrayBug_data"
49
+ * "matrix[i][j]" -> "matrix"
50
+ * "item.field" -> "item"
51
+ * "Motor_speed" -> "Motor_speed"
52
+ */
53
+ function extractResolvedBaseIdentifier(resolvedTarget: string): string {
54
+ // Assumes resolvedTarget always starts with a valid identifier (not empty or starting with [ . ->)
55
+ // as generated by generateAssignmentTarget()
56
+ const bracketIndex = resolvedTarget.indexOf("[");
57
+ const dotIndex = resolvedTarget.indexOf(".");
58
+ const arrowIndex = resolvedTarget.indexOf("->");
59
+
60
+ // Find the earliest terminator
61
+ let endIndex = resolvedTarget.length;
62
+ if (bracketIndex !== -1 && bracketIndex < endIndex) {
63
+ endIndex = bracketIndex;
64
+ }
65
+ if (dotIndex !== -1 && dotIndex < endIndex) {
66
+ endIndex = dotIndex;
67
+ }
68
+ if (arrowIndex !== -1 && arrowIndex < endIndex) {
69
+ endIndex = arrowIndex;
70
+ }
71
+
72
+ return resolvedTarget.substring(0, endIndex);
73
+ }
74
+
35
75
  /**
36
76
  * Extract base identifier from assignment target.
37
77
  * With unified grammar, all patterns use IDENTIFIER postfixTargetOp*.
@@ -100,6 +140,13 @@ function buildAssignmentContext(
100
140
  // Generate value expression
101
141
  const generatedValue = deps.generateExpression(valueCtx);
102
142
 
143
+ // Generate fully-resolved target (with scope prefixes)
144
+ const resolvedTarget = deps.generateAssignmentTarget(targetCtx);
145
+
146
+ // Extract resolved base identifier for type lookups
147
+ // Removes subscripts ([...]) and member access (. or ->) from the end
148
+ const resolvedBaseIdentifier = extractResolvedBaseIdentifier(resolvedTarget);
149
+
103
150
  // Extract target info
104
151
  const hasGlobal = targetCtx.GLOBAL() !== null;
105
152
  const hasThis = targetCtx.THIS() !== null;
@@ -152,6 +199,8 @@ function buildAssignmentContext(
152
199
  cOp,
153
200
  isCompound,
154
201
  generatedValue,
202
+ resolvedTarget,
203
+ resolvedBaseIdentifier,
155
204
  firstIdTypeInfo,
156
205
  memberAccessDepth,
157
206
  subscriptDepth,
@@ -67,6 +67,21 @@ interface IAssignmentContext {
67
67
  /** Generated C expression for the value (right-hand side) */
68
68
  readonly generatedValue: string;
69
69
 
70
+ /**
71
+ * Fully-resolved assignment target with scope prefixes applied.
72
+ * Use this instead of raw identifiers to ensure proper scope resolution.
73
+ * Example: "data" inside scope ArrayBug -> "ArrayBug_data"
74
+ */
75
+ readonly resolvedTarget: string;
76
+
77
+ /**
78
+ * Resolved base identifier for type lookups.
79
+ * Extracted from resolvedTarget by removing subscripts and member access.
80
+ * Example: "ArrayBug_data[0]" -> "ArrayBug_data"
81
+ * Use this for CodeGenState.typeRegistry lookups instead of identifiers[0].
82
+ */
83
+ readonly resolvedBaseIdentifier: string;
84
+
70
85
  // === Type info (looked up from registry) ===
71
86
 
72
87
  /** First identifier's type info, if found */
@@ -15,6 +15,11 @@ import TTypeInfo from "../../types/TTypeInfo";
15
15
  function createMockContext(
16
16
  overrides: Partial<IAssignmentContext> = {},
17
17
  ): IAssignmentContext {
18
+ // Compute resolvedBaseIdentifier from resolvedTarget if not explicitly provided
19
+ const resolvedTarget = overrides.resolvedTarget ?? "x";
20
+ const resolvedBaseIdentifier =
21
+ overrides.resolvedBaseIdentifier ?? resolvedTarget.split(/[[.]/)[0];
22
+
18
23
  return {
19
24
  statementCtx: {} as IAssignmentContext["statementCtx"],
20
25
  targetCtx: {} as IAssignmentContext["targetCtx"],
@@ -31,6 +36,8 @@ function createMockContext(
31
36
  cOp: "=",
32
37
  isCompound: false,
33
38
  generatedValue: "5",
39
+ resolvedTarget,
40
+ resolvedBaseIdentifier,
34
41
  firstIdTypeInfo: null,
35
42
  memberAccessDepth: 0,
36
43
  subscriptDepth: 0,
@@ -141,7 +148,7 @@ describe("AssignmentClassifier - Bitmap Fields", () => {
141
148
  ["StatusFlags", new Map([["Running", { offset: 0, width: 1 }]])],
142
149
  ]);
143
150
  setupSymbols({ bitmapFields });
144
- CodeGenState.typeRegistry.set(
151
+ CodeGenState.setVariableTypeInfo(
145
152
  "flags",
146
153
  createTypeInfo({ isBitmap: true, bitmapTypeName: "StatusFlags" }),
147
154
  );
@@ -162,7 +169,7 @@ describe("AssignmentClassifier - Bitmap Fields", () => {
162
169
  ["StatusFlags", new Map([["Mode", { offset: 4, width: 4 }]])],
163
170
  ]);
164
171
  setupSymbols({ bitmapFields });
165
- CodeGenState.typeRegistry.set(
172
+ CodeGenState.setVariableTypeInfo(
166
173
  "flags",
167
174
  createTypeInfo({ isBitmap: true, bitmapTypeName: "StatusFlags" }),
168
175
  );
@@ -206,7 +213,7 @@ describe("AssignmentClassifier - Bitmap Fields", () => {
206
213
  ["Device", new Map([["flags", "DeviceFlags"]])],
207
214
  ]);
208
215
  setupSymbols({ bitmapFields, knownStructs, structFields });
209
- CodeGenState.typeRegistry.set(
216
+ CodeGenState.setVariableTypeInfo(
210
217
  "device",
211
218
  createTypeInfo({ baseType: "Device" }),
212
219
  );
@@ -233,7 +240,10 @@ describe("AssignmentClassifier - Integer Bit Access", () => {
233
240
  });
234
241
 
235
242
  it("classifies single bit access on integer", () => {
236
- CodeGenState.typeRegistry.set("flags", createTypeInfo({ baseType: "u8" }));
243
+ CodeGenState.setVariableTypeInfo(
244
+ "flags",
245
+ createTypeInfo({ baseType: "u8" }),
246
+ );
237
247
 
238
248
  const ctx = createMockContext({
239
249
  identifiers: ["flags"],
@@ -246,7 +256,10 @@ describe("AssignmentClassifier - Integer Bit Access", () => {
246
256
  });
247
257
 
248
258
  it("classifies bit range access on integer", () => {
249
- CodeGenState.typeRegistry.set("flags", createTypeInfo({ baseType: "u32" }));
259
+ CodeGenState.setVariableTypeInfo(
260
+ "flags",
261
+ createTypeInfo({ baseType: "u32" }),
262
+ );
250
263
 
251
264
  const ctx = createMockContext({
252
265
  identifiers: ["flags"],
@@ -275,7 +288,7 @@ describe("AssignmentClassifier - Array Access", () => {
275
288
  });
276
289
 
277
290
  it("classifies simple array element", () => {
278
- CodeGenState.typeRegistry.set(
291
+ CodeGenState.setVariableTypeInfo(
279
292
  "arr",
280
293
  createTypeInfo({
281
294
  isArray: true,
@@ -296,7 +309,7 @@ describe("AssignmentClassifier - Array Access", () => {
296
309
  });
297
310
 
298
311
  it("classifies array slice", () => {
299
- CodeGenState.typeRegistry.set(
312
+ CodeGenState.setVariableTypeInfo(
300
313
  "buffer",
301
314
  createTypeInfo({
302
315
  isArray: true,
@@ -329,7 +342,7 @@ describe("AssignmentClassifier - String Assignments", () => {
329
342
  });
330
343
 
331
344
  it("classifies simple string variable", () => {
332
- CodeGenState.typeRegistry.set(
345
+ CodeGenState.setVariableTypeInfo(
333
346
  "name",
334
347
  createTypeInfo({
335
348
  baseType: "string<32>",
@@ -341,7 +354,7 @@ describe("AssignmentClassifier - String Assignments", () => {
341
354
  const ctx = createMockContext({
342
355
  identifiers: ["name"],
343
356
  isSimpleIdentifier: true,
344
- firstIdTypeInfo: CodeGenState.typeRegistry.get("name")!,
357
+ firstIdTypeInfo: CodeGenState.getVariableTypeInfo("name")!,
345
358
  });
346
359
 
347
360
  expect(AssignmentClassifier.classify(ctx)).toBe(
@@ -355,7 +368,7 @@ describe("AssignmentClassifier - String Assignments", () => {
355
368
  ["Person", new Map([["name", "string<64>"]])],
356
369
  ]);
357
370
  setupSymbols({ knownStructs, structFields });
358
- CodeGenState.typeRegistry.set(
371
+ CodeGenState.setVariableTypeInfo(
359
372
  "person",
360
373
  createTypeInfo({ baseType: "Person" }),
361
374
  );
@@ -382,7 +395,7 @@ describe("AssignmentClassifier - Special Compound", () => {
382
395
  });
383
396
 
384
397
  it("classifies atomic RMW", () => {
385
- CodeGenState.typeRegistry.set(
398
+ CodeGenState.setVariableTypeInfo(
386
399
  "counter",
387
400
  createTypeInfo({
388
401
  baseType: "u32",
@@ -401,7 +414,7 @@ describe("AssignmentClassifier - Special Compound", () => {
401
414
  });
402
415
 
403
416
  it("classifies overflow clamp", () => {
404
- CodeGenState.typeRegistry.set(
417
+ CodeGenState.setVariableTypeInfo(
405
418
  "saturated",
406
419
  createTypeInfo({
407
420
  baseType: "u8",
@@ -422,7 +435,7 @@ describe("AssignmentClassifier - Special Compound", () => {
422
435
  });
423
436
 
424
437
  it("does not classify float as overflow clamp", () => {
425
- CodeGenState.typeRegistry.set(
438
+ CodeGenState.setVariableTypeInfo(
426
439
  "value",
427
440
  createTypeInfo({
428
441
  baseType: "f32",
@@ -641,7 +654,7 @@ describe("AssignmentClassifier - Bitmap Array Element Field", () => {
641
654
  ["StatusFlags", new Map([["Active", { offset: 0, width: 1 }]])],
642
655
  ]);
643
656
  setupSymbols({ bitmapFields });
644
- CodeGenState.typeRegistry.set(
657
+ CodeGenState.setVariableTypeInfo(
645
658
  "flagsArr",
646
659
  createTypeInfo({
647
660
  isBitmap: true,
@@ -675,7 +688,7 @@ describe("AssignmentClassifier - Multi-dim Array Bit Indexing", () => {
675
688
  });
676
689
 
677
690
  it("classifies matrix[i][j][bit] as ARRAY_ELEMENT_BIT", () => {
678
- CodeGenState.typeRegistry.set(
691
+ CodeGenState.setVariableTypeInfo(
679
692
  "matrix",
680
693
  createTypeInfo({
681
694
  baseType: "u32",
@@ -702,7 +715,7 @@ describe("AssignmentClassifier - Multi-dim Array Bit Indexing", () => {
702
715
  });
703
716
 
704
717
  it("classifies matrix[i][j] as MULTI_DIM_ARRAY_ELEMENT", () => {
705
- CodeGenState.typeRegistry.set(
718
+ CodeGenState.setVariableTypeInfo(
706
719
  "matrix",
707
720
  createTypeInfo({
708
721
  baseType: "u32",
@@ -868,7 +881,7 @@ describe("AssignmentClassifier - Member Chain", () => {
868
881
  const knownStructs = new Set(["Config"]);
869
882
  const structFields = new Map([["Config", new Map([["items", "Item"]])]]);
870
883
  setupSymbols({ knownStructs, structFields });
871
- CodeGenState.typeRegistry.set(
884
+ CodeGenState.setVariableTypeInfo(
872
885
  "config",
873
886
  createTypeInfo({ baseType: "Config" }),
874
887
  );
@@ -20,26 +20,30 @@ function gen(): ICodeGenApi {
20
20
 
21
21
  /**
22
22
  * Handle simple array element: arr[i] <- value
23
+ *
24
+ * Uses resolvedTarget which includes scope prefix and subscript,
25
+ * e.g., "data[0]" inside scope ArrayBug -> "ArrayBug_data[0]"
23
26
  */
24
27
  function handleArrayElement(ctx: IAssignmentContext): string {
25
- const name = ctx.identifiers[0];
26
- const index = gen().generateExpression(ctx.subscripts[0]);
27
-
28
- return `${name}[${index}] ${ctx.cOp} ${ctx.generatedValue};`;
28
+ return `${ctx.resolvedTarget} ${ctx.cOp} ${ctx.generatedValue};`;
29
29
  }
30
30
 
31
31
  /**
32
32
  * Handle multi-dimensional array element: matrix[i][j] <- value
33
+ *
34
+ * Uses resolvedTarget which includes scope prefix and all subscripts.
35
+ * Uses resolvedBaseIdentifier for type lookups to support scoped arrays.
33
36
  */
34
37
  function handleMultiDimArrayElement(ctx: IAssignmentContext): string {
35
- const name = ctx.identifiers[0];
36
- const typeInfo = CodeGenState.typeRegistry.get(name);
38
+ // Use resolvedBaseIdentifier for type lookup (includes scope prefix)
39
+ // e.g., "ArrayBug_data" instead of "data"
40
+ const typeInfo = CodeGenState.getVariableTypeInfo(ctx.resolvedBaseIdentifier);
37
41
 
38
42
  // ADR-036: Compile-time bounds checking for constant indices
39
43
  if (typeInfo?.arrayDimensions) {
40
44
  const line = ctx.subscripts[0]?.start?.line ?? 0;
41
45
  TypeValidator.checkArrayBounds(
42
- name,
46
+ ctx.resolvedBaseIdentifier,
43
47
  [...typeInfo.arrayDimensions],
44
48
  [...ctx.subscripts],
45
49
  line,
@@ -47,11 +51,7 @@ function handleMultiDimArrayElement(ctx: IAssignmentContext): string {
47
51
  );
48
52
  }
49
53
 
50
- const indices = ctx.subscripts
51
- .map((e) => gen().generateExpression(e))
52
- .join("][");
53
-
54
- return `${name}[${indices}] ${ctx.cOp} ${ctx.generatedValue};`;
54
+ return `${ctx.resolvedTarget} ${ctx.cOp} ${ctx.generatedValue};`;
55
55
  }
56
56
 
57
57
  /**
@@ -69,18 +69,21 @@ function handleArraySlice(ctx: IAssignmentContext): string {
69
69
  );
70
70
  }
71
71
 
72
- const name = ctx.identifiers[0];
73
- const typeInfo = CodeGenState.typeRegistry.get(name);
72
+ // Use resolvedBaseIdentifier for type lookup (includes scope prefix)
73
+ const name = ctx.resolvedBaseIdentifier;
74
+ const typeInfo = CodeGenState.getVariableTypeInfo(name);
74
75
 
75
76
  // Get line number for error messages
76
77
  const line = ctx.subscripts[0].start?.line ?? 0;
77
78
 
78
79
  // Validate 1D array only
79
80
  if (typeInfo?.arrayDimensions && typeInfo.arrayDimensions.length > 1) {
81
+ // Use raw identifier in error message for clarity
82
+ const rawName = ctx.identifiers[0];
80
83
  throw new Error(
81
84
  `${line}:0 Error: Slice assignment is only valid on one-dimensional arrays. ` +
82
- `'${name}' has ${typeInfo.arrayDimensions.length} dimensions. ` +
83
- `Access the innermost dimension first (e.g., ${name}[index][offset, length]).`,
85
+ `'${rawName}' has ${typeInfo.arrayDimensions.length} dimensions. ` +
86
+ `Access the innermost dimension first (e.g., ${rawName}[index][offset, length]).`,
84
87
  );
85
88
  }
86
89
 
@@ -109,17 +112,21 @@ function handleArraySlice(ctx: IAssignmentContext): string {
109
112
  } else if (typeInfo?.arrayDimensions?.[0]) {
110
113
  capacity = typeInfo.arrayDimensions[0];
111
114
  } else {
115
+ // Use raw identifier in error message for clarity
116
+ const rawName = ctx.identifiers[0];
112
117
  throw new Error(
113
- `${line}:0 Error: Cannot determine buffer size for '${name}' at compile time.`,
118
+ `${line}:0 Error: Cannot determine buffer size for '${rawName}' at compile time.`,
114
119
  );
115
120
  }
116
121
 
117
122
  // Bounds validation
118
123
  if (offsetValue + lengthValue > capacity) {
124
+ // Use raw identifier in error message for clarity
125
+ const rawName = ctx.identifiers[0];
119
126
  throw new Error(
120
127
  `${line}:0 Error: Slice assignment out of bounds: ` +
121
128
  `offset(${offsetValue}) + length(${lengthValue}) = ${offsetValue + lengthValue} ` +
122
- `exceeds buffer capacity(${capacity}) for '${name}'.`,
129
+ `exceeds buffer capacity(${capacity}) for '${rawName}'.`,
123
130
  );
124
131
  }
125
132