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.
- package/package.json +1 -1
- package/src/transpiler/Transpiler.ts +50 -51
- 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/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +32 -82
- package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +17 -61
- package/src/transpiler/output/codegen/CodeGenerator.ts +22 -59
- package/src/transpiler/output/codegen/TypeResolver.ts +2 -2
- package/src/transpiler/output/codegen/TypeValidator.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +5 -4
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +665 -1315
- package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +1 -1
- package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +1 -1
- package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +1 -1
- package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +1 -1
- package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +1 -1
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +1 -1
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +1 -1
- package/src/transpiler/output/codegen/assignment/handlers/AccessPatternHandlers.ts +24 -27
- package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +25 -18
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +27 -33
- package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +39 -42
- package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +39 -97
- package/src/transpiler/output/codegen/assignment/handlers/RegisterUtils.ts +75 -0
- package/src/transpiler/output/codegen/assignment/handlers/SimpleHandler.ts +9 -6
- package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +30 -22
- package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +42 -50
- package/src/transpiler/output/codegen/assignment/handlers/TAssignmentHandler.ts +6 -5
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +81 -134
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +85 -124
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +82 -124
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +135 -297
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +105 -227
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterUtils.test.ts +214 -1
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +66 -127
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/StringHandlers.test.ts +37 -83
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +162 -0
- 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/ArrayInitHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +1 -1
- package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +1 -1
- package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
- package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/MemberAccessValidator.ts +47 -6
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/MemberAccessValidator.test.ts +109 -3
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/types/ICodeGenApi.ts +57 -0
- package/src/transpiler/{output/codegen → state}/CodeGenState.ts +86 -26
- package/src/transpiler/{output/codegen → state}/__tests__/CodeGenState.test.ts +131 -2
- package/src/transpiler/logic/analysis/AnalyzerContextBuilder.ts +0 -58
- package/src/transpiler/logic/analysis/__tests__/AnalyzerContextBuilder.test.ts +0 -137
- package/src/transpiler/output/codegen/assignment/handlers/IHandlerDeps.ts +0 -161
package/package.json
CHANGED
|
@@ -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 "./
|
|
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
|
-
|
|
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(
|
|
341
|
-
|
|
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
|
|
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
|
-
|
|
435
|
-
this.
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
1154
|
+
const collector = new CppSymbolCollector(
|
|
1155
|
+
filePath,
|
|
1156
|
+
CodeGenState.symbolTable,
|
|
1157
|
+
);
|
|
1158
1158
|
const symbols = collector.collect(tree);
|
|
1159
|
-
|
|
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 =
|
|
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
|
-
|
|
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:
|
|
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
|
|
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
|
-
/**
|
|
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);
|