c-next 0.1.62 → 0.1.64

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 +848 -1382
  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 +462 -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
@@ -132,6 +132,12 @@ import AssignmentTargetExtractor from "./helpers/AssignmentTargetExtractor";
132
132
  import TypeGenerationHelper from "./helpers/TypeGenerationHelper";
133
133
  // Phase 5: Cast validation helper for improved testability
134
134
  import CastValidator from "./helpers/CastValidator";
135
+ // Global state for code generation (simplifies debugging, eliminates DI complexity)
136
+ import CodeGenState from "./CodeGenState";
137
+ // Extracted resolvers that use CodeGenState
138
+ import SizeofResolver from "./resolution/SizeofResolver";
139
+ import EnumTypeResolver from "./resolution/EnumTypeResolver";
140
+ import ScopeResolver from "./resolution/ScopeResolver";
135
141
 
136
142
  const {
137
143
  generateOverflowHelpers: helperGenerateOverflowHelpers,
@@ -179,25 +185,6 @@ interface FunctionSignature {
179
185
  }>;
180
186
  }
181
187
 
182
- /**
183
- * ADR-029: Callback type info for Function-as-Type pattern
184
- * Each function definition creates both a callable function AND a type
185
- */
186
- interface CallbackTypeInfo {
187
- functionName: string; // The original function name (also the type name)
188
- returnType: string; // Return type for typedef (C type)
189
- parameters: Array<{
190
- // Parameter info for typedef
191
- name: string;
192
- type: string; // C type
193
- isConst: boolean;
194
- isPointer: boolean; // ADR-006: Non-array params become pointers
195
- isArray: boolean; // Array parameters pass naturally as pointers
196
- arrayDims: string; // Array dimensions if applicable
197
- }>;
198
- typedefName: string; // e.g., "onReceive_fp"
199
- }
200
-
201
188
  /**
202
189
  * ADR-049: Target platform capabilities for code generation
203
190
  */
@@ -249,7 +236,7 @@ interface GeneratorContext {
249
236
  indentLevel: number;
250
237
  scopeMembers: Map<string, Set<string>>; // scope -> member names (ADR-016)
251
238
  currentParameters: Map<string, TParameterInfo>; // ADR-006: track params for pointer semantics
252
- // Issue #558: modifiedParameters removed - now uses analysis-phase results from this.modifiedParameters
239
+ // Issue #558: modifiedParameters removed - now uses analysis-phase results from CodeGenState.modifiedParameters
253
240
  localArrays: Set<string>; // ADR-006: track local array variables (no & needed)
254
241
  localVariables: Set<string>; // ADR-016: track local variables (allowed as bare identifiers)
255
242
  floatBitShadows: Set<string>; // Track declared shadow variables for float bit indexing
@@ -279,9 +266,6 @@ export default class CodeGenerator implements IOrchestrator {
279
266
  ["f64", "0.0"],
280
267
  ]);
281
268
 
282
- /** ADR-044: Debug mode generates panic-on-overflow helpers */
283
- private debugMode: boolean = false;
284
-
285
269
  private context: GeneratorContext =
286
270
  CodeGenerator.createDefaultContext(DEFAULT_TARGET);
287
271
 
@@ -318,55 +302,6 @@ export default class CodeGenerator implements IOrchestrator {
318
302
  };
319
303
  }
320
304
 
321
- // Issue #60: Symbol fields moved to SymbolCollector
322
- // Remaining fields not yet extracted:
323
-
324
- private knownFunctions: Set<string> = new Set(); // Track C-Next defined functions
325
-
326
- private functionSignatures: Map<string, FunctionSignature> = new Map(); // ADR-013: Track function parameter const-ness
327
-
328
- // Bug #8: Track compile-time const values for array size resolution at file scope
329
- private constValues: Map<string, number> = new Map(); // constName -> numeric value
330
-
331
- // ADR-029: Callback types registry
332
- private callbackTypes: Map<string, CallbackTypeInfo> = new Map(); // funcName -> CallbackTypeInfo
333
-
334
- private callbackFieldTypes: Map<string, string> = new Map(); // "Struct.field" -> callbackTypeName
335
-
336
- // ADR-044: Track which overflow helper types and operations are needed
337
- private usedClampOps: Set<string> = new Set(); // Format: "add_u8", "sub_u16", "mul_u32"
338
-
339
- private usedSafeDivOps: Set<string> = new Set(); // ADR-051: Format: "div_u32", "mod_i16"
340
-
341
- // Track required standard library includes
342
- private needsStdint: boolean = false; // For u8, u16, u32, u64, i8, i16, i32, i64
343
-
344
- private needsStdbool: boolean = false; // For bool type
345
-
346
- private needsString: boolean = false; // ADR-045: For strlen, strncpy, etc.
347
-
348
- private needsFloatStaticAssert: boolean = false; // For float bit indexing size verification
349
-
350
- private needsISR: boolean = false; // ADR-040: For ISR function pointer type
351
-
352
- private needsCMSIS: boolean = false; // ADR-049/050: For atomic intrinsics and critical sections
353
-
354
- private needsLimits: boolean = false; // Issue #632: For float-to-int clamp casts
355
-
356
- private needsIrqWrappers: boolean = false; // Issue #473: IRQ wrappers for critical sections
357
-
358
- /** External symbol table for cross-language interop */
359
- private symbolTable: SymbolTable | null = null;
360
-
361
- /** ADR-010: Source file path for validating includes */
362
- private sourcePath: string | null = null;
363
-
364
- /** Issue #349: Include directories for resolving angle-bracket .cnx includes */
365
- private includeDirs: string[] = [];
366
-
367
- /** Issue #349: Input directories for calculating relative paths */
368
- private inputs: string[] = [];
369
-
370
305
  /** Token stream for comment extraction (ADR-043) */
371
306
  private tokenStream: CommonTokenStream | null = null;
372
307
 
@@ -374,117 +309,18 @@ export default class CodeGenerator implements IOrchestrator {
374
309
 
375
310
  private readonly commentFormatter: CommentFormatter = new CommentFormatter();
376
311
 
377
- /** Type resolution and classification */
378
- private typeResolver: TypeResolver | null = null;
312
+ /** Type resolution and classification - now a static class, no instance needed */
379
313
 
380
314
  /** Symbol collection - ADR-055: Now uses ISymbolInfo from TSymbolInfoAdapter */
381
315
  public symbols: ICodeGenSymbols | null = null;
382
316
 
383
- /** Type validation - Issue #63: Extracted from CodeGenerator */
384
- private typeValidator: TypeValidator | null = null;
385
-
386
- /** Issue #644: String length counter for strlen caching optimization */
387
- private stringLengthCounter: StringLengthCounter | null = null;
388
-
389
- /** Issue #644: Member chain analyzer for bit access pattern detection */
390
- private memberChainAnalyzer: MemberChainAnalyzer | null = null;
391
-
392
- /** Issue #644: Float bit write helper for shadow variable pattern */
393
- private floatBitHelper: FloatBitHelper | null = null;
394
-
395
317
  /** Issue #644: String declaration helper for bounded/array/concat strings */
396
- private stringDeclHelper: StringDeclHelper | null = null;
397
-
398
- /** Issue #644: Enum assignment validator for type-safe enum assignments */
399
- private enumValidator: EnumAssignmentValidator | null = null;
400
318
 
401
319
  /** Issue #644: Array initialization helper for size inference and fill-all */
402
- private arrayInitHelper: ArrayInitHelper | null = null;
403
-
404
- /** Issue #644: Assignment expected type resolution helper */
405
- private expectedTypeResolver: AssignmentExpectedTypeResolver | null = null;
406
-
407
- /** Issue #644: Assignment validation coordinator helper */
408
- private assignmentValidator: AssignmentValidator | null = null;
409
320
 
410
321
  /** Generator registry for modular code generation (ADR-053) */
411
322
  private readonly registry: GeneratorRegistry = new GeneratorRegistry();
412
323
 
413
- /** Issue #250: C++ mode - use temp vars instead of compound literals */
414
- private cppMode: boolean = false;
415
-
416
- /** Issue #644: C/C++ mode helper for consolidated mode-specific patterns */
417
- private cppHelper: CppModeHelper | null = null;
418
-
419
- /** Issue #250: Pending temp variable declarations for C++ mode */
420
- private pendingTempDeclarations: string[] = [];
421
-
422
- /** Issue #250: Counter for unique temp variable names */
423
- private tempVarCounter: number = 0;
424
-
425
- /** Issue #517: Pending field assignments for C++ class struct init */
426
- private pendingCppClassAssignments: string[] = [];
427
-
428
- /**
429
- * Issue #269: Tracks which parameters are modified (directly or transitively)
430
- * Map of functionName -> Set of modified parameter names
431
- */
432
- private readonly modifiedParameters: Map<string, Set<string>> = new Map();
433
-
434
- /**
435
- * Issue #579: Tracks which parameters have subscript access (read or write)
436
- * These parameters must become pointers to support array access semantics
437
- * Map of functionName -> Set of parameter names with subscript access
438
- */
439
- private readonly subscriptAccessedParameters: Map<string, Set<string>> =
440
- new Map();
441
-
442
- /**
443
- * Issue #558: Pending cross-file modifications to inject after analyzePassByValue clears.
444
- * Set by Pipeline before generate() to share modifications from previously processed files.
445
- */
446
- private pendingCrossFileModifications: ReadonlyMap<
447
- string,
448
- ReadonlySet<string>
449
- > | null = null;
450
-
451
- /**
452
- * Issue #558: Pending cross-file parameter lists to inject for transitive propagation.
453
- */
454
- private pendingCrossFileParamLists: ReadonlyMap<
455
- string,
456
- readonly string[]
457
- > | null = null;
458
-
459
- /**
460
- * Issue #269: Tracks which parameters should pass by value
461
- * Map of functionName -> Set of passByValue parameter names
462
- */
463
- private readonly passByValueParams: Map<string, Set<string>> = new Map();
464
-
465
- /**
466
- * Issue #269: Tracks function call relationships for transitive modification analysis
467
- * Map of functionName -> Array of {callee, paramIndex, argParamName}
468
- * where argParamName is the caller's parameter passed as argument
469
- */
470
- private readonly functionCallGraph: Map<
471
- string,
472
- Array<{ callee: string; paramIndex: number; argParamName: string }>
473
- > = new Map();
474
-
475
- /**
476
- * Issue #269: Tracks function parameter lists for call graph analysis
477
- * Map of functionName -> Array of parameter names in order
478
- */
479
- private readonly functionParamLists: Map<string, string[]> = new Map();
480
-
481
- /**
482
- * Issue #369: Tracks whether self-include was added.
483
- * When true, skip struct/enum/bitmap definitions in .c file because
484
- * they'll be defined in the included header.
485
- */
486
- private selfIncludeAdded: boolean = false;
487
-
488
324
  /**
489
325
  * Initialize generator registry with extracted generators.
490
326
  * Called once before code generation begins.
@@ -617,17 +453,17 @@ export default class CodeGenerator implements IOrchestrator {
617
453
  */
618
454
  getInput(): IGeneratorInput {
619
455
  return {
620
- symbolTable: this.symbolTable,
621
- symbols: this.symbols,
622
- typeRegistry: this.context.typeRegistry,
623
- functionSignatures: this.functionSignatures,
624
- knownFunctions: this.knownFunctions,
625
- knownStructs: this.symbols?.knownStructs ?? new Set(),
626
- constValues: this.constValues,
627
- callbackTypes: this.callbackTypes,
628
- callbackFieldTypes: this.callbackFieldTypes,
629
- targetCapabilities: this.context.targetCapabilities,
630
- debugMode: this.debugMode,
456
+ symbolTable: CodeGenState.symbolTable,
457
+ symbols: CodeGenState.symbols,
458
+ typeRegistry: CodeGenState.typeRegistry,
459
+ functionSignatures: CodeGenState.functionSignatures,
460
+ knownFunctions: CodeGenState.knownFunctions,
461
+ knownStructs: CodeGenState.symbols?.knownStructs ?? new Set(),
462
+ constValues: CodeGenState.constValues,
463
+ callbackTypes: CodeGenState.callbackTypes,
464
+ callbackFieldTypes: CodeGenState.callbackFieldTypes,
465
+ targetCapabilities: CodeGenState.targetCapabilities,
466
+ debugMode: CodeGenState.debugMode,
631
467
  };
632
468
  }
633
469
 
@@ -637,20 +473,20 @@ export default class CodeGenerator implements IOrchestrator {
637
473
  */
638
474
  getState(): IGeneratorState {
639
475
  return {
640
- currentScope: this.context.currentScope,
641
- indentLevel: this.context.indentLevel,
642
- inFunctionBody: this.context.inFunctionBody,
643
- currentParameters: this.context.currentParameters,
644
- localVariables: this.context.localVariables,
645
- localArrays: this.context.localArrays,
646
- expectedType: this.context.expectedType,
647
- selfIncludeAdded: this.selfIncludeAdded, // Issue #369
476
+ currentScope: CodeGenState.currentScope,
477
+ indentLevel: CodeGenState.indentLevel,
478
+ inFunctionBody: CodeGenState.inFunctionBody,
479
+ currentParameters: CodeGenState.currentParameters,
480
+ localVariables: CodeGenState.localVariables,
481
+ localArrays: CodeGenState.localArrays,
482
+ expectedType: CodeGenState.expectedType,
483
+ selfIncludeAdded: CodeGenState.selfIncludeAdded, // Issue #369
648
484
  // Issue #644: Postfix expression state
649
- scopeMembers: this.context.scopeMembers,
650
- mainArgsName: this.context.mainArgsName,
651
- floatBitShadows: this.context.floatBitShadows,
652
- floatShadowCurrent: this.context.floatShadowCurrent,
653
- lengthCache: this.context.lengthCache,
485
+ scopeMembers: CodeGenState.scopeMembers,
486
+ mainArgsName: CodeGenState.mainArgsName,
487
+ floatBitShadows: CodeGenState.floatBitShadows,
488
+ floatShadowCurrent: CodeGenState.floatShadowCurrent,
489
+ lengthCache: CodeGenState.lengthCache,
654
490
  };
655
491
  }
656
492
 
@@ -671,64 +507,68 @@ export default class CodeGenerator implements IOrchestrator {
671
507
 
672
508
  // Helper function effects
673
509
  case "helper":
674
- this.usedClampOps.add(`${effect.operation}_${effect.cnxType}`);
510
+ CodeGenState.usedClampOps.add(
511
+ `${effect.operation}_${effect.cnxType}`,
512
+ );
675
513
  break;
676
514
  case "safe-div":
677
- this.usedSafeDivOps.add(`${effect.operation}_${effect.cnxType}`);
515
+ CodeGenState.usedSafeDivOps.add(
516
+ `${effect.operation}_${effect.cnxType}`,
517
+ );
678
518
  break;
679
519
 
680
520
  // Type registration effects
681
521
  case "register-type":
682
- this.context.typeRegistry.set(effect.name, effect.info);
522
+ CodeGenState.typeRegistry.set(effect.name, effect.info);
683
523
  break;
684
524
  case "register-local":
685
- this.context.localVariables.add(effect.name);
525
+ CodeGenState.localVariables.add(effect.name);
686
526
  if (effect.isArray) {
687
- this.context.localArrays.add(effect.name);
527
+ CodeGenState.localArrays.add(effect.name);
688
528
  }
689
529
  break;
690
530
  case "register-const-value":
691
- this.constValues.set(effect.name, effect.value);
531
+ CodeGenState.constValues.set(effect.name, effect.value);
692
532
  break;
693
533
 
694
534
  // Scope effects (ADR-016)
695
535
  case "set-scope":
696
- this.context.currentScope = effect.name;
536
+ CodeGenState.currentScope = effect.name;
697
537
  break;
698
538
 
699
539
  // Function body effects
700
540
  case "enter-function-body":
701
- this.context.inFunctionBody = true;
702
- this.context.localVariables.clear();
703
- this.context.localArrays.clear();
704
- this.context.floatBitShadows.clear();
705
- this.context.floatShadowCurrent.clear();
541
+ CodeGenState.inFunctionBody = true;
542
+ CodeGenState.localVariables.clear();
543
+ CodeGenState.localArrays.clear();
544
+ CodeGenState.floatBitShadows.clear();
545
+ CodeGenState.floatShadowCurrent.clear();
706
546
  break;
707
547
  case "exit-function-body":
708
- this.context.inFunctionBody = false;
709
- this.context.localVariables.clear();
710
- this.context.localArrays.clear();
711
- this.context.floatBitShadows.clear();
712
- this.context.floatShadowCurrent.clear();
548
+ CodeGenState.inFunctionBody = false;
549
+ CodeGenState.localVariables.clear();
550
+ CodeGenState.localArrays.clear();
551
+ CodeGenState.floatBitShadows.clear();
552
+ CodeGenState.floatShadowCurrent.clear();
713
553
  break;
714
554
  case "set-parameters":
715
- this.context.currentParameters = new Map(effect.params);
555
+ CodeGenState.currentParameters = new Map(effect.params);
716
556
  break;
717
557
  case "clear-parameters":
718
- this.context.currentParameters.clear();
558
+ CodeGenState.currentParameters.clear();
719
559
  break;
720
560
 
721
561
  // Callback effects
722
562
  case "register-callback-field":
723
- this.callbackFieldTypes.set(effect.key, effect.typeName);
563
+ CodeGenState.callbackFieldTypes.set(effect.key, effect.typeName);
724
564
  break;
725
565
 
726
566
  // Array initializer effects
727
567
  case "set-array-init-count":
728
- this.context.lastArrayInitCount = effect.count;
568
+ CodeGenState.lastArrayInitCount = effect.count;
729
569
  break;
730
570
  case "set-array-fill-value":
731
- this.context.lastArrayFillValue = effect.value;
571
+ CodeGenState.lastArrayFillValue = effect.value;
732
572
  break;
733
573
  }
734
574
  }
@@ -743,28 +583,28 @@ export default class CodeGenerator implements IOrchestrator {
743
583
  private requireInclude(header: TIncludeHeader): void {
744
584
  switch (header) {
745
585
  case "stdint":
746
- this.needsStdint = true;
586
+ CodeGenState.needsStdint = true;
747
587
  break;
748
588
  case "stdbool":
749
- this.needsStdbool = true;
589
+ CodeGenState.needsStdbool = true;
750
590
  break;
751
591
  case "string":
752
- this.needsString = true;
592
+ CodeGenState.needsString = true;
753
593
  break;
754
594
  case "cmsis":
755
- this.needsCMSIS = true;
595
+ CodeGenState.needsCMSIS = true;
756
596
  break;
757
597
  case "limits":
758
- this.needsLimits = true;
598
+ CodeGenState.needsLimits = true;
759
599
  break;
760
600
  case "isr":
761
- this.needsISR = true;
601
+ CodeGenState.needsISR = true;
762
602
  break;
763
603
  case "float_static_assert":
764
- this.needsFloatStaticAssert = true;
604
+ CodeGenState.needsFloatStaticAssert = true;
765
605
  break;
766
606
  case "irq_wrappers":
767
- this.needsIrqWrappers = true;
607
+ CodeGenState.needsIrqWrappers = true;
768
608
  break;
769
609
  }
770
610
  }
@@ -773,7 +613,7 @@ export default class CodeGenerator implements IOrchestrator {
773
613
  * Get the current indentation string.
774
614
  */
775
615
  getIndent(): string {
776
- return FormatUtils.indent(this.context.indentLevel);
616
+ return FormatUtils.indent(CodeGenState.indentLevel);
777
617
  }
778
618
 
779
619
  /**
@@ -784,10 +624,10 @@ export default class CodeGenerator implements IOrchestrator {
784
624
  */
785
625
  resolveIdentifier(identifier: string): string {
786
626
  // Check current scope first (inner scope shadows outer)
787
- if (this.context.currentScope) {
788
- const members = this.context.scopeMembers.get(this.context.currentScope);
627
+ if (CodeGenState.currentScope) {
628
+ const members = CodeGenState.scopeMembers.get(CodeGenState.currentScope);
789
629
  if (members?.has(identifier)) {
790
- return `${this.context.currentScope}_${identifier}`;
630
+ return `${CodeGenState.currentScope}_${identifier}`;
791
631
  }
792
632
  }
793
633
 
@@ -813,10 +653,10 @@ export default class CodeGenerator implements IOrchestrator {
813
653
  ctx: Parser.ExpressionContext,
814
654
  expectedType: string | null,
815
655
  ): string {
816
- const savedExpectedType = this.context.expectedType;
817
- this.context.expectedType = expectedType;
656
+ const savedExpectedType = CodeGenState.expectedType;
657
+ CodeGenState.expectedType = expectedType;
818
658
  const result = this.generateExpression(ctx);
819
- this.context.expectedType = savedExpectedType;
659
+ CodeGenState.expectedType = savedExpectedType;
820
660
  return result;
821
661
  }
822
662
 
@@ -833,12 +673,12 @@ export default class CodeGenerator implements IOrchestrator {
833
673
 
834
674
  // Generate the C type using the helper with dependencies
835
675
  return TypeGenerationHelper.generate(ctx, {
836
- currentScope: this.context.currentScope,
676
+ currentScope: CodeGenState.currentScope,
837
677
  isCppScopeSymbol: (name) => this.isCppScopeSymbol(name),
838
678
  checkNeedsStructKeyword: (name) =>
839
- this.symbolTable?.checkNeedsStructKeyword(name) ?? false,
679
+ CodeGenState.symbolTable?.checkNeedsStructKeyword(name) ?? false,
840
680
  validateCrossScopeVisibility: (scope, member) =>
841
- this._validateCrossScopeVisibility(scope, member),
681
+ ScopeResolver.validateCrossScopeVisibility(scope, member),
842
682
  });
843
683
  }
844
684
 
@@ -882,9 +722,9 @@ export default class CodeGenerator implements IOrchestrator {
882
722
  */
883
723
  isKnownStruct(typeName: string): boolean {
884
724
  return SymbolLookupHelper.isKnownStruct(
885
- this.symbols?.knownStructs,
886
- this.symbols?.knownBitmaps,
887
- this.symbolTable,
725
+ CodeGenState.symbols?.knownStructs,
726
+ CodeGenState.symbols?.knownBitmaps,
727
+ CodeGenState.symbolTable,
888
728
  typeName,
889
729
  );
890
730
  }
@@ -894,7 +734,7 @@ export default class CodeGenerator implements IOrchestrator {
894
734
  * Part of IOrchestrator interface - delegates to TypeResolver.
895
735
  */
896
736
  isFloatType(typeName: string): boolean {
897
- return this.typeResolver!.isFloatType(typeName);
737
+ return TypeResolver.isFloatType(typeName);
898
738
  }
899
739
 
900
740
  /**
@@ -902,7 +742,7 @@ export default class CodeGenerator implements IOrchestrator {
902
742
  * Part of IOrchestrator interface - delegates to TypeResolver.
903
743
  */
904
744
  isIntegerType(typeName: string): boolean {
905
- return this.typeResolver!.isIntegerType(typeName);
745
+ return TypeResolver.isIntegerType(typeName);
906
746
  }
907
747
 
908
748
  /**
@@ -911,8 +751,8 @@ export default class CodeGenerator implements IOrchestrator {
911
751
  */
912
752
  isCNextFunction(name: string): boolean {
913
753
  return SymbolLookupHelper.isCNextFunctionCombined(
914
- this.knownFunctions,
915
- this.symbolTable,
754
+ CodeGenState.knownFunctions,
755
+ CodeGenState.symbolTable,
916
756
  name,
917
757
  );
918
758
  }
@@ -926,7 +766,7 @@ export default class CodeGenerator implements IOrchestrator {
926
766
  getExpressionEnumType(
927
767
  ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
928
768
  ): string | null {
929
- return this._getExpressionEnumType(ctx);
769
+ return EnumTypeResolver.resolve(ctx);
930
770
  }
931
771
 
932
772
  /**
@@ -955,7 +795,7 @@ export default class CodeGenerator implements IOrchestrator {
955
795
 
956
796
  // Check if it's a simple variable of string type
957
797
  if (/^[a-zA-Z_]\w*$/.exec(text)) {
958
- const typeInfo = this.context.typeRegistry.get(text);
798
+ const typeInfo = CodeGenState.typeRegistry.get(text);
959
799
  if (typeInfo?.isString) {
960
800
  return true;
961
801
  }
@@ -975,7 +815,7 @@ export default class CodeGenerator implements IOrchestrator {
975
815
  return false;
976
816
  }
977
817
  const arrayName = arrayAccessMatch[1];
978
- const typeInfo = this.context.typeRegistry.get(arrayName);
818
+ const typeInfo = CodeGenState.typeRegistry.get(arrayName);
979
819
  // Check if base type is a string type
980
820
  if (
981
821
  typeInfo?.isString ||
@@ -1017,7 +857,11 @@ export default class CodeGenerator implements IOrchestrator {
1017
857
  memberName: string,
1018
858
  isGlobalAccess: boolean = false,
1019
859
  ): void {
1020
- this._validateCrossScopeVisibility(scopeName, memberName, isGlobalAccess);
860
+ ScopeResolver.validateCrossScopeVisibility(
861
+ scopeName,
862
+ memberName,
863
+ isGlobalAccess,
864
+ );
1021
865
  }
1022
866
 
1023
867
  /**
@@ -1030,7 +874,7 @@ export default class CodeGenerator implements IOrchestrator {
1030
874
  op: string,
1031
875
  ctx: Parser.ShiftExpressionContext,
1032
876
  ): void {
1033
- this.typeValidator!.validateShiftAmount(leftType, rightExpr, op, ctx);
877
+ TypeValidator.validateShiftAmount(leftType, rightExpr, op, ctx);
1034
878
  }
1035
879
 
1036
880
  /**
@@ -1038,7 +882,7 @@ export default class CodeGenerator implements IOrchestrator {
1038
882
  * Part of IOrchestrator interface - delegates to TypeValidator.
1039
883
  */
1040
884
  validateTernaryCondition(condition: Parser.OrExpressionContext): void {
1041
- this.typeValidator!.validateTernaryCondition(condition);
885
+ TypeValidator.validateTernaryCondition(condition);
1042
886
  }
1043
887
 
1044
888
  /**
@@ -1049,7 +893,7 @@ export default class CodeGenerator implements IOrchestrator {
1049
893
  expr: Parser.OrExpressionContext,
1050
894
  branchName: string,
1051
895
  ): void {
1052
- this.typeValidator!.validateNoNestedTernary(expr, branchName);
896
+ TypeValidator.validateNoNestedTernary(expr, branchName);
1053
897
  }
1054
898
 
1055
899
  // === Function Call Helpers (ADR-053 A2 Phase 5) ===
@@ -1078,7 +922,7 @@ export default class CodeGenerator implements IOrchestrator {
1078
922
  * Part of IOrchestrator interface - delegates to TypeValidator.
1079
923
  */
1080
924
  isConstValue(name: string): boolean {
1081
- return this.typeValidator!.isConstValue(name);
925
+ return TypeValidator.isConstValue(name);
1082
926
  }
1083
927
 
1084
928
  /**
@@ -1086,7 +930,7 @@ export default class CodeGenerator implements IOrchestrator {
1086
930
  * Part of IOrchestrator interface.
1087
931
  */
1088
932
  getKnownEnums(): ReadonlySet<string> {
1089
- return this.symbols!.knownEnums;
933
+ return CodeGenState.symbols!.knownEnums;
1090
934
  }
1091
935
 
1092
936
  /**
@@ -1094,7 +938,7 @@ export default class CodeGenerator implements IOrchestrator {
1094
938
  * Part of IOrchestrator interface.
1095
939
  */
1096
940
  isCppMode(): boolean {
1097
- return this.cppMode;
941
+ return CodeGenState.cppMode;
1098
942
  }
1099
943
 
1100
944
  /**
@@ -1103,7 +947,10 @@ export default class CodeGenerator implements IOrchestrator {
1103
947
  * Part of IOrchestrator interface.
1104
948
  */
1105
949
  isCppEnumClass(typeName: string): boolean {
1106
- return SymbolLookupHelper.isCppEnumClass(this.symbolTable, typeName);
950
+ return SymbolLookupHelper.isCppEnumClass(
951
+ CodeGenState.symbolTable,
952
+ typeName,
953
+ );
1107
954
  }
1108
955
 
1109
956
  /**
@@ -1111,7 +958,7 @@ export default class CodeGenerator implements IOrchestrator {
1111
958
  * Part of IOrchestrator interface.
1112
959
  */
1113
960
  getExpressionType(ctx: Parser.ExpressionContext): string | null {
1114
- return this.typeResolver!.getExpressionType(ctx);
961
+ return TypeResolver.getExpressionType(ctx);
1115
962
  }
1116
963
 
1117
964
  /**
@@ -1124,9 +971,9 @@ export default class CodeGenerator implements IOrchestrator {
1124
971
 
1125
972
  for (const stmt of ctx.statement()) {
1126
973
  // Temporarily increment for any nested context that needs absolute level
1127
- this.context.indentLevel++;
974
+ CodeGenState.indentLevel++;
1128
975
  const stmtCode = this.generateStatement(stmt);
1129
- this.context.indentLevel--;
976
+ CodeGenState.indentLevel--;
1130
977
 
1131
978
  if (stmtCode) {
1132
979
  // Add one level of indent to each line (relative indentation)
@@ -1147,7 +994,7 @@ export default class CodeGenerator implements IOrchestrator {
1147
994
  * Part of IOrchestrator interface (ADR-053 A3).
1148
995
  */
1149
996
  validateNoEarlyExits(ctx: Parser.BlockContext): void {
1150
- this.typeValidator!.validateNoEarlyExits(ctx);
997
+ TypeValidator.validateNoEarlyExits(ctx);
1151
998
  }
1152
999
 
1153
1000
  /**
@@ -1184,9 +1031,9 @@ export default class CodeGenerator implements IOrchestrator {
1184
1031
  }
1185
1032
 
1186
1033
  // Issue #250: Prepend any pending temp variable declarations (C++ mode)
1187
- if (this.pendingTempDeclarations.length > 0) {
1188
- const tempDecls = this.pendingTempDeclarations.join("\n");
1189
- this.pendingTempDeclarations = [];
1034
+ if (CodeGenState.pendingTempDeclarations.length > 0) {
1035
+ const tempDecls = CodeGenState.pendingTempDeclarations.join("\n");
1036
+ CodeGenState.pendingTempDeclarations = [];
1190
1037
  return tempDecls + "\n" + result;
1191
1038
  }
1192
1039
 
@@ -1199,11 +1046,11 @@ export default class CodeGenerator implements IOrchestrator {
1199
1046
  * Part of IOrchestrator interface.
1200
1047
  */
1201
1048
  flushPendingTempDeclarations(): string {
1202
- if (this.pendingTempDeclarations.length === 0) {
1049
+ if (CodeGenState.pendingTempDeclarations.length === 0) {
1203
1050
  return "";
1204
1051
  }
1205
- const decls = this.pendingTempDeclarations.join("\n");
1206
- this.pendingTempDeclarations = [];
1052
+ const decls = CodeGenState.pendingTempDeclarations.join("\n");
1053
+ CodeGenState.pendingTempDeclarations = [];
1207
1054
  return decls;
1208
1055
  }
1209
1056
 
@@ -1212,7 +1059,7 @@ export default class CodeGenerator implements IOrchestrator {
1212
1059
  * Part of IOrchestrator interface (ADR-053 A3).
1213
1060
  */
1214
1061
  indent(text: string): string {
1215
- return FormatUtils.indentAllLines(text, this.context.indentLevel);
1062
+ return FormatUtils.indentAllLines(text, CodeGenState.indentLevel);
1216
1063
  }
1217
1064
 
1218
1065
  /**
@@ -1223,7 +1070,7 @@ export default class CodeGenerator implements IOrchestrator {
1223
1070
  ctx: Parser.SwitchStatementContext,
1224
1071
  switchExpr: Parser.ExpressionContext,
1225
1072
  ): void {
1226
- this.typeValidator!.validateSwitchStatement(ctx, switchExpr);
1073
+ TypeValidator.validateSwitchStatement(ctx, switchExpr);
1227
1074
  }
1228
1075
 
1229
1076
  /**
@@ -1231,7 +1078,7 @@ export default class CodeGenerator implements IOrchestrator {
1231
1078
  * Part of IOrchestrator interface (ADR-053 A3).
1232
1079
  */
1233
1080
  validateDoWhileCondition(ctx: Parser.ExpressionContext): void {
1234
- this.typeValidator!.validateDoWhileCondition(ctx);
1081
+ TypeValidator.validateDoWhileCondition(ctx);
1235
1082
  }
1236
1083
 
1237
1084
  /**
@@ -1242,7 +1089,7 @@ export default class CodeGenerator implements IOrchestrator {
1242
1089
  ctx: Parser.ExpressionContext,
1243
1090
  conditionType: string,
1244
1091
  ): void {
1245
- this.typeValidator!.validateConditionNoFunctionCall(ctx, conditionType);
1092
+ TypeValidator.validateConditionNoFunctionCall(ctx, conditionType);
1246
1093
  }
1247
1094
 
1248
1095
  /**
@@ -1252,7 +1099,7 @@ export default class CodeGenerator implements IOrchestrator {
1252
1099
  validateTernaryConditionNoFunctionCall(
1253
1100
  ctx: Parser.OrExpressionContext,
1254
1101
  ): void {
1255
- this.typeValidator!.validateTernaryConditionNoFunctionCall(ctx);
1102
+ TypeValidator.validateTernaryConditionNoFunctionCall(ctx);
1256
1103
  }
1257
1104
 
1258
1105
  /**
@@ -1280,7 +1127,7 @@ export default class CodeGenerator implements IOrchestrator {
1280
1127
  safeIdentifier,
1281
1128
  hasGlobal,
1282
1129
  hasThis,
1283
- this.context.currentScope,
1130
+ CodeGenState.currentScope,
1284
1131
  );
1285
1132
 
1286
1133
  // No postfix operations - return base
@@ -1321,8 +1168,8 @@ export default class CodeGenerator implements IOrchestrator {
1321
1168
  countStringLengthAccesses(
1322
1169
  ctx: Parser.ExpressionContext,
1323
1170
  ): Map<string, number> {
1324
- // Issue #644: Delegate to extracted StringLengthCounter
1325
- return this.stringLengthCounter!.countExpression(ctx);
1171
+ // Issue #644: Delegate to extracted StringLengthCounter (now static)
1172
+ return StringLengthCounter.countExpression(ctx);
1326
1173
  }
1327
1174
 
1328
1175
  /**
@@ -1333,8 +1180,8 @@ export default class CodeGenerator implements IOrchestrator {
1333
1180
  ctx: Parser.BlockContext,
1334
1181
  counts: Map<string, number>,
1335
1182
  ): void {
1336
- // Issue #644: Delegate to extracted StringLengthCounter
1337
- this.stringLengthCounter!.countBlockInto(ctx, counts);
1183
+ // Issue #644: Delegate to extracted StringLengthCounter (now static)
1184
+ StringLengthCounter.countBlockInto(ctx, counts);
1338
1185
  }
1339
1186
 
1340
1187
  /**
@@ -1354,7 +1201,7 @@ export default class CodeGenerator implements IOrchestrator {
1354
1201
  }
1355
1202
 
1356
1203
  if (declarations.length > 0) {
1357
- this.context.lengthCache = cache;
1204
+ CodeGenState.lengthCache = cache;
1358
1205
  return declarations.join("\n") + "\n";
1359
1206
  }
1360
1207
 
@@ -1366,7 +1213,7 @@ export default class CodeGenerator implements IOrchestrator {
1366
1213
  * Part of IOrchestrator interface (ADR-053 A3).
1367
1214
  */
1368
1215
  clearLengthCache(): void {
1369
- this.context.lengthCache = null;
1216
+ CodeGenState.lengthCache = null;
1370
1217
  }
1371
1218
 
1372
1219
  /**
@@ -1374,7 +1221,7 @@ export default class CodeGenerator implements IOrchestrator {
1374
1221
  * Part of IOrchestrator interface (ADR-053 A3).
1375
1222
  */
1376
1223
  registerLocalVariable(name: string): void {
1377
- this.context.localVariables.add(name);
1224
+ CodeGenState.localVariables.add(name);
1378
1225
  }
1379
1226
 
1380
1227
  // === Declaration Generation (ADR-053 A4) ===
@@ -1384,7 +1231,7 @@ export default class CodeGenerator implements IOrchestrator {
1384
1231
  if (dim.expression()) {
1385
1232
  // Bug #8: At file scope, resolve const values to numeric literals
1386
1233
  // because C doesn't allow const variables as array sizes at file scope
1387
- if (!this.context.inFunctionBody) {
1234
+ if (!CodeGenState.inFunctionBody) {
1388
1235
  const constValue = this.tryEvaluateConstant(dim.expression()!);
1389
1236
  if (constValue !== undefined) {
1390
1237
  return `[${constValue}]`;
@@ -1408,8 +1255,8 @@ export default class CodeGenerator implements IOrchestrator {
1408
1255
  // ADR-016: Handle this.Type for scoped types (e.g., this.State -> Motor_State)
1409
1256
  if (ctx.scopedType()) {
1410
1257
  const typeName = ctx.scopedType()!.IDENTIFIER().getText();
1411
- if (this.context.currentScope) {
1412
- return `${this.context.currentScope}_${typeName}`;
1258
+ if (CodeGenState.currentScope) {
1259
+ return `${CodeGenState.currentScope}_${typeName}`;
1413
1260
  }
1414
1261
  return typeName;
1415
1262
  }
@@ -1424,6 +1271,16 @@ export default class CodeGenerator implements IOrchestrator {
1424
1271
  const identifierNames = identifiers.map((id) => id.getText());
1425
1272
  return this.resolveQualifiedType(identifierNames);
1426
1273
  }
1274
+ // Handle C-Next array type syntax (Type[N]) - return base type without dimension
1275
+ if (ctx.arrayType()) {
1276
+ const arrayTypeCtx = ctx.arrayType()!;
1277
+ if (arrayTypeCtx.primitiveType()) {
1278
+ return arrayTypeCtx.primitiveType()!.getText();
1279
+ }
1280
+ if (arrayTypeCtx.userType()) {
1281
+ return arrayTypeCtx.userType()!.getText();
1282
+ }
1283
+ }
1427
1284
  if (ctx.userType()) {
1428
1285
  return ctx.userType()!.getText();
1429
1286
  }
@@ -1436,7 +1293,7 @@ export default class CodeGenerator implements IOrchestrator {
1436
1293
  /** Try to evaluate a constant expression at compile time */
1437
1294
  tryEvaluateConstant(ctx: Parser.ExpressionContext): number | undefined {
1438
1295
  return ArrayDimensionParser.parseSingleDimension(ctx, {
1439
- constValues: this.constValues,
1296
+ constValues: CodeGenState.constValues,
1440
1297
  typeWidths: TYPE_WIDTH,
1441
1298
  isKnownStruct: (name) => this.isKnownStruct(name),
1442
1299
  });
@@ -1457,7 +1314,7 @@ export default class CodeGenerator implements IOrchestrator {
1457
1314
  const resolved = this._resolveTypeNameFromContext(typeCtx);
1458
1315
  if (resolved) {
1459
1316
  // Check if enum
1460
- if (this.symbols!.knownEnums.has(resolved.name)) {
1317
+ if (CodeGenState.symbols!.knownEnums.has(resolved.name)) {
1461
1318
  return this._getEnumZeroValue(resolved.name, resolved.separator);
1462
1319
  }
1463
1320
  // Check if C++ type needing {} (only for userType, not qualified/scoped/global)
@@ -1531,7 +1388,7 @@ export default class CodeGenerator implements IOrchestrator {
1531
1388
  // Variable - check type registry
1532
1389
  const identifierRegex = /^[a-zA-Z_]\w*$/;
1533
1390
  if (identifierRegex.test(exprCode)) {
1534
- const typeInfo = this.context.typeRegistry.get(exprCode);
1391
+ const typeInfo = CodeGenState.typeRegistry.get(exprCode);
1535
1392
  if (typeInfo?.isString && typeInfo.stringCapacity !== undefined) {
1536
1393
  return typeInfo.stringCapacity;
1537
1394
  }
@@ -1554,7 +1411,7 @@ export default class CodeGenerator implements IOrchestrator {
1554
1411
 
1555
1412
  /** Check if a callback type is used as a struct field type */
1556
1413
  isCallbackTypeUsedAsFieldType(funcName: string): boolean {
1557
- for (const callbackType of this.callbackFieldTypes.values()) {
1414
+ for (const callbackType of CodeGenState.callbackFieldTypes.values()) {
1558
1415
  if (callbackType === funcName) {
1559
1416
  return true;
1560
1417
  }
@@ -1565,7 +1422,8 @@ export default class CodeGenerator implements IOrchestrator {
1565
1422
  // === Scope Management (A4) ===
1566
1423
 
1567
1424
  setCurrentScope(name: string | null): void {
1568
- this.context.currentScope = name;
1425
+ CodeGenState.currentScope = name;
1426
+ CodeGenState.currentScope = name;
1569
1427
  }
1570
1428
 
1571
1429
  /**
@@ -1573,7 +1431,8 @@ export default class CodeGenerator implements IOrchestrator {
1573
1431
  * Part of IOrchestrator interface.
1574
1432
  */
1575
1433
  setCurrentFunctionName(name: string | null): void {
1576
- this.context.currentFunctionName = name;
1434
+ CodeGenState.currentFunctionName = name;
1435
+ CodeGenState.currentFunctionName = name;
1577
1436
  }
1578
1437
 
1579
1438
  /**
@@ -1581,36 +1440,43 @@ export default class CodeGenerator implements IOrchestrator {
1581
1440
  * Used by return statement generation to set expectedType.
1582
1441
  */
1583
1442
  getCurrentFunctionReturnType(): string | null {
1584
- return this.context.currentFunctionReturnType;
1443
+ return CodeGenState.currentFunctionReturnType;
1585
1444
  }
1586
1445
 
1587
1446
  /**
1588
1447
  * Issue #477: Set the current function's return type for enum inference.
1589
1448
  */
1590
1449
  setCurrentFunctionReturnType(returnType: string | null): void {
1591
- this.context.currentFunctionReturnType = returnType;
1450
+ CodeGenState.currentFunctionReturnType = returnType;
1451
+ CodeGenState.currentFunctionReturnType = returnType;
1592
1452
  }
1593
1453
 
1594
1454
  // === Function Body Management (A4) ===
1595
1455
 
1596
1456
  enterFunctionBody(): void {
1597
- this.context.localVariables.clear();
1598
- this.context.floatBitShadows.clear();
1599
- this.context.floatShadowCurrent.clear();
1457
+ CodeGenState.localVariables.clear();
1458
+ CodeGenState.floatBitShadows.clear();
1459
+ CodeGenState.floatShadowCurrent.clear();
1600
1460
  // Issue #558: modifiedParameters tracking removed - uses analysis-phase results
1601
- this.context.inFunctionBody = true;
1461
+ CodeGenState.inFunctionBody = true;
1462
+ // Sync with CodeGenState
1463
+ CodeGenState.enterFunctionBody();
1602
1464
  }
1603
1465
 
1604
1466
  exitFunctionBody(): void {
1605
- this.context.inFunctionBody = false;
1606
- this.context.localVariables.clear();
1607
- this.context.floatBitShadows.clear();
1608
- this.context.floatShadowCurrent.clear();
1609
- this.context.mainArgsName = null;
1467
+ CodeGenState.inFunctionBody = false;
1468
+ CodeGenState.localVariables.clear();
1469
+ CodeGenState.floatBitShadows.clear();
1470
+ CodeGenState.floatShadowCurrent.clear();
1471
+ CodeGenState.mainArgsName = null;
1472
+ // Sync with CodeGenState
1473
+ CodeGenState.exitFunctionBody();
1474
+ CodeGenState.mainArgsName = null;
1610
1475
  }
1611
1476
 
1612
1477
  setMainArgsName(name: string | null): void {
1613
- this.context.mainArgsName = name;
1478
+ CodeGenState.mainArgsName = name;
1479
+ CodeGenState.mainArgsName = name;
1614
1480
  }
1615
1481
 
1616
1482
  isMainFunctionWithArgs(
@@ -1624,7 +1490,7 @@ export default class CodeGenerator implements IOrchestrator {
1624
1490
  * ADR-029: Generate typedef for callback type
1625
1491
  */
1626
1492
  generateCallbackTypedef(funcName: string): string | null {
1627
- const callbackInfo = this.callbackTypes.get(funcName);
1493
+ const callbackInfo = CodeGenState.callbackTypes.get(funcName);
1628
1494
  if (!callbackInfo) {
1629
1495
  return null;
1630
1496
  }
@@ -1674,8 +1540,8 @@ export default class CodeGenerator implements IOrchestrator {
1674
1540
  updateFunctionParamsAutoConst(functionName: string): void {
1675
1541
  // Collect unmodified parameters for this function using analysis results
1676
1542
  const unmodifiedParams = new Set<string>();
1677
- const modifiedSet = this.modifiedParameters.get(functionName);
1678
- for (const [paramName] of this.context.currentParameters) {
1543
+ const modifiedSet = CodeGenState.modifiedParameters.get(functionName);
1544
+ for (const [paramName] of CodeGenState.currentParameters) {
1679
1545
  if (!modifiedSet?.has(paramName)) {
1680
1546
  unmodifiedParams.add(paramName);
1681
1547
  }
@@ -1698,9 +1564,11 @@ export default class CodeGenerator implements IOrchestrator {
1698
1564
  * This is the unified source of truth for modification tracking.
1699
1565
  */
1700
1566
  private _isCurrentParameterModified(paramName: string): boolean {
1701
- const funcName = this.context.currentFunctionName;
1567
+ const funcName = CodeGenState.currentFunctionName;
1702
1568
  if (!funcName) return false;
1703
- return this.modifiedParameters.get(funcName)?.has(paramName) ?? false;
1569
+ return (
1570
+ CodeGenState.modifiedParameters.get(funcName)?.has(paramName) ?? false
1571
+ );
1704
1572
  }
1705
1573
 
1706
1574
  /**
@@ -1708,7 +1576,7 @@ export default class CodeGenerator implements IOrchestrator {
1708
1576
  * Returns function name -> set of modified parameter names.
1709
1577
  */
1710
1578
  getModifiedParameters(): ReadonlyMap<string, Set<string>> {
1711
- return this.modifiedParameters;
1579
+ return CodeGenState.modifiedParameters;
1712
1580
  }
1713
1581
 
1714
1582
  /**
@@ -1719,15 +1587,15 @@ export default class CodeGenerator implements IOrchestrator {
1719
1587
  modifications: ReadonlyMap<string, ReadonlySet<string>>,
1720
1588
  paramLists: ReadonlyMap<string, readonly string[]>,
1721
1589
  ): void {
1722
- this.pendingCrossFileModifications = modifications;
1723
- this.pendingCrossFileParamLists = paramLists;
1590
+ CodeGenState.pendingCrossFileModifications = modifications;
1591
+ CodeGenState.pendingCrossFileParamLists = paramLists;
1724
1592
  }
1725
1593
 
1726
1594
  /**
1727
1595
  * Issue #558: Get the function parameter lists for cross-file propagation.
1728
1596
  */
1729
1597
  getFunctionParamLists(): ReadonlyMap<string, string[]> {
1730
- return this.functionParamLists;
1598
+ return CodeGenState.functionParamLists;
1731
1599
  }
1732
1600
 
1733
1601
  /**
@@ -1750,14 +1618,14 @@ export default class CodeGenerator implements IOrchestrator {
1750
1618
  paramLists: Map<string, string[]>;
1751
1619
  } {
1752
1620
  // Save current state
1753
- const savedModifications = new Map(this.modifiedParameters);
1754
- const savedParamLists = new Map(this.functionParamLists);
1755
- const savedCallGraph = new Map(this.functionCallGraph);
1621
+ const savedModifications = new Map(CodeGenState.modifiedParameters);
1622
+ const savedParamLists = new Map(CodeGenState.functionParamLists);
1623
+ const savedCallGraph = new Map(CodeGenState.functionCallGraph);
1756
1624
 
1757
1625
  // Clear for fresh analysis
1758
- this.modifiedParameters.clear();
1759
- this.functionParamLists.clear();
1760
- this.functionCallGraph.clear();
1626
+ CodeGenState.modifiedParameters.clear();
1627
+ CodeGenState.functionParamLists.clear();
1628
+ CodeGenState.functionCallGraph.clear();
1761
1629
 
1762
1630
  // Issue #565: Inject cross-file data BEFORE collecting this file's info
1763
1631
  this.injectCrossFileData(crossFileModifications, crossFileParamLists);
@@ -1770,9 +1638,9 @@ export default class CodeGenerator implements IOrchestrator {
1770
1638
 
1771
1639
  // Issue #565: Run transitive propagation with full context
1772
1640
  TransitiveModificationPropagator.propagate(
1773
- this.functionCallGraph,
1774
- this.functionParamLists,
1775
- this.modifiedParameters,
1641
+ CodeGenState.functionCallGraph,
1642
+ CodeGenState.functionParamLists,
1643
+ CodeGenState.modifiedParameters,
1776
1644
  );
1777
1645
 
1778
1646
  // Capture results - only include functions NOT from cross-file injection
@@ -1783,9 +1651,9 @@ export default class CodeGenerator implements IOrchestrator {
1783
1651
  const paramLists = this.extractThisFileParamLists(crossFileParamLists);
1784
1652
 
1785
1653
  // Restore previous state
1786
- this.restoreMapState(this.modifiedParameters, savedModifications);
1787
- this.restoreMapState(this.functionParamLists, savedParamLists);
1788
- this.restoreMapState(this.functionCallGraph, savedCallGraph);
1654
+ this.restoreMapState(CodeGenState.modifiedParameters, savedModifications);
1655
+ this.restoreMapState(CodeGenState.functionParamLists, savedParamLists);
1656
+ this.restoreMapState(CodeGenState.functionCallGraph, savedCallGraph);
1789
1657
 
1790
1658
  return { modifications, paramLists };
1791
1659
  }
@@ -1799,12 +1667,12 @@ export default class CodeGenerator implements IOrchestrator {
1799
1667
  ): void {
1800
1668
  if (crossFileModifications) {
1801
1669
  for (const [funcName, params] of crossFileModifications) {
1802
- this.modifiedParameters.set(funcName, new Set(params));
1670
+ CodeGenState.modifiedParameters.set(funcName, new Set(params));
1803
1671
  }
1804
1672
  }
1805
1673
  if (crossFileParamLists) {
1806
1674
  for (const [funcName, params] of crossFileParamLists) {
1807
- this.functionParamLists.set(funcName, [...params]);
1675
+ CodeGenState.functionParamLists.set(funcName, [...params]);
1808
1676
  }
1809
1677
  }
1810
1678
  }
@@ -1820,7 +1688,7 @@ export default class CodeGenerator implements IOrchestrator {
1820
1688
  ): Map<string, Set<string>> {
1821
1689
  const modifications = new Map<string, Set<string>>();
1822
1690
 
1823
- for (const [funcName, params] of this.modifiedParameters) {
1691
+ for (const [funcName, params] of CodeGenState.modifiedParameters) {
1824
1692
  if (!injectedFuncs.has(funcName)) {
1825
1693
  // Function defined in this file - include all its modifications
1826
1694
  modifications.set(funcName, new Set(params));
@@ -1857,7 +1725,10 @@ export default class CodeGenerator implements IOrchestrator {
1857
1725
  crossFileParamLists?: ReadonlyMap<string, readonly string[]>,
1858
1726
  ): Map<string, string[]> {
1859
1727
  return SetMapHelper.copyArrayValues(
1860
- SetMapHelper.filterExclude(this.functionParamLists, crossFileParamLists),
1728
+ SetMapHelper.filterExclude(
1729
+ CodeGenState.functionParamLists,
1730
+ crossFileParamLists,
1731
+ ),
1861
1732
  );
1862
1733
  }
1863
1734
 
@@ -1882,7 +1753,7 @@ export default class CodeGenerator implements IOrchestrator {
1882
1753
  }
1883
1754
 
1884
1755
  // Get the parameter name at the given index from the function signature
1885
- const sig = this.functionSignatures.get(funcName);
1756
+ const sig = CodeGenState.functionSignatures.get(funcName);
1886
1757
  if (!sig || paramIndex >= sig.parameters.length) {
1887
1758
  return false;
1888
1759
  }
@@ -1896,7 +1767,7 @@ export default class CodeGenerator implements IOrchestrator {
1896
1767
  * Issue #268: Check if a name is a parameter of the current function.
1897
1768
  */
1898
1769
  isCurrentParameter(name: string): boolean {
1899
- return this.context.currentParameters.has(name);
1770
+ return CodeGenState.currentParameters.has(name);
1900
1771
  }
1901
1772
 
1902
1773
  // === Postfix Expression Helpers (Issue #644) ===
@@ -1952,8 +1823,8 @@ export default class CodeGenerator implements IOrchestrator {
1952
1823
  */
1953
1824
  isKnownScope(name: string): boolean {
1954
1825
  return SymbolLookupHelper.isKnownScope(
1955
- this.symbols?.knownScopes,
1956
- this.symbolTable,
1826
+ CodeGenState.symbols?.knownScopes,
1827
+ CodeGenState.symbolTable,
1957
1828
  name,
1958
1829
  );
1959
1830
  }
@@ -1965,7 +1836,7 @@ export default class CodeGenerator implements IOrchestrator {
1965
1836
  isCppScopeSymbol(name: string): boolean {
1966
1837
  return CppNamespaceUtils.isCppNamespace(
1967
1838
  name,
1968
- this.symbolTable ?? undefined,
1839
+ CodeGenState.symbolTable ?? undefined,
1969
1840
  );
1970
1841
  }
1971
1842
 
@@ -1986,8 +1857,8 @@ export default class CodeGenerator implements IOrchestrator {
1986
1857
  fieldName: string,
1987
1858
  ): { type: string; dimensions?: (number | string)[] } | null {
1988
1859
  // First check SymbolTable (C header structs)
1989
- if (this.symbolTable) {
1990
- const fieldInfo = this.symbolTable.getStructFieldInfo(
1860
+ if (CodeGenState.symbolTable) {
1861
+ const fieldInfo = CodeGenState.symbolTable.getStructFieldInfo(
1991
1862
  structType,
1992
1863
  fieldName,
1993
1864
  );
@@ -2000,12 +1871,12 @@ export default class CodeGenerator implements IOrchestrator {
2000
1871
  }
2001
1872
 
2002
1873
  // Fall back to local C-Next struct fields
2003
- const localFields = this.symbols!.structFields.get(structType);
1874
+ const localFields = CodeGenState.symbols!.structFields.get(structType);
2004
1875
  if (localFields) {
2005
1876
  const fieldType = localFields.get(fieldName);
2006
1877
  if (fieldType) {
2007
1878
  const fieldDimensions =
2008
- this.symbols!.structFieldDimensions.get(structType);
1879
+ CodeGenState.symbols!.structFieldDimensions.get(structType);
2009
1880
  const dimensions = fieldDimensions?.get(fieldName);
2010
1881
  return {
2011
1882
  type: fieldType,
@@ -2027,7 +1898,9 @@ export default class CodeGenerator implements IOrchestrator {
2027
1898
 
2028
1899
  const isArray =
2029
1900
  (fieldInfo.dimensions !== undefined && fieldInfo.dimensions.length > 0) ||
2030
- (this.symbols!.structFieldArrays.get(structType)?.has(memberName) ??
1901
+ (CodeGenState.symbols!.structFieldArrays.get(structType)?.has(
1902
+ memberName,
1903
+ ) ??
2031
1904
  false);
2032
1905
  const dims = fieldInfo.dimensions?.filter(
2033
1906
  (d): d is number => typeof d === "number",
@@ -2057,7 +1930,7 @@ export default class CodeGenerator implements IOrchestrator {
2057
1930
  * Part of IOrchestrator interface.
2058
1931
  */
2059
1932
  addPendingTempDeclaration(declaration: string): void {
2060
- this.pendingTempDeclarations.push(declaration);
1933
+ CodeGenState.pendingTempDeclarations.push(declaration);
2061
1934
  }
2062
1935
 
2063
1936
  /**
@@ -2065,7 +1938,7 @@ export default class CodeGenerator implements IOrchestrator {
2065
1938
  * Part of IOrchestrator interface.
2066
1939
  */
2067
1940
  registerFloatBitShadow(shadowName: string): void {
2068
- this.context.floatBitShadows.add(shadowName);
1941
+ CodeGenState.floatBitShadows.add(shadowName);
2069
1942
  }
2070
1943
 
2071
1944
  /**
@@ -2073,7 +1946,7 @@ export default class CodeGenerator implements IOrchestrator {
2073
1946
  * Part of IOrchestrator interface.
2074
1947
  */
2075
1948
  markFloatShadowCurrent(shadowName: string): void {
2076
- this.context.floatShadowCurrent.add(shadowName);
1949
+ CodeGenState.floatShadowCurrent.add(shadowName);
2077
1950
  }
2078
1951
 
2079
1952
  /**
@@ -2081,7 +1954,7 @@ export default class CodeGenerator implements IOrchestrator {
2081
1954
  * Part of IOrchestrator interface.
2082
1955
  */
2083
1956
  hasFloatBitShadow(shadowName: string): boolean {
2084
- return this.context.floatBitShadows.has(shadowName);
1957
+ return CodeGenState.floatBitShadows.has(shadowName);
2085
1958
  }
2086
1959
 
2087
1960
  /**
@@ -2089,7 +1962,7 @@ export default class CodeGenerator implements IOrchestrator {
2089
1962
  * Part of IOrchestrator interface.
2090
1963
  */
2091
1964
  isFloatShadowCurrent(shadowName: string): boolean {
2092
- return this.context.floatShadowCurrent.has(shadowName);
1965
+ return CodeGenState.floatShadowCurrent.has(shadowName);
2093
1966
  }
2094
1967
 
2095
1968
  // ===========================================================================
@@ -2113,11 +1986,11 @@ export default class CodeGenerator implements IOrchestrator {
2113
1986
  return {
2114
1987
  isFloatType: (typeName: string) => this._isFloatType(typeName),
2115
1988
  isKnownPrimitive: (typeName: string) => this._isKnownPrimitive(typeName),
2116
- knownEnums: this.symbols!.knownEnums,
1989
+ knownEnums: CodeGenState.symbols!.knownEnums,
2117
1990
  isParameterPassByValue: (funcName: string, paramName: string) =>
2118
1991
  this._isParameterPassByValueByName(funcName, paramName),
2119
- currentFunctionName: this.context.currentFunctionName,
2120
- maybeDereference: (id: string) => this.cppHelper!.maybeDereference(id),
1992
+ currentFunctionName: CodeGenState.currentFunctionName,
1993
+ maybeDereference: (id: string) => CppModeHelper.maybeDereference(id),
2121
1994
  };
2122
1995
  }
2123
1996
 
@@ -2128,7 +2001,8 @@ export default class CodeGenerator implements IOrchestrator {
2128
2001
  private _buildMemberSeparatorDeps(): IMemberSeparatorDeps {
2129
2002
  return {
2130
2003
  isKnownScope: (name: string) => this.isKnownScope(name),
2131
- isKnownRegister: (name: string) => this.symbols!.knownRegisters.has(name),
2004
+ isKnownRegister: (name: string) =>
2005
+ CodeGenState.symbols!.knownRegisters.has(name),
2132
2006
  validateCrossScopeVisibility: (scopeName: string, memberName: string) =>
2133
2007
  this.validateCrossScopeVisibility(scopeName, memberName),
2134
2008
  validateRegisterAccess: (
@@ -2137,7 +2011,9 @@ export default class CodeGenerator implements IOrchestrator {
2137
2011
  hasGlobal: boolean,
2138
2012
  ) => this._validateRegisterAccess(registerName, memberName, hasGlobal),
2139
2013
  getStructParamSeparator: () =>
2140
- memberAccessChain.getStructParamSeparator({ cppMode: this.cppMode }),
2014
+ memberAccessChain.getStructParamSeparator({
2015
+ cppMode: CodeGenState.cppMode,
2016
+ }),
2141
2017
  };
2142
2018
  }
2143
2019
 
@@ -2150,10 +2026,10 @@ export default class CodeGenerator implements IOrchestrator {
2150
2026
  hasGlobal: boolean,
2151
2027
  ): void {
2152
2028
  // Only validate when inside a scope and accessing without global. prefix
2153
- if (this.context.currentScope && !hasGlobal) {
2029
+ if (CodeGenState.currentScope && !hasGlobal) {
2154
2030
  throw new Error(
2155
2031
  `Error: Use 'global.${registerName}.${memberName}' to access register '${registerName}' ` +
2156
- `from inside scope '${this.context.currentScope}'`,
2032
+ `from inside scope '${CodeGenState.currentScope}'`,
2157
2033
  );
2158
2034
  }
2159
2035
  }
@@ -2165,7 +2041,10 @@ export default class CodeGenerator implements IOrchestrator {
2165
2041
  * We check for the existence of a constructor symbol (TypeName::ClassName).
2166
2042
  */
2167
2043
  private _isCppClassWithConstructor(typeName: string): boolean {
2168
- return CppConstructorHelper.hasConstructor(typeName, this.symbolTable);
2044
+ return CppConstructorHelper.hasConstructor(
2045
+ typeName,
2046
+ CodeGenState.symbolTable,
2047
+ );
2169
2048
  }
2170
2049
 
2171
2050
  private foldBooleanToInt(expr: string): string {
@@ -2203,7 +2082,7 @@ export default class CodeGenerator implements IOrchestrator {
2203
2082
  * C++ types with constructors may fail with {0} but work with {}.
2204
2083
  */
2205
2084
  private isCppType(typeName: string): boolean {
2206
- return SymbolLookupHelper.isCppType(this.symbolTable, typeName);
2085
+ return SymbolLookupHelper.isCppType(CodeGenState.symbolTable, typeName);
2207
2086
  }
2208
2087
 
2209
2088
  /**
@@ -2219,12 +2098,6 @@ export default class CodeGenerator implements IOrchestrator {
2219
2098
  tokenStream?: CommonTokenStream,
2220
2099
  options?: ICodeGeneratorOptions,
2221
2100
  ): string {
2222
- // Store symbol table for function lookup
2223
- this.symbolTable = symbolTable ?? null;
2224
-
2225
- // Initialize options and configuration
2226
- this.initializeGenerateOptions(options, tokenStream);
2227
-
2228
2101
  // ADR-049: Determine target capabilities with priority: CLI > pragma > default
2229
2102
  const targetCapabilities = this.resolveTargetCapabilities(
2230
2103
  tree,
@@ -2237,16 +2110,22 @@ export default class CodeGenerator implements IOrchestrator {
2237
2110
  this.generatorsInitialized = true;
2238
2111
  }
2239
2112
 
2240
- // Reset state for fresh generation
2113
+ // Reset state for fresh generation (must be before any state assignments)
2241
2114
  this.resetGeneratorState(targetCapabilities);
2242
2115
 
2116
+ // Initialize options and configuration (after reset)
2117
+ this.initializeGenerateOptions(options, tokenStream);
2118
+
2119
+ // Store symbol table for function lookup (after reset)
2120
+ CodeGenState.symbolTable = symbolTable ?? null;
2121
+
2243
2122
  // ADR-055: Use pre-collected symbolInfo from Pipeline (TSymbolInfoAdapter)
2244
2123
  if (!options?.symbolInfo) {
2245
2124
  throw new Error(
2246
2125
  "symbolInfo is required - use CNextResolver + TSymbolInfoAdapter",
2247
2126
  );
2248
2127
  }
2249
- this.symbols = options.symbolInfo;
2128
+ CodeGenState.symbols = options.symbolInfo;
2250
2129
 
2251
2130
  // Initialize symbol data and const values
2252
2131
  this.initializeSymbolData();
@@ -2268,15 +2147,14 @@ export default class CodeGenerator implements IOrchestrator {
2268
2147
  options: ICodeGeneratorOptions | undefined,
2269
2148
  tokenStream: CommonTokenStream | undefined,
2270
2149
  ): void {
2271
- this.debugMode = options?.debugMode ?? false;
2272
- this.sourcePath = options?.sourcePath ?? null;
2273
- this.includeDirs = options?.includeDirs ?? [];
2274
- this.inputs = options?.inputs ?? [];
2275
- this.cppMode = options?.cppMode ?? false;
2276
- this.cppHelper = new CppModeHelper({ cppMode: this.cppMode });
2277
- this.pendingTempDeclarations = [];
2278
- this.tempVarCounter = 0;
2279
- this.pendingCppClassAssignments = [];
2150
+ CodeGenState.debugMode = options?.debugMode ?? false;
2151
+ CodeGenState.sourcePath = options?.sourcePath ?? null;
2152
+ CodeGenState.includeDirs = options?.includeDirs ?? [];
2153
+ CodeGenState.inputs = options?.inputs ?? [];
2154
+ CodeGenState.cppMode = options?.cppMode ?? false;
2155
+ CodeGenState.pendingTempDeclarations = [];
2156
+ CodeGenState.tempVarCounter = 0;
2157
+ CodeGenState.pendingCppClassAssignments = [];
2280
2158
 
2281
2159
  this.tokenStream = tokenStream ?? null;
2282
2160
  this.commentExtractor = this.tokenStream
@@ -2288,40 +2166,44 @@ export default class CodeGenerator implements IOrchestrator {
2288
2166
  * Reset all generator state for a fresh generation pass.
2289
2167
  */
2290
2168
  private resetGeneratorState(targetCapabilities: TargetCapabilities): void {
2169
+ // Reset global state first
2170
+ CodeGenState.reset(targetCapabilities);
2171
+
2172
+ // Reset local context (will gradually migrate to CodeGenState)
2291
2173
  this.context = CodeGenerator.createDefaultContext(targetCapabilities);
2292
2174
 
2293
- this.knownFunctions = new Set();
2294
- this.functionSignatures = new Map();
2295
- this.callbackTypes = new Map();
2296
- this.callbackFieldTypes = new Map();
2297
- this.usedClampOps = new Set();
2298
- this.usedSafeDivOps = new Set();
2299
- this.needsStdint = false;
2300
- this.needsStdbool = false;
2301
- this.needsString = false;
2302
- this.needsFloatStaticAssert = false;
2303
- this.needsISR = false;
2304
- this.needsCMSIS = false;
2305
- this.needsLimits = false;
2306
- this.needsIrqWrappers = false;
2307
- this.selfIncludeAdded = false;
2175
+ CodeGenState.knownFunctions = new Set();
2176
+ CodeGenState.functionSignatures = new Map();
2177
+ CodeGenState.callbackTypes = new Map();
2178
+ CodeGenState.callbackFieldTypes = new Map();
2179
+ CodeGenState.usedClampOps = new Set();
2180
+ CodeGenState.usedSafeDivOps = new Set();
2181
+ CodeGenState.needsStdint = false;
2182
+ CodeGenState.needsStdbool = false;
2183
+ CodeGenState.needsString = false;
2184
+ CodeGenState.needsFloatStaticAssert = false;
2185
+ CodeGenState.needsISR = false;
2186
+ CodeGenState.needsCMSIS = false;
2187
+ CodeGenState.needsLimits = false;
2188
+ CodeGenState.needsIrqWrappers = false;
2189
+ CodeGenState.selfIncludeAdded = false;
2308
2190
  }
2309
2191
 
2310
2192
  /**
2311
2193
  * Initialize symbol data and const values from symbol table.
2312
2194
  */
2313
2195
  private initializeSymbolData(): void {
2314
- const symbols = this.symbols!;
2196
+ const symbols = CodeGenState.symbols!;
2315
2197
 
2316
- // Copy symbol data to context.scopeMembers
2198
+ // Copy symbol data to CodeGenState.scopeMembers
2317
2199
  for (const [scopeName, members] of symbols.scopeMembers) {
2318
- this.context.scopeMembers.set(scopeName, new Set(members));
2200
+ CodeGenState.scopeMembers.set(scopeName, new Set(members));
2319
2201
  }
2320
2202
 
2321
2203
  // Issue #461: Initialize constValues from symbol table
2322
- this.constValues = new Map();
2323
- if (this.symbolTable) {
2324
- for (const symbol of this.symbolTable.getAllSymbols()) {
2204
+ CodeGenState.constValues = new Map();
2205
+ if (CodeGenState.symbolTable) {
2206
+ for (const symbol of CodeGenState.symbolTable.getAllSymbols()) {
2325
2207
  if (
2326
2208
  symbol.kind === ESymbolKind.Variable &&
2327
2209
  symbol.isConst &&
@@ -2329,7 +2211,9 @@ export default class CodeGenerator implements IOrchestrator {
2329
2211
  ) {
2330
2212
  const value = LiteralUtils.parseIntegerLiteral(symbol.initialValue);
2331
2213
  if (value !== undefined) {
2332
- this.constValues.set(symbol.name, value);
2214
+ CodeGenState.constValues.set(symbol.name, value);
2215
+ // Also populate CodeGenState
2216
+ CodeGenState.constValues.set(symbol.name, value);
2333
2217
  }
2334
2218
  }
2335
2219
  }
@@ -2340,141 +2224,9 @@ export default class CodeGenerator implements IOrchestrator {
2340
2224
  * Initialize all helper objects needed for code generation.
2341
2225
  */
2342
2226
  private initializeHelperObjects(tree: Parser.ProgramContext): void {
2343
- const symbols = this.symbols!;
2344
-
2345
- // Initialize type resolver
2346
- this.typeResolver = new TypeResolver({
2347
- symbols: symbols,
2348
- symbolTable: this.symbolTable,
2349
- typeRegistry: this.context.typeRegistry,
2350
- resolveIdentifier: (name: string) => this.resolveIdentifier(name),
2351
- });
2352
-
2353
2227
  // Collect function/callback information
2354
2228
  this.collectFunctionsAndCallbacks(tree);
2355
2229
  this.analyzePassByValue(tree);
2356
-
2357
- // Initialize type validator
2358
- this.typeValidator = new TypeValidator({
2359
- symbols: symbols,
2360
- symbolTable: this.symbolTable,
2361
- typeRegistry: this.context.typeRegistry,
2362
- typeResolver: this.typeResolver,
2363
- callbackTypes: this.callbackTypes,
2364
- knownFunctions: this.knownFunctions,
2365
- knownGlobals: new Set(),
2366
- getCurrentScope: () => this.context.currentScope,
2367
- getScopeMembers: () => this.context.scopeMembers,
2368
- getCurrentParameters: () => this.context.currentParameters,
2369
- getLocalVariables: () => this.context.localVariables,
2370
- resolveIdentifier: (name: string) => this.resolveIdentifier(name),
2371
- getExpressionType: (ctx: unknown) =>
2372
- this.getExpressionType(ctx as Parser.ExpressionContext),
2373
- });
2374
-
2375
- // Initialize remaining helpers
2376
- this.initializeAnalysisHelpers(symbols);
2377
- }
2378
-
2379
- /**
2380
- * Initialize analysis and generation helpers.
2381
- */
2382
- private initializeAnalysisHelpers(symbols: ICodeGenSymbols): void {
2383
- this.stringLengthCounter = new StringLengthCounter((name: string) =>
2384
- this.context.typeRegistry.get(name),
2385
- );
2386
-
2387
- this.memberChainAnalyzer = new MemberChainAnalyzer({
2388
- typeRegistry: this.context.typeRegistry,
2389
- structFields: symbols.structFields,
2390
- structFieldArrays: symbols.structFieldArrays,
2391
- isKnownStruct: (name) => this.isKnownStruct(name),
2392
- generateExpression: (ctx) => this.generateExpression(ctx),
2393
- });
2394
-
2395
- this.floatBitHelper = new FloatBitHelper({
2396
- cppMode: this.cppMode,
2397
- state: {
2398
- floatBitShadows: this.context.floatBitShadows,
2399
- floatShadowCurrent: this.context.floatShadowCurrent,
2400
- },
2401
- generateBitMask: (width, is64Bit) => this.generateBitMask(width, is64Bit),
2402
- foldBooleanToInt: (expr) => this.foldBooleanToInt(expr),
2403
- requireInclude: (header) => this.requireInclude(header),
2404
- });
2405
-
2406
- // Create arrayInitState proxy
2407
- const context = this.context;
2408
- const arrayInitState = {
2409
- get lastArrayInitCount() {
2410
- return context.lastArrayInitCount;
2411
- },
2412
- set lastArrayInitCount(val: number) {
2413
- context.lastArrayInitCount = val;
2414
- },
2415
- get lastArrayFillValue() {
2416
- return context.lastArrayFillValue;
2417
- },
2418
- set lastArrayFillValue(val: string | undefined) {
2419
- context.lastArrayFillValue = val;
2420
- },
2421
- };
2422
-
2423
- this.stringDeclHelper = new StringDeclHelper({
2424
- typeRegistry: this.context.typeRegistry,
2425
- getInFunctionBody: () => this.context.inFunctionBody,
2426
- getIndentLevel: () => this.context.indentLevel,
2427
- arrayInitState,
2428
- localArrays: this.context.localArrays,
2429
- generateExpression: (ctx) => this.generateExpression(ctx),
2430
- generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
2431
- getStringConcatOperands: (ctx) => this._getStringConcatOperands(ctx),
2432
- getSubstringOperands: (ctx) => this._getSubstringOperands(ctx),
2433
- getStringLiteralLength: (literal) => StringUtils.literalLength(literal),
2434
- getStringExprCapacity: (exprCode) => this.getStringExprCapacity(exprCode),
2435
- requireStringInclude: () => this.requireInclude("string"),
2436
- });
2437
-
2438
- this.enumValidator = new EnumAssignmentValidator({
2439
- knownEnums: symbols.knownEnums,
2440
- getCurrentScope: () => this.context.currentScope,
2441
- getExpressionEnumType: (ctx) => this.getExpressionEnumType(ctx),
2442
- isIntegerExpression: (ctx) => this._isIntegerExpression(ctx),
2443
- });
2444
-
2445
- this.arrayInitHelper = new ArrayInitHelper({
2446
- typeRegistry: this.context.typeRegistry,
2447
- localArrays: this.context.localArrays,
2448
- arrayInitState: arrayInitState,
2449
- getExpectedType: () => this.context.expectedType,
2450
- setExpectedType: (type) => {
2451
- this.context.expectedType = type;
2452
- },
2453
- generateExpression: (ctx) => this.generateExpression(ctx),
2454
- getTypeName: (ctx) => this.getTypeName(ctx),
2455
- generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
2456
- });
2457
-
2458
- this.expectedTypeResolver = new AssignmentExpectedTypeResolver({
2459
- typeRegistry: this.context.typeRegistry,
2460
- structFields: symbols.structFields,
2461
- isKnownStruct: (name) => this.isKnownStruct(name),
2462
- });
2463
-
2464
- this.assignmentValidator = new AssignmentValidator({
2465
- typeValidator: this.typeValidator!,
2466
- enumValidator: this.enumValidator,
2467
- typeRegistry: this.context.typeRegistry,
2468
- floatShadowCurrent: this.context.floatShadowCurrent,
2469
- registerMemberAccess: symbols.registerMemberAccess,
2470
- callbackFieldTypes: this.callbackFieldTypes,
2471
- isKnownStruct: (name) => this.isKnownStruct(name),
2472
- isIntegerType: (name) => this._isIntegerType(name),
2473
- getExpressionType: (ctx) => this.getExpressionType(ctx),
2474
- tryEvaluateConstant: (ctx) => this.tryEvaluateConstant(ctx),
2475
- isCallbackTypeUsedAsFieldType: (name) =>
2476
- this.isCallbackTypeUsedAsFieldType(name),
2477
- });
2478
2230
  }
2479
2231
 
2480
2232
  /**
@@ -2485,9 +2237,7 @@ export default class CodeGenerator implements IOrchestrator {
2485
2237
  options: ICodeGeneratorOptions | undefined,
2486
2238
  ): string {
2487
2239
  const output: string[] = [];
2488
- const symbols = this.symbols!;
2489
- const typeValidator = this.typeValidator!;
2490
-
2240
+ const symbols = CodeGenState.symbols!;
2491
2241
  // Add header comment
2492
2242
  output.push(
2493
2243
  "/**",
@@ -2498,16 +2248,17 @@ export default class CodeGenerator implements IOrchestrator {
2498
2248
  );
2499
2249
 
2500
2250
  // Self-include for extern "C" linkage
2501
- if (symbols.hasPublicSymbols() && this.sourcePath) {
2251
+ if (symbols.hasPublicSymbols() && CodeGenState.sourcePath) {
2502
2252
  const pathToUse =
2503
- options?.sourceRelativePath || this.sourcePath.replace(/^.*[\\/]/, "");
2253
+ options?.sourceRelativePath ||
2254
+ CodeGenState.sourcePath.replace(/^.*[\\/]/, "");
2504
2255
  const headerName = pathToUse.replace(/\.cnx$|\.cnext$/, ".h");
2505
2256
  output.push(`#include "${headerName}"`, "");
2506
- this.selfIncludeAdded = true;
2257
+ CodeGenState.selfIncludeAdded = true;
2507
2258
  }
2508
2259
 
2509
2260
  // Process include directives
2510
- this.processIncludeDirectives(tree, output, typeValidator);
2261
+ this.processIncludeDirectives(tree, output);
2511
2262
 
2512
2263
  // Process preprocessor directives
2513
2264
  this.processPreprocessorDirectives(tree, output);
@@ -2531,10 +2282,9 @@ export default class CodeGenerator implements IOrchestrator {
2531
2282
  private processIncludeDirectives(
2532
2283
  tree: Parser.ProgramContext,
2533
2284
  output: string[],
2534
- typeValidator: TypeValidator,
2535
2285
  ): void {
2536
- const includePaths = this.sourcePath
2537
- ? IncludeDiscovery.discoverIncludePaths(this.sourcePath)
2286
+ const includePaths = CodeGenState.sourcePath
2287
+ ? IncludeDiscovery.discoverIncludePaths(CodeGenState.sourcePath)
2538
2288
  : [];
2539
2289
 
2540
2290
  for (const includeDir of tree.includeDirective()) {
@@ -2542,14 +2292,14 @@ export default class CodeGenerator implements IOrchestrator {
2542
2292
  output.push(...this.formatLeadingComments(leadingComments));
2543
2293
 
2544
2294
  const lineNumber = includeDir.start?.line ?? 0;
2545
- typeValidator.validateIncludeNotImplementationFile(
2295
+ TypeValidator.validateIncludeNotImplementationFile(
2546
2296
  includeDir.getText(),
2547
2297
  lineNumber,
2548
2298
  );
2549
- typeValidator.validateIncludeNoCnxAlternative(
2299
+ TypeValidator.validateIncludeNoCnxAlternative(
2550
2300
  includeDir.getText(),
2551
2301
  lineNumber,
2552
- this.sourcePath,
2302
+ CodeGenState.sourcePath,
2553
2303
  includePaths,
2554
2304
  );
2555
2305
 
@@ -2607,11 +2357,11 @@ export default class CodeGenerator implements IOrchestrator {
2607
2357
  private addAutoIncludes(output: string[]): void {
2608
2358
  const autoIncludes: string[] = [];
2609
2359
 
2610
- if (this.needsStdint) autoIncludes.push("#include <stdint.h>");
2611
- if (this.needsStdbool) autoIncludes.push("#include <stdbool.h>");
2612
- if (this.needsString) autoIncludes.push("#include <string.h>");
2613
- if (this.needsCMSIS) autoIncludes.push("#include <cmsis_gcc.h>");
2614
- if (this.needsLimits) autoIncludes.push("#include <limits.h>");
2360
+ if (CodeGenState.needsStdint) autoIncludes.push("#include <stdint.h>");
2361
+ if (CodeGenState.needsStdbool) autoIncludes.push("#include <stdbool.h>");
2362
+ if (CodeGenState.needsString) autoIncludes.push("#include <string.h>");
2363
+ if (CodeGenState.needsCMSIS) autoIncludes.push("#include <cmsis_gcc.h>");
2364
+ if (CodeGenState.needsLimits) autoIncludes.push("#include <limits.h>");
2615
2365
 
2616
2366
  if (autoIncludes.length > 0) {
2617
2367
  output.push(...autoIncludes, "");
@@ -2622,7 +2372,7 @@ export default class CodeGenerator implements IOrchestrator {
2622
2372
  * Add generated helpers (static asserts, IRQ wrappers, typedefs, etc.).
2623
2373
  */
2624
2374
  private addGeneratedHelpers(output: string[]): void {
2625
- if (this.needsFloatStaticAssert) {
2375
+ if (CodeGenState.needsFloatStaticAssert) {
2626
2376
  output.push(
2627
2377
  '_Static_assert(sizeof(float) == 4, "Float bit indexing requires 32-bit float");',
2628
2378
  '_Static_assert(sizeof(double) == 8, "Float bit indexing requires 64-bit double");',
@@ -2630,7 +2380,7 @@ export default class CodeGenerator implements IOrchestrator {
2630
2380
  );
2631
2381
  }
2632
2382
 
2633
- if (this.needsIrqWrappers) {
2383
+ if (CodeGenState.needsIrqWrappers) {
2634
2384
  output.push(
2635
2385
  "// ADR-050: IRQ wrappers to avoid macro collisions with platform headers",
2636
2386
  "static inline void __cnx_disable_irq(void) { __disable_irq(); }",
@@ -2640,7 +2390,7 @@ export default class CodeGenerator implements IOrchestrator {
2640
2390
  );
2641
2391
  }
2642
2392
 
2643
- if (this.needsISR) {
2393
+ if (CodeGenState.needsISR) {
2644
2394
  output.push(
2645
2395
  "/* ADR-040: ISR function pointer type */",
2646
2396
  "typedef void (*ISR)(void);",
@@ -2722,9 +2472,9 @@ export default class CodeGenerator implements IOrchestrator {
2722
2472
  */
2723
2473
  private transformIncludeDirective(includeText: string): string {
2724
2474
  return includeTransformIncludeDirective(includeText, {
2725
- sourcePath: this.sourcePath,
2726
- includeDirs: this.includeDirs,
2727
- inputs: this.inputs,
2475
+ sourcePath: CodeGenState.sourcePath,
2476
+ includeDirs: CodeGenState.includeDirs,
2477
+ inputs: CodeGenState.inputs,
2728
2478
  });
2729
2479
  }
2730
2480
 
@@ -2765,8 +2515,8 @@ export default class CodeGenerator implements IOrchestrator {
2765
2515
  const scopeName = scopeDecl.IDENTIFIER().getText();
2766
2516
 
2767
2517
  // Set scope context for scoped type resolution (this.Type)
2768
- const savedScope = this.context.currentScope;
2769
- this.context.currentScope = scopeName;
2518
+ const savedScope = CodeGenState.currentScope;
2519
+ CodeGenState.currentScope = scopeName;
2770
2520
 
2771
2521
  for (const member of scopeDecl.scopeMember()) {
2772
2522
  if (member.functionDeclaration()) {
@@ -2774,20 +2524,20 @@ export default class CodeGenerator implements IOrchestrator {
2774
2524
  const funcName = funcDecl.IDENTIFIER().getText();
2775
2525
  // Track fully qualified function name: Scope_function
2776
2526
  const fullName = `${scopeName}_${funcName}`;
2777
- this.knownFunctions.add(fullName);
2527
+ CodeGenState.knownFunctions.add(fullName);
2778
2528
  // ADR-013: Track function signature for const checking
2779
2529
  const sig = this.extractFunctionSignature(
2780
2530
  fullName,
2781
2531
  funcDecl.parameterList() ?? null,
2782
2532
  );
2783
- this.functionSignatures.set(fullName, sig);
2533
+ CodeGenState.functionSignatures.set(fullName, sig);
2784
2534
  // ADR-029: Register scoped function as callback type
2785
2535
  this.registerCallbackType(fullName, funcDecl);
2786
2536
  }
2787
2537
  }
2788
2538
 
2789
2539
  // Restore previous scope context
2790
- this.context.currentScope = savedScope;
2540
+ CodeGenState.currentScope = savedScope;
2791
2541
  }
2792
2542
 
2793
2543
  /**
@@ -2803,8 +2553,11 @@ export default class CodeGenerator implements IOrchestrator {
2803
2553
  const fieldType = this.getTypeName(member.type());
2804
2554
 
2805
2555
  // Track callback field types (needed for typedef generation)
2806
- if (this.callbackTypes.has(fieldType)) {
2807
- this.callbackFieldTypes.set(`${structName}.${fieldName}`, fieldType);
2556
+ if (CodeGenState.callbackTypes.has(fieldType)) {
2557
+ CodeGenState.callbackFieldTypes.set(
2558
+ `${structName}.${fieldName}`,
2559
+ fieldType,
2560
+ );
2808
2561
  }
2809
2562
  }
2810
2563
  }
@@ -2816,13 +2569,13 @@ export default class CodeGenerator implements IOrchestrator {
2816
2569
  funcDecl: Parser.FunctionDeclarationContext,
2817
2570
  ): void {
2818
2571
  const name = funcDecl.IDENTIFIER().getText();
2819
- this.knownFunctions.add(name);
2572
+ CodeGenState.knownFunctions.add(name);
2820
2573
  // ADR-013: Track function signature for const checking
2821
2574
  const sig = this.extractFunctionSignature(
2822
2575
  name,
2823
2576
  funcDecl.parameterList() ?? null,
2824
2577
  );
2825
- this.functionSignatures.set(name, sig);
2578
+ CodeGenState.functionSignatures.set(name, sig);
2826
2579
  // ADR-029: Register function as callback type
2827
2580
  this.registerCallbackType(name, funcDecl);
2828
2581
  }
@@ -2865,7 +2618,7 @@ export default class CodeGenerator implements IOrchestrator {
2865
2618
  const constName = varDecl.IDENTIFIER().getText();
2866
2619
  const constValue = this.tryEvaluateConstant(varDecl.expression()!);
2867
2620
  if (constValue !== undefined) {
2868
- this.constValues.set(constName, constValue);
2621
+ CodeGenState.constValues.set(constName, constValue);
2869
2622
  }
2870
2623
  }
2871
2624
  }
@@ -2880,8 +2633,8 @@ export default class CodeGenerator implements IOrchestrator {
2880
2633
  const scopeName = scopeDecl.IDENTIFIER().getText();
2881
2634
 
2882
2635
  // Set currentScope so that this.Type references resolve correctly
2883
- const savedScope = this.context.currentScope;
2884
- this.context.currentScope = scopeName;
2636
+ const savedScope = CodeGenState.currentScope;
2637
+ this.setCurrentScope(scopeName);
2885
2638
 
2886
2639
  for (const member of scopeDecl.scopeMember()) {
2887
2640
  if (member.variableDeclaration()) {
@@ -2894,7 +2647,7 @@ export default class CodeGenerator implements IOrchestrator {
2894
2647
  }
2895
2648
 
2896
2649
  // Restore previous scope
2897
- this.context.currentScope = savedScope;
2650
+ this.setCurrentScope(savedScope);
2898
2651
  }
2899
2652
 
2900
2653
  // Issue #60: collectEnum and collectBitmap methods removed - now in SymbolCollector
@@ -2913,10 +2666,10 @@ export default class CodeGenerator implements IOrchestrator {
2913
2666
  */
2914
2667
  private analyzePassByValue(tree: Parser.ProgramContext): void {
2915
2668
  // Reset analysis state
2916
- this.modifiedParameters.clear();
2917
- this.passByValueParams.clear();
2918
- this.functionCallGraph.clear();
2919
- this.functionParamLists.clear();
2669
+ CodeGenState.modifiedParameters.clear();
2670
+ CodeGenState.passByValueParams.clear();
2671
+ CodeGenState.functionCallGraph.clear();
2672
+ CodeGenState.functionParamLists.clear();
2920
2673
 
2921
2674
  // Phase 1: Collect function parameter lists and direct modifications
2922
2675
  this.collectFunctionParametersAndModifications(tree);
@@ -2927,9 +2680,9 @@ export default class CodeGenerator implements IOrchestrator {
2927
2680
 
2928
2681
  // Phase 2: Fixed-point iteration for transitive modifications
2929
2682
  TransitiveModificationPropagator.propagate(
2930
- this.functionCallGraph,
2931
- this.functionParamLists,
2932
- this.modifiedParameters,
2683
+ CodeGenState.functionCallGraph,
2684
+ CodeGenState.functionParamLists,
2685
+ CodeGenState.modifiedParameters,
2933
2686
  );
2934
2687
 
2935
2688
  // Phase 3: Determine which parameters can pass by value
@@ -2941,19 +2694,22 @@ export default class CodeGenerator implements IOrchestrator {
2941
2694
  * SonarCloud S3776: Extracted from analyzePassByValue().
2942
2695
  */
2943
2696
  private injectCrossFileModifications(): void {
2944
- if (!this.pendingCrossFileModifications) return;
2697
+ if (!CodeGenState.pendingCrossFileModifications) return;
2945
2698
 
2946
- for (const [funcName, params] of this.pendingCrossFileModifications) {
2947
- const existing = this.modifiedParameters.get(funcName);
2699
+ for (const [
2700
+ funcName,
2701
+ params,
2702
+ ] of CodeGenState.pendingCrossFileModifications) {
2703
+ const existing = CodeGenState.modifiedParameters.get(funcName);
2948
2704
  if (existing) {
2949
2705
  for (const param of params) {
2950
2706
  existing.add(param);
2951
2707
  }
2952
2708
  } else {
2953
- this.modifiedParameters.set(funcName, new Set(params));
2709
+ CodeGenState.modifiedParameters.set(funcName, new Set(params));
2954
2710
  }
2955
2711
  }
2956
- this.pendingCrossFileModifications = null; // Clear after use
2712
+ CodeGenState.pendingCrossFileModifications = null; // Clear after use
2957
2713
  }
2958
2714
 
2959
2715
  /**
@@ -2961,14 +2717,14 @@ export default class CodeGenerator implements IOrchestrator {
2961
2717
  * SonarCloud S3776: Extracted from analyzePassByValue().
2962
2718
  */
2963
2719
  private injectCrossFileParamLists(): void {
2964
- if (!this.pendingCrossFileParamLists) return;
2720
+ if (!CodeGenState.pendingCrossFileParamLists) return;
2965
2721
 
2966
- for (const [funcName, params] of this.pendingCrossFileParamLists) {
2967
- if (!this.functionParamLists.has(funcName)) {
2968
- this.functionParamLists.set(funcName, [...params]);
2722
+ for (const [funcName, params] of CodeGenState.pendingCrossFileParamLists) {
2723
+ if (!CodeGenState.functionParamLists.has(funcName)) {
2724
+ CodeGenState.functionParamLists.set(funcName, [...params]);
2969
2725
  }
2970
2726
  }
2971
- this.pendingCrossFileParamLists = null; // Clear after use
2727
+ CodeGenState.pendingCrossFileParamLists = null; // Clear after use
2972
2728
  }
2973
2729
 
2974
2730
  /**
@@ -3020,13 +2776,13 @@ export default class CodeGenerator implements IOrchestrator {
3020
2776
  paramNames.push(param.IDENTIFIER().getText());
3021
2777
  }
3022
2778
  }
3023
- this.functionParamLists.set(funcName, paramNames);
2779
+ CodeGenState.functionParamLists.set(funcName, paramNames);
3024
2780
 
3025
2781
  // Initialize modified set
3026
- this.modifiedParameters.set(funcName, new Set());
2782
+ CodeGenState.modifiedParameters.set(funcName, new Set());
3027
2783
  // Issue #579: Initialize subscript access tracking
3028
- this.subscriptAccessedParameters.set(funcName, new Set());
3029
- this.functionCallGraph.set(funcName, []);
2784
+ CodeGenState.subscriptAccessedParameters.set(funcName, new Set());
2785
+ CodeGenState.functionCallGraph.set(funcName, []);
3030
2786
 
3031
2787
  // Walk the function body to find modifications and calls
3032
2788
  const block = funcDecl.block();
@@ -3102,12 +2858,14 @@ export default class CodeGenerator implements IOrchestrator {
3102
2858
  baseIdentifier &&
3103
2859
  paramSet.has(baseIdentifier)
3104
2860
  ) {
3105
- this.subscriptAccessedParameters.get(funcName)!.add(baseIdentifier);
2861
+ CodeGenState.subscriptAccessedParameters
2862
+ .get(funcName)!
2863
+ .add(baseIdentifier);
3106
2864
  }
3107
2865
 
3108
2866
  // Track as modified parameter
3109
2867
  if (baseIdentifier && paramSet.has(baseIdentifier)) {
3110
- this.modifiedParameters.get(funcName)!.add(baseIdentifier);
2868
+ CodeGenState.modifiedParameters.get(funcName)!.add(baseIdentifier);
3111
2869
  }
3112
2870
  }
3113
2871
 
@@ -3179,7 +2937,7 @@ export default class CodeGenerator implements IOrchestrator {
3179
2937
  (op) => op.expression().length === 1,
3180
2938
  );
3181
2939
  if (hasSingleIndexSubscript) {
3182
- this.subscriptAccessedParameters.get(funcName)!.add(primaryId);
2940
+ CodeGenState.subscriptAccessedParameters.get(funcName)!.add(primaryId);
3183
2941
  }
3184
2942
  }
3185
2943
 
@@ -3356,7 +3114,7 @@ export default class CodeGenerator implements IOrchestrator {
3356
3114
  const arg = args[i];
3357
3115
  const argName = ExpressionUtils.extractIdentifier(arg);
3358
3116
  if (argName && paramSet.has(argName)) {
3359
- this.functionCallGraph.get(funcName)!.push({
3117
+ CodeGenState.functionCallGraph.get(funcName)!.push({
3360
3118
  callee: calleeName,
3361
3119
  paramIndex: i,
3362
3120
  argParamName: argName,
@@ -3406,12 +3164,13 @@ export default class CodeGenerator implements IOrchestrator {
3406
3164
  "bool",
3407
3165
  ]);
3408
3166
 
3409
- for (const [funcName, paramNames] of this.functionParamLists) {
3167
+ for (const [funcName, paramNames] of CodeGenState.functionParamLists) {
3410
3168
  const passByValue = new Set<string>();
3411
- const modified = this.modifiedParameters.get(funcName) ?? new Set();
3169
+ const modified =
3170
+ CodeGenState.modifiedParameters.get(funcName) ?? new Set();
3412
3171
 
3413
3172
  // Get function declaration to check parameter types
3414
- const funcSig = this.functionSignatures.get(funcName);
3173
+ const funcSig = CodeGenState.functionSignatures.get(funcName);
3415
3174
  if (funcSig) {
3416
3175
  for (let i = 0; i < paramNames.length; i++) {
3417
3176
  const paramName = paramNames[i];
@@ -3429,8 +3188,9 @@ export default class CodeGenerator implements IOrchestrator {
3429
3188
  const isModified = modified.has(paramName);
3430
3189
  // Issue #579: Parameters with subscript access must become pointers
3431
3190
  const hasSubscriptAccess =
3432
- this.subscriptAccessedParameters.get(funcName)?.has(paramName) ??
3433
- false;
3191
+ CodeGenState.subscriptAccessedParameters
3192
+ .get(funcName)
3193
+ ?.has(paramName) ?? false;
3434
3194
 
3435
3195
  if (
3436
3196
  isSmallPrimitive &&
@@ -3443,7 +3203,7 @@ export default class CodeGenerator implements IOrchestrator {
3443
3203
  }
3444
3204
  }
3445
3205
 
3446
- this.passByValueParams.set(funcName, passByValue);
3206
+ CodeGenState.passByValueParams.set(funcName, passByValue);
3447
3207
  }
3448
3208
  }
3449
3209
 
@@ -3455,7 +3215,7 @@ export default class CodeGenerator implements IOrchestrator {
3455
3215
  funcName: string,
3456
3216
  paramName: string,
3457
3217
  ): boolean {
3458
- const passByValue = this.passByValueParams.get(funcName);
3218
+ const passByValue = CodeGenState.passByValueParams.get(funcName);
3459
3219
  return passByValue?.has(paramName) ?? false;
3460
3220
  }
3461
3221
 
@@ -3464,7 +3224,7 @@ export default class CodeGenerator implements IOrchestrator {
3464
3224
  * Part of IOrchestrator interface - used by CallExprGenerator.
3465
3225
  */
3466
3226
  isParameterPassByValue(funcName: string, paramIndex: number): boolean {
3467
- const paramList = this.functionParamLists.get(funcName);
3227
+ const paramList = CodeGenState.functionParamLists.get(funcName);
3468
3228
  if (!paramList || paramIndex < 0 || paramIndex >= paramList.length) {
3469
3229
  return false;
3470
3230
  }
@@ -3478,7 +3238,7 @@ export default class CodeGenerator implements IOrchestrator {
3478
3238
  * Used by HeaderGenerator to ensure header and implementation signatures match.
3479
3239
  */
3480
3240
  getPassByValueParams(): ReadonlyMap<string, ReadonlySet<string>> {
3481
- return this.passByValueParams;
3241
+ return CodeGenState.passByValueParams;
3482
3242
  }
3483
3243
 
3484
3244
  /**
@@ -3498,7 +3258,7 @@ export default class CodeGenerator implements IOrchestrator {
3498
3258
  arrayDim: Parser.ArrayDimensionContext[] | null,
3499
3259
  ): number[] | undefined {
3500
3260
  return ArrayDimensionParser.parseAllDimensions(arrayDim, {
3501
- constValues: this.constValues,
3261
+ constValues: CodeGenState.constValues,
3502
3262
  typeWidths: TYPE_WIDTH,
3503
3263
  isKnownStruct: (name) => this.isKnownStruct(name),
3504
3264
  });
@@ -3528,8 +3288,8 @@ export default class CodeGenerator implements IOrchestrator {
3528
3288
  // ADR-017: Check if this is an enum type
3529
3289
  if (
3530
3290
  TypeRegistrationUtils.tryRegisterEnumType(
3531
- this.context.typeRegistry,
3532
- this.symbols!,
3291
+ CodeGenState.typeRegistry,
3292
+ CodeGenState.symbols!,
3533
3293
  registrationOptions,
3534
3294
  )
3535
3295
  ) {
@@ -3540,8 +3300,8 @@ export default class CodeGenerator implements IOrchestrator {
3540
3300
  const bitmapDimensions = this._evaluateArrayDimensions(arrayDim);
3541
3301
  if (
3542
3302
  TypeRegistrationUtils.tryRegisterBitmapType(
3543
- this.context.typeRegistry,
3544
- this.symbols!,
3303
+ CodeGenState.typeRegistry,
3304
+ CodeGenState.symbols!,
3545
3305
  registrationOptions,
3546
3306
  bitmapDimensions,
3547
3307
  )
@@ -3607,7 +3367,7 @@ export default class CodeGenerator implements IOrchestrator {
3607
3367
  const allDims =
3608
3368
  additionalDims.length > 0 ? [...additionalDims, stringDim] : [stringDim];
3609
3369
 
3610
- this.context.typeRegistry.set(registryName, {
3370
+ CodeGenState.typeRegistry.set(registryName, {
3611
3371
  baseType: "char",
3612
3372
  bitWidth: 8,
3613
3373
  isArray: true,
@@ -3635,8 +3395,8 @@ export default class CodeGenerator implements IOrchestrator {
3635
3395
  if (typeCtx.scopedType()) {
3636
3396
  // ADR-016: Handle this.Type for scoped types (e.g., this.State -> Motor_State)
3637
3397
  const typeName = typeCtx.scopedType()!.IDENTIFIER().getText();
3638
- return this.context.currentScope
3639
- ? `${this.context.currentScope}_${typeName}`
3398
+ return CodeGenState.currentScope
3399
+ ? `${CodeGenState.currentScope}_${typeName}`
3640
3400
  : typeName;
3641
3401
  }
3642
3402
 
@@ -3755,6 +3515,42 @@ export default class CodeGenerator implements IOrchestrator {
3755
3515
  if (arrayTypeCtx.primitiveType()) {
3756
3516
  baseType = arrayTypeCtx.primitiveType()!.getText();
3757
3517
  bitWidth = TYPE_WIDTH[baseType] || 0;
3518
+ } else if (arrayTypeCtx.userType()) {
3519
+ // Handle user types (structs, enums, bitmaps)
3520
+ baseType = arrayTypeCtx.userType()!.getText();
3521
+
3522
+ const combinedArrayDim = arrayDim ?? [];
3523
+
3524
+ // Check if this is an enum or bitmap type and delegate to proper registration
3525
+ if (
3526
+ this._tryRegisterEnumOrBitmapType(
3527
+ registryName,
3528
+ baseType,
3529
+ isConst,
3530
+ combinedArrayDim,
3531
+ overflowBehavior,
3532
+ isAtomic,
3533
+ )
3534
+ ) {
3535
+ // Enum/bitmap was registered, but we need to update with arrayType dimension
3536
+ const existingInfo = CodeGenState.typeRegistry.get(registryName);
3537
+ if (existingInfo) {
3538
+ const arrayTypeDim =
3539
+ this._parseArrayTypeDimensionFromCtx(arrayTypeCtx);
3540
+ const allDims = arrayTypeDim
3541
+ ? [arrayTypeDim, ...(existingInfo.arrayDimensions ?? [])]
3542
+ : existingInfo.arrayDimensions;
3543
+ CodeGenState.typeRegistry.set(registryName, {
3544
+ ...existingInfo,
3545
+ isArray: true,
3546
+ arrayDimensions: allDims,
3547
+ });
3548
+ }
3549
+ return;
3550
+ }
3551
+
3552
+ // Not an enum/bitmap - register as regular user type (struct)
3553
+ // bitWidth already initialized to 0, no reassignment needed
3758
3554
  }
3759
3555
 
3760
3556
  if (!baseType) {
@@ -3766,7 +3562,7 @@ export default class CodeGenerator implements IOrchestrator {
3766
3562
  arrayDim,
3767
3563
  );
3768
3564
 
3769
- this.context.typeRegistry.set(registryName, {
3565
+ CodeGenState.typeRegistry.set(registryName, {
3770
3566
  baseType,
3771
3567
  bitWidth,
3772
3568
  isArray: true,
@@ -3777,6 +3573,20 @@ export default class CodeGenerator implements IOrchestrator {
3777
3573
  });
3778
3574
  }
3779
3575
 
3576
+ /**
3577
+ * Parse array dimension from arrayType context.
3578
+ */
3579
+ private _parseArrayTypeDimensionFromCtx(
3580
+ arrayTypeCtx: Parser.ArrayTypeContext,
3581
+ ): number | undefined {
3582
+ const sizeExpr = arrayTypeCtx.expression();
3583
+ if (!sizeExpr) {
3584
+ return undefined;
3585
+ }
3586
+ const size = Number.parseInt(sizeExpr.getText(), 10);
3587
+ return Number.isNaN(size) ? undefined : size;
3588
+ }
3589
+
3780
3590
  /**
3781
3591
  * Collect array dimensions from array type and additional dimensions
3782
3592
  */
@@ -3824,7 +3634,7 @@ export default class CodeGenerator implements IOrchestrator {
3824
3634
  ? this._evaluateArrayDimensions(arrayDim)
3825
3635
  : undefined;
3826
3636
 
3827
- this.context.typeRegistry.set(registryName, {
3637
+ CodeGenState.typeRegistry.set(registryName, {
3828
3638
  baseType,
3829
3639
  bitWidth,
3830
3640
  isArray,
@@ -3840,14 +3650,15 @@ export default class CodeGenerator implements IOrchestrator {
3840
3650
  * Part of IOrchestrator interface.
3841
3651
  */
3842
3652
  isStructType(typeName: string): boolean {
3843
- return this.typeResolver!.isStructType(typeName);
3653
+ return TypeResolver.isStructType(typeName);
3844
3654
  }
3845
3655
 
3846
3656
  /**
3847
3657
  * Set up parameter tracking for a function
3848
3658
  */
3849
3659
  private _setParameters(params: Parser.ParameterListContext | null): void {
3850
- this.context.currentParameters.clear();
3660
+ CodeGenState.currentParameters.clear();
3661
+ CodeGenState.currentParameters.clear();
3851
3662
  if (!params) return;
3852
3663
 
3853
3664
  for (const param of params.parameter()) {
@@ -3868,7 +3679,7 @@ export default class CodeGenerator implements IOrchestrator {
3868
3679
  const typeInfo = this._resolveParameterTypeInfo(typeCtx);
3869
3680
 
3870
3681
  // Register in currentParameters
3871
- this.context.currentParameters.set(name, {
3682
+ const paramInfo = {
3872
3683
  name,
3873
3684
  baseType: typeInfo.typeName,
3874
3685
  isArray,
@@ -3876,7 +3687,8 @@ export default class CodeGenerator implements IOrchestrator {
3876
3687
  isConst,
3877
3688
  isCallback: typeInfo.isCallback,
3878
3689
  isString: typeInfo.isString,
3879
- });
3690
+ };
3691
+ CodeGenState.currentParameters.set(name, paramInfo);
3880
3692
 
3881
3693
  // Register in typeRegistry
3882
3694
  this._registerParameterType(name, typeInfo, param, isArray, isConst);
@@ -3905,7 +3717,7 @@ export default class CodeGenerator implements IOrchestrator {
3905
3717
  return {
3906
3718
  typeName,
3907
3719
  isStruct: this.isStructType(typeName),
3908
- isCallback: this.callbackTypes.has(typeName),
3720
+ isCallback: CodeGenState.callbackTypes.has(typeName),
3909
3721
  isString: false,
3910
3722
  };
3911
3723
  }
@@ -3926,8 +3738,8 @@ export default class CodeGenerator implements IOrchestrator {
3926
3738
 
3927
3739
  if (typeCtx.scopedType()) {
3928
3740
  const localTypeName = typeCtx.scopedType()!.IDENTIFIER().getText();
3929
- const typeName = this.context.currentScope
3930
- ? `${this.context.currentScope}_${localTypeName}`
3741
+ const typeName = CodeGenState.currentScope
3742
+ ? `${CodeGenState.currentScope}_${localTypeName}`
3931
3743
  : localTypeName;
3932
3744
  return {
3933
3745
  typeName,
@@ -3978,8 +3790,8 @@ export default class CodeGenerator implements IOrchestrator {
3978
3790
  const { typeName, isString } = typeInfo;
3979
3791
  const typeCtx = param.type();
3980
3792
 
3981
- const isEnum = this.symbols!.knownEnums.has(typeName);
3982
- const isBitmap = this.symbols!.knownBitmaps.has(typeName);
3793
+ const isEnum = CodeGenState.symbols!.knownEnums.has(typeName);
3794
+ const isBitmap = CodeGenState.symbols!.knownBitmaps.has(typeName);
3983
3795
 
3984
3796
  // Extract array dimensions
3985
3797
  const arrayDimensions = isArray
@@ -3992,10 +3804,10 @@ export default class CodeGenerator implements IOrchestrator {
3992
3804
  arrayDimensions.push(stringCapacity + 1);
3993
3805
  }
3994
3806
 
3995
- this.context.typeRegistry.set(name, {
3807
+ const registeredType = {
3996
3808
  baseType: typeName,
3997
3809
  bitWidth: isBitmap
3998
- ? this.symbols!.bitmapBitWidth.get(typeName) || 0
3810
+ ? CodeGenState.symbols!.bitmapBitWidth.get(typeName) || 0
3999
3811
  : TYPE_WIDTH[typeName] || 0,
4000
3812
  isArray,
4001
3813
  arrayDimensions: arrayDimensions.length > 0 ? arrayDimensions : undefined,
@@ -4007,7 +3819,8 @@ export default class CodeGenerator implements IOrchestrator {
4007
3819
  isString,
4008
3820
  stringCapacity,
4009
3821
  isParameter: true,
4010
- });
3822
+ };
3823
+ CodeGenState.typeRegistry.set(name, registeredType);
4011
3824
  }
4012
3825
 
4013
3826
  /**
@@ -4028,11 +3841,14 @@ export default class CodeGenerator implements IOrchestrator {
4028
3841
  */
4029
3842
  private _clearParameters(): void {
4030
3843
  // ADR-025: Remove parameter types from typeRegistry
4031
- for (const name of this.context.currentParameters.keys()) {
4032
- this.context.typeRegistry.delete(name);
3844
+ for (const name of CodeGenState.currentParameters.keys()) {
3845
+ CodeGenState.typeRegistry.delete(name);
3846
+ CodeGenState.typeRegistry.delete(name);
4033
3847
  }
4034
- this.context.currentParameters.clear();
4035
- this.context.localArrays.clear();
3848
+ CodeGenState.currentParameters.clear();
3849
+ CodeGenState.localArrays.clear();
3850
+ CodeGenState.currentParameters.clear();
3851
+ CodeGenState.localArrays.clear();
4036
3852
  }
4037
3853
 
4038
3854
  /**
@@ -4054,7 +3870,10 @@ export default class CodeGenerator implements IOrchestrator {
4054
3870
  const paramName = param.IDENTIFIER().getText();
4055
3871
  const isConst = param.constModifier() !== null;
4056
3872
  // arrayDimension() returns an array (due to grammar's *), so check length
4057
- const isArray = param.arrayDimension().length > 0;
3873
+ // Also check C-Next style array type (e.g., u8[8] param)
3874
+ const isArray =
3875
+ param.arrayDimension().length > 0 ||
3876
+ param.type().arrayType() !== null;
4058
3877
  const baseType = this.getTypeName(param.type());
4059
3878
  parameters.push({ name: paramName, baseType, isConst, isArray });
4060
3879
  }
@@ -4087,17 +3906,18 @@ export default class CodeGenerator implements IOrchestrator {
4087
3906
  const typeName = this.getTypeName(param.type());
4088
3907
  const isConst = param.constModifier() !== null;
4089
3908
  const dims = param.arrayDimension();
4090
- const isArray = dims.length > 0;
3909
+ const arrayTypeCtx = param.type().arrayType();
3910
+ const isArray = dims.length > 0 || arrayTypeCtx !== null;
4091
3911
 
4092
3912
  // ADR-029: Check if parameter type is itself a callback type
4093
- const isCallbackParam = this.callbackTypes.has(typeName);
3913
+ const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
4094
3914
 
4095
3915
  let paramType: string;
4096
3916
  let isPointer: boolean;
4097
3917
 
4098
3918
  if (isCallbackParam) {
4099
3919
  // Use the callback typedef name
4100
- const cbInfo = this.callbackTypes.get(typeName)!;
3920
+ const cbInfo = CodeGenState.callbackTypes.get(typeName)!;
4101
3921
  paramType = cbInfo.typedefName;
4102
3922
  isPointer = false; // Function pointers are already pointers
4103
3923
  } else {
@@ -4106,9 +3926,14 @@ export default class CodeGenerator implements IOrchestrator {
4106
3926
  isPointer = !isArray;
4107
3927
  }
4108
3928
 
4109
- const arrayDims = isArray
4110
- ? dims.map((d) => this.generateArrayDimension(d)).join("")
4111
- : "";
3929
+ let arrayDims: string;
3930
+ if (dims.length > 0) {
3931
+ arrayDims = dims.map((d) => this.generateArrayDimension(d)).join("");
3932
+ } else if (arrayTypeCtx) {
3933
+ arrayDims = `[${this.generateExpression(arrayTypeCtx.expression())}]`;
3934
+ } else {
3935
+ arrayDims = "";
3936
+ }
4112
3937
  parameters.push({
4113
3938
  name: paramName,
4114
3939
  type: paramType,
@@ -4120,7 +3945,7 @@ export default class CodeGenerator implements IOrchestrator {
4120
3945
  }
4121
3946
  }
4122
3947
 
4123
- this.callbackTypes.set(name, {
3948
+ CodeGenState.callbackTypes.set(name, {
4124
3949
  functionName: name,
4125
3950
  returnType,
4126
3951
  parameters,
@@ -4134,187 +3959,9 @@ export default class CodeGenerator implements IOrchestrator {
4134
3959
  // Issue #63: validateCallbackAssignment, callbackSignaturesMatch, isConstValue,
4135
3960
  // and validateBareIdentifierInScope moved to TypeValidator
4136
3961
 
4137
- /**
4138
- * ADR-016: Check this.State.IDLE pattern (this.Enum.Member inside scope)
4139
- */
4140
- private _getEnumTypeFromThisEnum(parts: string[]): string | null {
4141
- if (parts[0] !== "this" || !this.context.currentScope || parts.length < 3) {
4142
- return null;
4143
- }
4144
- const enumName = parts[1];
4145
- const scopedEnumName = `${this.context.currentScope}_${enumName}`;
4146
- return this.symbols!.knownEnums.has(scopedEnumName) ? scopedEnumName : null;
4147
- }
4148
-
4149
- /**
4150
- * Issue #478: Check global.Enum.Member pattern (global.ECategory.CAT_A)
4151
- */
4152
- private _getEnumTypeFromGlobalEnum(parts: string[]): string | null {
4153
- if (parts[0] !== "global" || parts.length < 3) {
4154
- return null;
4155
- }
4156
- const enumName = parts[1];
4157
- return this.symbols!.knownEnums.has(enumName) ? enumName : null;
4158
- }
4159
-
4160
- /**
4161
- * ADR-016: Check this.variable pattern (this.varName where varName is enum type)
4162
- */
4163
- private _getEnumTypeFromThisVariable(parts: string[]): string | null {
4164
- if (
4165
- parts[0] !== "this" ||
4166
- !this.context.currentScope ||
4167
- parts.length !== 2
4168
- ) {
4169
- return null;
4170
- }
4171
- const varName = parts[1];
4172
- const scopedVarName = `${this.context.currentScope}_${varName}`;
4173
- const typeInfo = this.context.typeRegistry.get(scopedVarName);
4174
- if (typeInfo?.isEnum && typeInfo.enumTypeName) {
4175
- return typeInfo.enumTypeName;
4176
- }
4177
- return null;
4178
- }
4179
-
4180
- /**
4181
- * Check scoped enum: Motor.State.IDLE -> Motor_State
4182
- */
4183
- private _getEnumTypeFromScopedEnum(parts: string[]): string | null {
4184
- if (parts.length < 3) {
4185
- return null;
4186
- }
4187
- const scopeName = parts[0];
4188
- const enumName = parts[1];
4189
- const scopedEnumName = `${scopeName}_${enumName}`;
4190
- return this.symbols!.knownEnums.has(scopedEnumName) ? scopedEnumName : null;
4191
- }
4192
-
4193
- /**
4194
- * Check if parts represent an enum member access and return the enum type.
4195
- */
4196
- private _getEnumTypeFromMemberAccess(parts: string[]): string | null {
4197
- if (parts.length < 2) {
4198
- return null;
4199
- }
4200
-
4201
- // ADR-016: Check this.State.IDLE pattern
4202
- const thisEnumType = this._getEnumTypeFromThisEnum(parts);
4203
- if (thisEnumType) return thisEnumType;
4204
-
4205
- // Issue #478: Check global.Enum.Member pattern
4206
- const globalEnumType = this._getEnumTypeFromGlobalEnum(parts);
4207
- if (globalEnumType) return globalEnumType;
4208
-
4209
- // ADR-016: Check this.variable pattern
4210
- const thisVarType = this._getEnumTypeFromThisVariable(parts);
4211
- if (thisVarType) return thisVarType;
4212
-
4213
- // Check simple enum: State.IDLE
4214
- const possibleEnum = parts[0];
4215
- if (this.symbols!.knownEnums.has(possibleEnum)) {
4216
- return possibleEnum;
4217
- }
4218
-
4219
- // Check scoped enum: Motor.State.IDLE -> Motor_State
4220
- return this._getEnumTypeFromScopedEnum(parts);
4221
- }
4222
-
4223
- /**
4224
- * ADR-017: Extract enum type from an expression.
4225
- * Returns the enum type name if the expression is an enum value, null otherwise.
4226
- *
4227
- * Handles:
4228
- * - Variable of enum type: `currentState` -> 'State'
4229
- * - Enum member access: `State.IDLE` -> 'State'
4230
- * - Scoped enum member: `Motor.State.IDLE` -> 'Motor_State'
4231
- * - ADR-016: this.State.IDLE -> 'CurrentScope_State'
4232
- * - ADR-016: this.variable -> enum type if variable is of enum type
4233
- */
4234
- private _getExpressionEnumType(
4235
- ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
4236
- ): string | null {
4237
- const text = ctx.getText();
4238
-
4239
- // Check if it's a function call returning an enum
4240
- const enumReturnType = this._getFunctionCallEnumType(text);
4241
- if (enumReturnType) {
4242
- return enumReturnType;
4243
- }
4244
-
4245
- // Check if it's a simple identifier that's an enum variable
4246
- if (/^[a-zA-Z_]\w*$/.exec(text)) {
4247
- const typeInfo = this.context.typeRegistry.get(text);
4248
- if (typeInfo?.isEnum && typeInfo.enumTypeName) {
4249
- return typeInfo.enumTypeName;
4250
- }
4251
- }
4252
-
4253
- // Check member access patterns: EnumType.MEMBER, Scope.EnumType.MEMBER, etc.
4254
- return this._getEnumTypeFromMemberAccess(text.split("."));
4255
- }
4256
-
4257
- /**
4258
- * Check if an expression is a function call returning an enum type.
4259
- * Handles patterns:
4260
- * - func() or func(args) - global function
4261
- * - Scope.method() or Scope.method(args) - scope method from outside
4262
- * - this.method() or this.method(args) - scope method from inside
4263
- * - global.func() or global.func(args) - global function from inside scope
4264
- * - global.Scope.method() or global.Scope.method(args) - scope method from inside another scope
4265
- */
4266
- private _getFunctionCallEnumType(text: string): string | null {
4267
- // Check if this looks like a function call (contains parentheses)
4268
- const parenIndex = text.indexOf("(");
4269
- if (parenIndex === -1) {
4270
- return null;
4271
- }
4272
-
4273
- // Extract the function reference (everything before the opening paren)
4274
- const funcRef = text.substring(0, parenIndex);
4275
- const parts = funcRef.split(".");
4276
-
4277
- let fullFuncName: string | null = null;
4278
-
4279
- if (parts.length === 1) {
4280
- // Simple function call: func()
4281
- fullFuncName = parts[0];
4282
- } else if (parts.length === 2) {
4283
- if (parts[0] === "this" && this.context.currentScope) {
4284
- // this.method() -> Scope_method
4285
- fullFuncName = `${this.context.currentScope}_${parts[1]}`;
4286
- } else if (parts[0] === "global") {
4287
- // global.func() -> func
4288
- fullFuncName = parts[1];
4289
- } else if (this.symbols!.knownScopes.has(parts[0])) {
4290
- // Scope.method() -> Scope_method
4291
- fullFuncName = `${parts[0]}_${parts[1]}`;
4292
- }
4293
- } else if (parts.length === 3) {
4294
- if (parts[0] === "global" && this.symbols!.knownScopes.has(parts[1])) {
4295
- // global.Scope.method() -> Scope_method
4296
- fullFuncName = `${parts[1]}_${parts[2]}`;
4297
- }
4298
- }
4299
-
4300
- if (!fullFuncName) {
4301
- return null;
4302
- }
4303
-
4304
- // Look up the function's return type
4305
- const returnType = this.symbols!.functionReturnTypes.get(fullFuncName);
4306
- if (!returnType) {
4307
- return null;
4308
- }
4309
-
4310
- // Check if the return type is an enum
4311
- if (this.symbols!.knownEnums.has(returnType)) {
4312
- return returnType;
4313
- }
4314
-
4315
- return null;
4316
- }
4317
-
3962
+ // EnumTypeResolver now handles: _getEnumTypeFromThisEnum, _getEnumTypeFromGlobalEnum,
3963
+ // _getEnumTypeFromThisVariable, _getEnumTypeFromScopedEnum, _getEnumTypeFromMemberAccess,
3964
+ // _getExpressionEnumType, _getFunctionCallEnumType
4318
3965
  /**
4319
3966
  * ADR-017: Check if an expression represents an integer literal or numeric type.
4320
3967
  * Used to detect comparisons between enums and integers.
@@ -4322,30 +3969,7 @@ export default class CodeGenerator implements IOrchestrator {
4322
3969
  private _isIntegerExpression(
4323
3970
  ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
4324
3971
  ): boolean {
4325
- const text = ctx.getText();
4326
-
4327
- // Check for integer literals
4328
- if (
4329
- /^-?\d+$/.exec(text) ||
4330
- /^0[xX][0-9a-fA-F]+$/.exec(text) ||
4331
- /^0[bB][01]+$/.exec(text)
4332
- ) {
4333
- return true;
4334
- }
4335
-
4336
- // Check if it's a variable of primitive integer type
4337
- if (/^[a-zA-Z_]\w*$/.exec(text)) {
4338
- const typeInfo = this.context.typeRegistry.get(text);
4339
- if (
4340
- typeInfo &&
4341
- !typeInfo.isEnum &&
4342
- TypeCheckUtils.isInteger(typeInfo.baseType)
4343
- ) {
4344
- return true;
4345
- }
4346
- }
4347
-
4348
- return false;
3972
+ return EnumAssignmentValidator.isIntegerExpression(ctx);
4349
3973
  }
4350
3974
 
4351
3975
  /**
@@ -4358,38 +3982,10 @@ export default class CodeGenerator implements IOrchestrator {
4358
3982
  leftCapacity: number;
4359
3983
  rightCapacity: number;
4360
3984
  } | null {
4361
- // Navigate to the additive expression level
4362
- const ternary = ctx.ternaryExpression();
4363
- if (!ternary) return null;
4364
-
4365
- const orExprs = ternary.orExpression();
4366
- if (orExprs.length !== 1) return null;
4367
-
4368
- const or = orExprs[0];
4369
- if (or.andExpression().length !== 1) return null;
4370
-
4371
- const and = or.andExpression()[0];
4372
- if (and.equalityExpression().length !== 1) return null;
4373
-
4374
- const eq = and.equalityExpression()[0];
4375
- if (eq.relationalExpression().length !== 1) return null;
4376
-
4377
- const rel = eq.relationalExpression()[0];
4378
- if (rel.bitwiseOrExpression().length !== 1) return null;
4379
-
4380
- const bor = rel.bitwiseOrExpression()[0];
4381
- if (bor.bitwiseXorExpression().length !== 1) return null;
4382
-
4383
- const bxor = bor.bitwiseXorExpression()[0];
4384
- if (bxor.bitwiseAndExpression().length !== 1) return null;
4385
-
4386
- const band = bxor.bitwiseAndExpression()[0];
4387
- if (band.shiftExpression().length !== 1) return null;
4388
-
4389
- const shift = band.shiftExpression()[0];
4390
- if (shift.additiveExpression().length !== 1) return null;
4391
-
4392
- const add = shift.additiveExpression()[0];
3985
+ // Navigate to the additive expression level using ExpressionUnwrapper
3986
+ // Issue #707: Deduplicated expression tree navigation
3987
+ const add = ExpressionUnwrapper.getAdditiveExpression(ctx);
3988
+ if (!add) return null;
4393
3989
  const multExprs = add.multiplicativeExpression();
4394
3990
 
4395
3991
  // Need exactly 2 operands for simple concatenation
@@ -4460,7 +4056,7 @@ export default class CodeGenerator implements IOrchestrator {
4460
4056
  const sourceName = sourceId.getText();
4461
4057
 
4462
4058
  // Check if source is a string type
4463
- const typeInfo = this.context.typeRegistry.get(sourceName);
4059
+ const typeInfo = CodeGenState.typeRegistry.get(sourceName);
4464
4060
  if (!typeInfo?.isString || typeInfo.stringCapacity === undefined) {
4465
4061
  return null;
4466
4062
  }
@@ -4494,11 +4090,11 @@ export default class CodeGenerator implements IOrchestrator {
4494
4090
  // NOTE: Public isIntegerType and isFloatType moved to IOrchestrator interface (ADR-053 A2)
4495
4091
  // Private versions kept for internal use
4496
4092
  private _isIntegerType(typeName: string): boolean {
4497
- return this.typeResolver!.isIntegerType(typeName);
4093
+ return TypeResolver.isIntegerType(typeName);
4498
4094
  }
4499
4095
 
4500
4096
  private _isFloatType(typeName: string): boolean {
4501
- return this.typeResolver!.isFloatType(typeName);
4097
+ return TypeResolver.isFloatType(typeName);
4502
4098
  }
4503
4099
 
4504
4100
  /**
@@ -4509,7 +4105,7 @@ export default class CodeGenerator implements IOrchestrator {
4509
4105
  sourceType: string,
4510
4106
  targetType: string,
4511
4107
  ): boolean {
4512
- return this.typeResolver!.isNarrowingConversion(sourceType, targetType);
4108
+ return TypeResolver.isNarrowingConversion(sourceType, targetType);
4513
4109
  }
4514
4110
 
4515
4111
  /**
@@ -4517,7 +4113,7 @@ export default class CodeGenerator implements IOrchestrator {
4517
4113
  * Sign change occurs when converting between signed and unsigned types
4518
4114
  */
4519
4115
  private isSignConversion(sourceType: string, targetType: string): boolean {
4520
- return this.typeResolver!.isSignConversion(sourceType, targetType);
4116
+ return TypeResolver.isSignConversion(sourceType, targetType);
4521
4117
  }
4522
4118
 
4523
4119
  /**
@@ -4530,7 +4126,7 @@ export default class CodeGenerator implements IOrchestrator {
4530
4126
  literalText: string,
4531
4127
  targetType: string,
4532
4128
  ): void {
4533
- this.typeResolver!.validateLiteralFitsType(literalText, targetType);
4129
+ TypeResolver.validateLiteralFitsType(literalText, targetType);
4534
4130
  }
4535
4131
 
4536
4132
  /**
@@ -4539,7 +4135,7 @@ export default class CodeGenerator implements IOrchestrator {
4539
4135
  private getUnaryExpressionType(
4540
4136
  ctx: Parser.UnaryExpressionContext,
4541
4137
  ): string | null {
4542
- return this.typeResolver!.getUnaryExpressionType(ctx);
4138
+ return TypeResolver.getUnaryExpressionType(ctx);
4543
4139
  }
4544
4140
 
4545
4141
  /**
@@ -4550,7 +4146,7 @@ export default class CodeGenerator implements IOrchestrator {
4550
4146
  targetType: string,
4551
4147
  sourceType: string | null,
4552
4148
  ): void {
4553
- this.typeResolver!.validateTypeConversion(targetType, sourceType);
4149
+ TypeResolver.validateTypeConversion(targetType, sourceType);
4554
4150
  }
4555
4151
 
4556
4152
  // Issue #63: checkConstAssignment moved to TypeValidator
@@ -4588,7 +4184,7 @@ export default class CodeGenerator implements IOrchestrator {
4588
4184
  ctx: Parser.ExpressionContext,
4589
4185
  targetParamBaseType?: string,
4590
4186
  ): boolean {
4591
- if (!this.cppMode) return false;
4187
+ if (!CodeGenState.cppMode) return false;
4592
4188
  if (!targetParamBaseType) return false;
4593
4189
 
4594
4190
  const postfix = ExpressionUnwrapper.getPostfixExpression(ctx);
@@ -4602,7 +4198,7 @@ export default class CodeGenerator implements IOrchestrator {
4602
4198
  const ops = postfix.postfixOp();
4603
4199
 
4604
4200
  // Case 1: Direct parameter member access (cfg.value)
4605
- const paramInfo = this.context.currentParameters.get(baseId);
4201
+ const paramInfo = CodeGenState.currentParameters.get(baseId);
4606
4202
  if (paramInfo) {
4607
4203
  return this._needsParamMemberConversion(paramInfo, targetParamBaseType);
4608
4204
  }
@@ -4647,7 +4243,7 @@ export default class CodeGenerator implements IOrchestrator {
4647
4243
  baseId: string,
4648
4244
  targetParamBaseType: string,
4649
4245
  ): boolean {
4650
- const typeInfo = this.context.typeRegistry.get(baseId);
4246
+ const typeInfo = CodeGenState.typeRegistry.get(baseId);
4651
4247
  return CppMemberHelper.needsComplexMemberConversion(
4652
4248
  this._toPostfixOps(ops),
4653
4249
  typeInfo,
@@ -4674,8 +4270,8 @@ export default class CodeGenerator implements IOrchestrator {
4674
4270
  const baseId = primary.IDENTIFIER()?.getText();
4675
4271
  if (!baseId) return false;
4676
4272
 
4677
- const typeInfo = this.context.typeRegistry.get(baseId);
4678
- const paramInfo = this.context.currentParameters.get(baseId);
4273
+ const typeInfo = CodeGenState.typeRegistry.get(baseId);
4274
+ const paramInfo = CodeGenState.currentParameters.get(baseId);
4679
4275
 
4680
4276
  return CppMemberHelper.isStringSubscriptPattern(
4681
4277
  hasPostfixOps,
@@ -4728,11 +4324,11 @@ export default class CodeGenerator implements IOrchestrator {
4728
4324
  // 2. Parameter: currentParameters.get(baseId).baseType
4729
4325
  let structType: string | undefined;
4730
4326
 
4731
- const typeInfo = this.context.typeRegistry.get(baseId);
4327
+ const typeInfo = CodeGenState.typeRegistry.get(baseId);
4732
4328
  if (typeInfo) {
4733
4329
  structType = typeInfo.baseType;
4734
4330
  } else {
4735
- const paramInfo = this.context.currentParameters.get(baseId);
4331
+ const paramInfo = CodeGenState.currentParameters.get(baseId);
4736
4332
  if (paramInfo) {
4737
4333
  structType = paramInfo.baseType;
4738
4334
  }
@@ -4784,26 +4380,33 @@ export default class CodeGenerator implements IOrchestrator {
4784
4380
  */
4785
4381
  private _handleIdentifierArg(id: string): string {
4786
4382
  // Parameters are already pointers
4787
- if (this.context.currentParameters.get(id)) {
4383
+ if (CodeGenState.currentParameters.get(id)) {
4788
4384
  return id;
4789
4385
  }
4790
4386
 
4791
4387
  // Local arrays decay to pointers
4792
- if (this.context.localArrays.has(id)) {
4388
+ if (CodeGenState.localArrays.has(id)) {
4389
+ return id;
4390
+ }
4391
+
4392
+ // Global arrays also decay to pointers (check typeRegistry)
4393
+ // But NOT strings - strings need & (they're char arrays but passed by reference)
4394
+ const typeInfo = CodeGenState.typeRegistry.get(id);
4395
+ if (typeInfo?.isArray && !typeInfo.isString) {
4793
4396
  return id;
4794
4397
  }
4795
4398
 
4796
4399
  // Scope member - may need prefixing
4797
- if (this.context.currentScope) {
4798
- const members = this.context.scopeMembers.get(this.context.currentScope);
4400
+ if (CodeGenState.currentScope) {
4401
+ const members = CodeGenState.scopeMembers.get(CodeGenState.currentScope);
4799
4402
  if (members?.has(id)) {
4800
- const scopedName = `${this.context.currentScope}_${id}`;
4801
- return this.cppHelper!.maybeAddressOf(scopedName);
4403
+ const scopedName = `${CodeGenState.currentScope}_${id}`;
4404
+ return CppModeHelper.maybeAddressOf(scopedName);
4802
4405
  }
4803
4406
  }
4804
4407
 
4805
4408
  // Local variable - add & (except in C++ mode)
4806
- return this.cppHelper!.maybeAddressOf(id);
4409
+ return CppModeHelper.maybeAddressOf(id);
4807
4410
  }
4808
4411
 
4809
4412
  /**
@@ -4825,7 +4428,7 @@ export default class CodeGenerator implements IOrchestrator {
4825
4428
 
4826
4429
  // Generate expression with address-of
4827
4430
  const generatedExpr = this.generateExpression(ctx);
4828
- const expr = this.cppHelper!.maybeAddressOf(generatedExpr);
4431
+ const expr = CppModeHelper.maybeAddressOf(generatedExpr);
4829
4432
 
4830
4433
  // String subscript access may need cast
4831
4434
  if (lvalueType === "array") {
@@ -4869,10 +4472,12 @@ export default class CodeGenerator implements IOrchestrator {
4869
4472
  ): string {
4870
4473
  const cType = TYPE_MAP[targetParamBaseType] || "uint8_t";
4871
4474
  const value = this.generateExpression(ctx);
4872
- const tempName = `_cnx_tmp_${this.tempVarCounter++}`;
4873
- const castExpr = this.cppHelper!.cast(cType, value);
4874
- this.pendingTempDeclarations.push(`${cType} ${tempName} = ${castExpr};`);
4875
- return this.cppHelper!.maybeAddressOf(tempName);
4475
+ const tempName = `_cnx_tmp_${CodeGenState.tempVarCounter++}`;
4476
+ const castExpr = CppModeHelper.cast(cType, value);
4477
+ CodeGenState.pendingTempDeclarations.push(
4478
+ `${cType} ${tempName} = ${castExpr};`,
4479
+ );
4480
+ return CppModeHelper.maybeAddressOf(tempName);
4876
4481
  }
4877
4482
 
4878
4483
  /**
@@ -4889,7 +4494,7 @@ export default class CodeGenerator implements IOrchestrator {
4889
4494
 
4890
4495
  const cType = TYPE_MAP[targetParamBaseType];
4891
4496
  if (cType && !["float", "double", "bool", "void"].includes(cType)) {
4892
- return this.cppHelper!.reinterpretCast(`${cType}*`, expr);
4497
+ return CppModeHelper.reinterpretCast(`${cType}*`, expr);
4893
4498
  }
4894
4499
 
4895
4500
  return expr;
@@ -4914,7 +4519,7 @@ export default class CodeGenerator implements IOrchestrator {
4914
4519
  const value = this.generateExpression(ctx);
4915
4520
 
4916
4521
  // C++ mode: rvalues can bind to const T&
4917
- if (this.cppMode) {
4522
+ if (CodeGenState.cppMode) {
4918
4523
  return value;
4919
4524
  }
4920
4525
 
@@ -4937,21 +4542,21 @@ export default class CodeGenerator implements IOrchestrator {
4937
4542
  // Issue #369: Skip struct/enum/bitmap definitions when self-include is added
4938
4543
  // These types will be defined in the included header file
4939
4544
  if (ctx.structDeclaration()) {
4940
- if (this.selfIncludeAdded) {
4545
+ if (CodeGenState.selfIncludeAdded) {
4941
4546
  return ""; // Definition will come from header
4942
4547
  }
4943
4548
  return this.generateStruct(ctx.structDeclaration()!);
4944
4549
  }
4945
4550
  // ADR-017: Handle enum declarations
4946
4551
  if (ctx.enumDeclaration()) {
4947
- if (this.selfIncludeAdded) {
4552
+ if (CodeGenState.selfIncludeAdded) {
4948
4553
  return ""; // Definition will come from header
4949
4554
  }
4950
4555
  return this.generateEnum(ctx.enumDeclaration()!);
4951
4556
  }
4952
4557
  // ADR-034: Handle bitmap declarations
4953
4558
  if (ctx.bitmapDeclaration()) {
4954
- if (this.selfIncludeAdded) {
4559
+ if (CodeGenState.selfIncludeAdded) {
4955
4560
  return ""; // Definition will come from header
4956
4561
  }
4957
4562
  return this.generateBitmap(ctx.bitmapDeclaration()!);
@@ -4980,7 +4585,7 @@ export default class CodeGenerator implements IOrchestrator {
4980
4585
 
4981
4586
  // Fallback to inline implementation (will be removed after migration)
4982
4587
  const name = ctx.IDENTIFIER().getText();
4983
- this.context.currentScope = name;
4588
+ CodeGenState.currentScope = name;
4984
4589
 
4985
4590
  const lines: string[] = [];
4986
4591
  lines.push(`/* Scope: ${name} */`);
@@ -4990,7 +4595,7 @@ export default class CodeGenerator implements IOrchestrator {
4990
4595
  }
4991
4596
 
4992
4597
  lines.push("");
4993
- this.context.currentScope = null;
4598
+ CodeGenState.currentScope = null;
4994
4599
  return lines.join("\n");
4995
4600
  }
4996
4601
 
@@ -5046,10 +4651,18 @@ export default class CodeGenerator implements IOrchestrator {
5046
4651
  const prefix = isPrivate ? "static " : "";
5047
4652
 
5048
4653
  const arrayDims = varDecl.arrayDimension();
5049
- const isArray = arrayDims.length > 0;
4654
+ const hasArrayTypeSyntax = varDecl.type().arrayType() !== null;
4655
+ const isArray = arrayDims.length > 0 || hasArrayTypeSyntax;
5050
4656
 
5051
4657
  let decl = `${prefix}${type} ${fullName}`;
5052
- if (isArray) {
4658
+
4659
+ // Handle arrayType dimension (C-Next style: u8[16] data)
4660
+ if (hasArrayTypeSyntax) {
4661
+ decl += this._getArrayTypeDimension(varDecl.type());
4662
+ }
4663
+
4664
+ // Handle arrayDimension (C-style or additional dimensions)
4665
+ if (arrayDims.length > 0) {
5053
4666
  decl += this.generateArrayDimensions(arrayDims);
5054
4667
  }
5055
4668
 
@@ -5091,9 +4704,9 @@ export default class CodeGenerator implements IOrchestrator {
5091
4704
  const prefix = isPrivate ? "static " : "";
5092
4705
 
5093
4706
  // Issue #269: Set current function name for pass-by-value lookup
5094
- this.context.currentFunctionName = fullName;
4707
+ CodeGenState.currentFunctionName = fullName;
5095
4708
  // Issue #477: Set return type for enum inference in return statements
5096
- this.context.currentFunctionReturnType = funcDecl.type().getText();
4709
+ CodeGenState.currentFunctionReturnType = funcDecl.type().getText();
5097
4710
 
5098
4711
  // Track parameters for ADR-006 pointer semantics
5099
4712
  this._setParameters(funcDecl.parameterList() ?? null);
@@ -5114,8 +4727,8 @@ export default class CodeGenerator implements IOrchestrator {
5114
4727
 
5115
4728
  // ADR-016: Exit function body context
5116
4729
  this.exitFunctionBody();
5117
- this.context.currentFunctionName = null;
5118
- this.context.currentFunctionReturnType = null;
4730
+ CodeGenState.currentFunctionName = null;
4731
+ CodeGenState.currentFunctionReturnType = null;
5119
4732
  this._clearParameters();
5120
4733
 
5121
4734
  lines.push("", `${prefix}${returnType} ${fullName}(${params}) ${body}`);
@@ -5198,155 +4811,14 @@ export default class CodeGenerator implements IOrchestrator {
5198
4811
  // ========================================================================
5199
4812
 
5200
4813
  private generateStruct(ctx: Parser.StructDeclarationContext): string {
5201
- // ADR-053: Check registry for extracted generator
4814
+ // ADR-053: Delegates to extracted StructGenerator
5202
4815
  const generator = this.registry.getDeclaration("struct");
5203
- if (generator) {
5204
- const result = generator(ctx, this.getInput(), this.getState(), this);
5205
- this.applyEffects(result.effects);
5206
- return result.code;
5207
- }
5208
-
5209
- // Fallback to inline implementation (will be removed after migration)
5210
- const name = ctx.IDENTIFIER().getText();
5211
- const callbackFields: Array<{ fieldName: string; callbackType: string }> =
5212
- [];
5213
-
5214
- const lines: string[] = [];
5215
- lines.push(`typedef struct {`);
5216
-
5217
- for (const member of ctx.structMember()) {
5218
- const fieldLine = this.generateStructFieldLine(
5219
- name,
5220
- member,
5221
- callbackFields,
5222
- );
5223
- lines.push(fieldLine);
5224
- }
5225
-
5226
- lines.push(`} ${name};`, "");
5227
-
5228
- // ADR-029: Generate init function if struct has callback fields
5229
- if (callbackFields.length > 0) {
5230
- lines.push(this.generateStructInitFunction(name, callbackFields));
5231
- }
5232
-
5233
- return lines.join("\n");
5234
- }
5235
-
5236
- /**
5237
- * Generate a single struct field line.
5238
- * SonarCloud S3776: Extracted from generateStruct().
5239
- */
5240
- private generateStructFieldLine(
5241
- structName: string,
5242
- member: Parser.StructMemberContext,
5243
- callbackFields: Array<{ fieldName: string; callbackType: string }>,
5244
- ): string {
5245
- const fieldName = member.IDENTIFIER().getText();
5246
- const typeName = this.getTypeName(member.type());
5247
- const arrayDims = member.arrayDimension();
5248
- const isArray = arrayDims.length > 0;
5249
-
5250
- // ADR-029: Check if this is a callback type field
5251
- if (this.callbackTypes.has(typeName)) {
5252
- return this.generateCallbackFieldLine(
5253
- structName,
5254
- fieldName,
5255
- typeName,
5256
- arrayDims,
5257
- isArray,
5258
- callbackFields,
5259
- );
5260
- }
5261
-
5262
- return this.generateRegularFieldLine(
5263
- structName,
5264
- fieldName,
5265
- member,
5266
- arrayDims,
5267
- isArray,
5268
- );
5269
- }
5270
-
5271
- /**
5272
- * Generate a callback type field line.
5273
- * SonarCloud S3776: Extracted from generateStruct().
5274
- */
5275
- private generateCallbackFieldLine(
5276
- structName: string,
5277
- fieldName: string,
5278
- typeName: string,
5279
- arrayDims: Parser.ArrayDimensionContext[],
5280
- isArray: boolean,
5281
- callbackFields: Array<{ fieldName: string; callbackType: string }>,
5282
- ): string {
5283
- const callbackInfo = this.callbackTypes.get(typeName)!;
5284
- callbackFields.push({ fieldName, callbackType: typeName });
5285
-
5286
- // Track callback field for assignment validation
5287
- this.callbackFieldTypes.set(`${structName}.${fieldName}`, typeName);
5288
-
5289
- if (isArray) {
5290
- const dims = this.generateArrayDimensions(arrayDims);
5291
- return ` ${callbackInfo.typedefName} ${fieldName}${dims};`;
5292
- }
5293
- return ` ${callbackInfo.typedefName} ${fieldName};`;
5294
- }
5295
-
5296
- /**
5297
- * Generate a regular (non-callback) field line.
5298
- * SonarCloud S3776: Extracted from generateStruct().
5299
- */
5300
- private generateRegularFieldLine(
5301
- structName: string,
5302
- fieldName: string,
5303
- member: Parser.StructMemberContext,
5304
- arrayDims: Parser.ArrayDimensionContext[],
5305
- isArray: boolean,
5306
- ): string {
5307
- const type = this.generateType(member.type());
5308
-
5309
- // Check if we have tracked dimensions for this field
5310
- const trackedDimensions =
5311
- this.symbols!.structFieldDimensions.get(structName);
5312
- const fieldDims = trackedDimensions?.get(fieldName);
5313
-
5314
- if (fieldDims && fieldDims.length > 0) {
5315
- const dimsStr = fieldDims.map((d) => `[${d}]`).join("");
5316
- return ` ${type} ${fieldName}${dimsStr};`;
5317
- }
5318
-
5319
- if (isArray) {
5320
- const dims = this.generateArrayDimensions(arrayDims);
5321
- return ` ${type} ${fieldName}${dims};`;
5322
- }
5323
-
5324
- return ` ${type} ${fieldName};`;
5325
- }
5326
-
5327
- /**
5328
- * ADR-029: Generate init function for structs with callback fields
5329
- * Sets all callback fields to their default functions
5330
- */
5331
- private generateStructInitFunction(
5332
- structName: string,
5333
- callbackFields: Array<{ fieldName: string; callbackType: string }>,
5334
- ): string {
5335
- const lines: string[] = [];
5336
- lines.push(
5337
- `${structName} ${structName}_init(void) {`,
5338
- ` return (${structName}){`,
5339
- );
5340
-
5341
- for (let i = 0; i < callbackFields.length; i++) {
5342
- const field = callbackFields[i];
5343
- const comma = i < callbackFields.length - 1 ? "," : "";
5344
- lines.push(` .${field.fieldName} = ${field.callbackType}${comma}`);
4816
+ if (!generator) {
4817
+ throw new Error("Error: struct generator not registered");
5345
4818
  }
5346
-
5347
- lines.push(` };`, `}`, "");
5348
-
5349
- return lines.join("\n");
4819
+ const result = generator(ctx, this.getInput(), this.getState(), this);
4820
+ this.applyEffects(result.effects);
4821
+ return result.code;
5350
4822
  }
5351
4823
 
5352
4824
  // ========================================================================
@@ -5358,44 +4830,16 @@ export default class CodeGenerator implements IOrchestrator {
5358
4830
  * enum State { IDLE, RUNNING, ERROR <- 255 }
5359
4831
  * -> typedef enum { State_IDLE = 0, State_RUNNING = 1, State_ERROR = 255 } State;
5360
4832
  *
5361
- * ADR-053: Delegates to extracted generator if registered.
4833
+ * ADR-053: Delegates to extracted EnumGenerator.
5362
4834
  */
5363
4835
  private generateEnum(ctx: Parser.EnumDeclarationContext): string {
5364
- // ADR-053: Check registry for extracted generator
5365
4836
  const generator = this.registry.getDeclaration("enum");
5366
- if (generator) {
5367
- const result = generator(ctx, this.getInput(), this.getState(), this);
5368
- this.applyEffects(result.effects);
5369
- return result.code;
5370
- }
5371
-
5372
- // Fallback to inline implementation (will be removed after migration)
5373
- const name = ctx.IDENTIFIER().getText();
5374
- const prefix = this.context.currentScope
5375
- ? `${this.context.currentScope}_`
5376
- : "";
5377
- const fullName = `${prefix}${name}`;
5378
-
5379
- const lines: string[] = [];
5380
- lines.push(`typedef enum {`);
5381
-
5382
- const members = this.symbols!.enumMembers.get(fullName);
5383
- if (!members) {
5384
- throw new Error(`Error: Enum ${fullName} not found in registry`);
5385
- }
5386
-
5387
- const memberEntries = Array.from(members.entries());
5388
-
5389
- for (let i = 0; i < memberEntries.length; i++) {
5390
- const [memberName, value] = memberEntries[i];
5391
- const fullMemberName = `${fullName}_${memberName}`;
5392
- const comma = i < memberEntries.length - 1 ? "," : "";
5393
- lines.push(` ${fullMemberName} = ${value}${comma}`);
4837
+ if (!generator) {
4838
+ throw new Error("Error: enum generator not registered");
5394
4839
  }
5395
-
5396
- lines.push(`} ${fullName};`, "");
5397
-
5398
- return lines.join("\n");
4840
+ const result = generator(ctx, this.getInput(), this.getState(), this);
4841
+ this.applyEffects(result.effects);
4842
+ return result.code;
5399
4843
  }
5400
4844
 
5401
4845
  /**
@@ -5416,12 +4860,12 @@ export default class CodeGenerator implements IOrchestrator {
5416
4860
 
5417
4861
  // Fallback to inline implementation (will be removed after migration)
5418
4862
  const name = ctx.IDENTIFIER().getText();
5419
- const prefix = this.context.currentScope
5420
- ? `${this.context.currentScope}_`
4863
+ const prefix = CodeGenState.currentScope
4864
+ ? `${CodeGenState.currentScope}_`
5421
4865
  : "";
5422
4866
  const fullName = `${prefix}${name}`;
5423
4867
 
5424
- const backingType = this.symbols!.bitmapBackingType.get(fullName);
4868
+ const backingType = CodeGenState.symbols!.bitmapBackingType.get(fullName);
5425
4869
  if (!backingType) {
5426
4870
  throw new Error(`Error: Bitmap ${fullName} not found in registry`);
5427
4871
  }
@@ -5433,7 +4877,7 @@ export default class CodeGenerator implements IOrchestrator {
5433
4877
  // Generate comment with field layout
5434
4878
  lines.push(`/* Bitmap: ${fullName} */`);
5435
4879
 
5436
- const fields = this.symbols!.bitmapFields.get(fullName);
4880
+ const fields = CodeGenState.symbols!.bitmapFields.get(fullName);
5437
4881
  if (fields) {
5438
4882
  lines.push("/* Fields:");
5439
4883
  for (const [fieldName, info] of fields.entries()) {
@@ -5467,7 +4911,7 @@ export default class CodeGenerator implements IOrchestrator {
5467
4911
  // Reject redundant type in struct initializer
5468
4912
  // Wrong: const Point p <- Point { x: 0 };
5469
4913
  // Right: const Point p <- { x: 0 };
5470
- if (ctx.IDENTIFIER() && this.context.expectedType) {
4914
+ if (ctx.IDENTIFIER() && CodeGenState.expectedType) {
5471
4915
  const explicitType = ctx.IDENTIFIER()!.getText();
5472
4916
  throw new Error(
5473
4917
  `Redundant type '${explicitType}' in struct initializer. ` +
@@ -5479,8 +4923,8 @@ export default class CodeGenerator implements IOrchestrator {
5479
4923
  let typeName: string;
5480
4924
  if (ctx.IDENTIFIER()) {
5481
4925
  typeName = ctx.IDENTIFIER()!.getText();
5482
- } else if (this.context.expectedType) {
5483
- typeName = this.context.expectedType;
4926
+ } else if (CodeGenState.expectedType) {
4927
+ typeName = CodeGenState.expectedType;
5484
4928
  } else {
5485
4929
  // This should not happen in valid code
5486
4930
  throw new Error(
@@ -5495,7 +4939,7 @@ export default class CodeGenerator implements IOrchestrator {
5495
4939
  // so designated initializers { .field = value } don't work with them.
5496
4940
  // We check the SymbolTable for a constructor symbol (TypeName::TypeName).
5497
4941
  const isCppClass =
5498
- this.cppMode && this._isCppClassWithConstructor(typeName);
4942
+ CodeGenState.cppMode && this._isCppClassWithConstructor(typeName);
5499
4943
 
5500
4944
  if (!fieldList) {
5501
4945
  // Empty initializer: Point {} -> (Point){ 0 } or {} for C++ classes
@@ -5504,13 +4948,13 @@ export default class CodeGenerator implements IOrchestrator {
5504
4948
 
5505
4949
  // Get field type info for nested initializers
5506
4950
  // Issue #502: Check both local struct fields and SymbolTable (for C++ header structs)
5507
- const structFieldTypes = this.symbols!.structFields.get(typeName);
4951
+ const structFieldTypes = CodeGenState.symbols!.structFields.get(typeName);
5508
4952
 
5509
4953
  const fields = fieldList.fieldInitializer().map((field) => {
5510
4954
  const fieldName = field.IDENTIFIER().getText();
5511
4955
 
5512
4956
  // Set expected type for nested initializers
5513
- const savedExpectedType = this.context.expectedType;
4957
+ const savedExpectedType = CodeGenState.expectedType;
5514
4958
  if (structFieldTypes?.has(fieldName)) {
5515
4959
  // Issue #502: Convert underscore format to correct output format
5516
4960
  // C-Next struct fields may store C++ types with _ separator (e.g., SeaDash_Parse_ParseResult)
@@ -5524,13 +4968,13 @@ export default class CodeGenerator implements IOrchestrator {
5524
4968
  fieldType = parts.join("::");
5525
4969
  }
5526
4970
  }
5527
- this.context.expectedType = fieldType;
4971
+ CodeGenState.expectedType = fieldType;
5528
4972
  }
5529
4973
 
5530
4974
  const value = this.generateExpression(field.expression());
5531
4975
 
5532
4976
  // Restore expected type
5533
- this.context.expectedType = savedExpectedType;
4977
+ CodeGenState.expectedType = savedExpectedType;
5534
4978
 
5535
4979
  return { fieldName, value };
5536
4980
  });
@@ -5538,7 +4982,9 @@ export default class CodeGenerator implements IOrchestrator {
5538
4982
  // Issue #517: For C++ classes, store assignments for later and return {}
5539
4983
  if (isCppClass) {
5540
4984
  for (const { fieldName, value } of fields) {
5541
- this.pendingCppClassAssignments.push(`${fieldName} = ${value};`);
4985
+ CodeGenState.pendingCppClassAssignments.push(
4986
+ `${fieldName} = ${value};`,
4987
+ );
5542
4988
  }
5543
4989
  return "{}";
5544
4990
  }
@@ -5562,8 +5008,8 @@ export default class CodeGenerator implements IOrchestrator {
5562
5008
  // Fill-all: [0*] -> {0}
5563
5009
  const fillValue = this.generateExpression(ctx.expression()!);
5564
5010
  // Store element count as 0 to signal fill-all (size comes from declaration)
5565
- this.context.lastArrayInitCount = 0;
5566
- this.context.lastArrayFillValue = fillValue;
5011
+ CodeGenState.lastArrayInitCount = 0;
5012
+ CodeGenState.lastArrayFillValue = fillValue;
5567
5013
  return `{${fillValue}}`;
5568
5014
  }
5569
5015
 
@@ -5587,8 +5033,8 @@ export default class CodeGenerator implements IOrchestrator {
5587
5033
  }
5588
5034
 
5589
5035
  // Store element count for size inference
5590
- this.context.lastArrayInitCount = generatedElements.length;
5591
- this.context.lastArrayFillValue = undefined;
5036
+ CodeGenState.lastArrayInitCount = generatedElements.length;
5037
+ CodeGenState.lastArrayFillValue = undefined;
5592
5038
 
5593
5039
  return `{${generatedElements.join(", ")}}`;
5594
5040
  }
@@ -5656,21 +5102,21 @@ export default class CodeGenerator implements IOrchestrator {
5656
5102
  ctx: Parser.FunctionDeclarationContext,
5657
5103
  ): void {
5658
5104
  // Issue #269: Set current function name for pass-by-value lookup
5659
- const fullFuncName = this.context.currentScope
5660
- ? `${this.context.currentScope}_${name}`
5105
+ const fullFuncName = CodeGenState.currentScope
5106
+ ? `${CodeGenState.currentScope}_${name}`
5661
5107
  : name;
5662
- this.context.currentFunctionName = fullFuncName;
5108
+ CodeGenState.currentFunctionName = fullFuncName;
5663
5109
  // Issue #477: Set return type for enum inference in return statements
5664
- this.context.currentFunctionReturnType = ctx.type().getText();
5110
+ CodeGenState.currentFunctionReturnType = ctx.type().getText();
5665
5111
 
5666
5112
  // Track parameters for ADR-006 pointer semantics
5667
5113
  this._setParameters(ctx.parameterList() ?? null);
5668
5114
 
5669
5115
  // ADR-016: Clear local variables and mark that we're in a function body
5670
- this.context.localVariables.clear();
5671
- this.context.floatBitShadows.clear();
5672
- this.context.floatShadowCurrent.clear();
5673
- this.context.inFunctionBody = true;
5116
+ CodeGenState.localVariables.clear();
5117
+ CodeGenState.floatBitShadows.clear();
5118
+ CodeGenState.floatShadowCurrent.clear();
5119
+ CodeGenState.inFunctionBody = true;
5674
5120
  }
5675
5121
 
5676
5122
  /**
@@ -5685,7 +5131,7 @@ export default class CodeGenerator implements IOrchestrator {
5685
5131
  if (isMainWithArgs) {
5686
5132
  // Special case: main(u8 args[][]) -> int main(int argc, char *argv[])
5687
5133
  const argsParam = ctx.parameterList()!.parameter()[0];
5688
- this.context.mainArgsName = argsParam.IDENTIFIER().getText();
5134
+ CodeGenState.mainArgsName = argsParam.IDENTIFIER().getText();
5689
5135
  return {
5690
5136
  actualReturnType: "int",
5691
5137
  initialParams: "int argc, char *argv[]",
@@ -5701,13 +5147,13 @@ export default class CodeGenerator implements IOrchestrator {
5701
5147
  * Clean up context after function generation
5702
5148
  */
5703
5149
  private _cleanupFunctionContext(): void {
5704
- this.context.inFunctionBody = false;
5705
- this.context.localVariables.clear();
5706
- this.context.floatBitShadows.clear();
5707
- this.context.floatShadowCurrent.clear();
5708
- this.context.mainArgsName = null;
5709
- this.context.currentFunctionName = null;
5710
- this.context.currentFunctionReturnType = null;
5150
+ CodeGenState.inFunctionBody = false;
5151
+ CodeGenState.localVariables.clear();
5152
+ CodeGenState.floatBitShadows.clear();
5153
+ CodeGenState.floatShadowCurrent.clear();
5154
+ CodeGenState.mainArgsName = null;
5155
+ CodeGenState.currentFunctionName = null;
5156
+ CodeGenState.currentFunctionReturnType = null;
5711
5157
  this._clearParameters();
5712
5158
  }
5713
5159
 
@@ -5737,13 +5183,22 @@ export default class CodeGenerator implements IOrchestrator {
5737
5183
  const dims = ctx.arrayDimension();
5738
5184
 
5739
5185
  // ADR-029: Check if this is a callback type parameter
5740
- if (this.callbackTypes.has(typeName)) {
5741
- const callbackInfo = this.callbackTypes.get(typeName)!;
5186
+ if (CodeGenState.callbackTypes.has(typeName)) {
5187
+ const callbackInfo = CodeGenState.callbackTypes.get(typeName)!;
5742
5188
  return `${callbackInfo.typedefName} ${name}`;
5743
5189
  }
5744
5190
 
5745
5191
  const type = this.generateType(ctx.type());
5746
5192
 
5193
+ // Handle C-Next style array type in parameter (e.g., u8[8] param)
5194
+ const arrayTypeCtx = ctx.type().arrayType();
5195
+ if (arrayTypeCtx) {
5196
+ const dimExpr = this.generateExpression(arrayTypeCtx.expression());
5197
+ const wasModified = this._isCurrentParameterModified(name);
5198
+ const autoConst = !wasModified && !constMod ? "const " : "";
5199
+ return `${autoConst}${constMod}${type} ${name}[${dimExpr}]`;
5200
+ }
5201
+
5747
5202
  // Try special cases first
5748
5203
  const stringArrayResult = this._tryGenerateStringArrayParam(
5749
5204
  ctx,
@@ -5825,12 +5280,12 @@ export default class CodeGenerator implements IOrchestrator {
5825
5280
  // ISR, float, enum types
5826
5281
  if (typeName === "ISR") return true;
5827
5282
  if (this._isFloatType(typeName)) return true;
5828
- if (this.symbols!.knownEnums.has(typeName)) return true;
5283
+ if (CodeGenState.symbols!.knownEnums.has(typeName)) return true;
5829
5284
 
5830
5285
  // Small unmodified primitives
5831
5286
  if (
5832
- this.context.currentFunctionName &&
5833
- this._isParameterPassByValueByName(this.context.currentFunctionName, name)
5287
+ CodeGenState.currentFunctionName &&
5288
+ this._isParameterPassByValueByName(CodeGenState.currentFunctionName, name)
5834
5289
  ) {
5835
5290
  return true;
5836
5291
  }
@@ -5871,7 +5326,7 @@ export default class CodeGenerator implements IOrchestrator {
5871
5326
 
5872
5327
  const wasModified = this._isCurrentParameterModified(name);
5873
5328
  const autoConst = !wasModified && !constMod ? "const " : "";
5874
- const refOrPtr = this.cppHelper!.refOrPtr();
5329
+ const refOrPtr = CppModeHelper.refOrPtr();
5875
5330
  return `${autoConst}${constMod}${type}${refOrPtr} ${name}`;
5876
5331
  }
5877
5332
 
@@ -5889,24 +5344,39 @@ export default class CodeGenerator implements IOrchestrator {
5889
5344
  // Issue #696: Use helper for modifier extraction and validation
5890
5345
  const modifiers = VariableModifierBuilder.build(
5891
5346
  ctx,
5892
- this.context.inFunctionBody,
5347
+ CodeGenState.inFunctionBody,
5893
5348
  );
5894
5349
 
5895
5350
  const name = ctx.IDENTIFIER().getText();
5896
5351
  const typeCtx = ctx.type();
5352
+
5353
+ // Reject C-style array declarations (u16 arr[8]) - require C-Next style (u16[8] arr)
5354
+ this._validateArrayDeclarationSyntax(ctx, typeCtx, name);
5355
+
5897
5356
  const type = this._inferVariableType(ctx, name);
5898
5357
 
5899
5358
  // Track local variable metadata
5900
5359
  this._trackLocalVariable(ctx, name);
5901
5360
 
5902
5361
  // ADR-045: Handle bounded string type specially - early return
5903
- const stringResult = this.stringDeclHelper!.generateStringDecl(
5362
+ const stringResult = StringDeclHelper.generateStringDecl(
5904
5363
  typeCtx,
5905
5364
  name,
5906
5365
  ctx.expression() ?? null,
5907
5366
  ctx.arrayDimension(),
5908
5367
  modifiers,
5909
5368
  ctx.constModifier() !== null,
5369
+ {
5370
+ generateExpression: (exprCtx) => this.generateExpression(exprCtx),
5371
+ generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
5372
+ getStringConcatOperands: (concatCtx) =>
5373
+ this._getStringConcatOperands(concatCtx),
5374
+ getSubstringOperands: (substrCtx) =>
5375
+ this._getSubstringOperands(substrCtx),
5376
+ getStringExprCapacity: (exprCode) =>
5377
+ this.getStringExprCapacity(exprCode),
5378
+ requireStringInclude: () => this.requireInclude("string"),
5379
+ },
5910
5380
  );
5911
5381
  if (stringResult.handled) {
5912
5382
  return stringResult.code;
@@ -5965,24 +5435,25 @@ export default class CodeGenerator implements IOrchestrator {
5965
5435
  ctx: Parser.VariableDeclarationContext,
5966
5436
  name: string,
5967
5437
  ): void {
5968
- if (!this.context.inFunctionBody) {
5438
+ if (!CodeGenState.inFunctionBody) {
5969
5439
  return;
5970
5440
  }
5971
5441
 
5972
5442
  this.trackVariableType(ctx);
5973
- this.context.localVariables.add(name);
5443
+ CodeGenState.localVariables.add(name);
5974
5444
 
5975
5445
  // Bug #8: Track local const values for array size and bit index resolution
5976
5446
  if (ctx.constModifier() && ctx.expression()) {
5977
5447
  const constValue = this.tryEvaluateConstant(ctx.expression()!);
5978
5448
  if (constValue !== undefined) {
5979
- this.constValues.set(name, constValue);
5449
+ CodeGenState.constValues.set(name, constValue);
5980
5450
  }
5981
5451
  }
5982
5452
  }
5983
5453
 
5984
5454
  /**
5985
5455
  * Issue #696: Handle array declaration with dimension parsing and init.
5456
+ * Bug fix: Also handles C-Next style arrayType syntax (u16[8] myArray).
5986
5457
  */
5987
5458
  private _handleArrayDeclaration(
5988
5459
  ctx: Parser.VariableDeclarationContext,
@@ -5991,42 +5462,97 @@ export default class CodeGenerator implements IOrchestrator {
5991
5462
  decl: string,
5992
5463
  ): { handled: boolean; code: string; decl: string; isArray: boolean } {
5993
5464
  const arrayDims = ctx.arrayDimension();
5994
- const isArray = arrayDims.length > 0;
5465
+ const hasArrayTypeSyntax = typeCtx.arrayType() !== null;
5466
+ const isArray = arrayDims.length > 0 || hasArrayTypeSyntax;
5995
5467
 
5996
5468
  if (!isArray) {
5997
5469
  return { handled: false, code: "", decl, isArray: false };
5998
5470
  }
5999
5471
 
5472
+ // Generate dimension string from arrayType syntax (u16[8] myArray)
5473
+ const arrayTypeDimStr = this._getArrayTypeDimension(typeCtx);
5474
+
6000
5475
  const hasEmptyArrayDim = arrayDims.some((dim) => !dim.expression());
6001
- const declaredSize = this._parseFirstArrayDimension(arrayDims);
5476
+ const declaredSize =
5477
+ this._parseArrayTypeDimension(typeCtx) ??
5478
+ this._parseFirstArrayDimension(arrayDims);
6002
5479
 
6003
5480
  // ADR-035: Handle array initializers with size inference
6004
5481
  if (ctx.expression()) {
6005
- const arrayInitResult = this.arrayInitHelper!.processArrayInit(
5482
+ const arrayInitResult = ArrayInitHelper.processArrayInit(
6006
5483
  name,
6007
5484
  typeCtx,
6008
5485
  ctx.expression()!,
6009
5486
  arrayDims,
6010
5487
  hasEmptyArrayDim,
6011
5488
  declaredSize,
5489
+ {
5490
+ generateExpression: (exprCtx) => this.generateExpression(exprCtx),
5491
+ getTypeName: (typeCtxParam) => this.getTypeName(typeCtxParam),
5492
+ generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
5493
+ },
6012
5494
  );
6013
5495
  if (arrayInitResult) {
5496
+ // Track as local array for type resolution
5497
+ CodeGenState.localArrays.add(name);
5498
+ // Include arrayType dimension before arrayDimension dimensions
5499
+ const fullDimSuffix = arrayTypeDimStr + arrayInitResult.dimensionSuffix;
6014
5500
  return {
6015
5501
  handled: true,
6016
- code: `${decl}${arrayInitResult.dimensionSuffix} = ${arrayInitResult.initValue};`,
5502
+ code: `${decl}${fullDimSuffix} = ${arrayInitResult.initValue};`,
6017
5503
  decl,
6018
5504
  isArray: true,
6019
5505
  };
6020
5506
  }
6021
5507
  }
6022
5508
 
6023
- // Generate dimensions and track as local array
6024
- const newDecl = decl + this.generateArrayDimensions(arrayDims);
6025
- this.context.localArrays.add(name);
5509
+ // Generate dimensions: arrayType dimension first, then arrayDimension dimensions
5510
+ const newDecl =
5511
+ decl + arrayTypeDimStr + this.generateArrayDimensions(arrayDims);
5512
+ CodeGenState.localArrays.add(name);
6026
5513
 
6027
5514
  return { handled: false, code: "", decl: newDecl, isArray: true };
6028
5515
  }
6029
5516
 
5517
+ /**
5518
+ * Get array dimension string from arrayType syntax (u16[8] -> "[8]").
5519
+ * Evaluates const expressions to their numeric values for C compatibility.
5520
+ */
5521
+ private _getArrayTypeDimension(typeCtx: Parser.TypeContext): string {
5522
+ if (!typeCtx.arrayType()) {
5523
+ return "";
5524
+ }
5525
+ const sizeExpr = typeCtx.arrayType()!.expression();
5526
+ if (!sizeExpr) {
5527
+ return "[]";
5528
+ }
5529
+ // Try to evaluate as constant first (required for C file-scope arrays)
5530
+ const constValue = this.tryEvaluateConstant(sizeExpr);
5531
+ if (constValue !== undefined) {
5532
+ return `[${constValue}]`;
5533
+ }
5534
+ // Fall back to expression text (for macros, enums, etc.)
5535
+ return `[${this.generateExpression(sizeExpr)}]`;
5536
+ }
5537
+
5538
+ /**
5539
+ * Parse array dimension from arrayType syntax for size validation.
5540
+ */
5541
+ private _parseArrayTypeDimension(typeCtx: Parser.TypeContext): number | null {
5542
+ if (!typeCtx.arrayType()) {
5543
+ return null;
5544
+ }
5545
+ const sizeExpr = typeCtx.arrayType()!.expression();
5546
+ if (!sizeExpr) {
5547
+ return null;
5548
+ }
5549
+ const sizeText = sizeExpr.getText();
5550
+ if (/^\d+$/.exec(sizeText)) {
5551
+ return Number.parseInt(sizeText, 10);
5552
+ }
5553
+ return null;
5554
+ }
5555
+
6030
5556
  /**
6031
5557
  * Issue #696: Parse first array dimension for validation.
6032
5558
  */
@@ -6043,6 +5569,95 @@ export default class CodeGenerator implements IOrchestrator {
6043
5569
  return null;
6044
5570
  }
6045
5571
 
5572
+ /**
5573
+ * Validate array declaration syntax - reject C-style, require C-Next style.
5574
+ * C-style: u16 arr[8] (all dimensions after identifier) - REJECTED
5575
+ * C-Next style: u16[8] arr (first dimension in type) - REQUIRED
5576
+ * Multi-dim C-Next: u16[4] arr[2] (first in type, rest after) - ALLOWED
5577
+ * Exceptions (grammar limitations):
5578
+ * - Empty dimensions for size inference: u8 arr[] <- [...]
5579
+ * - Qualified types: SeaDash.Parse.Result arr[3] (no arrayType support)
5580
+ * - Scoped/global types: this.Type arr[3], global.Type arr[3]
5581
+ * - String types: string<N> arr[3]
5582
+ */
5583
+ private _validateArrayDeclarationSyntax(
5584
+ ctx: Parser.VariableDeclarationContext,
5585
+ typeCtx: Parser.TypeContext,
5586
+ name: string,
5587
+ ): void {
5588
+ const arrayDims = ctx.arrayDimension();
5589
+ if (arrayDims.length === 0) {
5590
+ return; // Not an array declaration
5591
+ }
5592
+
5593
+ // If type already has arrayType, additional dimensions are allowed (multi-dim)
5594
+ if (typeCtx.arrayType()) {
5595
+ return; // Valid C-Next style: u16[4] arr[2] → uint16_t arr[4][2]
5596
+ }
5597
+
5598
+ // Allow empty first dimension for size inference: u8 arr[] <- [1, 2, 3]
5599
+ // The grammar doesn't support u8[] arr syntax, so this is the only way
5600
+ if (arrayDims.length === 1 && !arrayDims[0].expression()) {
5601
+ return; // Size inference pattern allowed
5602
+ }
5603
+
5604
+ // Allow C-style for multi-dimensional arrays: u8 matrix[4][4]
5605
+ // The arrayType grammar only supports single dimension, so multi-dim needs C-style
5606
+ if (arrayDims.length > 1) {
5607
+ return; // Multi-dimensional arrays need C-style
5608
+ }
5609
+
5610
+ // Allow C-style for types that don't support arrayType syntax:
5611
+ // - Qualified types (Scope.Type, Namespace::Type)
5612
+ // - Scoped types (this.Type)
5613
+ // - Global types (global.Type)
5614
+ // - String types (string<N>)
5615
+ // - Bitmap types (code generator doesn't yet handle arrayType for bitmaps)
5616
+ if (
5617
+ typeCtx.qualifiedType() ||
5618
+ typeCtx.scopedType() ||
5619
+ typeCtx.globalType() ||
5620
+ typeCtx.stringType()
5621
+ ) {
5622
+ return; // Grammar limitation - these can't use arrayType
5623
+ }
5624
+
5625
+ // C-style array declaration detected - reject with helpful error
5626
+ const baseType = this._extractBaseTypeName(typeCtx);
5627
+ const dimensions = arrayDims
5628
+ .map((dim) => `[${dim.expression()?.getText() ?? ""}]`)
5629
+ .join("");
5630
+ const line = ctx.start?.line ?? 0;
5631
+ const col = ctx.start?.column ?? 0;
5632
+
5633
+ throw new Error(
5634
+ `${line}:${col} C-style array declaration is not allowed. ` +
5635
+ `Use '${baseType}${dimensions} ${name}' instead of '${baseType} ${name}${dimensions}'`,
5636
+ );
5637
+ }
5638
+
5639
+ /**
5640
+ * Extract base type name from type context for error messages.
5641
+ */
5642
+ private _extractBaseTypeName(typeCtx: Parser.TypeContext): string {
5643
+ if (typeCtx.primitiveType()) {
5644
+ return typeCtx.primitiveType()!.getText();
5645
+ }
5646
+ if (typeCtx.userType()) {
5647
+ return typeCtx.userType()!.getText();
5648
+ }
5649
+ if (typeCtx.arrayType()) {
5650
+ const arrCtx = typeCtx.arrayType()!;
5651
+ if (arrCtx.primitiveType()) {
5652
+ return arrCtx.primitiveType()!.getText();
5653
+ }
5654
+ if (arrCtx.userType()) {
5655
+ return arrCtx.userType()!.getText();
5656
+ }
5657
+ }
5658
+ return typeCtx.getText();
5659
+ }
5660
+
6046
5661
  /**
6047
5662
  * Issue #696: Generate variable initializer with validation.
6048
5663
  */
@@ -6058,17 +5673,17 @@ export default class CodeGenerator implements IOrchestrator {
6058
5673
  }
6059
5674
 
6060
5675
  const typeName = this.getTypeName(typeCtx);
6061
- const savedExpectedType = this.context.expectedType;
6062
- this.context.expectedType = typeName;
5676
+ const savedExpectedType = CodeGenState.expectedType;
5677
+ CodeGenState.expectedType = typeName;
6063
5678
 
6064
5679
  // ADR-017: Validate enum type for initialization
6065
- this.enumValidator!.validateEnumAssignment(typeName, ctx.expression()!);
5680
+ EnumAssignmentValidator.validateEnumAssignment(typeName, ctx.expression()!);
6066
5681
 
6067
5682
  // ADR-024: Validate integer literals and type conversions
6068
5683
  this._validateIntegerInitializer(ctx, typeName);
6069
5684
 
6070
5685
  const result = `${decl} = ${this.generateExpression(ctx.expression()!)}`;
6071
- this.context.expectedType = savedExpectedType;
5686
+ CodeGenState.expectedType = savedExpectedType;
6072
5687
 
6073
5688
  return result;
6074
5689
  }
@@ -6116,20 +5731,20 @@ export default class CodeGenerator implements IOrchestrator {
6116
5731
  name: string,
6117
5732
  decl: string,
6118
5733
  ): string {
6119
- if (this.pendingCppClassAssignments.length === 0) {
5734
+ if (CodeGenState.pendingCppClassAssignments.length === 0) {
6120
5735
  return `${decl};`;
6121
5736
  }
6122
5737
 
6123
- if (this.context.inFunctionBody) {
6124
- const assignments = this.pendingCppClassAssignments
5738
+ if (CodeGenState.inFunctionBody) {
5739
+ const assignments = CodeGenState.pendingCppClassAssignments
6125
5740
  .map((a) => `${name}.${a}`)
6126
5741
  .join("\n");
6127
- this.pendingCppClassAssignments = [];
5742
+ CodeGenState.pendingCppClassAssignments = [];
6128
5743
  return `${decl};\n${assignments}`;
6129
5744
  }
6130
5745
 
6131
5746
  // At global scope, we can't emit assignment statements.
6132
- this.pendingCppClassAssignments = [];
5747
+ CodeGenState.pendingCppClassAssignments = [];
6133
5748
  throw new Error(
6134
5749
  `Error: C++ class '${this.getTypeName(typeCtx)}' with constructor cannot use struct initializer ` +
6135
5750
  `syntax at global scope. Use constructor syntax or initialize fields separately.`,
@@ -6157,14 +5772,14 @@ export default class CodeGenerator implements IOrchestrator {
6157
5772
  const argName = argNode.getText();
6158
5773
 
6159
5774
  // Check if it exists in type registry
6160
- const typeInfo = this.context.typeRegistry.get(argName);
5775
+ const typeInfo = CodeGenState.typeRegistry.get(argName);
6161
5776
 
6162
5777
  // Also check scoped variables if inside a scope
6163
5778
  let scopedArgName = argName;
6164
5779
  let scopedTypeInfo = typeInfo;
6165
- if (!typeInfo && this.context.currentScope) {
6166
- scopedArgName = `${this.context.currentScope}_${argName}`;
6167
- scopedTypeInfo = this.context.typeRegistry.get(scopedArgName);
5780
+ if (!typeInfo && CodeGenState.currentScope) {
5781
+ scopedArgName = `${CodeGenState.currentScope}_${argName}`;
5782
+ scopedTypeInfo = CodeGenState.typeRegistry.get(scopedArgName);
6168
5783
  }
6169
5784
 
6170
5785
  if (!typeInfo && !scopedTypeInfo) {
@@ -6188,7 +5803,7 @@ export default class CodeGenerator implements IOrchestrator {
6188
5803
  }
6189
5804
 
6190
5805
  // Track the variable in type registry (as an external C++ type)
6191
- this.context.typeRegistry.set(name, {
5806
+ CodeGenState.typeRegistry.set(name, {
6192
5807
  baseType: type,
6193
5808
  bitWidth: 0, // Unknown for C++ types
6194
5809
  isArray: false,
@@ -6198,8 +5813,8 @@ export default class CodeGenerator implements IOrchestrator {
6198
5813
  });
6199
5814
 
6200
5815
  // Track as local variable if inside function body
6201
- if (this.context.inFunctionBody) {
6202
- this.context.localVariables.add(name);
5816
+ if (CodeGenState.inFunctionBody) {
5817
+ CodeGenState.localVariables.add(name);
6203
5818
  }
6204
5819
 
6205
5820
  return `${type} ${name}(${resolvedArgs.join(", ")});`;
@@ -6217,6 +5832,14 @@ export default class CodeGenerator implements IOrchestrator {
6217
5832
  return "{}";
6218
5833
  }
6219
5834
  }
5835
+ // Also check C-Next style array type (e.g., CppClass[4]) where
5836
+ // the userType is nested inside arrayType.
5837
+ if (typeCtx.arrayType()?.userType()) {
5838
+ const typeName = typeCtx.arrayType()!.userType()!.getText();
5839
+ if (this._needsEmptyBraceInit(typeName)) {
5840
+ return "{}";
5841
+ }
5842
+ }
6220
5843
  // Template types are always C++ classes
6221
5844
  if (typeCtx.templateType()) {
6222
5845
  return "{}";
@@ -6231,7 +5854,7 @@ export default class CodeGenerator implements IOrchestrator {
6231
5854
  * ADR-017: Enums initialize to first member
6232
5855
  */
6233
5856
  private _getEnumZeroValue(enumName: string, separator: string = "_"): string {
6234
- const members = this.symbols!.enumMembers.get(enumName);
5857
+ const members = CodeGenState.symbols!.enumMembers.get(enumName);
6235
5858
  if (!members) {
6236
5859
  return `(${enumName})0`;
6237
5860
  }
@@ -6264,8 +5887,8 @@ export default class CodeGenerator implements IOrchestrator {
6264
5887
  // ADR-016: Check for scoped types (this.Type)
6265
5888
  if (typeCtx.scopedType()) {
6266
5889
  const localName = typeCtx.scopedType()!.IDENTIFIER().getText();
6267
- const name = this.context.currentScope
6268
- ? `${this.context.currentScope}_${localName}`
5890
+ const name = CodeGenState.currentScope
5891
+ ? `${CodeGenState.currentScope}_${localName}`
6269
5892
  : localName;
6270
5893
  return { name, separator: "_", checkCppType: false };
6271
5894
  }
@@ -6312,7 +5935,7 @@ export default class CodeGenerator implements IOrchestrator {
6312
5935
  }
6313
5936
  // In C++ mode, unknown user types may have non-trivial constructors
6314
5937
  // Known structs (C-Next or C headers) are POD types where {0} works
6315
- return this.cppMode && !this.isKnownStruct(typeName);
5938
+ return CodeGenState.cppMode && !this.isKnownStruct(typeName);
6316
5939
  }
6317
5940
 
6318
5941
  /**
@@ -6329,11 +5952,11 @@ export default class CodeGenerator implements IOrchestrator {
6329
5952
  // ADR-109: Build handler dependencies for assignment dispatch
6330
5953
  private buildHandlerDeps(): IHandlerDeps {
6331
5954
  return {
6332
- symbols: this.symbols!,
6333
- typeRegistry: this.context.typeRegistry,
6334
- currentScope: this.context.currentScope,
6335
- currentParameters: this.context.currentParameters,
6336
- targetCapabilities: this.context.targetCapabilities,
5955
+ symbols: CodeGenState.symbols!,
5956
+ typeRegistry: CodeGenState.typeRegistry,
5957
+ currentScope: CodeGenState.currentScope,
5958
+ currentParameters: CodeGenState.currentParameters,
5959
+ targetCapabilities: CodeGenState.targetCapabilities,
6337
5960
  generateExpression: (ctx) => this.generateExpression(ctx),
6338
5961
  tryEvaluateConstant: (ctx) => this.tryEvaluateConstant(ctx),
6339
5962
  generateAssignmentTarget: (ctx) => this.generateAssignmentTarget(ctx),
@@ -6342,11 +5965,11 @@ export default class CodeGenerator implements IOrchestrator {
6342
5965
  getMemberTypeInfo: (structType, memberName) =>
6343
5966
  this.getMemberTypeInfo(structType, memberName),
6344
5967
  validateBitmapFieldLiteral: (expr, width, fieldName) =>
6345
- this.typeValidator!.validateBitmapFieldLiteral(expr, width, fieldName),
5968
+ TypeValidator.validateBitmapFieldLiteral(expr, width, fieldName),
6346
5969
  validateCrossScopeVisibility: (scopeName, memberName) =>
6347
5970
  this.validateCrossScopeVisibility(scopeName, memberName),
6348
5971
  checkArrayBounds: (arrayName, dimensions, indexExprs, line) =>
6349
- this.typeValidator!.checkArrayBounds(
5972
+ TypeValidator.checkArrayBounds(
6350
5973
  arrayName,
6351
5974
  [...dimensions],
6352
5975
  [...indexExprs],
@@ -6379,7 +6002,10 @@ export default class CodeGenerator implements IOrchestrator {
6379
6002
  bitIndex?: string;
6380
6003
  baseType?: string;
6381
6004
  } {
6382
- return this.memberChainAnalyzer!.analyze(targetCtx);
6005
+ // Issue #644: MemberChainAnalyzer is now static, pass generateExpression callback
6006
+ return MemberChainAnalyzer.analyze(targetCtx, (ctx) =>
6007
+ this.generateExpression(ctx),
6008
+ );
6383
6009
  }
6384
6010
 
6385
6011
  /**
@@ -6393,12 +6019,18 @@ export default class CodeGenerator implements IOrchestrator {
6393
6019
  width: string | null,
6394
6020
  value: string,
6395
6021
  ): string | null {
6396
- return this.floatBitHelper!.generateFloatBitWrite(
6022
+ // Issue #644: FloatBitHelper is now static, pass callbacks
6023
+ return FloatBitHelper.generateFloatBitWrite(
6397
6024
  name,
6398
6025
  typeInfo,
6399
6026
  bitIndex,
6400
6027
  width,
6401
6028
  value,
6029
+ {
6030
+ generateBitMask: (w, is64Bit) => this.generateBitMask(w, is64Bit),
6031
+ foldBooleanToInt: (expr) => this.foldBooleanToInt(expr),
6032
+ requireInclude: (header) => this.requireInclude(header),
6033
+ },
6402
6034
  );
6403
6035
  }
6404
6036
 
@@ -6408,22 +6040,23 @@ export default class CodeGenerator implements IOrchestrator {
6408
6040
 
6409
6041
  // Issue #644: Set expected type for inferred struct initializers and overflow behavior
6410
6042
  // Delegated to AssignmentExpectedTypeResolver helper
6411
- const savedExpectedType = this.context.expectedType;
6412
- const savedAssignmentContext = { ...this.context.assignmentContext };
6043
+ const savedExpectedType = CodeGenState.expectedType;
6044
+ const savedAssignmentContext = { ...CodeGenState.assignmentContext };
6413
6045
 
6414
- const resolved = this.expectedTypeResolver!.resolve(targetCtx);
6046
+ // Issue #644: AssignmentExpectedTypeResolver is now static
6047
+ const resolved = AssignmentExpectedTypeResolver.resolve(targetCtx);
6415
6048
  if (resolved.expectedType) {
6416
- this.context.expectedType = resolved.expectedType;
6049
+ CodeGenState.expectedType = resolved.expectedType;
6417
6050
  }
6418
6051
  if (resolved.assignmentContext) {
6419
- this.context.assignmentContext = resolved.assignmentContext;
6052
+ CodeGenState.assignmentContext = resolved.assignmentContext;
6420
6053
  }
6421
6054
 
6422
6055
  const value = this.generateExpression(ctx.expression());
6423
6056
 
6424
6057
  // Restore expected type and assignment context
6425
- this.context.expectedType = savedExpectedType;
6426
- this.context.assignmentContext = savedAssignmentContext;
6058
+ CodeGenState.expectedType = savedExpectedType;
6059
+ CodeGenState.assignmentContext = savedAssignmentContext;
6427
6060
 
6428
6061
  // Get the assignment operator and map to C equivalent
6429
6062
  const operatorCtx = ctx.assignmentOperator();
@@ -6433,29 +6066,27 @@ export default class CodeGenerator implements IOrchestrator {
6433
6066
 
6434
6067
  // Issue #644: Validate assignment (const, enum, integer, array bounds, callbacks)
6435
6068
  // Delegated to AssignmentValidator helper to reduce cognitive complexity
6436
- this.assignmentValidator!.validate(
6069
+ AssignmentValidator.validate(
6437
6070
  targetCtx,
6438
6071
  ctx.expression(),
6439
6072
  isCompound,
6440
6073
  ctx.start?.line ?? 0,
6074
+ {
6075
+ getExpressionType: (exprCtx) => this.getExpressionType(exprCtx),
6076
+ tryEvaluateConstant: (exprCtx) => this.tryEvaluateConstant(exprCtx),
6077
+ isCallbackTypeUsedAsFieldType: (name) =>
6078
+ this.isCallbackTypeUsedAsFieldType(name),
6079
+ },
6441
6080
  );
6442
6081
 
6443
6082
  // ADR-109: Dispatch to assignment handlers
6444
6083
  // Build context, classify, and dispatch - all patterns handled by handlers
6445
6084
  const assignCtx = buildAssignmentContext(ctx, {
6446
- typeRegistry: this.context.typeRegistry,
6085
+ typeRegistry: CodeGenState.typeRegistry,
6447
6086
  generateExpression: () => value,
6448
6087
  });
6449
6088
  const handlerDeps = this.buildHandlerDeps();
6450
- const classifier = new AssignmentClassifier({
6451
- symbols: handlerDeps.symbols,
6452
- typeRegistry: handlerDeps.typeRegistry,
6453
- currentScope: handlerDeps.currentScope,
6454
- isKnownStruct: handlerDeps.isKnownStruct,
6455
- isKnownScope: handlerDeps.isKnownScope,
6456
- getMemberTypeInfo: handlerDeps.getMemberTypeInfo,
6457
- });
6458
- const assignmentKind = classifier.classify(assignCtx);
6089
+ const assignmentKind = AssignmentClassifier.classify(assignCtx);
6459
6090
  const handler = AssignmentHandlerRegistry.getHandler(assignmentKind);
6460
6091
  return handler(assignCtx, handlerDeps);
6461
6092
  }
@@ -6475,7 +6106,7 @@ export default class CodeGenerator implements IOrchestrator {
6475
6106
  cOp,
6476
6107
  value,
6477
6108
  typeInfo,
6478
- this.context.targetCapabilities,
6109
+ CodeGenState.targetCapabilities,
6479
6110
  );
6480
6111
  this.applyEffects(result.effects);
6481
6112
  return result.code;
@@ -6487,16 +6118,16 @@ export default class CodeGenerator implements IOrchestrator {
6487
6118
  private _buildSimpleIdentifierDeps(): ISimpleIdentifierDeps {
6488
6119
  return {
6489
6120
  getParameterInfo: (name: string) =>
6490
- this.context.currentParameters.get(name),
6121
+ CodeGenState.currentParameters.get(name),
6491
6122
  resolveParameter: (name: string, paramInfo: TParameterInfo) =>
6492
6123
  ParameterDereferenceResolver.resolve(
6493
6124
  name,
6494
6125
  paramInfo,
6495
6126
  this._buildParameterDereferenceDeps(),
6496
6127
  ),
6497
- isLocalVariable: (name: string) => this.context.localVariables.has(name),
6128
+ isLocalVariable: (name: string) => CodeGenState.localVariables.has(name),
6498
6129
  resolveBareIdentifier: (name: string, isLocal: boolean) =>
6499
- this.typeValidator!.resolveBareIdentifier(name, isLocal, (n: string) =>
6130
+ TypeValidator.resolveBareIdentifier(name, isLocal, (n: string) =>
6500
6131
  this.isKnownStruct(n),
6501
6132
  ),
6502
6133
  };
@@ -6522,7 +6153,7 @@ export default class CodeGenerator implements IOrchestrator {
6522
6153
  hasGlobal: boolean,
6523
6154
  hasThis: boolean,
6524
6155
  ): IPostfixChainDeps {
6525
- const paramInfo = this.context.currentParameters.get(firstId);
6156
+ const paramInfo = CodeGenState.currentParameters.get(firstId);
6526
6157
  const isStructParam = paramInfo?.isStruct ?? false;
6527
6158
  const isCppAccess = hasGlobal && this.isCppScopeSymbol(firstId);
6528
6159
  const separatorDeps = this._buildMemberSeparatorDeps();
@@ -6532,7 +6163,7 @@ export default class CodeGenerator implements IOrchestrator {
6532
6163
  firstId,
6533
6164
  hasGlobal,
6534
6165
  hasThis,
6535
- this.context.currentScope,
6166
+ CodeGenState.currentScope,
6536
6167
  isStructParam,
6537
6168
  separatorDeps,
6538
6169
  isCppAccess,
@@ -6556,37 +6187,7 @@ export default class CodeGenerator implements IOrchestrator {
6556
6187
  };
6557
6188
  }
6558
6189
 
6559
- // ADR-016: Validate cross-scope visibility (issue #165)
6560
- private _validateCrossScopeVisibility(
6561
- scopeName: string,
6562
- memberName: string,
6563
- isGlobalAccess: boolean = false,
6564
- ): void {
6565
- // Error if referencing own scope by name (must use this. prefix)
6566
- // Exception: global.Scope.member is allowed for explicit qualification
6567
- if (!isGlobalAccess && this.context.currentScope === scopeName) {
6568
- throw new Error(
6569
- `Error: Cannot reference own scope '${scopeName}' by name. ` +
6570
- `Use 'this.${memberName}' instead of '${scopeName}.${memberName}'`,
6571
- );
6572
- }
6573
-
6574
- // Check private member access (skip for own scope - we can access our own privates)
6575
- const isOwnScope = this.context.currentScope === scopeName;
6576
- if (!isOwnScope) {
6577
- const visibility =
6578
- this.symbols!.scopeMemberVisibility.get(scopeName)?.get(memberName);
6579
- if (visibility === "private") {
6580
- const context = this.context.currentScope
6581
- ? `from scope '${this.context.currentScope}'`
6582
- : "from outside the scope";
6583
- throw new Error(
6584
- `Cannot access private member '${memberName}' of scope '${scopeName}' ${context}. ` +
6585
- `Only public members are accessible outside their scope.`,
6586
- );
6587
- }
6588
- }
6589
- }
6190
+ // ADR-016: _validateCrossScopeVisibility moved to ScopeResolver
6590
6191
 
6591
6192
  // Issue #387: Dead methods removed (generateGlobalMemberAccess, generateGlobalArrayAccess,
6592
6193
  // generateThisMemberAccess, generateThisArrayAccess) - now handled by unified doGenerateAssignmentTarget
@@ -6672,7 +6273,7 @@ export default class CodeGenerator implements IOrchestrator {
6672
6273
  * ADR-016: 'this' returns a marker that postfixOps will transform to Scope_member
6673
6274
  */
6674
6275
  private _resolveThisKeyword(): string {
6675
- if (!this.context.currentScope) {
6276
+ if (!CodeGenState.currentScope) {
6676
6277
  throw new Error("Error: 'this' can only be used inside a scope");
6677
6278
  }
6678
6279
  return "__THIS_SCOPE__";
@@ -6684,12 +6285,12 @@ export default class CodeGenerator implements IOrchestrator {
6684
6285
  */
6685
6286
  private _resolveIdentifierExpression(id: string): string {
6686
6287
  // Special case: main function's args parameter -> argv
6687
- if (this.context.mainArgsName && id === this.context.mainArgsName) {
6288
+ if (CodeGenState.mainArgsName && id === CodeGenState.mainArgsName) {
6688
6289
  return "argv";
6689
6290
  }
6690
6291
 
6691
6292
  // ADR-006: Check if it's a function parameter
6692
- const paramInfo = this.context.currentParameters.get(id);
6293
+ const paramInfo = CodeGenState.currentParameters.get(id);
6693
6294
  if (paramInfo) {
6694
6295
  return ParameterDereferenceResolver.resolve(
6695
6296
  id,
@@ -6699,15 +6300,16 @@ export default class CodeGenerator implements IOrchestrator {
6699
6300
  }
6700
6301
 
6701
6302
  // ADR-016: Resolve bare identifier using local -> scope -> global priority
6702
- const isLocalVariable = this.context.localVariables.has(id);
6703
- const resolved = this.typeValidator!.resolveBareIdentifier(
6303
+ const isLocalVariable = CodeGenState.localVariables.has(id);
6304
+ const resolved = TypeValidator.resolveBareIdentifier(
6704
6305
  id,
6705
6306
  isLocalVariable,
6706
6307
  (name: string) => this.isKnownStruct(name),
6707
6308
  );
6708
6309
  if (resolved !== null) {
6709
6310
  // Issue #741: Check if this is a private const that should be inlined
6710
- const constValue = this.symbols!.scopePrivateConstValues.get(resolved);
6311
+ const constValue =
6312
+ CodeGenState.symbols!.scopePrivateConstValues.get(resolved);
6711
6313
  if (constValue !== undefined) {
6712
6314
  return constValue;
6713
6315
  }
@@ -6731,19 +6333,21 @@ export default class CodeGenerator implements IOrchestrator {
6731
6333
  private _resolveUnqualifiedEnumMember(id: string): string | null {
6732
6334
  // Type-aware resolution: check only the expected enum type
6733
6335
  if (
6734
- this.context.expectedType &&
6735
- this.symbols!.knownEnums.has(this.context.expectedType)
6336
+ CodeGenState.expectedType &&
6337
+ CodeGenState.symbols!.knownEnums.has(CodeGenState.expectedType)
6736
6338
  ) {
6737
- const members = this.symbols!.enumMembers.get(this.context.expectedType);
6339
+ const members = CodeGenState.symbols!.enumMembers.get(
6340
+ CodeGenState.expectedType,
6341
+ );
6738
6342
  if (members?.has(id)) {
6739
- return `${this.context.expectedType}${this.getScopeSeparator(false)}${id}`;
6343
+ return `${CodeGenState.expectedType}${this.getScopeSeparator(false)}${id}`;
6740
6344
  }
6741
6345
  return null;
6742
6346
  }
6743
6347
 
6744
6348
  // No expected enum type - search all enums but error on ambiguity
6745
6349
  const matchingEnums: string[] = [];
6746
- for (const [enumName, members] of this.symbols!.enumMembers) {
6350
+ for (const [enumName, members] of CodeGenState.symbols!.enumMembers) {
6747
6351
  if (members.has(id)) {
6748
6352
  matchingEnums.push(enumName);
6749
6353
  }
@@ -6771,7 +6375,7 @@ export default class CodeGenerator implements IOrchestrator {
6771
6375
 
6772
6376
  // Issue #304/#644: Transform NULL → nullptr in C++ mode
6773
6377
  if (result.code === "NULL") {
6774
- return this.cppHelper!.nullLiteral();
6378
+ return CppModeHelper.nullLiteral();
6775
6379
  }
6776
6380
 
6777
6381
  return result.code;
@@ -6837,7 +6441,7 @@ export default class CodeGenerator implements IOrchestrator {
6837
6441
  }
6838
6442
 
6839
6443
  // Issue #267/#644: Use C++ casts when cppMode is enabled for MISRA compliance
6840
- return this.cppHelper!.cast(targetType, expr);
6444
+ return CppModeHelper.cast(targetType, expr);
6841
6445
  }
6842
6446
 
6843
6447
  /**
@@ -6863,7 +6467,7 @@ export default class CodeGenerator implements IOrchestrator {
6863
6467
 
6864
6468
  if (!maxValue) {
6865
6469
  // Unknown type, fall back to raw cast - Issue #644
6866
- return this.cppHelper!.cast(targetType, expr);
6470
+ return CppModeHelper.cast(targetType, expr);
6867
6471
  }
6868
6472
 
6869
6473
  // Mark that we need limits.h for the type limit macros
@@ -6883,161 +6487,20 @@ export default class CodeGenerator implements IOrchestrator {
6883
6487
  // Generate clamping expression:
6884
6488
  // (expr > MAX) ? MAX : (expr < MIN) ? MIN : (type)(expr)
6885
6489
  // Note: For unsigned targets, MIN is 0 so we check < 0.0
6886
- const finalCast = this.cppHelper!.cast(targetType, `(${expr})`);
6490
+ const finalCast = CppModeHelper.cast(targetType, `(${expr})`);
6887
6491
  return `((${expr}) > ${maxComparison} ? ${maxValue} : (${expr}) < ${minComparison} ? ${minValue} : ${finalCast})`;
6888
6492
  }
6889
6493
 
6890
6494
  /**
6891
6495
  * ADR-023: Generate sizeof expression
6892
- * sizeof(type) -> sizeof(c_type)
6893
- * sizeof(variable) -> sizeof(variable)
6894
- * With safety checks:
6895
- * - E0601: sizeof on array parameter is error
6896
- * - E0602: Side effects in sizeof are error
6496
+ * Delegates to SizeofResolver which uses CodeGenState.
6897
6497
  */
6898
6498
  private generateSizeofExpr(ctx: Parser.SizeofExpressionContext): string {
6899
- // Check if it's sizeof(type) or sizeof(expression)
6900
- // Note: Due to grammar ambiguity, sizeof(variable) may parse as sizeof(type)
6901
- // when the variable name matches userType (just an identifier)
6902
- if (ctx.type()) {
6903
- return this._sizeofType(ctx.type()!);
6904
- }
6905
- return this._sizeofExpression(ctx.expression()!);
6906
- }
6907
-
6908
- /**
6909
- * Handle sizeof(type) - may actually be sizeof(variable) due to grammar ambiguity
6910
- */
6911
- private _sizeofType(typeCtx: Parser.TypeContext): string {
6912
- // qualifiedType matches IDENTIFIER.IDENTIFIER, could be struct.member
6913
- if (typeCtx.qualifiedType()) {
6914
- const result = this._sizeofQualifiedType(typeCtx.qualifiedType()!);
6915
- if (result) return result;
6916
- // Fall through to generateType for actual type references (Scope.Type)
6917
- }
6918
-
6919
- // userType is just IDENTIFIER, could be a variable reference
6920
- if (typeCtx.userType()) {
6921
- return this._sizeofUserType(typeCtx.getText());
6922
- }
6923
-
6924
- // It's a primitive or other type - generate normally
6925
- return `sizeof(${this.generateType(typeCtx)})`;
6926
- }
6927
-
6928
- /**
6929
- * Handle sizeof(qualified.type) - may be struct.member access
6930
- * Returns null if this is actually a type reference (Scope.Type)
6931
- */
6932
- private _sizeofQualifiedType(
6933
- qualifiedCtx: Parser.QualifiedTypeContext,
6934
- ): string | null {
6935
- const identifiers = qualifiedCtx.IDENTIFIER();
6936
- const firstName = identifiers[0].getText();
6937
- const memberName = identifiers[1].getText();
6938
-
6939
- // Check if first identifier is a local variable (struct instance)
6940
- if (this.context.localVariables.has(firstName)) {
6941
- return `sizeof(${firstName}.${memberName})`;
6942
- }
6943
-
6944
- // Check if first identifier is a parameter (struct parameter)
6945
- const paramInfo = this.context.currentParameters.get(firstName);
6946
- if (paramInfo) {
6947
- const sep = paramInfo.isStruct ? "->" : ".";
6948
- return `sizeof(${firstName}${sep}${memberName})`;
6949
- }
6950
-
6951
- // Check if first identifier is a global variable
6952
- // If not a scope or enum, it's likely a global struct variable
6953
- if (
6954
- !this.isKnownScope(firstName) &&
6955
- !this.symbols!.knownEnums.has(firstName)
6956
- ) {
6957
- return `sizeof(${firstName}.${memberName})`;
6958
- }
6959
-
6960
- // It's an actual type reference (Scope.Type), return null to fall through
6961
- return null;
6962
- }
6963
-
6964
- /**
6965
- * Handle sizeof(identifier) - could be variable or type name
6966
- */
6967
- private _sizeofUserType(varName: string): string {
6968
- // Check if it's a known parameter
6969
- const paramInfo = this.context.currentParameters.get(varName);
6970
- if (paramInfo) {
6971
- return this._sizeofParameter(varName, paramInfo);
6972
- }
6973
-
6974
- // Check if it's a known local variable, struct type, or enum type
6975
- // For all these cases, generate sizeof(name) directly
6976
- // Unknown identifiers are also treated as variables for safety
6977
- return `sizeof(${varName})`;
6978
- }
6979
-
6980
- /**
6981
- * Handle sizeof on a parameter - validates and generates appropriate code
6982
- */
6983
- private _sizeofParameter(
6984
- varName: string,
6985
- paramInfo: { isArray?: boolean; isCallback?: boolean; isStruct?: boolean },
6986
- ): string {
6987
- // E0601: Array parameters decay to pointers
6988
- if (paramInfo.isArray) {
6989
- this._throwArrayParamSizeofError(varName);
6990
- }
6991
- // For pass-by-reference parameters (non-array, non-callback, non-struct),
6992
- // use pointer dereference
6993
- if (!paramInfo.isCallback && !paramInfo.isStruct) {
6994
- return `sizeof(*${varName})`;
6995
- }
6996
- return `sizeof(${varName})`;
6997
- }
6998
-
6999
- /**
7000
- * Throw E0601 error for sizeof on array parameter
7001
- */
7002
- private _throwArrayParamSizeofError(varName: string): never {
7003
- throw new Error(
7004
- `Error[E0601]: sizeof() on array parameter '${varName}' returns pointer size. ` +
7005
- `Use ${varName}.length for element count or sizeof(elementType) * ${varName}.length for bytes`,
7006
- );
7007
- }
7008
-
7009
- /**
7010
- * Handle sizeof(expression) with validation
7011
- */
7012
- private _sizeofExpression(expr: Parser.ExpressionContext): string {
7013
- // E0601: Check if expression is an array parameter
7014
- const varName = this.getSingleIdentifierFromExpr(expr);
7015
- if (varName) {
7016
- const paramInfo = this.context.currentParameters.get(varName);
7017
- if (paramInfo?.isArray) {
7018
- this._throwArrayParamSizeofError(varName);
7019
- }
7020
- }
7021
-
7022
- // E0602: Check for side effects
7023
- if (this.hasSideEffects(expr)) {
7024
- throw new Error(
7025
- `Error[E0602]: sizeof() operand must not have side effects (MISRA C:2012 Rule 13.6)`,
7026
- );
7027
- }
7028
-
7029
- return `sizeof(${this.generateExpression(expr)})`;
7030
- }
7031
-
7032
- /**
7033
- * ADR-023: Extract simple identifier from expression for parameter checking
7034
- * Returns the identifier name if expression is a simple variable reference, null otherwise
7035
- * Issue #707: Delegates to ExpressionUnwrapper utility.
7036
- */
7037
- private getSingleIdentifierFromExpr(
7038
- expr: Parser.ExpressionContext,
7039
- ): string | null {
7040
- return ExpressionUnwrapper.getSimpleIdentifier(expr);
6499
+ return SizeofResolver.generate(ctx, {
6500
+ generateType: (typeCtx) => this.generateType(typeCtx),
6501
+ generateExpression: (exprCtx) => this.generateExpression(exprCtx),
6502
+ hasSideEffects: (exprCtx) => this.hasSideEffects(exprCtx),
6503
+ });
7041
6504
  }
7042
6505
 
7043
6506
  /**
@@ -7099,7 +6562,10 @@ export default class CodeGenerator implements IOrchestrator {
7099
6562
  * ADR-053 A5: Delegates to HelperGenerator
7100
6563
  */
7101
6564
  private generateOverflowHelpers(): string[] {
7102
- return helperGenerateOverflowHelpers(this.usedClampOps, this.debugMode);
6565
+ return helperGenerateOverflowHelpers(
6566
+ CodeGenState.usedClampOps,
6567
+ CodeGenState.debugMode,
6568
+ );
7103
6569
  }
7104
6570
 
7105
6571
  /**
@@ -7108,7 +6574,7 @@ export default class CodeGenerator implements IOrchestrator {
7108
6574
  private markClampOpUsed(operation: string, cnxType: string): void {
7109
6575
  // Only generate helpers for integer types (not float/bool)
7110
6576
  if (TYPE_WIDTH[cnxType] && TypeCheckUtils.isInteger(cnxType)) {
7111
- this.usedClampOps.add(`${operation}_${cnxType}`);
6577
+ CodeGenState.usedClampOps.add(`${operation}_${cnxType}`);
7112
6578
  }
7113
6579
  }
7114
6580
 
@@ -7144,7 +6610,7 @@ export default class CodeGenerator implements IOrchestrator {
7144
6610
  * Format leading comments with current indentation
7145
6611
  */
7146
6612
  private formatLeadingComments(comments: IComment[]): string[] {
7147
- const indent = FormatUtils.indent(this.context.indentLevel);
6613
+ const indent = FormatUtils.indent(CodeGenState.indentLevel);
7148
6614
  return commentFormatLeadingComments(
7149
6615
  comments,
7150
6616
  this.commentFormatter,
@@ -7157,6 +6623,6 @@ export default class CodeGenerator implements IOrchestrator {
7157
6623
  * ADR-053 A5: Delegates to HelperGenerator
7158
6624
  */
7159
6625
  private generateSafeDivHelpers(): string[] {
7160
- return helperGenerateSafeDivHelpers(this.usedSafeDivOps);
6626
+ return helperGenerateSafeDivHelpers(CodeGenState.usedSafeDivOps);
7161
6627
  }
7162
6628
  }