c-next 0.1.62 → 0.1.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +86 -63
  2. package/package.json +1 -1
  3. package/src/transpiler/Transpiler.ts +3 -2
  4. package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
  5. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +1 -1
  6. package/src/transpiler/__tests__/Transpiler.test.ts +0 -23
  7. package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
  8. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
  9. package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
  10. package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
  11. package/src/transpiler/output/codegen/CodeGenerator.ts +817 -1377
  12. package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
  13. package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
  14. package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
  15. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +326 -60
  16. package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
  17. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
  18. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
  19. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
  20. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +39 -43
  21. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +52 -55
  22. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +122 -62
  23. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
  24. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +143 -126
  25. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +287 -320
  26. package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
  27. package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
  28. package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
  29. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +121 -51
  30. package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
  31. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
  32. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
  33. package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
  34. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
  35. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +21 -30
  36. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +56 -53
  37. package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
  38. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
  39. package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
  40. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
  41. package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
  42. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
  43. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
  44. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
  45. package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
  46. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
  47. package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
  48. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
  49. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
  50. package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
  51. package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
  52. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
  53. package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
  54. package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
  55. package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
@@ -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
  /**
@@ -4090,14 +3906,14 @@ export default class CodeGenerator implements IOrchestrator {
4090
3906
  const isArray = dims.length > 0;
4091
3907
 
4092
3908
  // ADR-029: Check if parameter type is itself a callback type
4093
- const isCallbackParam = this.callbackTypes.has(typeName);
3909
+ const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
4094
3910
 
4095
3911
  let paramType: string;
4096
3912
  let isPointer: boolean;
4097
3913
 
4098
3914
  if (isCallbackParam) {
4099
3915
  // Use the callback typedef name
4100
- const cbInfo = this.callbackTypes.get(typeName)!;
3916
+ const cbInfo = CodeGenState.callbackTypes.get(typeName)!;
4101
3917
  paramType = cbInfo.typedefName;
4102
3918
  isPointer = false; // Function pointers are already pointers
4103
3919
  } else {
@@ -4120,7 +3936,7 @@ export default class CodeGenerator implements IOrchestrator {
4120
3936
  }
4121
3937
  }
4122
3938
 
4123
- this.callbackTypes.set(name, {
3939
+ CodeGenState.callbackTypes.set(name, {
4124
3940
  functionName: name,
4125
3941
  returnType,
4126
3942
  parameters,
@@ -4134,187 +3950,9 @@ export default class CodeGenerator implements IOrchestrator {
4134
3950
  // Issue #63: validateCallbackAssignment, callbackSignaturesMatch, isConstValue,
4135
3951
  // and validateBareIdentifierInScope moved to TypeValidator
4136
3952
 
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
-
3953
+ // EnumTypeResolver now handles: _getEnumTypeFromThisEnum, _getEnumTypeFromGlobalEnum,
3954
+ // _getEnumTypeFromThisVariable, _getEnumTypeFromScopedEnum, _getEnumTypeFromMemberAccess,
3955
+ // _getExpressionEnumType, _getFunctionCallEnumType
4318
3956
  /**
4319
3957
  * ADR-017: Check if an expression represents an integer literal or numeric type.
4320
3958
  * Used to detect comparisons between enums and integers.
@@ -4322,30 +3960,7 @@ export default class CodeGenerator implements IOrchestrator {
4322
3960
  private _isIntegerExpression(
4323
3961
  ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
4324
3962
  ): 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;
3963
+ return EnumAssignmentValidator.isIntegerExpression(ctx);
4349
3964
  }
4350
3965
 
4351
3966
  /**
@@ -4358,38 +3973,10 @@ export default class CodeGenerator implements IOrchestrator {
4358
3973
  leftCapacity: number;
4359
3974
  rightCapacity: number;
4360
3975
  } | 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];
3976
+ // Navigate to the additive expression level using ExpressionUnwrapper
3977
+ // Issue #707: Deduplicated expression tree navigation
3978
+ const add = ExpressionUnwrapper.getAdditiveExpression(ctx);
3979
+ if (!add) return null;
4393
3980
  const multExprs = add.multiplicativeExpression();
4394
3981
 
4395
3982
  // Need exactly 2 operands for simple concatenation
@@ -4460,7 +4047,7 @@ export default class CodeGenerator implements IOrchestrator {
4460
4047
  const sourceName = sourceId.getText();
4461
4048
 
4462
4049
  // Check if source is a string type
4463
- const typeInfo = this.context.typeRegistry.get(sourceName);
4050
+ const typeInfo = CodeGenState.typeRegistry.get(sourceName);
4464
4051
  if (!typeInfo?.isString || typeInfo.stringCapacity === undefined) {
4465
4052
  return null;
4466
4053
  }
@@ -4494,11 +4081,11 @@ export default class CodeGenerator implements IOrchestrator {
4494
4081
  // NOTE: Public isIntegerType and isFloatType moved to IOrchestrator interface (ADR-053 A2)
4495
4082
  // Private versions kept for internal use
4496
4083
  private _isIntegerType(typeName: string): boolean {
4497
- return this.typeResolver!.isIntegerType(typeName);
4084
+ return TypeResolver.isIntegerType(typeName);
4498
4085
  }
4499
4086
 
4500
4087
  private _isFloatType(typeName: string): boolean {
4501
- return this.typeResolver!.isFloatType(typeName);
4088
+ return TypeResolver.isFloatType(typeName);
4502
4089
  }
4503
4090
 
4504
4091
  /**
@@ -4509,7 +4096,7 @@ export default class CodeGenerator implements IOrchestrator {
4509
4096
  sourceType: string,
4510
4097
  targetType: string,
4511
4098
  ): boolean {
4512
- return this.typeResolver!.isNarrowingConversion(sourceType, targetType);
4099
+ return TypeResolver.isNarrowingConversion(sourceType, targetType);
4513
4100
  }
4514
4101
 
4515
4102
  /**
@@ -4517,7 +4104,7 @@ export default class CodeGenerator implements IOrchestrator {
4517
4104
  * Sign change occurs when converting between signed and unsigned types
4518
4105
  */
4519
4106
  private isSignConversion(sourceType: string, targetType: string): boolean {
4520
- return this.typeResolver!.isSignConversion(sourceType, targetType);
4107
+ return TypeResolver.isSignConversion(sourceType, targetType);
4521
4108
  }
4522
4109
 
4523
4110
  /**
@@ -4530,7 +4117,7 @@ export default class CodeGenerator implements IOrchestrator {
4530
4117
  literalText: string,
4531
4118
  targetType: string,
4532
4119
  ): void {
4533
- this.typeResolver!.validateLiteralFitsType(literalText, targetType);
4120
+ TypeResolver.validateLiteralFitsType(literalText, targetType);
4534
4121
  }
4535
4122
 
4536
4123
  /**
@@ -4539,7 +4126,7 @@ export default class CodeGenerator implements IOrchestrator {
4539
4126
  private getUnaryExpressionType(
4540
4127
  ctx: Parser.UnaryExpressionContext,
4541
4128
  ): string | null {
4542
- return this.typeResolver!.getUnaryExpressionType(ctx);
4129
+ return TypeResolver.getUnaryExpressionType(ctx);
4543
4130
  }
4544
4131
 
4545
4132
  /**
@@ -4550,7 +4137,7 @@ export default class CodeGenerator implements IOrchestrator {
4550
4137
  targetType: string,
4551
4138
  sourceType: string | null,
4552
4139
  ): void {
4553
- this.typeResolver!.validateTypeConversion(targetType, sourceType);
4140
+ TypeResolver.validateTypeConversion(targetType, sourceType);
4554
4141
  }
4555
4142
 
4556
4143
  // Issue #63: checkConstAssignment moved to TypeValidator
@@ -4588,7 +4175,7 @@ export default class CodeGenerator implements IOrchestrator {
4588
4175
  ctx: Parser.ExpressionContext,
4589
4176
  targetParamBaseType?: string,
4590
4177
  ): boolean {
4591
- if (!this.cppMode) return false;
4178
+ if (!CodeGenState.cppMode) return false;
4592
4179
  if (!targetParamBaseType) return false;
4593
4180
 
4594
4181
  const postfix = ExpressionUnwrapper.getPostfixExpression(ctx);
@@ -4602,7 +4189,7 @@ export default class CodeGenerator implements IOrchestrator {
4602
4189
  const ops = postfix.postfixOp();
4603
4190
 
4604
4191
  // Case 1: Direct parameter member access (cfg.value)
4605
- const paramInfo = this.context.currentParameters.get(baseId);
4192
+ const paramInfo = CodeGenState.currentParameters.get(baseId);
4606
4193
  if (paramInfo) {
4607
4194
  return this._needsParamMemberConversion(paramInfo, targetParamBaseType);
4608
4195
  }
@@ -4647,7 +4234,7 @@ export default class CodeGenerator implements IOrchestrator {
4647
4234
  baseId: string,
4648
4235
  targetParamBaseType: string,
4649
4236
  ): boolean {
4650
- const typeInfo = this.context.typeRegistry.get(baseId);
4237
+ const typeInfo = CodeGenState.typeRegistry.get(baseId);
4651
4238
  return CppMemberHelper.needsComplexMemberConversion(
4652
4239
  this._toPostfixOps(ops),
4653
4240
  typeInfo,
@@ -4674,8 +4261,8 @@ export default class CodeGenerator implements IOrchestrator {
4674
4261
  const baseId = primary.IDENTIFIER()?.getText();
4675
4262
  if (!baseId) return false;
4676
4263
 
4677
- const typeInfo = this.context.typeRegistry.get(baseId);
4678
- const paramInfo = this.context.currentParameters.get(baseId);
4264
+ const typeInfo = CodeGenState.typeRegistry.get(baseId);
4265
+ const paramInfo = CodeGenState.currentParameters.get(baseId);
4679
4266
 
4680
4267
  return CppMemberHelper.isStringSubscriptPattern(
4681
4268
  hasPostfixOps,
@@ -4728,11 +4315,11 @@ export default class CodeGenerator implements IOrchestrator {
4728
4315
  // 2. Parameter: currentParameters.get(baseId).baseType
4729
4316
  let structType: string | undefined;
4730
4317
 
4731
- const typeInfo = this.context.typeRegistry.get(baseId);
4318
+ const typeInfo = CodeGenState.typeRegistry.get(baseId);
4732
4319
  if (typeInfo) {
4733
4320
  structType = typeInfo.baseType;
4734
4321
  } else {
4735
- const paramInfo = this.context.currentParameters.get(baseId);
4322
+ const paramInfo = CodeGenState.currentParameters.get(baseId);
4736
4323
  if (paramInfo) {
4737
4324
  structType = paramInfo.baseType;
4738
4325
  }
@@ -4784,26 +4371,33 @@ export default class CodeGenerator implements IOrchestrator {
4784
4371
  */
4785
4372
  private _handleIdentifierArg(id: string): string {
4786
4373
  // Parameters are already pointers
4787
- if (this.context.currentParameters.get(id)) {
4374
+ if (CodeGenState.currentParameters.get(id)) {
4788
4375
  return id;
4789
4376
  }
4790
4377
 
4791
4378
  // Local arrays decay to pointers
4792
- if (this.context.localArrays.has(id)) {
4379
+ if (CodeGenState.localArrays.has(id)) {
4380
+ return id;
4381
+ }
4382
+
4383
+ // Global arrays also decay to pointers (check typeRegistry)
4384
+ // But NOT strings - strings need & (they're char arrays but passed by reference)
4385
+ const typeInfo = CodeGenState.typeRegistry.get(id);
4386
+ if (typeInfo?.isArray && !typeInfo.isString) {
4793
4387
  return id;
4794
4388
  }
4795
4389
 
4796
4390
  // Scope member - may need prefixing
4797
- if (this.context.currentScope) {
4798
- const members = this.context.scopeMembers.get(this.context.currentScope);
4391
+ if (CodeGenState.currentScope) {
4392
+ const members = CodeGenState.scopeMembers.get(CodeGenState.currentScope);
4799
4393
  if (members?.has(id)) {
4800
- const scopedName = `${this.context.currentScope}_${id}`;
4801
- return this.cppHelper!.maybeAddressOf(scopedName);
4394
+ const scopedName = `${CodeGenState.currentScope}_${id}`;
4395
+ return CppModeHelper.maybeAddressOf(scopedName);
4802
4396
  }
4803
4397
  }
4804
4398
 
4805
4399
  // Local variable - add & (except in C++ mode)
4806
- return this.cppHelper!.maybeAddressOf(id);
4400
+ return CppModeHelper.maybeAddressOf(id);
4807
4401
  }
4808
4402
 
4809
4403
  /**
@@ -4825,7 +4419,7 @@ export default class CodeGenerator implements IOrchestrator {
4825
4419
 
4826
4420
  // Generate expression with address-of
4827
4421
  const generatedExpr = this.generateExpression(ctx);
4828
- const expr = this.cppHelper!.maybeAddressOf(generatedExpr);
4422
+ const expr = CppModeHelper.maybeAddressOf(generatedExpr);
4829
4423
 
4830
4424
  // String subscript access may need cast
4831
4425
  if (lvalueType === "array") {
@@ -4869,10 +4463,12 @@ export default class CodeGenerator implements IOrchestrator {
4869
4463
  ): string {
4870
4464
  const cType = TYPE_MAP[targetParamBaseType] || "uint8_t";
4871
4465
  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);
4466
+ const tempName = `_cnx_tmp_${CodeGenState.tempVarCounter++}`;
4467
+ const castExpr = CppModeHelper.cast(cType, value);
4468
+ CodeGenState.pendingTempDeclarations.push(
4469
+ `${cType} ${tempName} = ${castExpr};`,
4470
+ );
4471
+ return CppModeHelper.maybeAddressOf(tempName);
4876
4472
  }
4877
4473
 
4878
4474
  /**
@@ -4889,7 +4485,7 @@ export default class CodeGenerator implements IOrchestrator {
4889
4485
 
4890
4486
  const cType = TYPE_MAP[targetParamBaseType];
4891
4487
  if (cType && !["float", "double", "bool", "void"].includes(cType)) {
4892
- return this.cppHelper!.reinterpretCast(`${cType}*`, expr);
4488
+ return CppModeHelper.reinterpretCast(`${cType}*`, expr);
4893
4489
  }
4894
4490
 
4895
4491
  return expr;
@@ -4914,7 +4510,7 @@ export default class CodeGenerator implements IOrchestrator {
4914
4510
  const value = this.generateExpression(ctx);
4915
4511
 
4916
4512
  // C++ mode: rvalues can bind to const T&
4917
- if (this.cppMode) {
4513
+ if (CodeGenState.cppMode) {
4918
4514
  return value;
4919
4515
  }
4920
4516
 
@@ -4937,21 +4533,21 @@ export default class CodeGenerator implements IOrchestrator {
4937
4533
  // Issue #369: Skip struct/enum/bitmap definitions when self-include is added
4938
4534
  // These types will be defined in the included header file
4939
4535
  if (ctx.structDeclaration()) {
4940
- if (this.selfIncludeAdded) {
4536
+ if (CodeGenState.selfIncludeAdded) {
4941
4537
  return ""; // Definition will come from header
4942
4538
  }
4943
4539
  return this.generateStruct(ctx.structDeclaration()!);
4944
4540
  }
4945
4541
  // ADR-017: Handle enum declarations
4946
4542
  if (ctx.enumDeclaration()) {
4947
- if (this.selfIncludeAdded) {
4543
+ if (CodeGenState.selfIncludeAdded) {
4948
4544
  return ""; // Definition will come from header
4949
4545
  }
4950
4546
  return this.generateEnum(ctx.enumDeclaration()!);
4951
4547
  }
4952
4548
  // ADR-034: Handle bitmap declarations
4953
4549
  if (ctx.bitmapDeclaration()) {
4954
- if (this.selfIncludeAdded) {
4550
+ if (CodeGenState.selfIncludeAdded) {
4955
4551
  return ""; // Definition will come from header
4956
4552
  }
4957
4553
  return this.generateBitmap(ctx.bitmapDeclaration()!);
@@ -4980,7 +4576,7 @@ export default class CodeGenerator implements IOrchestrator {
4980
4576
 
4981
4577
  // Fallback to inline implementation (will be removed after migration)
4982
4578
  const name = ctx.IDENTIFIER().getText();
4983
- this.context.currentScope = name;
4579
+ CodeGenState.currentScope = name;
4984
4580
 
4985
4581
  const lines: string[] = [];
4986
4582
  lines.push(`/* Scope: ${name} */`);
@@ -4990,7 +4586,7 @@ export default class CodeGenerator implements IOrchestrator {
4990
4586
  }
4991
4587
 
4992
4588
  lines.push("");
4993
- this.context.currentScope = null;
4589
+ CodeGenState.currentScope = null;
4994
4590
  return lines.join("\n");
4995
4591
  }
4996
4592
 
@@ -5046,10 +4642,18 @@ export default class CodeGenerator implements IOrchestrator {
5046
4642
  const prefix = isPrivate ? "static " : "";
5047
4643
 
5048
4644
  const arrayDims = varDecl.arrayDimension();
5049
- const isArray = arrayDims.length > 0;
4645
+ const hasArrayTypeSyntax = varDecl.type().arrayType() !== null;
4646
+ const isArray = arrayDims.length > 0 || hasArrayTypeSyntax;
5050
4647
 
5051
4648
  let decl = `${prefix}${type} ${fullName}`;
5052
- if (isArray) {
4649
+
4650
+ // Handle arrayType dimension (C-Next style: u8[16] data)
4651
+ if (hasArrayTypeSyntax) {
4652
+ decl += this._getArrayTypeDimension(varDecl.type());
4653
+ }
4654
+
4655
+ // Handle arrayDimension (C-style or additional dimensions)
4656
+ if (arrayDims.length > 0) {
5053
4657
  decl += this.generateArrayDimensions(arrayDims);
5054
4658
  }
5055
4659
 
@@ -5091,9 +4695,9 @@ export default class CodeGenerator implements IOrchestrator {
5091
4695
  const prefix = isPrivate ? "static " : "";
5092
4696
 
5093
4697
  // Issue #269: Set current function name for pass-by-value lookup
5094
- this.context.currentFunctionName = fullName;
4698
+ CodeGenState.currentFunctionName = fullName;
5095
4699
  // Issue #477: Set return type for enum inference in return statements
5096
- this.context.currentFunctionReturnType = funcDecl.type().getText();
4700
+ CodeGenState.currentFunctionReturnType = funcDecl.type().getText();
5097
4701
 
5098
4702
  // Track parameters for ADR-006 pointer semantics
5099
4703
  this._setParameters(funcDecl.parameterList() ?? null);
@@ -5114,8 +4718,8 @@ export default class CodeGenerator implements IOrchestrator {
5114
4718
 
5115
4719
  // ADR-016: Exit function body context
5116
4720
  this.exitFunctionBody();
5117
- this.context.currentFunctionName = null;
5118
- this.context.currentFunctionReturnType = null;
4721
+ CodeGenState.currentFunctionName = null;
4722
+ CodeGenState.currentFunctionReturnType = null;
5119
4723
  this._clearParameters();
5120
4724
 
5121
4725
  lines.push("", `${prefix}${returnType} ${fullName}(${params}) ${body}`);
@@ -5198,155 +4802,14 @@ export default class CodeGenerator implements IOrchestrator {
5198
4802
  // ========================================================================
5199
4803
 
5200
4804
  private generateStruct(ctx: Parser.StructDeclarationContext): string {
5201
- // ADR-053: Check registry for extracted generator
4805
+ // ADR-053: Delegates to extracted StructGenerator
5202
4806
  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}`);
4807
+ if (!generator) {
4808
+ throw new Error("Error: struct generator not registered");
5345
4809
  }
5346
-
5347
- lines.push(` };`, `}`, "");
5348
-
5349
- return lines.join("\n");
4810
+ const result = generator(ctx, this.getInput(), this.getState(), this);
4811
+ this.applyEffects(result.effects);
4812
+ return result.code;
5350
4813
  }
5351
4814
 
5352
4815
  // ========================================================================
@@ -5358,44 +4821,16 @@ export default class CodeGenerator implements IOrchestrator {
5358
4821
  * enum State { IDLE, RUNNING, ERROR <- 255 }
5359
4822
  * -> typedef enum { State_IDLE = 0, State_RUNNING = 1, State_ERROR = 255 } State;
5360
4823
  *
5361
- * ADR-053: Delegates to extracted generator if registered.
4824
+ * ADR-053: Delegates to extracted EnumGenerator.
5362
4825
  */
5363
4826
  private generateEnum(ctx: Parser.EnumDeclarationContext): string {
5364
- // ADR-053: Check registry for extracted generator
5365
4827
  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}`);
4828
+ if (!generator) {
4829
+ throw new Error("Error: enum generator not registered");
5394
4830
  }
5395
-
5396
- lines.push(`} ${fullName};`, "");
5397
-
5398
- return lines.join("\n");
4831
+ const result = generator(ctx, this.getInput(), this.getState(), this);
4832
+ this.applyEffects(result.effects);
4833
+ return result.code;
5399
4834
  }
5400
4835
 
5401
4836
  /**
@@ -5416,12 +4851,12 @@ export default class CodeGenerator implements IOrchestrator {
5416
4851
 
5417
4852
  // Fallback to inline implementation (will be removed after migration)
5418
4853
  const name = ctx.IDENTIFIER().getText();
5419
- const prefix = this.context.currentScope
5420
- ? `${this.context.currentScope}_`
4854
+ const prefix = CodeGenState.currentScope
4855
+ ? `${CodeGenState.currentScope}_`
5421
4856
  : "";
5422
4857
  const fullName = `${prefix}${name}`;
5423
4858
 
5424
- const backingType = this.symbols!.bitmapBackingType.get(fullName);
4859
+ const backingType = CodeGenState.symbols!.bitmapBackingType.get(fullName);
5425
4860
  if (!backingType) {
5426
4861
  throw new Error(`Error: Bitmap ${fullName} not found in registry`);
5427
4862
  }
@@ -5433,7 +4868,7 @@ export default class CodeGenerator implements IOrchestrator {
5433
4868
  // Generate comment with field layout
5434
4869
  lines.push(`/* Bitmap: ${fullName} */`);
5435
4870
 
5436
- const fields = this.symbols!.bitmapFields.get(fullName);
4871
+ const fields = CodeGenState.symbols!.bitmapFields.get(fullName);
5437
4872
  if (fields) {
5438
4873
  lines.push("/* Fields:");
5439
4874
  for (const [fieldName, info] of fields.entries()) {
@@ -5467,7 +4902,7 @@ export default class CodeGenerator implements IOrchestrator {
5467
4902
  // Reject redundant type in struct initializer
5468
4903
  // Wrong: const Point p <- Point { x: 0 };
5469
4904
  // Right: const Point p <- { x: 0 };
5470
- if (ctx.IDENTIFIER() && this.context.expectedType) {
4905
+ if (ctx.IDENTIFIER() && CodeGenState.expectedType) {
5471
4906
  const explicitType = ctx.IDENTIFIER()!.getText();
5472
4907
  throw new Error(
5473
4908
  `Redundant type '${explicitType}' in struct initializer. ` +
@@ -5479,8 +4914,8 @@ export default class CodeGenerator implements IOrchestrator {
5479
4914
  let typeName: string;
5480
4915
  if (ctx.IDENTIFIER()) {
5481
4916
  typeName = ctx.IDENTIFIER()!.getText();
5482
- } else if (this.context.expectedType) {
5483
- typeName = this.context.expectedType;
4917
+ } else if (CodeGenState.expectedType) {
4918
+ typeName = CodeGenState.expectedType;
5484
4919
  } else {
5485
4920
  // This should not happen in valid code
5486
4921
  throw new Error(
@@ -5495,7 +4930,7 @@ export default class CodeGenerator implements IOrchestrator {
5495
4930
  // so designated initializers { .field = value } don't work with them.
5496
4931
  // We check the SymbolTable for a constructor symbol (TypeName::TypeName).
5497
4932
  const isCppClass =
5498
- this.cppMode && this._isCppClassWithConstructor(typeName);
4933
+ CodeGenState.cppMode && this._isCppClassWithConstructor(typeName);
5499
4934
 
5500
4935
  if (!fieldList) {
5501
4936
  // Empty initializer: Point {} -> (Point){ 0 } or {} for C++ classes
@@ -5504,13 +4939,13 @@ export default class CodeGenerator implements IOrchestrator {
5504
4939
 
5505
4940
  // Get field type info for nested initializers
5506
4941
  // Issue #502: Check both local struct fields and SymbolTable (for C++ header structs)
5507
- const structFieldTypes = this.symbols!.structFields.get(typeName);
4942
+ const structFieldTypes = CodeGenState.symbols!.structFields.get(typeName);
5508
4943
 
5509
4944
  const fields = fieldList.fieldInitializer().map((field) => {
5510
4945
  const fieldName = field.IDENTIFIER().getText();
5511
4946
 
5512
4947
  // Set expected type for nested initializers
5513
- const savedExpectedType = this.context.expectedType;
4948
+ const savedExpectedType = CodeGenState.expectedType;
5514
4949
  if (structFieldTypes?.has(fieldName)) {
5515
4950
  // Issue #502: Convert underscore format to correct output format
5516
4951
  // C-Next struct fields may store C++ types with _ separator (e.g., SeaDash_Parse_ParseResult)
@@ -5524,13 +4959,13 @@ export default class CodeGenerator implements IOrchestrator {
5524
4959
  fieldType = parts.join("::");
5525
4960
  }
5526
4961
  }
5527
- this.context.expectedType = fieldType;
4962
+ CodeGenState.expectedType = fieldType;
5528
4963
  }
5529
4964
 
5530
4965
  const value = this.generateExpression(field.expression());
5531
4966
 
5532
4967
  // Restore expected type
5533
- this.context.expectedType = savedExpectedType;
4968
+ CodeGenState.expectedType = savedExpectedType;
5534
4969
 
5535
4970
  return { fieldName, value };
5536
4971
  });
@@ -5538,7 +4973,9 @@ export default class CodeGenerator implements IOrchestrator {
5538
4973
  // Issue #517: For C++ classes, store assignments for later and return {}
5539
4974
  if (isCppClass) {
5540
4975
  for (const { fieldName, value } of fields) {
5541
- this.pendingCppClassAssignments.push(`${fieldName} = ${value};`);
4976
+ CodeGenState.pendingCppClassAssignments.push(
4977
+ `${fieldName} = ${value};`,
4978
+ );
5542
4979
  }
5543
4980
  return "{}";
5544
4981
  }
@@ -5562,8 +4999,8 @@ export default class CodeGenerator implements IOrchestrator {
5562
4999
  // Fill-all: [0*] -> {0}
5563
5000
  const fillValue = this.generateExpression(ctx.expression()!);
5564
5001
  // Store element count as 0 to signal fill-all (size comes from declaration)
5565
- this.context.lastArrayInitCount = 0;
5566
- this.context.lastArrayFillValue = fillValue;
5002
+ CodeGenState.lastArrayInitCount = 0;
5003
+ CodeGenState.lastArrayFillValue = fillValue;
5567
5004
  return `{${fillValue}}`;
5568
5005
  }
5569
5006
 
@@ -5587,8 +5024,8 @@ export default class CodeGenerator implements IOrchestrator {
5587
5024
  }
5588
5025
 
5589
5026
  // Store element count for size inference
5590
- this.context.lastArrayInitCount = generatedElements.length;
5591
- this.context.lastArrayFillValue = undefined;
5027
+ CodeGenState.lastArrayInitCount = generatedElements.length;
5028
+ CodeGenState.lastArrayFillValue = undefined;
5592
5029
 
5593
5030
  return `{${generatedElements.join(", ")}}`;
5594
5031
  }
@@ -5656,21 +5093,21 @@ export default class CodeGenerator implements IOrchestrator {
5656
5093
  ctx: Parser.FunctionDeclarationContext,
5657
5094
  ): void {
5658
5095
  // Issue #269: Set current function name for pass-by-value lookup
5659
- const fullFuncName = this.context.currentScope
5660
- ? `${this.context.currentScope}_${name}`
5096
+ const fullFuncName = CodeGenState.currentScope
5097
+ ? `${CodeGenState.currentScope}_${name}`
5661
5098
  : name;
5662
- this.context.currentFunctionName = fullFuncName;
5099
+ CodeGenState.currentFunctionName = fullFuncName;
5663
5100
  // Issue #477: Set return type for enum inference in return statements
5664
- this.context.currentFunctionReturnType = ctx.type().getText();
5101
+ CodeGenState.currentFunctionReturnType = ctx.type().getText();
5665
5102
 
5666
5103
  // Track parameters for ADR-006 pointer semantics
5667
5104
  this._setParameters(ctx.parameterList() ?? null);
5668
5105
 
5669
5106
  // 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;
5107
+ CodeGenState.localVariables.clear();
5108
+ CodeGenState.floatBitShadows.clear();
5109
+ CodeGenState.floatShadowCurrent.clear();
5110
+ CodeGenState.inFunctionBody = true;
5674
5111
  }
5675
5112
 
5676
5113
  /**
@@ -5685,7 +5122,7 @@ export default class CodeGenerator implements IOrchestrator {
5685
5122
  if (isMainWithArgs) {
5686
5123
  // Special case: main(u8 args[][]) -> int main(int argc, char *argv[])
5687
5124
  const argsParam = ctx.parameterList()!.parameter()[0];
5688
- this.context.mainArgsName = argsParam.IDENTIFIER().getText();
5125
+ CodeGenState.mainArgsName = argsParam.IDENTIFIER().getText();
5689
5126
  return {
5690
5127
  actualReturnType: "int",
5691
5128
  initialParams: "int argc, char *argv[]",
@@ -5701,13 +5138,13 @@ export default class CodeGenerator implements IOrchestrator {
5701
5138
  * Clean up context after function generation
5702
5139
  */
5703
5140
  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;
5141
+ CodeGenState.inFunctionBody = false;
5142
+ CodeGenState.localVariables.clear();
5143
+ CodeGenState.floatBitShadows.clear();
5144
+ CodeGenState.floatShadowCurrent.clear();
5145
+ CodeGenState.mainArgsName = null;
5146
+ CodeGenState.currentFunctionName = null;
5147
+ CodeGenState.currentFunctionReturnType = null;
5711
5148
  this._clearParameters();
5712
5149
  }
5713
5150
 
@@ -5737,8 +5174,8 @@ export default class CodeGenerator implements IOrchestrator {
5737
5174
  const dims = ctx.arrayDimension();
5738
5175
 
5739
5176
  // ADR-029: Check if this is a callback type parameter
5740
- if (this.callbackTypes.has(typeName)) {
5741
- const callbackInfo = this.callbackTypes.get(typeName)!;
5177
+ if (CodeGenState.callbackTypes.has(typeName)) {
5178
+ const callbackInfo = CodeGenState.callbackTypes.get(typeName)!;
5742
5179
  return `${callbackInfo.typedefName} ${name}`;
5743
5180
  }
5744
5181
 
@@ -5825,12 +5262,12 @@ export default class CodeGenerator implements IOrchestrator {
5825
5262
  // ISR, float, enum types
5826
5263
  if (typeName === "ISR") return true;
5827
5264
  if (this._isFloatType(typeName)) return true;
5828
- if (this.symbols!.knownEnums.has(typeName)) return true;
5265
+ if (CodeGenState.symbols!.knownEnums.has(typeName)) return true;
5829
5266
 
5830
5267
  // Small unmodified primitives
5831
5268
  if (
5832
- this.context.currentFunctionName &&
5833
- this._isParameterPassByValueByName(this.context.currentFunctionName, name)
5269
+ CodeGenState.currentFunctionName &&
5270
+ this._isParameterPassByValueByName(CodeGenState.currentFunctionName, name)
5834
5271
  ) {
5835
5272
  return true;
5836
5273
  }
@@ -5871,7 +5308,7 @@ export default class CodeGenerator implements IOrchestrator {
5871
5308
 
5872
5309
  const wasModified = this._isCurrentParameterModified(name);
5873
5310
  const autoConst = !wasModified && !constMod ? "const " : "";
5874
- const refOrPtr = this.cppHelper!.refOrPtr();
5311
+ const refOrPtr = CppModeHelper.refOrPtr();
5875
5312
  return `${autoConst}${constMod}${type}${refOrPtr} ${name}`;
5876
5313
  }
5877
5314
 
@@ -5889,24 +5326,39 @@ export default class CodeGenerator implements IOrchestrator {
5889
5326
  // Issue #696: Use helper for modifier extraction and validation
5890
5327
  const modifiers = VariableModifierBuilder.build(
5891
5328
  ctx,
5892
- this.context.inFunctionBody,
5329
+ CodeGenState.inFunctionBody,
5893
5330
  );
5894
5331
 
5895
5332
  const name = ctx.IDENTIFIER().getText();
5896
5333
  const typeCtx = ctx.type();
5334
+
5335
+ // Reject C-style array declarations (u16 arr[8]) - require C-Next style (u16[8] arr)
5336
+ this._validateArrayDeclarationSyntax(ctx, typeCtx, name);
5337
+
5897
5338
  const type = this._inferVariableType(ctx, name);
5898
5339
 
5899
5340
  // Track local variable metadata
5900
5341
  this._trackLocalVariable(ctx, name);
5901
5342
 
5902
5343
  // ADR-045: Handle bounded string type specially - early return
5903
- const stringResult = this.stringDeclHelper!.generateStringDecl(
5344
+ const stringResult = StringDeclHelper.generateStringDecl(
5904
5345
  typeCtx,
5905
5346
  name,
5906
5347
  ctx.expression() ?? null,
5907
5348
  ctx.arrayDimension(),
5908
5349
  modifiers,
5909
5350
  ctx.constModifier() !== null,
5351
+ {
5352
+ generateExpression: (exprCtx) => this.generateExpression(exprCtx),
5353
+ generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
5354
+ getStringConcatOperands: (concatCtx) =>
5355
+ this._getStringConcatOperands(concatCtx),
5356
+ getSubstringOperands: (substrCtx) =>
5357
+ this._getSubstringOperands(substrCtx),
5358
+ getStringExprCapacity: (exprCode) =>
5359
+ this.getStringExprCapacity(exprCode),
5360
+ requireStringInclude: () => this.requireInclude("string"),
5361
+ },
5910
5362
  );
5911
5363
  if (stringResult.handled) {
5912
5364
  return stringResult.code;
@@ -5965,24 +5417,25 @@ export default class CodeGenerator implements IOrchestrator {
5965
5417
  ctx: Parser.VariableDeclarationContext,
5966
5418
  name: string,
5967
5419
  ): void {
5968
- if (!this.context.inFunctionBody) {
5420
+ if (!CodeGenState.inFunctionBody) {
5969
5421
  return;
5970
5422
  }
5971
5423
 
5972
5424
  this.trackVariableType(ctx);
5973
- this.context.localVariables.add(name);
5425
+ CodeGenState.localVariables.add(name);
5974
5426
 
5975
5427
  // Bug #8: Track local const values for array size and bit index resolution
5976
5428
  if (ctx.constModifier() && ctx.expression()) {
5977
5429
  const constValue = this.tryEvaluateConstant(ctx.expression()!);
5978
5430
  if (constValue !== undefined) {
5979
- this.constValues.set(name, constValue);
5431
+ CodeGenState.constValues.set(name, constValue);
5980
5432
  }
5981
5433
  }
5982
5434
  }
5983
5435
 
5984
5436
  /**
5985
5437
  * Issue #696: Handle array declaration with dimension parsing and init.
5438
+ * Bug fix: Also handles C-Next style arrayType syntax (u16[8] myArray).
5986
5439
  */
5987
5440
  private _handleArrayDeclaration(
5988
5441
  ctx: Parser.VariableDeclarationContext,
@@ -5991,42 +5444,97 @@ export default class CodeGenerator implements IOrchestrator {
5991
5444
  decl: string,
5992
5445
  ): { handled: boolean; code: string; decl: string; isArray: boolean } {
5993
5446
  const arrayDims = ctx.arrayDimension();
5994
- const isArray = arrayDims.length > 0;
5447
+ const hasArrayTypeSyntax = typeCtx.arrayType() !== null;
5448
+ const isArray = arrayDims.length > 0 || hasArrayTypeSyntax;
5995
5449
 
5996
5450
  if (!isArray) {
5997
5451
  return { handled: false, code: "", decl, isArray: false };
5998
5452
  }
5999
5453
 
5454
+ // Generate dimension string from arrayType syntax (u16[8] myArray)
5455
+ const arrayTypeDimStr = this._getArrayTypeDimension(typeCtx);
5456
+
6000
5457
  const hasEmptyArrayDim = arrayDims.some((dim) => !dim.expression());
6001
- const declaredSize = this._parseFirstArrayDimension(arrayDims);
5458
+ const declaredSize =
5459
+ this._parseArrayTypeDimension(typeCtx) ??
5460
+ this._parseFirstArrayDimension(arrayDims);
6002
5461
 
6003
5462
  // ADR-035: Handle array initializers with size inference
6004
5463
  if (ctx.expression()) {
6005
- const arrayInitResult = this.arrayInitHelper!.processArrayInit(
5464
+ const arrayInitResult = ArrayInitHelper.processArrayInit(
6006
5465
  name,
6007
5466
  typeCtx,
6008
5467
  ctx.expression()!,
6009
5468
  arrayDims,
6010
5469
  hasEmptyArrayDim,
6011
5470
  declaredSize,
5471
+ {
5472
+ generateExpression: (exprCtx) => this.generateExpression(exprCtx),
5473
+ getTypeName: (typeCtxParam) => this.getTypeName(typeCtxParam),
5474
+ generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
5475
+ },
6012
5476
  );
6013
5477
  if (arrayInitResult) {
5478
+ // Track as local array for type resolution
5479
+ CodeGenState.localArrays.add(name);
5480
+ // Include arrayType dimension before arrayDimension dimensions
5481
+ const fullDimSuffix = arrayTypeDimStr + arrayInitResult.dimensionSuffix;
6014
5482
  return {
6015
5483
  handled: true,
6016
- code: `${decl}${arrayInitResult.dimensionSuffix} = ${arrayInitResult.initValue};`,
5484
+ code: `${decl}${fullDimSuffix} = ${arrayInitResult.initValue};`,
6017
5485
  decl,
6018
5486
  isArray: true,
6019
5487
  };
6020
5488
  }
6021
5489
  }
6022
5490
 
6023
- // Generate dimensions and track as local array
6024
- const newDecl = decl + this.generateArrayDimensions(arrayDims);
6025
- this.context.localArrays.add(name);
5491
+ // Generate dimensions: arrayType dimension first, then arrayDimension dimensions
5492
+ const newDecl =
5493
+ decl + arrayTypeDimStr + this.generateArrayDimensions(arrayDims);
5494
+ CodeGenState.localArrays.add(name);
6026
5495
 
6027
5496
  return { handled: false, code: "", decl: newDecl, isArray: true };
6028
5497
  }
6029
5498
 
5499
+ /**
5500
+ * Get array dimension string from arrayType syntax (u16[8] -> "[8]").
5501
+ * Evaluates const expressions to their numeric values for C compatibility.
5502
+ */
5503
+ private _getArrayTypeDimension(typeCtx: Parser.TypeContext): string {
5504
+ if (!typeCtx.arrayType()) {
5505
+ return "";
5506
+ }
5507
+ const sizeExpr = typeCtx.arrayType()!.expression();
5508
+ if (!sizeExpr) {
5509
+ return "[]";
5510
+ }
5511
+ // Try to evaluate as constant first (required for C file-scope arrays)
5512
+ const constValue = this.tryEvaluateConstant(sizeExpr);
5513
+ if (constValue !== undefined) {
5514
+ return `[${constValue}]`;
5515
+ }
5516
+ // Fall back to expression text (for macros, enums, etc.)
5517
+ return `[${this.generateExpression(sizeExpr)}]`;
5518
+ }
5519
+
5520
+ /**
5521
+ * Parse array dimension from arrayType syntax for size validation.
5522
+ */
5523
+ private _parseArrayTypeDimension(typeCtx: Parser.TypeContext): number | null {
5524
+ if (!typeCtx.arrayType()) {
5525
+ return null;
5526
+ }
5527
+ const sizeExpr = typeCtx.arrayType()!.expression();
5528
+ if (!sizeExpr) {
5529
+ return null;
5530
+ }
5531
+ const sizeText = sizeExpr.getText();
5532
+ if (/^\d+$/.exec(sizeText)) {
5533
+ return Number.parseInt(sizeText, 10);
5534
+ }
5535
+ return null;
5536
+ }
5537
+
6030
5538
  /**
6031
5539
  * Issue #696: Parse first array dimension for validation.
6032
5540
  */
@@ -6043,6 +5551,95 @@ export default class CodeGenerator implements IOrchestrator {
6043
5551
  return null;
6044
5552
  }
6045
5553
 
5554
+ /**
5555
+ * Validate array declaration syntax - reject C-style, require C-Next style.
5556
+ * C-style: u16 arr[8] (all dimensions after identifier) - REJECTED
5557
+ * C-Next style: u16[8] arr (first dimension in type) - REQUIRED
5558
+ * Multi-dim C-Next: u16[4] arr[2] (first in type, rest after) - ALLOWED
5559
+ * Exceptions (grammar limitations):
5560
+ * - Empty dimensions for size inference: u8 arr[] <- [...]
5561
+ * - Qualified types: SeaDash.Parse.Result arr[3] (no arrayType support)
5562
+ * - Scoped/global types: this.Type arr[3], global.Type arr[3]
5563
+ * - String types: string<N> arr[3]
5564
+ */
5565
+ private _validateArrayDeclarationSyntax(
5566
+ ctx: Parser.VariableDeclarationContext,
5567
+ typeCtx: Parser.TypeContext,
5568
+ name: string,
5569
+ ): void {
5570
+ const arrayDims = ctx.arrayDimension();
5571
+ if (arrayDims.length === 0) {
5572
+ return; // Not an array declaration
5573
+ }
5574
+
5575
+ // If type already has arrayType, additional dimensions are allowed (multi-dim)
5576
+ if (typeCtx.arrayType()) {
5577
+ return; // Valid C-Next style: u16[4] arr[2] → uint16_t arr[4][2]
5578
+ }
5579
+
5580
+ // Allow empty first dimension for size inference: u8 arr[] <- [1, 2, 3]
5581
+ // The grammar doesn't support u8[] arr syntax, so this is the only way
5582
+ if (arrayDims.length === 1 && !arrayDims[0].expression()) {
5583
+ return; // Size inference pattern allowed
5584
+ }
5585
+
5586
+ // Allow C-style for multi-dimensional arrays: u8 matrix[4][4]
5587
+ // The arrayType grammar only supports single dimension, so multi-dim needs C-style
5588
+ if (arrayDims.length > 1) {
5589
+ return; // Multi-dimensional arrays need C-style
5590
+ }
5591
+
5592
+ // Allow C-style for types that don't support arrayType syntax:
5593
+ // - Qualified types (Scope.Type, Namespace::Type)
5594
+ // - Scoped types (this.Type)
5595
+ // - Global types (global.Type)
5596
+ // - String types (string<N>)
5597
+ // - Bitmap types (code generator doesn't yet handle arrayType for bitmaps)
5598
+ if (
5599
+ typeCtx.qualifiedType() ||
5600
+ typeCtx.scopedType() ||
5601
+ typeCtx.globalType() ||
5602
+ typeCtx.stringType()
5603
+ ) {
5604
+ return; // Grammar limitation - these can't use arrayType
5605
+ }
5606
+
5607
+ // C-style array declaration detected - reject with helpful error
5608
+ const baseType = this._extractBaseTypeName(typeCtx);
5609
+ const dimensions = arrayDims
5610
+ .map((dim) => `[${dim.expression()?.getText() ?? ""}]`)
5611
+ .join("");
5612
+ const line = ctx.start?.line ?? 0;
5613
+ const col = ctx.start?.column ?? 0;
5614
+
5615
+ throw new Error(
5616
+ `${line}:${col} C-style array declaration is not allowed. ` +
5617
+ `Use '${baseType}${dimensions} ${name}' instead of '${baseType} ${name}${dimensions}'`,
5618
+ );
5619
+ }
5620
+
5621
+ /**
5622
+ * Extract base type name from type context for error messages.
5623
+ */
5624
+ private _extractBaseTypeName(typeCtx: Parser.TypeContext): string {
5625
+ if (typeCtx.primitiveType()) {
5626
+ return typeCtx.primitiveType()!.getText();
5627
+ }
5628
+ if (typeCtx.userType()) {
5629
+ return typeCtx.userType()!.getText();
5630
+ }
5631
+ if (typeCtx.arrayType()) {
5632
+ const arrCtx = typeCtx.arrayType()!;
5633
+ if (arrCtx.primitiveType()) {
5634
+ return arrCtx.primitiveType()!.getText();
5635
+ }
5636
+ if (arrCtx.userType()) {
5637
+ return arrCtx.userType()!.getText();
5638
+ }
5639
+ }
5640
+ return typeCtx.getText();
5641
+ }
5642
+
6046
5643
  /**
6047
5644
  * Issue #696: Generate variable initializer with validation.
6048
5645
  */
@@ -6058,17 +5655,17 @@ export default class CodeGenerator implements IOrchestrator {
6058
5655
  }
6059
5656
 
6060
5657
  const typeName = this.getTypeName(typeCtx);
6061
- const savedExpectedType = this.context.expectedType;
6062
- this.context.expectedType = typeName;
5658
+ const savedExpectedType = CodeGenState.expectedType;
5659
+ CodeGenState.expectedType = typeName;
6063
5660
 
6064
5661
  // ADR-017: Validate enum type for initialization
6065
- this.enumValidator!.validateEnumAssignment(typeName, ctx.expression()!);
5662
+ EnumAssignmentValidator.validateEnumAssignment(typeName, ctx.expression()!);
6066
5663
 
6067
5664
  // ADR-024: Validate integer literals and type conversions
6068
5665
  this._validateIntegerInitializer(ctx, typeName);
6069
5666
 
6070
5667
  const result = `${decl} = ${this.generateExpression(ctx.expression()!)}`;
6071
- this.context.expectedType = savedExpectedType;
5668
+ CodeGenState.expectedType = savedExpectedType;
6072
5669
 
6073
5670
  return result;
6074
5671
  }
@@ -6116,20 +5713,20 @@ export default class CodeGenerator implements IOrchestrator {
6116
5713
  name: string,
6117
5714
  decl: string,
6118
5715
  ): string {
6119
- if (this.pendingCppClassAssignments.length === 0) {
5716
+ if (CodeGenState.pendingCppClassAssignments.length === 0) {
6120
5717
  return `${decl};`;
6121
5718
  }
6122
5719
 
6123
- if (this.context.inFunctionBody) {
6124
- const assignments = this.pendingCppClassAssignments
5720
+ if (CodeGenState.inFunctionBody) {
5721
+ const assignments = CodeGenState.pendingCppClassAssignments
6125
5722
  .map((a) => `${name}.${a}`)
6126
5723
  .join("\n");
6127
- this.pendingCppClassAssignments = [];
5724
+ CodeGenState.pendingCppClassAssignments = [];
6128
5725
  return `${decl};\n${assignments}`;
6129
5726
  }
6130
5727
 
6131
5728
  // At global scope, we can't emit assignment statements.
6132
- this.pendingCppClassAssignments = [];
5729
+ CodeGenState.pendingCppClassAssignments = [];
6133
5730
  throw new Error(
6134
5731
  `Error: C++ class '${this.getTypeName(typeCtx)}' with constructor cannot use struct initializer ` +
6135
5732
  `syntax at global scope. Use constructor syntax or initialize fields separately.`,
@@ -6157,14 +5754,14 @@ export default class CodeGenerator implements IOrchestrator {
6157
5754
  const argName = argNode.getText();
6158
5755
 
6159
5756
  // Check if it exists in type registry
6160
- const typeInfo = this.context.typeRegistry.get(argName);
5757
+ const typeInfo = CodeGenState.typeRegistry.get(argName);
6161
5758
 
6162
5759
  // Also check scoped variables if inside a scope
6163
5760
  let scopedArgName = argName;
6164
5761
  let scopedTypeInfo = typeInfo;
6165
- if (!typeInfo && this.context.currentScope) {
6166
- scopedArgName = `${this.context.currentScope}_${argName}`;
6167
- scopedTypeInfo = this.context.typeRegistry.get(scopedArgName);
5762
+ if (!typeInfo && CodeGenState.currentScope) {
5763
+ scopedArgName = `${CodeGenState.currentScope}_${argName}`;
5764
+ scopedTypeInfo = CodeGenState.typeRegistry.get(scopedArgName);
6168
5765
  }
6169
5766
 
6170
5767
  if (!typeInfo && !scopedTypeInfo) {
@@ -6188,7 +5785,7 @@ export default class CodeGenerator implements IOrchestrator {
6188
5785
  }
6189
5786
 
6190
5787
  // Track the variable in type registry (as an external C++ type)
6191
- this.context.typeRegistry.set(name, {
5788
+ CodeGenState.typeRegistry.set(name, {
6192
5789
  baseType: type,
6193
5790
  bitWidth: 0, // Unknown for C++ types
6194
5791
  isArray: false,
@@ -6198,8 +5795,8 @@ export default class CodeGenerator implements IOrchestrator {
6198
5795
  });
6199
5796
 
6200
5797
  // Track as local variable if inside function body
6201
- if (this.context.inFunctionBody) {
6202
- this.context.localVariables.add(name);
5798
+ if (CodeGenState.inFunctionBody) {
5799
+ CodeGenState.localVariables.add(name);
6203
5800
  }
6204
5801
 
6205
5802
  return `${type} ${name}(${resolvedArgs.join(", ")});`;
@@ -6231,7 +5828,7 @@ export default class CodeGenerator implements IOrchestrator {
6231
5828
  * ADR-017: Enums initialize to first member
6232
5829
  */
6233
5830
  private _getEnumZeroValue(enumName: string, separator: string = "_"): string {
6234
- const members = this.symbols!.enumMembers.get(enumName);
5831
+ const members = CodeGenState.symbols!.enumMembers.get(enumName);
6235
5832
  if (!members) {
6236
5833
  return `(${enumName})0`;
6237
5834
  }
@@ -6264,8 +5861,8 @@ export default class CodeGenerator implements IOrchestrator {
6264
5861
  // ADR-016: Check for scoped types (this.Type)
6265
5862
  if (typeCtx.scopedType()) {
6266
5863
  const localName = typeCtx.scopedType()!.IDENTIFIER().getText();
6267
- const name = this.context.currentScope
6268
- ? `${this.context.currentScope}_${localName}`
5864
+ const name = CodeGenState.currentScope
5865
+ ? `${CodeGenState.currentScope}_${localName}`
6269
5866
  : localName;
6270
5867
  return { name, separator: "_", checkCppType: false };
6271
5868
  }
@@ -6312,7 +5909,7 @@ export default class CodeGenerator implements IOrchestrator {
6312
5909
  }
6313
5910
  // In C++ mode, unknown user types may have non-trivial constructors
6314
5911
  // Known structs (C-Next or C headers) are POD types where {0} works
6315
- return this.cppMode && !this.isKnownStruct(typeName);
5912
+ return CodeGenState.cppMode && !this.isKnownStruct(typeName);
6316
5913
  }
6317
5914
 
6318
5915
  /**
@@ -6329,11 +5926,11 @@ export default class CodeGenerator implements IOrchestrator {
6329
5926
  // ADR-109: Build handler dependencies for assignment dispatch
6330
5927
  private buildHandlerDeps(): IHandlerDeps {
6331
5928
  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,
5929
+ symbols: CodeGenState.symbols!,
5930
+ typeRegistry: CodeGenState.typeRegistry,
5931
+ currentScope: CodeGenState.currentScope,
5932
+ currentParameters: CodeGenState.currentParameters,
5933
+ targetCapabilities: CodeGenState.targetCapabilities,
6337
5934
  generateExpression: (ctx) => this.generateExpression(ctx),
6338
5935
  tryEvaluateConstant: (ctx) => this.tryEvaluateConstant(ctx),
6339
5936
  generateAssignmentTarget: (ctx) => this.generateAssignmentTarget(ctx),
@@ -6342,11 +5939,11 @@ export default class CodeGenerator implements IOrchestrator {
6342
5939
  getMemberTypeInfo: (structType, memberName) =>
6343
5940
  this.getMemberTypeInfo(structType, memberName),
6344
5941
  validateBitmapFieldLiteral: (expr, width, fieldName) =>
6345
- this.typeValidator!.validateBitmapFieldLiteral(expr, width, fieldName),
5942
+ TypeValidator.validateBitmapFieldLiteral(expr, width, fieldName),
6346
5943
  validateCrossScopeVisibility: (scopeName, memberName) =>
6347
5944
  this.validateCrossScopeVisibility(scopeName, memberName),
6348
5945
  checkArrayBounds: (arrayName, dimensions, indexExprs, line) =>
6349
- this.typeValidator!.checkArrayBounds(
5946
+ TypeValidator.checkArrayBounds(
6350
5947
  arrayName,
6351
5948
  [...dimensions],
6352
5949
  [...indexExprs],
@@ -6379,7 +5976,10 @@ export default class CodeGenerator implements IOrchestrator {
6379
5976
  bitIndex?: string;
6380
5977
  baseType?: string;
6381
5978
  } {
6382
- return this.memberChainAnalyzer!.analyze(targetCtx);
5979
+ // Issue #644: MemberChainAnalyzer is now static, pass generateExpression callback
5980
+ return MemberChainAnalyzer.analyze(targetCtx, (ctx) =>
5981
+ this.generateExpression(ctx),
5982
+ );
6383
5983
  }
6384
5984
 
6385
5985
  /**
@@ -6393,12 +5993,18 @@ export default class CodeGenerator implements IOrchestrator {
6393
5993
  width: string | null,
6394
5994
  value: string,
6395
5995
  ): string | null {
6396
- return this.floatBitHelper!.generateFloatBitWrite(
5996
+ // Issue #644: FloatBitHelper is now static, pass callbacks
5997
+ return FloatBitHelper.generateFloatBitWrite(
6397
5998
  name,
6398
5999
  typeInfo,
6399
6000
  bitIndex,
6400
6001
  width,
6401
6002
  value,
6003
+ {
6004
+ generateBitMask: (w, is64Bit) => this.generateBitMask(w, is64Bit),
6005
+ foldBooleanToInt: (expr) => this.foldBooleanToInt(expr),
6006
+ requireInclude: (header) => this.requireInclude(header),
6007
+ },
6402
6008
  );
6403
6009
  }
6404
6010
 
@@ -6408,22 +6014,23 @@ export default class CodeGenerator implements IOrchestrator {
6408
6014
 
6409
6015
  // Issue #644: Set expected type for inferred struct initializers and overflow behavior
6410
6016
  // Delegated to AssignmentExpectedTypeResolver helper
6411
- const savedExpectedType = this.context.expectedType;
6412
- const savedAssignmentContext = { ...this.context.assignmentContext };
6017
+ const savedExpectedType = CodeGenState.expectedType;
6018
+ const savedAssignmentContext = { ...CodeGenState.assignmentContext };
6413
6019
 
6414
- const resolved = this.expectedTypeResolver!.resolve(targetCtx);
6020
+ // Issue #644: AssignmentExpectedTypeResolver is now static
6021
+ const resolved = AssignmentExpectedTypeResolver.resolve(targetCtx);
6415
6022
  if (resolved.expectedType) {
6416
- this.context.expectedType = resolved.expectedType;
6023
+ CodeGenState.expectedType = resolved.expectedType;
6417
6024
  }
6418
6025
  if (resolved.assignmentContext) {
6419
- this.context.assignmentContext = resolved.assignmentContext;
6026
+ CodeGenState.assignmentContext = resolved.assignmentContext;
6420
6027
  }
6421
6028
 
6422
6029
  const value = this.generateExpression(ctx.expression());
6423
6030
 
6424
6031
  // Restore expected type and assignment context
6425
- this.context.expectedType = savedExpectedType;
6426
- this.context.assignmentContext = savedAssignmentContext;
6032
+ CodeGenState.expectedType = savedExpectedType;
6033
+ CodeGenState.assignmentContext = savedAssignmentContext;
6427
6034
 
6428
6035
  // Get the assignment operator and map to C equivalent
6429
6036
  const operatorCtx = ctx.assignmentOperator();
@@ -6433,29 +6040,27 @@ export default class CodeGenerator implements IOrchestrator {
6433
6040
 
6434
6041
  // Issue #644: Validate assignment (const, enum, integer, array bounds, callbacks)
6435
6042
  // Delegated to AssignmentValidator helper to reduce cognitive complexity
6436
- this.assignmentValidator!.validate(
6043
+ AssignmentValidator.validate(
6437
6044
  targetCtx,
6438
6045
  ctx.expression(),
6439
6046
  isCompound,
6440
6047
  ctx.start?.line ?? 0,
6048
+ {
6049
+ getExpressionType: (exprCtx) => this.getExpressionType(exprCtx),
6050
+ tryEvaluateConstant: (exprCtx) => this.tryEvaluateConstant(exprCtx),
6051
+ isCallbackTypeUsedAsFieldType: (name) =>
6052
+ this.isCallbackTypeUsedAsFieldType(name),
6053
+ },
6441
6054
  );
6442
6055
 
6443
6056
  // ADR-109: Dispatch to assignment handlers
6444
6057
  // Build context, classify, and dispatch - all patterns handled by handlers
6445
6058
  const assignCtx = buildAssignmentContext(ctx, {
6446
- typeRegistry: this.context.typeRegistry,
6059
+ typeRegistry: CodeGenState.typeRegistry,
6447
6060
  generateExpression: () => value,
6448
6061
  });
6449
6062
  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);
6063
+ const assignmentKind = AssignmentClassifier.classify(assignCtx);
6459
6064
  const handler = AssignmentHandlerRegistry.getHandler(assignmentKind);
6460
6065
  return handler(assignCtx, handlerDeps);
6461
6066
  }
@@ -6475,7 +6080,7 @@ export default class CodeGenerator implements IOrchestrator {
6475
6080
  cOp,
6476
6081
  value,
6477
6082
  typeInfo,
6478
- this.context.targetCapabilities,
6083
+ CodeGenState.targetCapabilities,
6479
6084
  );
6480
6085
  this.applyEffects(result.effects);
6481
6086
  return result.code;
@@ -6487,16 +6092,16 @@ export default class CodeGenerator implements IOrchestrator {
6487
6092
  private _buildSimpleIdentifierDeps(): ISimpleIdentifierDeps {
6488
6093
  return {
6489
6094
  getParameterInfo: (name: string) =>
6490
- this.context.currentParameters.get(name),
6095
+ CodeGenState.currentParameters.get(name),
6491
6096
  resolveParameter: (name: string, paramInfo: TParameterInfo) =>
6492
6097
  ParameterDereferenceResolver.resolve(
6493
6098
  name,
6494
6099
  paramInfo,
6495
6100
  this._buildParameterDereferenceDeps(),
6496
6101
  ),
6497
- isLocalVariable: (name: string) => this.context.localVariables.has(name),
6102
+ isLocalVariable: (name: string) => CodeGenState.localVariables.has(name),
6498
6103
  resolveBareIdentifier: (name: string, isLocal: boolean) =>
6499
- this.typeValidator!.resolveBareIdentifier(name, isLocal, (n: string) =>
6104
+ TypeValidator.resolveBareIdentifier(name, isLocal, (n: string) =>
6500
6105
  this.isKnownStruct(n),
6501
6106
  ),
6502
6107
  };
@@ -6522,7 +6127,7 @@ export default class CodeGenerator implements IOrchestrator {
6522
6127
  hasGlobal: boolean,
6523
6128
  hasThis: boolean,
6524
6129
  ): IPostfixChainDeps {
6525
- const paramInfo = this.context.currentParameters.get(firstId);
6130
+ const paramInfo = CodeGenState.currentParameters.get(firstId);
6526
6131
  const isStructParam = paramInfo?.isStruct ?? false;
6527
6132
  const isCppAccess = hasGlobal && this.isCppScopeSymbol(firstId);
6528
6133
  const separatorDeps = this._buildMemberSeparatorDeps();
@@ -6532,7 +6137,7 @@ export default class CodeGenerator implements IOrchestrator {
6532
6137
  firstId,
6533
6138
  hasGlobal,
6534
6139
  hasThis,
6535
- this.context.currentScope,
6140
+ CodeGenState.currentScope,
6536
6141
  isStructParam,
6537
6142
  separatorDeps,
6538
6143
  isCppAccess,
@@ -6556,37 +6161,7 @@ export default class CodeGenerator implements IOrchestrator {
6556
6161
  };
6557
6162
  }
6558
6163
 
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
- }
6164
+ // ADR-016: _validateCrossScopeVisibility moved to ScopeResolver
6590
6165
 
6591
6166
  // Issue #387: Dead methods removed (generateGlobalMemberAccess, generateGlobalArrayAccess,
6592
6167
  // generateThisMemberAccess, generateThisArrayAccess) - now handled by unified doGenerateAssignmentTarget
@@ -6672,7 +6247,7 @@ export default class CodeGenerator implements IOrchestrator {
6672
6247
  * ADR-016: 'this' returns a marker that postfixOps will transform to Scope_member
6673
6248
  */
6674
6249
  private _resolveThisKeyword(): string {
6675
- if (!this.context.currentScope) {
6250
+ if (!CodeGenState.currentScope) {
6676
6251
  throw new Error("Error: 'this' can only be used inside a scope");
6677
6252
  }
6678
6253
  return "__THIS_SCOPE__";
@@ -6684,12 +6259,12 @@ export default class CodeGenerator implements IOrchestrator {
6684
6259
  */
6685
6260
  private _resolveIdentifierExpression(id: string): string {
6686
6261
  // Special case: main function's args parameter -> argv
6687
- if (this.context.mainArgsName && id === this.context.mainArgsName) {
6262
+ if (CodeGenState.mainArgsName && id === CodeGenState.mainArgsName) {
6688
6263
  return "argv";
6689
6264
  }
6690
6265
 
6691
6266
  // ADR-006: Check if it's a function parameter
6692
- const paramInfo = this.context.currentParameters.get(id);
6267
+ const paramInfo = CodeGenState.currentParameters.get(id);
6693
6268
  if (paramInfo) {
6694
6269
  return ParameterDereferenceResolver.resolve(
6695
6270
  id,
@@ -6699,15 +6274,16 @@ export default class CodeGenerator implements IOrchestrator {
6699
6274
  }
6700
6275
 
6701
6276
  // ADR-016: Resolve bare identifier using local -> scope -> global priority
6702
- const isLocalVariable = this.context.localVariables.has(id);
6703
- const resolved = this.typeValidator!.resolveBareIdentifier(
6277
+ const isLocalVariable = CodeGenState.localVariables.has(id);
6278
+ const resolved = TypeValidator.resolveBareIdentifier(
6704
6279
  id,
6705
6280
  isLocalVariable,
6706
6281
  (name: string) => this.isKnownStruct(name),
6707
6282
  );
6708
6283
  if (resolved !== null) {
6709
6284
  // Issue #741: Check if this is a private const that should be inlined
6710
- const constValue = this.symbols!.scopePrivateConstValues.get(resolved);
6285
+ const constValue =
6286
+ CodeGenState.symbols!.scopePrivateConstValues.get(resolved);
6711
6287
  if (constValue !== undefined) {
6712
6288
  return constValue;
6713
6289
  }
@@ -6731,19 +6307,21 @@ export default class CodeGenerator implements IOrchestrator {
6731
6307
  private _resolveUnqualifiedEnumMember(id: string): string | null {
6732
6308
  // Type-aware resolution: check only the expected enum type
6733
6309
  if (
6734
- this.context.expectedType &&
6735
- this.symbols!.knownEnums.has(this.context.expectedType)
6310
+ CodeGenState.expectedType &&
6311
+ CodeGenState.symbols!.knownEnums.has(CodeGenState.expectedType)
6736
6312
  ) {
6737
- const members = this.symbols!.enumMembers.get(this.context.expectedType);
6313
+ const members = CodeGenState.symbols!.enumMembers.get(
6314
+ CodeGenState.expectedType,
6315
+ );
6738
6316
  if (members?.has(id)) {
6739
- return `${this.context.expectedType}${this.getScopeSeparator(false)}${id}`;
6317
+ return `${CodeGenState.expectedType}${this.getScopeSeparator(false)}${id}`;
6740
6318
  }
6741
6319
  return null;
6742
6320
  }
6743
6321
 
6744
6322
  // No expected enum type - search all enums but error on ambiguity
6745
6323
  const matchingEnums: string[] = [];
6746
- for (const [enumName, members] of this.symbols!.enumMembers) {
6324
+ for (const [enumName, members] of CodeGenState.symbols!.enumMembers) {
6747
6325
  if (members.has(id)) {
6748
6326
  matchingEnums.push(enumName);
6749
6327
  }
@@ -6771,7 +6349,7 @@ export default class CodeGenerator implements IOrchestrator {
6771
6349
 
6772
6350
  // Issue #304/#644: Transform NULL → nullptr in C++ mode
6773
6351
  if (result.code === "NULL") {
6774
- return this.cppHelper!.nullLiteral();
6352
+ return CppModeHelper.nullLiteral();
6775
6353
  }
6776
6354
 
6777
6355
  return result.code;
@@ -6837,7 +6415,7 @@ export default class CodeGenerator implements IOrchestrator {
6837
6415
  }
6838
6416
 
6839
6417
  // Issue #267/#644: Use C++ casts when cppMode is enabled for MISRA compliance
6840
- return this.cppHelper!.cast(targetType, expr);
6418
+ return CppModeHelper.cast(targetType, expr);
6841
6419
  }
6842
6420
 
6843
6421
  /**
@@ -6863,7 +6441,7 @@ export default class CodeGenerator implements IOrchestrator {
6863
6441
 
6864
6442
  if (!maxValue) {
6865
6443
  // Unknown type, fall back to raw cast - Issue #644
6866
- return this.cppHelper!.cast(targetType, expr);
6444
+ return CppModeHelper.cast(targetType, expr);
6867
6445
  }
6868
6446
 
6869
6447
  // Mark that we need limits.h for the type limit macros
@@ -6883,161 +6461,20 @@ export default class CodeGenerator implements IOrchestrator {
6883
6461
  // Generate clamping expression:
6884
6462
  // (expr > MAX) ? MAX : (expr < MIN) ? MIN : (type)(expr)
6885
6463
  // Note: For unsigned targets, MIN is 0 so we check < 0.0
6886
- const finalCast = this.cppHelper!.cast(targetType, `(${expr})`);
6464
+ const finalCast = CppModeHelper.cast(targetType, `(${expr})`);
6887
6465
  return `((${expr}) > ${maxComparison} ? ${maxValue} : (${expr}) < ${minComparison} ? ${minValue} : ${finalCast})`;
6888
6466
  }
6889
6467
 
6890
6468
  /**
6891
6469
  * 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
6470
+ * Delegates to SizeofResolver which uses CodeGenState.
6897
6471
  */
6898
6472
  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);
6473
+ return SizeofResolver.generate(ctx, {
6474
+ generateType: (typeCtx) => this.generateType(typeCtx),
6475
+ generateExpression: (exprCtx) => this.generateExpression(exprCtx),
6476
+ hasSideEffects: (exprCtx) => this.hasSideEffects(exprCtx),
6477
+ });
7041
6478
  }
7042
6479
 
7043
6480
  /**
@@ -7099,7 +6536,10 @@ export default class CodeGenerator implements IOrchestrator {
7099
6536
  * ADR-053 A5: Delegates to HelperGenerator
7100
6537
  */
7101
6538
  private generateOverflowHelpers(): string[] {
7102
- return helperGenerateOverflowHelpers(this.usedClampOps, this.debugMode);
6539
+ return helperGenerateOverflowHelpers(
6540
+ CodeGenState.usedClampOps,
6541
+ CodeGenState.debugMode,
6542
+ );
7103
6543
  }
7104
6544
 
7105
6545
  /**
@@ -7108,7 +6548,7 @@ export default class CodeGenerator implements IOrchestrator {
7108
6548
  private markClampOpUsed(operation: string, cnxType: string): void {
7109
6549
  // Only generate helpers for integer types (not float/bool)
7110
6550
  if (TYPE_WIDTH[cnxType] && TypeCheckUtils.isInteger(cnxType)) {
7111
- this.usedClampOps.add(`${operation}_${cnxType}`);
6551
+ CodeGenState.usedClampOps.add(`${operation}_${cnxType}`);
7112
6552
  }
7113
6553
  }
7114
6554
 
@@ -7144,7 +6584,7 @@ export default class CodeGenerator implements IOrchestrator {
7144
6584
  * Format leading comments with current indentation
7145
6585
  */
7146
6586
  private formatLeadingComments(comments: IComment[]): string[] {
7147
- const indent = FormatUtils.indent(this.context.indentLevel);
6587
+ const indent = FormatUtils.indent(CodeGenState.indentLevel);
7148
6588
  return commentFormatLeadingComments(
7149
6589
  comments,
7150
6590
  this.commentFormatter,
@@ -7157,6 +6597,6 @@ export default class CodeGenerator implements IOrchestrator {
7157
6597
  * ADR-053 A5: Delegates to HelperGenerator
7158
6598
  */
7159
6599
  private generateSafeDivHelpers(): string[] {
7160
- return helperGenerateSafeDivHelpers(this.usedSafeDivOps);
6600
+ return helperGenerateSafeDivHelpers(CodeGenState.usedSafeDivOps);
7161
6601
  }
7162
6602
  }