c-next 0.1.66 → 0.1.68

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 (70) hide show
  1. package/package.json +1 -1
  2. package/src/transpiler/Transpiler.ts +50 -51
  3. package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +41 -36
  4. package/src/transpiler/logic/analysis/__tests__/InitializationAnalyzer.test.ts +29 -28
  5. package/src/transpiler/logic/analysis/__tests__/runAnalyzers.test.ts +32 -19
  6. package/src/transpiler/logic/analysis/runAnalyzers.ts +8 -14
  7. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +32 -82
  8. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +17 -61
  9. package/src/transpiler/output/codegen/CodeGenerator.ts +22 -59
  10. package/src/transpiler/output/codegen/TypeResolver.ts +2 -2
  11. package/src/transpiler/output/codegen/TypeValidator.ts +1 -1
  12. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +5 -4
  13. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +665 -1315
  14. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +1 -1
  15. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +1 -1
  16. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +1 -1
  17. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +1 -1
  18. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +1 -1
  19. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +1 -1
  20. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +1 -1
  21. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +1 -1
  22. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +1 -1
  23. package/src/transpiler/output/codegen/assignment/handlers/AccessPatternHandlers.ts +24 -27
  24. package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +25 -18
  25. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +27 -33
  26. package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +39 -42
  27. package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +39 -97
  28. package/src/transpiler/output/codegen/assignment/handlers/RegisterUtils.ts +75 -0
  29. package/src/transpiler/output/codegen/assignment/handlers/SimpleHandler.ts +9 -6
  30. package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +30 -22
  31. package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +42 -50
  32. package/src/transpiler/output/codegen/assignment/handlers/TAssignmentHandler.ts +6 -5
  33. package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +81 -134
  34. package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +85 -124
  35. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +82 -124
  36. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +135 -297
  37. package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +105 -227
  38. package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterUtils.test.ts +214 -1
  39. package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +66 -127
  40. package/src/transpiler/output/codegen/assignment/handlers/__tests__/StringHandlers.test.ts +37 -83
  41. package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +162 -0
  42. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +31 -10
  43. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +66 -4
  44. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +1 -1
  45. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +1 -1
  46. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +1 -1
  47. package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +1 -1
  48. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
  49. package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +1 -1
  50. package/src/transpiler/output/codegen/helpers/MemberAccessValidator.ts +47 -6
  51. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +1 -1
  52. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +1 -1
  53. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +1 -1
  54. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +1 -1
  55. package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +1 -1
  56. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +1 -1
  57. package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +1 -1
  58. package/src/transpiler/output/codegen/helpers/__tests__/MemberAccessValidator.test.ts +109 -3
  59. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +1 -1
  60. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +1 -1
  61. package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +1 -1
  62. package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +1 -1
  63. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +1 -1
  64. package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +1 -1
  65. package/src/transpiler/output/codegen/types/ICodeGenApi.ts +57 -0
  66. package/src/transpiler/{output/codegen → state}/CodeGenState.ts +86 -26
  67. package/src/transpiler/{output/codegen → state}/__tests__/CodeGenState.test.ts +131 -2
  68. package/src/transpiler/logic/analysis/AnalyzerContextBuilder.ts +0 -58
  69. package/src/transpiler/logic/analysis/__tests__/AnalyzerContextBuilder.test.ts +0 -137
  70. package/src/transpiler/output/codegen/assignment/handlers/IHandlerDeps.ts +0 -161
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c-next",
3
- "version": "0.1.66",
3
+ "version": "0.1.68",
4
4
  "description": "A safer C for embedded systems development. Transpiles to clean, readable C.",
5
5
  "packageManager": "npm@11.9.0",
6
6
  "type": "module",
@@ -19,7 +19,7 @@ import CNextSourceParser from "./logic/parser/CNextSourceParser";
19
19
  import HeaderParser from "./logic/parser/HeaderParser";
20
20
 
21
21
  import CodeGenerator from "./output/codegen/CodeGenerator";
22
- import CodeGenState from "./output/codegen/CodeGenState";
22
+ import CodeGenState from "./state/CodeGenState";
23
23
  import HeaderGenerator from "./output/headers/HeaderGenerator";
24
24
  import ExternalTypeHeaderBuilder from "./output/headers/ExternalTypeHeaderBuilder";
25
25
  import ICodeGenSymbols from "./types/ICodeGenSymbols";
@@ -53,7 +53,6 @@ import ITranspileError from "../lib/types/ITranspileError";
53
53
  import TranspilerState from "./types/TranspilerState";
54
54
  import runAnalyzers from "./logic/analysis/runAnalyzers";
55
55
  import ModificationAnalyzer from "./logic/analysis/ModificationAnalyzer";
56
- import AnalyzerContextBuilder from "./logic/analysis/AnalyzerContextBuilder";
57
56
  import CacheManager from "../utils/cache/CacheManager";
58
57
  import MapUtils from "../utils/MapUtils";
59
58
  import detectCppSyntax from "./logic/detectCppSyntax";
@@ -65,7 +64,6 @@ import TransitiveEnumCollector from "./logic/symbols/TransitiveEnumCollector";
65
64
  */
66
65
  class Transpiler {
67
66
  private readonly config: Required<ITranspilerConfig>;
68
- private readonly symbolTable: SymbolTable;
69
67
  private readonly preprocessor: Preprocessor;
70
68
  private readonly codeGenerator: CodeGenerator;
71
69
  private readonly headerGenerator: HeaderGenerator;
@@ -108,7 +106,6 @@ class Transpiler {
108
106
  // Issue #211: Initialize cppDetected from config (--cpp flag sets this)
109
107
  this.cppDetected = this.config.cppRequired;
110
108
 
111
- this.symbolTable = new SymbolTable();
112
109
  this.preprocessor = new Preprocessor();
113
110
  this.codeGenerator = new CodeGenerator();
114
111
  this.headerGenerator = new HeaderGenerator();
@@ -249,7 +246,7 @@ class Transpiler {
249
246
  *
250
247
  * Both run() and transpileSource() delegate here after file discovery.
251
248
  *
252
- * Stage 2: Collect symbols from C/C++ headers
249
+ * Stage 2: Collect symbols from C/C++ headers (includes building analyzer context)
253
250
  * Stage 3: Collect symbols from C-Next files
254
251
  * Stage 3b: Resolve external const array dimensions
255
252
  * Stage 4: Check for symbol conflicts
@@ -260,8 +257,9 @@ class Transpiler {
260
257
  input: IPipelineInput,
261
258
  result: ITranspilerResult,
262
259
  ): Promise<void> {
263
- // Stage 2: Collect symbols from C/C++ headers
260
+ // Stage 2: Collect symbols from C/C++ headers and build analyzer context
264
261
  this._collectAllHeaderSymbols(input.headerFiles, result);
262
+ CodeGenState.buildExternalStructFields();
265
263
 
266
264
  // Stage 3: Collect symbols from C-Next files
267
265
  if (!this._collectAllCNextSymbolsFromPipeline(input.cnextFiles, result)) {
@@ -269,7 +267,7 @@ class Transpiler {
269
267
  }
270
268
 
271
269
  // Stage 3b: Resolve external const array dimensions
272
- this.symbolTable.resolveExternalArrayDimensions();
270
+ CodeGenState.symbolTable.resolveExternalArrayDimensions();
273
271
 
274
272
  // Stage 4: Check for symbol conflicts (skipped in standalone mode)
275
273
  if (!input.skipConflictCheck && !this._checkSymbolConflicts(result)) {
@@ -337,8 +335,11 @@ class Transpiler {
337
335
  try {
338
336
  // ADR-055: Use composable collectors via CNextResolver + TSymbolAdapter
339
337
  const tSymbols = CNextResolver.resolve(tree, file.path);
340
- const iSymbols = TSymbolAdapter.toISymbols(tSymbols, this.symbolTable);
341
- this.symbolTable.addSymbols(iSymbols);
338
+ const iSymbols = TSymbolAdapter.toISymbols(
339
+ tSymbols,
340
+ CodeGenState.symbolTable,
341
+ );
342
+ CodeGenState.symbolTable.addSymbols(iSymbols);
342
343
 
343
344
  // Issue #465: Store ICodeGenSymbols for external enum resolution in stage 5
344
345
  const symbolInfo = TSymbolInfoAdapter.convert(tSymbols);
@@ -394,14 +395,8 @@ class Transpiler {
394
395
  return this.buildParseOnlyResult(sourcePath, declarationCount);
395
396
  }
396
397
 
397
- // Run analyzers
398
- const externalStructFields =
399
- AnalyzerContextBuilder.buildExternalStructFields(this.symbolTable);
400
-
401
- const analyzerErrors = runAnalyzers(tree, tokenStream, {
402
- externalStructFields,
403
- symbolTable: this.symbolTable,
404
- });
398
+ // Run analyzers (reads externalStructFields and symbolTable from CodeGenState)
399
+ const analyzerErrors = runAnalyzers(tree, tokenStream);
405
400
  if (analyzerErrors.length > 0) {
406
401
  return this.buildErrorResult(
407
402
  sourcePath,
@@ -430,18 +425,13 @@ class Transpiler {
430
425
  this._setupCrossFileModifications();
431
426
 
432
427
  // Generate code
433
- const code = this.codeGenerator.generate(
434
- tree,
435
- this.symbolTable,
436
- tokenStream,
437
- {
438
- debugMode: this.config.debugMode,
439
- target: this.config.target,
440
- sourcePath,
441
- cppMode: this.cppDetected,
442
- symbolInfo,
443
- },
444
- );
428
+ const code = this.codeGenerator.generate(tree, tokenStream, {
429
+ debugMode: this.config.debugMode,
430
+ target: this.config.target,
431
+ sourcePath,
432
+ cppMode: this.cppDetected,
433
+ symbolInfo,
434
+ });
445
435
 
446
436
  // Collect user includes
447
437
  const userIncludes = IncludeExtractor.collectUserIncludes(tree);
@@ -461,7 +451,7 @@ class Transpiler {
461
451
  }
462
452
 
463
453
  // Update symbol parameters with auto-const info
464
- const symbols = this.symbolTable.getSymbolsByFile(sourcePath);
454
+ const symbols = CodeGenState.symbolTable.getSymbolsByFile(sourcePath);
465
455
  const unmodifiedParams = this.codeGenerator.getFunctionUnmodifiedParams();
466
456
  const knownEnums =
467
457
  this.state.getSymbolInfo(sourcePath)?.knownEnums ?? new Set<string>();
@@ -471,7 +461,6 @@ class Transpiler {
471
461
  const headerCode = this.generateHeaderContent(
472
462
  symbols,
473
463
  sourcePath,
474
- this.symbolTable,
475
464
  this.cppDetected,
476
465
  userIncludes,
477
466
  passByValueCopy,
@@ -631,7 +620,7 @@ class Transpiler {
631
620
  // Issue #587: Reset accumulated state for new run
632
621
  this.state.reset();
633
622
  // Issue #634: Reset symbol table for new run
634
- this.symbolTable.clear();
623
+ CodeGenState.symbolTable.clear();
635
624
  }
636
625
 
637
626
  /**
@@ -668,7 +657,7 @@ class Transpiler {
668
657
  * @returns true if no blocking conflicts, false otherwise
669
658
  */
670
659
  private _checkSymbolConflicts(result: ITranspilerResult): boolean {
671
- const conflicts = this.symbolTable.getConflicts();
660
+ const conflicts = CodeGenState.symbolTable.getConflicts();
672
661
  for (const conflict of conflicts) {
673
662
  result.conflicts.push(conflict.message);
674
663
  if (conflict.severity === "error") {
@@ -751,7 +740,7 @@ class Transpiler {
751
740
  if (warning) {
752
741
  result.warnings.push(warning);
753
742
  }
754
- result.symbolsCollected = this.symbolTable.size;
743
+ result.symbolsCollected = CodeGenState.symbolTable.size;
755
744
  result.warnings = [...result.warnings, ...this.warnings];
756
745
 
757
746
  if (this.cacheManager) {
@@ -1040,13 +1029,16 @@ class Transpiler {
1040
1029
 
1041
1030
  // Debug: Show symbols found
1042
1031
  if (this.config.debugMode) {
1043
- const symbols = this.symbolTable.getSymbolsByFile(file.path);
1032
+ const symbols = CodeGenState.symbolTable.getSymbolsByFile(file.path);
1044
1033
  console.log(`[DEBUG] Found ${symbols.length} symbols in ${file.path}`);
1045
1034
  }
1046
1035
 
1047
1036
  // Issue #590: Cache the results using simplified API
1048
1037
  if (this.cacheManager) {
1049
- this.cacheManager.setSymbolsFromTable(file.path, this.symbolTable);
1038
+ this.cacheManager.setSymbolsFromTable(
1039
+ file.path,
1040
+ CodeGenState.symbolTable,
1041
+ );
1050
1042
  }
1051
1043
  }
1052
1044
 
@@ -1065,10 +1057,12 @@ class Transpiler {
1065
1057
  }
1066
1058
 
1067
1059
  // Restore symbols, struct fields, needsStructKeyword, and enumBitWidth from cache
1068
- this.symbolTable.addSymbols(cached.symbols);
1069
- this.symbolTable.restoreStructFields(cached.structFields);
1070
- this.symbolTable.restoreNeedsStructKeyword(cached.needsStructKeyword);
1071
- this.symbolTable.restoreEnumBitWidths(cached.enumBitWidth);
1060
+ CodeGenState.symbolTable.addSymbols(cached.symbols);
1061
+ CodeGenState.symbolTable.restoreStructFields(cached.structFields);
1062
+ CodeGenState.symbolTable.restoreNeedsStructKeyword(
1063
+ cached.needsStructKeyword,
1064
+ );
1065
+ CodeGenState.symbolTable.restoreEnumBitWidths(cached.enumBitWidth);
1072
1066
 
1073
1067
  // Issue #211: Still check for C++ syntax even on cache hit
1074
1068
  this.detectCppFromFileType(file);
@@ -1140,10 +1134,13 @@ class Transpiler {
1140
1134
  private parsePureCHeader(content: string, filePath: string): void {
1141
1135
  const { tree } = HeaderParser.parseC(content);
1142
1136
  if (tree) {
1143
- const collector = new CSymbolCollector(filePath, this.symbolTable);
1137
+ const collector = new CSymbolCollector(
1138
+ filePath,
1139
+ CodeGenState.symbolTable,
1140
+ );
1144
1141
  const symbols = collector.collect(tree);
1145
1142
  if (symbols.length > 0) {
1146
- this.symbolTable.addSymbols(symbols);
1143
+ CodeGenState.symbolTable.addSymbols(symbols);
1147
1144
  }
1148
1145
  }
1149
1146
  }
@@ -1154,9 +1151,12 @@ class Transpiler {
1154
1151
  private parseCppHeader(content: string, filePath: string): void {
1155
1152
  const { tree } = HeaderParser.parseCpp(content);
1156
1153
  if (tree) {
1157
- const collector = new CppSymbolCollector(filePath, this.symbolTable);
1154
+ const collector = new CppSymbolCollector(
1155
+ filePath,
1156
+ CodeGenState.symbolTable,
1157
+ );
1158
1158
  const symbols = collector.collect(tree);
1159
- this.symbolTable.addSymbols(symbols);
1159
+ CodeGenState.symbolTable.addSymbols(symbols);
1160
1160
  }
1161
1161
  }
1162
1162
 
@@ -1168,7 +1168,7 @@ class Transpiler {
1168
1168
  * Stage 6: Generate header file for a C-Next file
1169
1169
  */
1170
1170
  private generateHeader(file: IDiscoveredFile): string | null {
1171
- const symbols = this.symbolTable.getSymbolsByFile(file.path);
1171
+ const symbols = CodeGenState.symbolTable.getSymbolsByFile(file.path);
1172
1172
  const exportedSymbols = symbols.filter((s) => s.isExported);
1173
1173
 
1174
1174
  if (exportedSymbols.length === 0) {
@@ -1199,12 +1199,12 @@ class Transpiler {
1199
1199
  // Issue #497: Build mapping from external types to their C header includes
1200
1200
  const externalTypeHeaders = ExternalTypeHeaderBuilder.build(
1201
1201
  this.state.getAllHeaderDirectives(),
1202
- this.symbolTable,
1202
+ CodeGenState.symbolTable,
1203
1203
  );
1204
1204
 
1205
1205
  // Issue #502: Include symbolTable in typeInput for C++ namespace type detection
1206
1206
  const typeInputWithSymbolTable = typeInput
1207
- ? { ...typeInput, symbolTable: this.symbolTable }
1207
+ ? { ...typeInput, symbolTable: CodeGenState.symbolTable }
1208
1208
  : undefined;
1209
1209
 
1210
1210
  const headerContent = this.headerGenerator.generate(
@@ -1274,7 +1274,6 @@ class Transpiler {
1274
1274
  private generateHeaderContent(
1275
1275
  symbols: ISymbol[],
1276
1276
  sourcePath: string,
1277
- symbolTable: SymbolTable,
1278
1277
  cppMode: boolean,
1279
1278
  userIncludes: string[],
1280
1279
  passByValueParams: Map<string, Set<string>>,
@@ -1318,12 +1317,12 @@ class Transpiler {
1318
1317
  // Issue #497: Build mapping from external types to their C header includes
1319
1318
  const externalTypeHeaders = ExternalTypeHeaderBuilder.build(
1320
1319
  this.state.getAllHeaderDirectives(),
1321
- symbolTable,
1320
+ CodeGenState.symbolTable,
1322
1321
  );
1323
1322
 
1324
1323
  // Issue #502: Include symbolTable in typeInput for C++ namespace type detection
1325
1324
  const typeInputWithSymbolTable = typeInput
1326
- ? { ...typeInput, symbolTable }
1325
+ ? { ...typeInput, symbolTable: CodeGenState.symbolTable }
1327
1326
  : undefined;
1328
1327
 
1329
1328
  // Issue #478: Pass all known enums for cross-file type handling
@@ -1429,7 +1428,7 @@ class Transpiler {
1429
1428
  * Get the symbol table (for testing/inspection)
1430
1429
  */
1431
1430
  getSymbolTable(): SymbolTable {
1432
- return this.symbolTable;
1431
+ return CodeGenState.symbolTable;
1433
1432
  }
1434
1433
 
1435
1434
  /**
@@ -21,6 +21,7 @@ import ExpressionUtils from "../../../utils/ExpressionUtils";
21
21
  import ParserUtils from "../../../utils/ParserUtils";
22
22
  import analyzePostfixOps from "../../../utils/PostfixAnalysisUtils";
23
23
  import SymbolTable from "../symbols/SymbolTable";
24
+ import CodeGenState from "../../state/CodeGenState";
24
25
  import ESourceLanguage from "../../../utils/types/ESourceLanguage";
25
26
  import ESymbolKind from "../../../utils/types/ESymbolKind";
26
27
 
@@ -408,8 +409,11 @@ class InitializationAnalyzer {
408
409
 
409
410
  private scopeStack: ScopeStack<IVariableState> = new ScopeStack();
410
411
 
411
- /** Known struct types and their fields */
412
- private readonly structFields: Map<string, Set<string>> = new Map();
412
+ /**
413
+ * C-Next struct fields from current file (collected at analysis time).
414
+ * External struct fields from C/C++ headers are accessed via CodeGenState.
415
+ */
416
+ private cnextStructFields: Map<string, Set<string>> = new Map();
413
417
 
414
418
  /** Track if we're processing a write target (left side of assignment) */
415
419
  private inWriteContext: boolean = false;
@@ -418,17 +422,25 @@ class InitializationAnalyzer {
418
422
  private symbolTable: SymbolTable | null = null;
419
423
 
420
424
  /**
421
- * Register external struct fields from C/C++ headers
422
- * This allows the analyzer to recognize types defined in headers
423
- *
424
- * @param externalFields Map of struct name -> Set of field names
425
+ * Get struct fields for a given struct type.
426
+ * Checks C-Next structs first, then falls back to CodeGenState for external structs.
425
427
  */
426
- public registerExternalStructFields(
427
- externalFields: Map<string, Set<string>>,
428
- ): void {
429
- for (const [structName, fields] of externalFields) {
430
- this.structFields.set(structName, fields);
428
+ private getStructFields(structName: string): Set<string> | undefined {
429
+ // Check C-Next structs from current file first
430
+ const cnextFields = this.cnextStructFields.get(structName);
431
+ if (cnextFields) {
432
+ return cnextFields;
431
433
  }
434
+
435
+ // Check external structs from CodeGenState
436
+ return CodeGenState.getExternalStructFields().get(structName);
437
+ }
438
+
439
+ /**
440
+ * Check if a type name is a known struct.
441
+ */
442
+ private isKnownStruct(typeName: string): boolean {
443
+ return this.getStructFields(typeName) !== undefined;
432
444
  }
433
445
 
434
446
  /**
@@ -469,9 +481,10 @@ class InitializationAnalyzer {
469
481
  this.errors = [];
470
482
  this.scopeStack = new ScopeStack();
471
483
  this.symbolTable = symbolTable ?? null;
472
- // Don't clear structFields - external fields may have been registered
484
+ // Clear C-Next struct fields from previous analysis (external fields come from CodeGenState)
485
+ this.cnextStructFields = new Map();
473
486
 
474
- // First pass: collect struct definitions
487
+ // First pass: collect struct definitions from current file
475
488
  this.collectStructDefinitions(tree);
476
489
 
477
490
  // Create global scope with all global/namespace variable declarations
@@ -553,7 +566,8 @@ class InitializationAnalyzer {
553
566
  }
554
567
 
555
568
  /**
556
- * Collect struct definitions to know their fields
569
+ * Collect struct definitions from current file to know their fields.
570
+ * This supplements the external struct fields from CodeGenState.
557
571
  */
558
572
  private collectStructDefinitions(tree: Parser.ProgramContext): void {
559
573
  for (const decl of tree.declaration()) {
@@ -567,7 +581,7 @@ class InitializationAnalyzer {
567
581
  fields.add(fieldName);
568
582
  }
569
583
 
570
- this.structFields.set(structName, fields);
584
+ this.cnextStructFields.set(structName, fields);
571
585
  }
572
586
  }
573
587
  }
@@ -610,9 +624,9 @@ class InitializationAnalyzer {
610
624
  this.enterScope();
611
625
  }
612
626
 
613
- const isStruct = typeName !== null && this.structFields.has(typeName);
627
+ const isStruct = typeName !== null && this.isKnownStruct(typeName);
614
628
  const fields = isStruct
615
- ? this.structFields.get(typeName)!
629
+ ? this.getStructFields(typeName)!
616
630
  : new Set<string>();
617
631
 
618
632
  // Issue #503: C++ classes with default constructors are automatically initialized
@@ -637,13 +651,11 @@ class InitializationAnalyzer {
637
651
  * SonarCloud S3776: Refactored to use helper methods.
638
652
  */
639
653
  public recordAssignment(name: string, field?: string): void {
640
- const structFields = this.structFields;
641
-
642
654
  this.scopeStack.update(name, (state) => {
643
655
  if (field) {
644
- this.recordFieldAssignment(state, field, structFields);
656
+ this.recordFieldAssignment(state, field);
645
657
  } else {
646
- this.recordWholeAssignment(state, structFields);
658
+ this.recordWholeAssignment(state);
647
659
  }
648
660
  return state;
649
661
  });
@@ -652,16 +664,12 @@ class InitializationAnalyzer {
652
664
  /**
653
665
  * Handle field-level assignment.
654
666
  */
655
- private recordFieldAssignment(
656
- state: IVariableState,
657
- field: string,
658
- structFields: Map<string, Set<string>>,
659
- ): void {
667
+ private recordFieldAssignment(state: IVariableState, field: string): void {
660
668
  state.initializedFields.add(field);
661
669
  // Check if all fields are now initialized
662
670
  if (!state.isStruct || !state.typeName) return;
663
671
 
664
- const allFields = structFields.get(state.typeName);
672
+ const allFields = this.getStructFields(state.typeName);
665
673
  if (!allFields) return;
666
674
 
667
675
  const allInitialized = [...allFields].every((f) =>
@@ -675,15 +683,12 @@ class InitializationAnalyzer {
675
683
  /**
676
684
  * Handle whole-variable assignment.
677
685
  */
678
- private recordWholeAssignment(
679
- state: IVariableState,
680
- structFields: Map<string, Set<string>>,
681
- ): void {
686
+ private recordWholeAssignment(state: IVariableState): void {
682
687
  state.initialized = true;
683
688
  // Mark all fields as initialized too
684
689
  if (!state.isStruct || !state.typeName) return;
685
690
 
686
- const fields = structFields.get(state.typeName);
691
+ const fields = this.getStructFields(state.typeName);
687
692
  if (fields) {
688
693
  state.initializedFields = new Set(fields);
689
694
  }
@@ -745,8 +750,8 @@ class InitializationAnalyzer {
745
750
  field: string,
746
751
  state: IVariableState,
747
752
  ): void {
748
- const structFields = this.structFields.get(state.typeName!);
749
- if (!structFields?.has(field)) return;
753
+ const structFieldSet = this.getStructFields(state.typeName!);
754
+ if (!structFieldSet?.has(field)) return;
750
755
 
751
756
  if (!state.initializedFields.has(field)) {
752
757
  this.addError(`${name}.${field}`, line, column, state.declaration, false);
@@ -874,9 +879,9 @@ class InitializationAnalyzer {
874
879
  this.enterScope();
875
880
  }
876
881
 
877
- const isStruct = typeName !== null && this.structFields.has(typeName);
882
+ const isStruct = typeName !== null && this.isKnownStruct(typeName);
878
883
  const fields = isStruct
879
- ? this.structFields.get(typeName)!
884
+ ? this.getStructFields(typeName)!
880
885
  : new Set<string>();
881
886
 
882
887
  const state: IVariableState = {
@@ -4,11 +4,12 @@
4
4
  */
5
5
 
6
6
  import { CharStream, CommonTokenStream } from "antlr4ng";
7
- import { describe, expect, it } from "vitest";
7
+ import { describe, expect, it, beforeEach } from "vitest";
8
8
  import { CNextLexer } from "../../parser/grammar/CNextLexer";
9
9
  import { CNextParser } from "../../parser/grammar/CNextParser";
10
10
  import InitializationAnalyzer from "../InitializationAnalyzer";
11
11
  import SymbolTable from "../../symbols/SymbolTable";
12
+ import CodeGenState from "../../../state/CodeGenState";
12
13
  import ESymbolKind from "../../../../utils/types/ESymbolKind";
13
14
  import ESourceLanguage from "../../../../utils/types/ESourceLanguage";
14
15
 
@@ -24,6 +25,12 @@ function parse(source: string) {
24
25
  }
25
26
 
26
27
  describe("InitializationAnalyzer", () => {
28
+ // Reset CodeGenState before each test
29
+ beforeEach(() => {
30
+ CodeGenState.reset();
31
+ CodeGenState.symbolTable.clear();
32
+ });
33
+
27
34
  // ========================================================================
28
35
  // Issue #503: C++ Class Initialization
29
36
  // ========================================================================
@@ -38,9 +45,8 @@ describe("InitializationAnalyzer", () => {
38
45
  `;
39
46
  const tree = parse(code);
40
47
 
41
- // Create symbol table with C++ class
42
- const symbolTable = new SymbolTable();
43
- symbolTable.addSymbol({
48
+ // Set up CodeGenState with C++ class
49
+ CodeGenState.symbolTable.addSymbol({
44
50
  name: "CppMessage",
45
51
  kind: ESymbolKind.Class,
46
52
  sourceLanguage: ESourceLanguage.Cpp,
@@ -49,14 +55,13 @@ describe("InitializationAnalyzer", () => {
49
55
  isExported: true,
50
56
  });
51
57
  // Add the field so the analyzer knows about it
52
- symbolTable.addStructField("CppMessage", "pgn", "u16");
58
+ CodeGenState.symbolTable.addStructField("CppMessage", "pgn", "u16");
53
59
 
54
- const analyzer = new InitializationAnalyzer();
55
- analyzer.registerExternalStructFields(
56
- new Map([["CppMessage", new Set(["pgn"])]]),
57
- );
60
+ // Build external struct fields from symbol table
61
+ CodeGenState.buildExternalStructFields();
58
62
 
59
- const errors = analyzer.analyze(tree, symbolTable);
63
+ const analyzer = new InitializationAnalyzer();
64
+ const errors = analyzer.analyze(tree, CodeGenState.symbolTable);
60
65
 
61
66
  // Should have NO errors - C++ class is initialized by constructor
62
67
  expect(errors).toHaveLength(0);
@@ -95,9 +100,8 @@ describe("InitializationAnalyzer", () => {
95
100
  `;
96
101
  const tree = parse(code);
97
102
 
98
- // Create symbol table with C++ struct (not class)
99
- const symbolTable = new SymbolTable();
100
- symbolTable.addSymbol({
103
+ // Set up CodeGenState with C++ struct (not class)
104
+ CodeGenState.symbolTable.addSymbol({
101
105
  name: "CppStruct",
102
106
  kind: ESymbolKind.Struct,
103
107
  sourceLanguage: ESourceLanguage.Cpp,
@@ -105,14 +109,13 @@ describe("InitializationAnalyzer", () => {
105
109
  sourceLine: 1,
106
110
  isExported: true,
107
111
  });
108
- symbolTable.addStructField("CppStruct", "value", "u32");
112
+ CodeGenState.symbolTable.addStructField("CppStruct", "value", "u32");
109
113
 
110
- const analyzer = new InitializationAnalyzer();
111
- analyzer.registerExternalStructFields(
112
- new Map([["CppStruct", new Set(["value"])]]),
113
- );
114
+ // Build external struct fields from symbol table
115
+ CodeGenState.buildExternalStructFields();
114
116
 
115
- const errors = analyzer.analyze(tree, symbolTable);
117
+ const analyzer = new InitializationAnalyzer();
118
+ const errors = analyzer.analyze(tree, CodeGenState.symbolTable);
116
119
 
117
120
  // Should have NO errors - C++ structs also have default constructors
118
121
  expect(errors).toHaveLength(0);
@@ -127,9 +130,8 @@ describe("InitializationAnalyzer", () => {
127
130
  `;
128
131
  const tree = parse(code);
129
132
 
130
- // Create symbol table with C struct (not C++)
131
- const symbolTable = new SymbolTable();
132
- symbolTable.addSymbol({
133
+ // Set up CodeGenState with C struct (not C++)
134
+ CodeGenState.symbolTable.addSymbol({
133
135
  name: "CStruct",
134
136
  kind: ESymbolKind.Struct,
135
137
  sourceLanguage: ESourceLanguage.C,
@@ -137,14 +139,13 @@ describe("InitializationAnalyzer", () => {
137
139
  sourceLine: 1,
138
140
  isExported: true,
139
141
  });
140
- symbolTable.addStructField("CStruct", "value", "u32");
142
+ CodeGenState.symbolTable.addStructField("CStruct", "value", "u32");
141
143
 
142
- const analyzer = new InitializationAnalyzer();
143
- analyzer.registerExternalStructFields(
144
- new Map([["CStruct", new Set(["value"])]]),
145
- );
144
+ // Build external struct fields from symbol table (as pipeline does)
145
+ CodeGenState.buildExternalStructFields();
146
146
 
147
- const errors = analyzer.analyze(tree, symbolTable);
147
+ const analyzer = new InitializationAnalyzer();
148
+ const errors = analyzer.analyze(tree, CodeGenState.symbolTable);
148
149
 
149
150
  // SHOULD have an error - C structs don't have constructors
150
151
  expect(errors.length).toBeGreaterThan(0);