c-next 0.1.67 → 0.1.69

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 (33) hide show
  1. package/package.json +1 -1
  2. package/src/transpiler/Transpiler.ts +5 -13
  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/output/codegen/CodeGenerator.ts +125 -135
  8. package/src/transpiler/output/codegen/TypeValidator.ts +2 -2
  9. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +2 -2
  10. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +29 -1
  11. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +1 -3
  12. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +3 -1
  13. package/src/transpiler/output/codegen/assignment/AssignmentContextBuilder.ts +49 -0
  14. package/src/transpiler/output/codegen/assignment/IAssignmentContext.ts +15 -0
  15. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +7 -0
  16. package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +24 -17
  17. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +16 -5
  18. package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +9 -1
  19. package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +18 -1
  20. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +9 -1
  21. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +9 -1
  22. package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +10 -1
  23. package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +9 -1
  24. package/src/transpiler/output/codegen/assignment/handlers/__tests__/StringHandlers.test.ts +9 -1
  25. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +31 -10
  26. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +66 -4
  27. package/src/transpiler/output/codegen/helpers/MemberAccessValidator.ts +47 -6
  28. package/src/transpiler/output/codegen/helpers/MemberSeparatorResolver.ts +6 -1
  29. package/src/transpiler/output/codegen/helpers/__tests__/MemberAccessValidator.test.ts +109 -3
  30. package/src/transpiler/state/CodeGenState.ts +75 -1
  31. package/src/transpiler/state/__tests__/CodeGenState.test.ts +124 -5
  32. package/src/transpiler/logic/analysis/AnalyzerContextBuilder.ts +0 -58
  33. package/src/transpiler/logic/analysis/__tests__/AnalyzerContextBuilder.test.ts +0 -137
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c-next",
3
- "version": "0.1.67",
3
+ "version": "0.1.69",
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",
@@ -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";
@@ -247,7 +246,7 @@ class Transpiler {
247
246
  *
248
247
  * Both run() and transpileSource() delegate here after file discovery.
249
248
  *
250
- * Stage 2: Collect symbols from C/C++ headers
249
+ * Stage 2: Collect symbols from C/C++ headers (includes building analyzer context)
251
250
  * Stage 3: Collect symbols from C-Next files
252
251
  * Stage 3b: Resolve external const array dimensions
253
252
  * Stage 4: Check for symbol conflicts
@@ -258,8 +257,9 @@ class Transpiler {
258
257
  input: IPipelineInput,
259
258
  result: ITranspilerResult,
260
259
  ): Promise<void> {
261
- // Stage 2: Collect symbols from C/C++ headers
260
+ // Stage 2: Collect symbols from C/C++ headers and build analyzer context
262
261
  this._collectAllHeaderSymbols(input.headerFiles, result);
262
+ CodeGenState.buildExternalStructFields();
263
263
 
264
264
  // Stage 3: Collect symbols from C-Next files
265
265
  if (!this._collectAllCNextSymbolsFromPipeline(input.cnextFiles, result)) {
@@ -395,16 +395,8 @@ class Transpiler {
395
395
  return this.buildParseOnlyResult(sourcePath, declarationCount);
396
396
  }
397
397
 
398
- // Run analyzers
399
- const externalStructFields =
400
- AnalyzerContextBuilder.buildExternalStructFields(
401
- CodeGenState.symbolTable,
402
- );
403
-
404
- const analyzerErrors = runAnalyzers(tree, tokenStream, {
405
- externalStructFields,
406
- symbolTable: CodeGenState.symbolTable,
407
- });
398
+ // Run analyzers (reads externalStructFields and symbolTable from CodeGenState)
399
+ const analyzerErrors = runAnalyzers(tree, tokenStream);
408
400
  if (analyzerErrors.length > 0) {
409
401
  return this.buildErrorResult(
410
402
  sourcePath,
@@ -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);
@@ -2,12 +2,13 @@
2
2
  * Unit tests for runAnalyzers
3
3
  * Tests that all 8 analyzers run in sequence with early returns on errors
4
4
  */
5
- import { describe, it, expect } from "vitest";
5
+ import { describe, it, expect, beforeEach } from "vitest";
6
6
  import { CharStream, CommonTokenStream } from "antlr4ng";
7
7
  import { CNextLexer } from "../../parser/grammar/CNextLexer";
8
8
  import { CNextParser } from "../../parser/grammar/CNextParser";
9
9
  import runAnalyzers from "../runAnalyzers";
10
10
  import SymbolTable from "../../symbols/SymbolTable";
11
+ import CodeGenState from "../../../state/CodeGenState";
11
12
  import ESymbolKind from "../../../../utils/types/ESymbolKind";
12
13
  import ESourceLanguage from "../../../../utils/types/ESourceLanguage";
13
14
 
@@ -24,6 +25,12 @@ function parseWithStream(source: string) {
24
25
  }
25
26
 
26
27
  describe("runAnalyzers", () => {
28
+ // Reset CodeGenState before each test
29
+ beforeEach(() => {
30
+ CodeGenState.reset();
31
+ CodeGenState.symbolTable.clear();
32
+ });
33
+
27
34
  // ========================================================================
28
35
  // Happy Path
29
36
  // ========================================================================
@@ -206,24 +213,33 @@ describe("runAnalyzers", () => {
206
213
  });
207
214
 
208
215
  // ========================================================================
209
- // Options: externalStructFields and symbolTable
216
+ // Options: CodeGenState integration and symbolTable
210
217
  // ========================================================================
211
218
 
212
219
  describe("options", () => {
213
- it("should pass externalStructFields to InitializationAnalyzer", () => {
214
- // Code that uses a field from an external struct - the externalStructFields
215
- // option tells the analyzer about external struct types
220
+ it("should read externalStructFields from CodeGenState", () => {
221
+ // Code that uses a field from an external struct - externalStructFields
222
+ // are now read from CodeGenState
216
223
  const { tree, tokenStream } = parseWithStream(`
217
224
  void main() {
218
225
  u32 x <- 5;
219
226
  }
220
227
  `);
221
228
 
222
- const externalStructFields = new Map<string, Set<string>>([
223
- ["ExternalStruct", new Set(["field1", "field2"])],
224
- ]);
229
+ // Set up external struct fields in CodeGenState
230
+ CodeGenState.symbolTable.addStructField(
231
+ "ExternalStruct",
232
+ "field1",
233
+ "u32",
234
+ );
235
+ CodeGenState.symbolTable.addStructField(
236
+ "ExternalStruct",
237
+ "field2",
238
+ "u32",
239
+ );
240
+ CodeGenState.buildExternalStructFields();
225
241
 
226
- const errors = runAnalyzers(tree, tokenStream, { externalStructFields });
242
+ const errors = runAnalyzers(tree, tokenStream);
227
243
  expect(errors).toHaveLength(0);
228
244
  });
229
245
 
@@ -248,18 +264,15 @@ describe("runAnalyzers", () => {
248
264
  expect(errors).toHaveLength(0);
249
265
  });
250
266
 
251
- it("should pass both options together", () => {
267
+ it("should use CodeGenState.symbolTable by default", () => {
252
268
  const { tree, tokenStream } = parseWithStream(`
253
269
  void main() {
254
270
  u32 x <- 5;
255
271
  }
256
272
  `);
257
273
 
258
- const externalStructFields = new Map<string, Set<string>>([
259
- ["CppMessage", new Set(["pgn"])],
260
- ]);
261
- const symbolTable = new SymbolTable();
262
- symbolTable.addSymbol({
274
+ // Set up C++ class in CodeGenState.symbolTable
275
+ CodeGenState.symbolTable.addSymbol({
263
276
  name: "CppMessage",
264
277
  kind: ESymbolKind.Class,
265
278
  sourceLanguage: ESourceLanguage.Cpp,
@@ -267,11 +280,11 @@ describe("runAnalyzers", () => {
267
280
  sourceLine: 1,
268
281
  isExported: true,
269
282
  });
283
+ CodeGenState.symbolTable.addStructField("CppMessage", "pgn", "u16");
284
+ CodeGenState.buildExternalStructFields();
270
285
 
271
- const errors = runAnalyzers(tree, tokenStream, {
272
- externalStructFields,
273
- symbolTable,
274
- });
286
+ // No options passed - should use CodeGenState.symbolTable
287
+ const errors = runAnalyzers(tree, tokenStream);
275
288
  expect(errors).toHaveLength(0);
276
289
  });
277
290
  });
@@ -17,20 +17,16 @@ import FloatModuloAnalyzer from "./FloatModuloAnalyzer";
17
17
  import CommentExtractor from "./CommentExtractor";
18
18
  import ITranspileError from "../../../lib/types/ITranspileError";
19
19
  import SymbolTable from "../symbols/SymbolTable";
20
+ import CodeGenState from "../../state/CodeGenState";
20
21
 
21
22
  /**
22
23
  * Options for running analyzers
23
24
  */
24
25
  interface IAnalyzerOptions {
25
- /**
26
- * External struct field information from C/C++ headers
27
- * Maps struct name -> Set of field names
28
- */
29
- externalStructFields?: Map<string, Set<string>>;
30
-
31
26
  /**
32
27
  * Symbol table containing external function definitions from C/C++ headers
33
- * Used by FunctionCallAnalyzer to recognize external functions
28
+ * Used by FunctionCallAnalyzer to recognize external functions.
29
+ * Falls back to CodeGenState.symbolTable if not provided.
34
30
  */
35
31
  symbolTable?: SymbolTable;
36
32
  }
@@ -100,13 +96,11 @@ function runAnalyzers(
100
96
 
101
97
  // 3. Initialization analysis (Rust-style use-before-init detection)
102
98
  const initAnalyzer = new InitializationAnalyzer();
103
- if (options?.externalStructFields) {
104
- initAnalyzer.registerExternalStructFields(options.externalStructFields);
105
- }
106
- // Issue #503: Pass symbol table so C++ classes with default constructors are recognized
99
+ // External struct fields and symbolTable are read from CodeGenState directly
100
+ const symbolTable = options?.symbolTable ?? CodeGenState.symbolTable;
107
101
  if (
108
102
  collectErrors(
109
- initAnalyzer.analyze(tree, options?.symbolTable),
103
+ initAnalyzer.analyze(tree, symbolTable),
110
104
  errors,
111
105
  formatWithCode,
112
106
  )
@@ -115,10 +109,10 @@ function runAnalyzers(
115
109
  }
116
110
 
117
111
  // 4. Call analysis (ADR-030: define-before-use)
118
- const funcAnalyzer = new FunctionCallAnalyzer();
112
+ const callAnalyzer = new FunctionCallAnalyzer();
119
113
  if (
120
114
  collectErrors(
121
- funcAnalyzer.analyze(tree, options?.symbolTable),
115
+ callAnalyzer.analyze(tree, symbolTable),
122
116
  errors,
123
117
  formatWithCode,
124
118
  )