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
@@ -4,37 +4,16 @@
4
4
  * Analyzes an assignment context and determines which AssignmentKind it is.
5
5
  * The classification order matches the original generateAssignment() method's
6
6
  * if-else chain to ensure identical behavior.
7
+ *
8
+ * Migrated to use CodeGenState instead of constructor DI.
7
9
  */
8
10
  import AssignmentKind from "./AssignmentKind";
9
11
  import IAssignmentContext from "./IAssignmentContext";
10
- import ICodeGenSymbols from "../../../types/ICodeGenSymbols";
12
+ import CodeGenState from "../CodeGenState";
11
13
  import SubscriptClassifier from "../subscript/SubscriptClassifier";
12
14
  import TTypeInfo from "../types/TTypeInfo";
13
15
  import TypeCheckUtils from "../../../../utils/TypeCheckUtils";
14
16
 
15
- /**
16
- * Dependencies for classification.
17
- */
18
- interface IClassifierDeps {
19
- /** Symbol information (registers, bitmaps, structs, etc.) */
20
- readonly symbols: ICodeGenSymbols;
21
-
22
- /** Type registry: variable name -> type info */
23
- readonly typeRegistry: ReadonlyMap<string, TTypeInfo>;
24
-
25
- /** Current scope name, null if not in scope */
26
- readonly currentScope: string | null;
27
-
28
- /** Check if a type name is a known struct */
29
- isKnownStruct(typeName: string): boolean;
30
-
31
- /** Check if a name is a known scope */
32
- isKnownScope(name: string): boolean;
33
-
34
- /** Get member type info for a struct field */
35
- getMemberTypeInfo(structType: string, memberName: string): TTypeInfo | null;
36
- }
37
-
38
17
  /**
39
18
  * Classifies assignment statements by analyzing their structure.
40
19
  *
@@ -48,12 +27,10 @@ interface IClassifierDeps {
48
27
  * 7. Simple fallback
49
28
  */
50
29
  class AssignmentClassifier {
51
- constructor(private readonly deps: IClassifierDeps) {}
52
-
53
30
  /**
54
31
  * Check if typeInfo represents a simple string type (not a 2D+ string array).
55
32
  */
56
- private isSimpleStringType(typeInfo: TTypeInfo | undefined): boolean {
33
+ private static isSimpleStringType(typeInfo: TTypeInfo | undefined): boolean {
57
34
  return (
58
35
  typeInfo?.isString === true &&
59
36
  typeInfo.stringCapacity !== undefined &&
@@ -64,7 +41,7 @@ class AssignmentClassifier {
64
41
  /**
65
42
  * Extract struct name and field name from a 2-identifier context.
66
43
  */
67
- private getStructFieldNames(
44
+ private static getStructFieldNames(
68
45
  ctx: IAssignmentContext,
69
46
  ): { structName: string; fieldName: string } | null {
70
47
  if (ctx.identifiers.length !== 2) {
@@ -76,39 +53,40 @@ class AssignmentClassifier {
76
53
  /**
77
54
  * Classify an assignment context into an AssignmentKind.
78
55
  */
79
- classify(ctx: IAssignmentContext): AssignmentKind {
56
+ static classify(ctx: IAssignmentContext): AssignmentKind {
80
57
  // === Priority 1: Bitmap field assignments ===
81
- const bitmapKind = this.classifyBitmapField(ctx);
58
+ const bitmapKind = AssignmentClassifier.classifyBitmapField(ctx);
82
59
  if (bitmapKind !== null) {
83
60
  return bitmapKind;
84
61
  }
85
62
 
86
63
  // === Priority 2: Member access with subscripts (arrays, register bits) ===
87
- const memberSubscriptKind = this.classifyMemberWithSubscript(ctx);
64
+ const memberSubscriptKind =
65
+ AssignmentClassifier.classifyMemberWithSubscript(ctx);
88
66
  if (memberSubscriptKind !== null) {
89
67
  return memberSubscriptKind;
90
68
  }
91
69
 
92
70
  // === Priority 3: Global/this prefix patterns ===
93
- const prefixKind = this.classifyPrefixPattern(ctx);
71
+ const prefixKind = AssignmentClassifier.classifyPrefixPattern(ctx);
94
72
  if (prefixKind !== null) {
95
73
  return prefixKind;
96
74
  }
97
75
 
98
76
  // === Priority 4: Simple array/bit access ===
99
- const arrayBitKind = this.classifyArrayOrBitAccess(ctx);
77
+ const arrayBitKind = AssignmentClassifier.classifyArrayOrBitAccess(ctx);
100
78
  if (arrayBitKind !== null) {
101
79
  return arrayBitKind;
102
80
  }
103
81
 
104
82
  // === Priority 5: Atomic/overflow compound assignments ===
105
- const specialKind = this.classifySpecialCompound(ctx);
83
+ const specialKind = AssignmentClassifier.classifySpecialCompound(ctx);
106
84
  if (specialKind !== null) {
107
85
  return specialKind;
108
86
  }
109
87
 
110
88
  // === Priority 6: String assignments ===
111
- const stringKind = this.classifyStringAssignment(ctx);
89
+ const stringKind = AssignmentClassifier.classifyStringAssignment(ctx);
112
90
  if (stringKind !== null) {
113
91
  return stringKind;
114
92
  }
@@ -127,7 +105,9 @@ class AssignmentClassifier {
127
105
  * Classify bitmap field assignments.
128
106
  * Patterns: var.field, struct.bitmapMember.field, REG.MEMBER.field, Scope.REG.MEMBER.field
129
107
  */
130
- private classifyBitmapField(ctx: IAssignmentContext): AssignmentKind | null {
108
+ private static classifyBitmapField(
109
+ ctx: IAssignmentContext,
110
+ ): AssignmentKind | null {
131
111
  // Must have member access without subscripts
132
112
  if (!ctx.hasMemberAccess || ctx.hasArrayAccess) {
133
113
  return null;
@@ -139,15 +119,19 @@ class AssignmentClassifier {
139
119
  }
140
120
 
141
121
  if (ids.length === 2) {
142
- return this.classifySimpleBitmapField(ids[0], ids[1]);
122
+ return AssignmentClassifier.classifySimpleBitmapField(ids[0], ids[1]);
143
123
  }
144
124
 
145
125
  if (ids.length === 3) {
146
- return this.classifyThreeIdBitmapField(ids[0], ids[1], ids[2]);
126
+ return AssignmentClassifier.classifyThreeIdBitmapField(
127
+ ids[0],
128
+ ids[1],
129
+ ids[2],
130
+ );
147
131
  }
148
132
 
149
133
  if (ids.length === 4) {
150
- return this.classifyScopedRegisterBitmapField(ids);
134
+ return AssignmentClassifier.classifyScopedRegisterBitmapField(ids);
151
135
  }
152
136
 
153
137
  return null;
@@ -156,16 +140,16 @@ class AssignmentClassifier {
156
140
  /**
157
141
  * Classify 2-id bitmap field: var.field
158
142
  */
159
- private classifySimpleBitmapField(
143
+ private static classifySimpleBitmapField(
160
144
  varName: string,
161
145
  fieldName: string,
162
146
  ): AssignmentKind | null {
163
- const typeInfo = this.deps.typeRegistry.get(varName);
147
+ const typeInfo = CodeGenState.typeRegistry.get(varName);
164
148
  if (!typeInfo?.isBitmap || !typeInfo.bitmapTypeName) {
165
149
  return null;
166
150
  }
167
151
 
168
- const width = this.lookupBitmapFieldWidth(
152
+ const width = AssignmentClassifier.lookupBitmapFieldWidth(
169
153
  typeInfo.bitmapTypeName,
170
154
  fieldName,
171
155
  );
@@ -181,19 +165,22 @@ class AssignmentClassifier {
181
165
  /**
182
166
  * Classify 3-id bitmap field: REG.MEMBER.field or struct.bitmapMember.field
183
167
  */
184
- private classifyThreeIdBitmapField(
168
+ private static classifyThreeIdBitmapField(
185
169
  firstName: string,
186
170
  secondName: string,
187
171
  fieldName: string,
188
172
  ): AssignmentKind | null {
189
173
  // Check if register member bitmap field: REG.MEMBER.field
190
- if (this.deps.symbols.knownRegisters.has(firstName)) {
191
- const bitmapType = this.lookupRegisterMemberBitmapType(
174
+ if (CodeGenState.symbols!.knownRegisters.has(firstName)) {
175
+ const bitmapType = AssignmentClassifier.lookupRegisterMemberBitmapType(
192
176
  firstName,
193
177
  secondName,
194
178
  );
195
179
  if (bitmapType) {
196
- const width = this.lookupBitmapFieldWidth(bitmapType, fieldName);
180
+ const width = AssignmentClassifier.lookupBitmapFieldWidth(
181
+ bitmapType,
182
+ fieldName,
183
+ );
197
184
  if (width !== null) {
198
185
  return AssignmentKind.REGISTER_MEMBER_BITMAP_FIELD;
199
186
  }
@@ -202,12 +189,15 @@ class AssignmentClassifier {
202
189
  }
203
190
 
204
191
  // Check if struct member bitmap field: struct.bitmapMember.field
205
- const structTypeInfo = this.deps.typeRegistry.get(firstName);
206
- if (!structTypeInfo || !this.deps.isKnownStruct(structTypeInfo.baseType)) {
192
+ const structTypeInfo = CodeGenState.typeRegistry.get(firstName);
193
+ if (
194
+ !structTypeInfo ||
195
+ !CodeGenState.isKnownStruct(structTypeInfo.baseType)
196
+ ) {
207
197
  return null;
208
198
  }
209
199
 
210
- const memberInfo = this.deps.getMemberTypeInfo(
200
+ const memberInfo = CodeGenState.getMemberTypeInfo(
211
201
  structTypeInfo.baseType,
212
202
  secondName,
213
203
  );
@@ -215,7 +205,10 @@ class AssignmentClassifier {
215
205
  return null;
216
206
  }
217
207
 
218
- const width = this.lookupBitmapFieldWidth(memberInfo.baseType, fieldName);
208
+ const width = AssignmentClassifier.lookupBitmapFieldWidth(
209
+ memberInfo.baseType,
210
+ fieldName,
211
+ );
219
212
  if (width !== null) {
220
213
  return AssignmentKind.STRUCT_MEMBER_BITMAP_FIELD;
221
214
  }
@@ -226,25 +219,31 @@ class AssignmentClassifier {
226
219
  /**
227
220
  * Classify 4-id scoped register bitmap field: Scope.REG.MEMBER.field
228
221
  */
229
- private classifyScopedRegisterBitmapField(
222
+ private static classifyScopedRegisterBitmapField(
230
223
  ids: readonly string[],
231
224
  ): AssignmentKind | null {
232
225
  const scopeName = ids[0];
233
- if (!this.deps.isKnownScope(scopeName)) {
226
+ if (!CodeGenState.isKnownScope(scopeName)) {
234
227
  return null;
235
228
  }
236
229
 
237
230
  const fullRegName = `${scopeName}_${ids[1]}`;
238
- if (!this.deps.symbols.knownRegisters.has(fullRegName)) {
231
+ if (!CodeGenState.symbols!.knownRegisters.has(fullRegName)) {
239
232
  return null;
240
233
  }
241
234
 
242
- const bitmapType = this.lookupRegisterMemberBitmapType(fullRegName, ids[2]);
235
+ const bitmapType = AssignmentClassifier.lookupRegisterMemberBitmapType(
236
+ fullRegName,
237
+ ids[2],
238
+ );
243
239
  if (!bitmapType) {
244
240
  return null;
245
241
  }
246
242
 
247
- const width = this.lookupBitmapFieldWidth(bitmapType, ids[3]);
243
+ const width = AssignmentClassifier.lookupBitmapFieldWidth(
244
+ bitmapType,
245
+ ids[3],
246
+ );
248
247
  if (width !== null) {
249
248
  return AssignmentKind.SCOPED_REGISTER_MEMBER_BITMAP_FIELD;
250
249
  }
@@ -256,7 +255,7 @@ class AssignmentClassifier {
256
255
  * Classify member access with subscripts.
257
256
  * Patterns: arr[i][j], struct.arr[i], REG.MEMBER[bit], matrix[i][j][bit]
258
257
  */
259
- private classifyMemberWithSubscript(
258
+ private static classifyMemberWithSubscript(
260
259
  ctx: IAssignmentContext,
261
260
  ): AssignmentKind | null {
262
261
  // Need subscripts through memberAccess pattern
@@ -271,7 +270,7 @@ class AssignmentClassifier {
271
270
 
272
271
  const ids = ctx.identifiers;
273
272
  const firstId = ids[0];
274
- const typeInfo = this.deps.typeRegistry.get(firstId);
273
+ const typeInfo = CodeGenState.typeRegistry.get(firstId);
275
274
 
276
275
  // Check for bit range through struct chain: devices[0].control[0, 4]
277
276
  // Detected by last subscript having 2 expressions (start, width)
@@ -281,12 +280,15 @@ class AssignmentClassifier {
281
280
 
282
281
  // Multi-dimensional array element: arr[i][j] (1 identifier, multiple subscripts)
283
282
  if (ids.length === 1) {
284
- return this.classifyMultiDimArrayAccess(typeInfo, ctx.subscripts.length);
283
+ return AssignmentClassifier.classifyMultiDimArrayAccess(
284
+ typeInfo,
285
+ ctx.subscripts.length,
286
+ );
285
287
  }
286
288
 
287
289
  // 2+ identifiers with subscripts: register bit or bitmap array
288
290
  if (ids.length >= 2) {
289
- const registerKind = this.classifyRegisterBitAccess(
291
+ const registerKind = AssignmentClassifier.classifyRegisterBitAccess(
290
292
  ids,
291
293
  ctx.subscripts.length,
292
294
  );
@@ -294,7 +296,7 @@ class AssignmentClassifier {
294
296
  return registerKind;
295
297
  }
296
298
 
297
- return this.classifyBitmapArrayField(
299
+ return AssignmentClassifier.classifyBitmapArrayField(
298
300
  ids[1],
299
301
  typeInfo,
300
302
  ctx.subscripts.length,
@@ -307,7 +309,7 @@ class AssignmentClassifier {
307
309
  /**
308
310
  * Classify multi-dimensional array access: arr[i][j] or arr[i][j][bit]
309
311
  */
310
- private classifyMultiDimArrayAccess(
312
+ private static classifyMultiDimArrayAccess(
311
313
  typeInfo: TTypeInfo | undefined,
312
314
  subscriptCount: number,
313
315
  ): AssignmentKind | null {
@@ -331,16 +333,16 @@ class AssignmentClassifier {
331
333
  /**
332
334
  * Classify register bit access: REG.MEMBER[bit] or Scope.REG.MEMBER[bit]
333
335
  */
334
- private classifyRegisterBitAccess(
336
+ private static classifyRegisterBitAccess(
335
337
  ids: readonly string[],
336
338
  subscriptCount: number,
337
339
  ): AssignmentKind | null {
338
340
  const firstId = ids[0];
339
341
 
340
342
  // Check for scoped register: Scope.REG.MEMBER[bit]
341
- if (this.deps.isKnownScope(firstId) && ids.length >= 3) {
343
+ if (CodeGenState.isKnownScope(firstId) && ids.length >= 3) {
342
344
  const scopedRegName = `${firstId}_${ids[1]}`;
343
- if (this.deps.symbols.knownRegisters.has(scopedRegName)) {
345
+ if (CodeGenState.symbols!.knownRegisters.has(scopedRegName)) {
344
346
  return subscriptCount === 2
345
347
  ? AssignmentKind.REGISTER_BIT_RANGE
346
348
  : AssignmentKind.REGISTER_BIT;
@@ -348,7 +350,7 @@ class AssignmentClassifier {
348
350
  }
349
351
 
350
352
  // Check for non-scoped register: REG.MEMBER[bit]
351
- if (this.deps.symbols.knownRegisters.has(firstId)) {
353
+ if (CodeGenState.symbols!.knownRegisters.has(firstId)) {
352
354
  return subscriptCount === 2
353
355
  ? AssignmentKind.REGISTER_BIT_RANGE
354
356
  : AssignmentKind.REGISTER_BIT;
@@ -360,7 +362,7 @@ class AssignmentClassifier {
360
362
  /**
361
363
  * Classify bitmap array element field: bitmapArr[i].field
362
364
  */
363
- private classifyBitmapArrayField(
365
+ private static classifyBitmapArrayField(
364
366
  secondId: string,
365
367
  typeInfo: TTypeInfo | undefined,
366
368
  subscriptCount: number,
@@ -373,7 +375,7 @@ class AssignmentClassifier {
373
375
  return null;
374
376
  }
375
377
 
376
- const width = this.lookupBitmapFieldWidth(
378
+ const width = AssignmentClassifier.lookupBitmapFieldWidth(
377
379
  typeInfo.bitmapTypeName,
378
380
  secondId,
379
381
  );
@@ -387,7 +389,7 @@ class AssignmentClassifier {
387
389
  /**
388
390
  * Classify global.* and this.* prefix patterns.
389
391
  */
390
- private classifyPrefixPattern(
392
+ private static classifyPrefixPattern(
391
393
  ctx: IAssignmentContext,
392
394
  ): AssignmentKind | null {
393
395
  if (!ctx.hasGlobal && !ctx.hasThis) {
@@ -395,11 +397,11 @@ class AssignmentClassifier {
395
397
  }
396
398
 
397
399
  if (ctx.hasGlobal && ctx.postfixOpsCount > 0) {
398
- return this.classifyGlobalPrefix(ctx);
400
+ return AssignmentClassifier.classifyGlobalPrefix(ctx);
399
401
  }
400
402
 
401
403
  if (ctx.hasThis && ctx.postfixOpsCount > 0) {
402
- return this.classifyThisPrefix(ctx);
404
+ return AssignmentClassifier.classifyThisPrefix(ctx);
403
405
  }
404
406
 
405
407
  return null;
@@ -408,11 +410,11 @@ class AssignmentClassifier {
408
410
  /**
409
411
  * Classify global.* patterns: global.reg[bit], global.arr[i], global.member
410
412
  */
411
- private classifyGlobalPrefix(ctx: IAssignmentContext): AssignmentKind {
413
+ private static classifyGlobalPrefix(ctx: IAssignmentContext): AssignmentKind {
412
414
  const firstId = ctx.identifiers[0];
413
415
 
414
416
  if (ctx.hasArrayAccess) {
415
- if (this.deps.symbols.knownRegisters.has(firstId)) {
417
+ if (CodeGenState.symbols!.knownRegisters.has(firstId)) {
416
418
  return AssignmentKind.GLOBAL_REGISTER_BIT;
417
419
  }
418
420
  return AssignmentKind.GLOBAL_ARRAY;
@@ -424,24 +426,27 @@ class AssignmentClassifier {
424
426
  /**
425
427
  * Classify this.* patterns: this.reg[bit], this.member, this.REG.MEMBER.field
426
428
  */
427
- private classifyThisPrefix(ctx: IAssignmentContext): AssignmentKind {
428
- if (!this.deps.currentScope) {
429
+ private static classifyThisPrefix(ctx: IAssignmentContext): AssignmentKind {
430
+ if (!CodeGenState.currentScope) {
429
431
  return AssignmentKind.THIS_MEMBER;
430
432
  }
431
433
 
432
434
  const firstId = ctx.identifiers[0];
433
- const scopedRegName = `${this.deps.currentScope}_${firstId}`;
435
+ const scopedRegName = `${CodeGenState.currentScope}_${firstId}`;
434
436
 
435
437
  if (ctx.hasArrayAccess) {
436
- return this.classifyThisWithArrayAccess(ctx, scopedRegName);
438
+ return AssignmentClassifier.classifyThisWithArrayAccess(
439
+ ctx,
440
+ scopedRegName,
441
+ );
437
442
  }
438
443
 
439
444
  // this.REG.MEMBER.field (scoped register bitmap field)
440
445
  if (
441
446
  ctx.identifiers.length === 3 &&
442
- this.deps.symbols.knownRegisters.has(scopedRegName)
447
+ CodeGenState.symbols!.knownRegisters.has(scopedRegName)
443
448
  ) {
444
- const bitmapType = this.lookupRegisterMemberBitmapType(
449
+ const bitmapType = AssignmentClassifier.lookupRegisterMemberBitmapType(
445
450
  scopedRegName,
446
451
  ctx.identifiers[1],
447
452
  );
@@ -456,11 +461,11 @@ class AssignmentClassifier {
456
461
  /**
457
462
  * Classify this.reg[bit] / this.arr[i] patterns with array access.
458
463
  */
459
- private classifyThisWithArrayAccess(
464
+ private static classifyThisWithArrayAccess(
460
465
  ctx: IAssignmentContext,
461
466
  scopedRegName: string,
462
467
  ): AssignmentKind {
463
- if (this.deps.symbols.knownRegisters.has(scopedRegName)) {
468
+ if (CodeGenState.symbols!.knownRegisters.has(scopedRegName)) {
464
469
  const hasBitRange = ctx.postfixOps.some((op) => op.COMMA() !== null);
465
470
  return hasBitRange
466
471
  ? AssignmentKind.SCOPED_REGISTER_BIT_RANGE
@@ -476,7 +481,7 @@ class AssignmentClassifier {
476
481
  * Issue #579: Uses shared SubscriptClassifier to ensure consistent behavior
477
482
  * with the expression path in CodeGenerator._generatePostfixExpr.
478
483
  */
479
- private classifyArrayOrBitAccess(
484
+ private static classifyArrayOrBitAccess(
480
485
  ctx: IAssignmentContext,
481
486
  ): AssignmentKind | null {
482
487
  // Must have arrayAccess without memberAccess or prefix
@@ -489,7 +494,7 @@ class AssignmentClassifier {
489
494
  }
490
495
 
491
496
  const name = ctx.identifiers[0];
492
- const typeInfo = this.deps.typeRegistry.get(name) ?? null;
497
+ const typeInfo = CodeGenState.typeRegistry.get(name) ?? null;
493
498
 
494
499
  // Use shared classifier for array vs bit access decision
495
500
  // Use lastSubscriptExprCount to distinguish [0][0] (two ops, each 1 expr)
@@ -542,7 +547,7 @@ class AssignmentClassifier {
542
547
  * Classify atomic and overflow-clamped compound assignments.
543
548
  * Handles simple identifiers, this.member, and global.member patterns.
544
549
  */
545
- private classifySpecialCompound(
550
+ private static classifySpecialCompound(
546
551
  ctx: IAssignmentContext,
547
552
  ): AssignmentKind | null {
548
553
  if (!ctx.isCompound) {
@@ -553,16 +558,16 @@ class AssignmentClassifier {
553
558
  let typeInfo;
554
559
  if (ctx.isSimpleIdentifier) {
555
560
  const id = ctx.identifiers[0];
556
- typeInfo = this.deps.typeRegistry.get(id);
557
- } else if (ctx.isSimpleThisAccess && this.deps.currentScope) {
561
+ typeInfo = CodeGenState.typeRegistry.get(id);
562
+ } else if (ctx.isSimpleThisAccess && CodeGenState.currentScope) {
558
563
  // this.member pattern: lookup using scoped name
559
564
  const memberName = ctx.identifiers[0];
560
- const scopedName = `${this.deps.currentScope}_${memberName}`;
561
- typeInfo = this.deps.typeRegistry.get(scopedName);
565
+ const scopedName = `${CodeGenState.currentScope}_${memberName}`;
566
+ typeInfo = CodeGenState.typeRegistry.get(scopedName);
562
567
  } else if (ctx.isSimpleGlobalAccess) {
563
568
  // global.member pattern: lookup using direct name
564
569
  const memberName = ctx.identifiers[0];
565
- typeInfo = this.deps.typeRegistry.get(memberName);
570
+ typeInfo = CodeGenState.typeRegistry.get(memberName);
566
571
  } else {
567
572
  return null;
568
573
  }
@@ -594,13 +599,13 @@ class AssignmentClassifier {
594
599
  /**
595
600
  * Check if a simple identifier is a string variable.
596
601
  */
597
- private _classifySimpleStringVar(
602
+ private static _classifySimpleStringVar(
598
603
  ctx: IAssignmentContext,
599
604
  ): AssignmentKind | null {
600
605
  if (!ctx.isSimpleIdentifier) return null;
601
606
  const id = ctx.identifiers[0];
602
- const typeInfo = this.deps.typeRegistry.get(id);
603
- return this.isSimpleStringType(typeInfo)
607
+ const typeInfo = CodeGenState.typeRegistry.get(id);
608
+ return AssignmentClassifier.isSimpleStringType(typeInfo)
604
609
  ? AssignmentKind.STRING_SIMPLE
605
610
  : null;
606
611
  }
@@ -608,14 +613,14 @@ class AssignmentClassifier {
608
613
  /**
609
614
  * Check if this.member is a string.
610
615
  */
611
- private _classifyThisMemberString(
616
+ private static _classifyThisMemberString(
612
617
  ctx: IAssignmentContext,
613
618
  ): AssignmentKind | null {
614
- if (!ctx.isSimpleThisAccess || !this.deps.currentScope) return null;
619
+ if (!ctx.isSimpleThisAccess || !CodeGenState.currentScope) return null;
615
620
  const memberName = ctx.identifiers[0];
616
- const scopedName = `${this.deps.currentScope}_${memberName}`;
617
- const typeInfo = this.deps.typeRegistry.get(scopedName);
618
- return this.isSimpleStringType(typeInfo)
621
+ const scopedName = `${CodeGenState.currentScope}_${memberName}`;
622
+ const typeInfo = CodeGenState.typeRegistry.get(scopedName);
623
+ return AssignmentClassifier.isSimpleStringType(typeInfo)
619
624
  ? AssignmentKind.STRING_THIS_MEMBER
620
625
  : null;
621
626
  }
@@ -623,13 +628,13 @@ class AssignmentClassifier {
623
628
  /**
624
629
  * Check if global.member is a string.
625
630
  */
626
- private _classifyGlobalString(
631
+ private static _classifyGlobalString(
627
632
  ctx: IAssignmentContext,
628
633
  ): AssignmentKind | null {
629
634
  if (!ctx.isSimpleGlobalAccess) return null;
630
635
  const id = ctx.identifiers[0];
631
- const typeInfo = this.deps.typeRegistry.get(id);
632
- return this.isSimpleStringType(typeInfo)
636
+ const typeInfo = CodeGenState.typeRegistry.get(id);
637
+ return AssignmentClassifier.isSimpleStringType(typeInfo)
633
638
  ? AssignmentKind.STRING_GLOBAL
634
639
  : null;
635
640
  }
@@ -638,9 +643,12 @@ class AssignmentClassifier {
638
643
  * Resolve struct type from variable name.
639
644
  * Returns the base struct type if valid, null if not a known struct.
640
645
  */
641
- private _resolveStructType(structName: string): string | null {
642
- const structTypeInfo = this.deps.typeRegistry.get(structName);
643
- if (!structTypeInfo || !this.deps.isKnownStruct(structTypeInfo.baseType)) {
646
+ private static _resolveStructType(structName: string): string | null {
647
+ const structTypeInfo = CodeGenState.typeRegistry.get(structName);
648
+ if (
649
+ !structTypeInfo ||
650
+ !CodeGenState.isKnownStruct(structTypeInfo.baseType)
651
+ ) {
644
652
  return null;
645
653
  }
646
654
  return structTypeInfo.baseType;
@@ -650,15 +658,17 @@ class AssignmentClassifier {
650
658
  * Resolve struct field type from struct variable name and field name.
651
659
  * Returns null if struct type can't be resolved or field doesn't exist.
652
660
  */
653
- private _resolveStructFieldType(structFieldNames: {
661
+ private static _resolveStructFieldType(structFieldNames: {
654
662
  structName: string;
655
663
  fieldName: string;
656
664
  }): { structType: string; fieldType: string | undefined } | null {
657
- const structType = this._resolveStructType(structFieldNames.structName);
665
+ const structType = AssignmentClassifier._resolveStructType(
666
+ structFieldNames.structName,
667
+ );
658
668
  if (!structType) {
659
669
  return null;
660
670
  }
661
- const structFields = this.deps.symbols.structFields.get(structType);
671
+ const structFields = CodeGenState.symbols!.structFields.get(structType);
662
672
  const fieldType = structFields?.get(structFieldNames.fieldName);
663
673
  return { structType, fieldType };
664
674
  }
@@ -666,14 +676,15 @@ class AssignmentClassifier {
666
676
  /**
667
677
  * Check if struct.field is a string field.
668
678
  */
669
- private _classifyStructFieldString(
679
+ private static _classifyStructFieldString(
670
680
  ctx: IAssignmentContext,
671
681
  structFieldNames: { structName: string; fieldName: string } | null,
672
682
  ): AssignmentKind | null {
673
683
  if (!ctx.hasMemberAccess || ctx.hasArrayAccess || !structFieldNames) {
674
684
  return null;
675
685
  }
676
- const resolved = this._resolveStructFieldType(structFieldNames);
686
+ const resolved =
687
+ AssignmentClassifier._resolveStructFieldType(structFieldNames);
677
688
  if (!resolved) {
678
689
  return null;
679
690
  }
@@ -685,7 +696,7 @@ class AssignmentClassifier {
685
696
  /**
686
697
  * Check if struct.arr[i] is a string array element.
687
698
  */
688
- private _classifyStructArrayElementString(
699
+ private static _classifyStructArrayElementString(
689
700
  ctx: IAssignmentContext,
690
701
  structFieldNames: { structName: string; fieldName: string } | null,
691
702
  ): AssignmentKind | null {
@@ -697,17 +708,19 @@ class AssignmentClassifier {
697
708
  ) {
698
709
  return null;
699
710
  }
700
- const resolved = this._resolveStructFieldType(structFieldNames);
711
+ const resolved =
712
+ AssignmentClassifier._resolveStructFieldType(structFieldNames);
701
713
  if (!resolved) {
702
714
  return null;
703
715
  }
704
716
 
705
717
  const { structType, fieldType } = resolved;
706
718
  const { fieldName } = structFieldNames;
707
- const fieldArrays = this.deps.symbols.structFieldArrays.get(structType);
708
- const dimensions = this.deps.symbols.structFieldDimensions
709
- .get(structType)
710
- ?.get(fieldName);
719
+ const fieldArrays = CodeGenState.symbols!.structFieldArrays.get(structType);
720
+ const dimensions =
721
+ CodeGenState.symbols!.structFieldDimensions.get(structType)?.get(
722
+ fieldName,
723
+ );
711
724
 
712
725
  const isStringArrayField =
713
726
  fieldType &&
@@ -724,30 +737,34 @@ class AssignmentClassifier {
724
737
  /**
725
738
  * Classify string assignments.
726
739
  */
727
- private classifyStringAssignment(
740
+ private static classifyStringAssignment(
728
741
  ctx: IAssignmentContext,
729
742
  ): AssignmentKind | null {
730
743
  // Simple string variable
731
- const simpleVar = this._classifySimpleStringVar(ctx);
744
+ const simpleVar = AssignmentClassifier._classifySimpleStringVar(ctx);
732
745
  if (simpleVar) return simpleVar;
733
746
 
734
747
  // this.member string
735
- const thisMember = this._classifyThisMemberString(ctx);
748
+ const thisMember = AssignmentClassifier._classifyThisMemberString(ctx);
736
749
  if (thisMember) return thisMember;
737
750
 
738
751
  // global.member string
739
- const globalMember = this._classifyGlobalString(ctx);
752
+ const globalMember = AssignmentClassifier._classifyGlobalString(ctx);
740
753
  if (globalMember) return globalMember;
741
754
 
742
755
  // struct.field or struct.arr[i] string
743
- const structFieldNames = this.getStructFieldNames(ctx);
744
- const structField = this._classifyStructFieldString(ctx, structFieldNames);
745
- if (structField) return structField;
746
-
747
- const structArrayElement = this._classifyStructArrayElementString(
756
+ const structFieldNames = AssignmentClassifier.getStructFieldNames(ctx);
757
+ const structField = AssignmentClassifier._classifyStructFieldString(
748
758
  ctx,
749
759
  structFieldNames,
750
760
  );
761
+ if (structField) return structField;
762
+
763
+ const structArrayElement =
764
+ AssignmentClassifier._classifyStructArrayElementString(
765
+ ctx,
766
+ structFieldNames,
767
+ );
751
768
  if (structArrayElement) return structArrayElement;
752
769
 
753
770
  return null;
@@ -757,11 +774,11 @@ class AssignmentClassifier {
757
774
  * Look up a bitmap field's width by bitmap type name and field name.
758
775
  * Returns the field width if found, or null if the bitmap/field doesn't exist.
759
776
  */
760
- private lookupBitmapFieldWidth(
777
+ private static lookupBitmapFieldWidth(
761
778
  bitmapTypeName: string,
762
779
  fieldName: string,
763
780
  ): number | null {
764
- const fields = this.deps.symbols.bitmapFields.get(bitmapTypeName);
781
+ const fields = CodeGenState.symbols!.bitmapFields.get(bitmapTypeName);
765
782
  if (fields?.has(fieldName)) {
766
783
  return fields.get(fieldName)!.width;
767
784
  }
@@ -772,12 +789,12 @@ class AssignmentClassifier {
772
789
  * Look up the bitmap type for a register member (e.g., "REG_MEMBER" -> "BitmapType").
773
790
  * Returns the bitmap type name if found, or null.
774
791
  */
775
- private lookupRegisterMemberBitmapType(
792
+ private static lookupRegisterMemberBitmapType(
776
793
  registerName: string,
777
794
  memberName: string,
778
795
  ): string | null {
779
796
  const key = `${registerName}_${memberName}`;
780
- return this.deps.symbols.registerMemberTypes.get(key) ?? null;
797
+ return CodeGenState.symbols!.registerMemberTypes.get(key) ?? null;
781
798
  }
782
799
  }
783
800