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.
- package/package.json +1 -1
- package/src/transpiler/Transpiler.ts +5 -13
- package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +41 -36
- package/src/transpiler/logic/analysis/__tests__/InitializationAnalyzer.test.ts +29 -28
- package/src/transpiler/logic/analysis/__tests__/runAnalyzers.test.ts +32 -19
- package/src/transpiler/logic/analysis/runAnalyzers.ts +8 -14
- package/src/transpiler/output/codegen/CodeGenerator.ts +125 -135
- package/src/transpiler/output/codegen/TypeValidator.ts +2 -2
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +2 -2
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +29 -1
- package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +1 -3
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +3 -1
- package/src/transpiler/output/codegen/assignment/AssignmentContextBuilder.ts +49 -0
- package/src/transpiler/output/codegen/assignment/IAssignmentContext.ts +15 -0
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +7 -0
- package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +24 -17
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +16 -5
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +9 -1
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +18 -1
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +9 -1
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +9 -1
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +10 -1
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +9 -1
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/StringHandlers.test.ts +9 -1
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +31 -10
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +66 -4
- package/src/transpiler/output/codegen/helpers/MemberAccessValidator.ts +47 -6
- package/src/transpiler/output/codegen/helpers/MemberSeparatorResolver.ts +6 -1
- package/src/transpiler/output/codegen/helpers/__tests__/MemberAccessValidator.test.ts +109 -3
- package/src/transpiler/state/CodeGenState.ts +75 -1
- package/src/transpiler/state/__tests__/CodeGenState.test.ts +124 -5
- package/src/transpiler/logic/analysis/AnalyzerContextBuilder.ts +0 -58
- package/src/transpiler/logic/analysis/__tests__/AnalyzerContextBuilder.test.ts +0 -137
package/package.json
CHANGED
|
@@ -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
|
|
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
|
-
/**
|
|
412
|
-
|
|
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
|
-
*
|
|
422
|
-
*
|
|
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
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
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
|
-
//
|
|
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.
|
|
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.
|
|
627
|
+
const isStruct = typeName !== null && this.isKnownStruct(typeName);
|
|
614
628
|
const fields = isStruct
|
|
615
|
-
? this.
|
|
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
|
|
656
|
+
this.recordFieldAssignment(state, field);
|
|
645
657
|
} else {
|
|
646
|
-
this.recordWholeAssignment(state
|
|
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 =
|
|
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 =
|
|
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
|
|
749
|
-
if (!
|
|
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.
|
|
882
|
+
const isStruct = typeName !== null && this.isKnownStruct(typeName);
|
|
878
883
|
const fields = isStruct
|
|
879
|
-
? this.
|
|
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
|
-
//
|
|
42
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
new Map([["CppMessage", new Set(["pgn"])]]),
|
|
57
|
-
);
|
|
60
|
+
// Build external struct fields from symbol table
|
|
61
|
+
CodeGenState.buildExternalStructFields();
|
|
58
62
|
|
|
59
|
-
const
|
|
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
|
-
//
|
|
99
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
new Map([["CppStruct", new Set(["value"])]]),
|
|
113
|
-
);
|
|
114
|
+
// Build external struct fields from symbol table
|
|
115
|
+
CodeGenState.buildExternalStructFields();
|
|
114
116
|
|
|
115
|
-
const
|
|
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
|
-
//
|
|
131
|
-
|
|
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
|
-
|
|
143
|
-
|
|
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
|
|
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:
|
|
216
|
+
// Options: CodeGenState integration and symbolTable
|
|
210
217
|
// ========================================================================
|
|
211
218
|
|
|
212
219
|
describe("options", () => {
|
|
213
|
-
it("should
|
|
214
|
-
// Code that uses a field from an external struct -
|
|
215
|
-
//
|
|
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
|
-
|
|
223
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
259
|
-
|
|
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
|
-
|
|
272
|
-
|
|
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
|
-
|
|
104
|
-
|
|
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,
|
|
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
|
|
112
|
+
const callAnalyzer = new FunctionCallAnalyzer();
|
|
119
113
|
if (
|
|
120
114
|
collectErrors(
|
|
121
|
-
|
|
115
|
+
callAnalyzer.analyze(tree, symbolTable),
|
|
122
116
|
errors,
|
|
123
117
|
formatWithCode,
|
|
124
118
|
)
|