c-next 0.1.66 → 0.1.67
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 +49 -42
- 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/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/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__/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 +46 -26
- package/src/transpiler/{output/codegen → state}/__tests__/CodeGenState.test.ts +12 -2
- 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";
|
|
@@ -65,7 +65,6 @@ import TransitiveEnumCollector from "./logic/symbols/TransitiveEnumCollector";
|
|
|
65
65
|
*/
|
|
66
66
|
class Transpiler {
|
|
67
67
|
private readonly config: Required<ITranspilerConfig>;
|
|
68
|
-
private readonly symbolTable: SymbolTable;
|
|
69
68
|
private readonly preprocessor: Preprocessor;
|
|
70
69
|
private readonly codeGenerator: CodeGenerator;
|
|
71
70
|
private readonly headerGenerator: HeaderGenerator;
|
|
@@ -108,7 +107,6 @@ class Transpiler {
|
|
|
108
107
|
// Issue #211: Initialize cppDetected from config (--cpp flag sets this)
|
|
109
108
|
this.cppDetected = this.config.cppRequired;
|
|
110
109
|
|
|
111
|
-
this.symbolTable = new SymbolTable();
|
|
112
110
|
this.preprocessor = new Preprocessor();
|
|
113
111
|
this.codeGenerator = new CodeGenerator();
|
|
114
112
|
this.headerGenerator = new HeaderGenerator();
|
|
@@ -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);
|
|
@@ -396,11 +397,13 @@ class Transpiler {
|
|
|
396
397
|
|
|
397
398
|
// Run analyzers
|
|
398
399
|
const externalStructFields =
|
|
399
|
-
AnalyzerContextBuilder.buildExternalStructFields(
|
|
400
|
+
AnalyzerContextBuilder.buildExternalStructFields(
|
|
401
|
+
CodeGenState.symbolTable,
|
|
402
|
+
);
|
|
400
403
|
|
|
401
404
|
const analyzerErrors = runAnalyzers(tree, tokenStream, {
|
|
402
405
|
externalStructFields,
|
|
403
|
-
symbolTable:
|
|
406
|
+
symbolTable: CodeGenState.symbolTable,
|
|
404
407
|
});
|
|
405
408
|
if (analyzerErrors.length > 0) {
|
|
406
409
|
return this.buildErrorResult(
|
|
@@ -430,18 +433,13 @@ class Transpiler {
|
|
|
430
433
|
this._setupCrossFileModifications();
|
|
431
434
|
|
|
432
435
|
// 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
|
-
);
|
|
436
|
+
const code = this.codeGenerator.generate(tree, tokenStream, {
|
|
437
|
+
debugMode: this.config.debugMode,
|
|
438
|
+
target: this.config.target,
|
|
439
|
+
sourcePath,
|
|
440
|
+
cppMode: this.cppDetected,
|
|
441
|
+
symbolInfo,
|
|
442
|
+
});
|
|
445
443
|
|
|
446
444
|
// Collect user includes
|
|
447
445
|
const userIncludes = IncludeExtractor.collectUserIncludes(tree);
|
|
@@ -461,7 +459,7 @@ class Transpiler {
|
|
|
461
459
|
}
|
|
462
460
|
|
|
463
461
|
// Update symbol parameters with auto-const info
|
|
464
|
-
const symbols =
|
|
462
|
+
const symbols = CodeGenState.symbolTable.getSymbolsByFile(sourcePath);
|
|
465
463
|
const unmodifiedParams = this.codeGenerator.getFunctionUnmodifiedParams();
|
|
466
464
|
const knownEnums =
|
|
467
465
|
this.state.getSymbolInfo(sourcePath)?.knownEnums ?? new Set<string>();
|
|
@@ -471,7 +469,6 @@ class Transpiler {
|
|
|
471
469
|
const headerCode = this.generateHeaderContent(
|
|
472
470
|
symbols,
|
|
473
471
|
sourcePath,
|
|
474
|
-
this.symbolTable,
|
|
475
472
|
this.cppDetected,
|
|
476
473
|
userIncludes,
|
|
477
474
|
passByValueCopy,
|
|
@@ -631,7 +628,7 @@ class Transpiler {
|
|
|
631
628
|
// Issue #587: Reset accumulated state for new run
|
|
632
629
|
this.state.reset();
|
|
633
630
|
// Issue #634: Reset symbol table for new run
|
|
634
|
-
|
|
631
|
+
CodeGenState.symbolTable.clear();
|
|
635
632
|
}
|
|
636
633
|
|
|
637
634
|
/**
|
|
@@ -668,7 +665,7 @@ class Transpiler {
|
|
|
668
665
|
* @returns true if no blocking conflicts, false otherwise
|
|
669
666
|
*/
|
|
670
667
|
private _checkSymbolConflicts(result: ITranspilerResult): boolean {
|
|
671
|
-
const conflicts =
|
|
668
|
+
const conflicts = CodeGenState.symbolTable.getConflicts();
|
|
672
669
|
for (const conflict of conflicts) {
|
|
673
670
|
result.conflicts.push(conflict.message);
|
|
674
671
|
if (conflict.severity === "error") {
|
|
@@ -751,7 +748,7 @@ class Transpiler {
|
|
|
751
748
|
if (warning) {
|
|
752
749
|
result.warnings.push(warning);
|
|
753
750
|
}
|
|
754
|
-
result.symbolsCollected =
|
|
751
|
+
result.symbolsCollected = CodeGenState.symbolTable.size;
|
|
755
752
|
result.warnings = [...result.warnings, ...this.warnings];
|
|
756
753
|
|
|
757
754
|
if (this.cacheManager) {
|
|
@@ -1040,13 +1037,16 @@ class Transpiler {
|
|
|
1040
1037
|
|
|
1041
1038
|
// Debug: Show symbols found
|
|
1042
1039
|
if (this.config.debugMode) {
|
|
1043
|
-
const symbols =
|
|
1040
|
+
const symbols = CodeGenState.symbolTable.getSymbolsByFile(file.path);
|
|
1044
1041
|
console.log(`[DEBUG] Found ${symbols.length} symbols in ${file.path}`);
|
|
1045
1042
|
}
|
|
1046
1043
|
|
|
1047
1044
|
// Issue #590: Cache the results using simplified API
|
|
1048
1045
|
if (this.cacheManager) {
|
|
1049
|
-
this.cacheManager.setSymbolsFromTable(
|
|
1046
|
+
this.cacheManager.setSymbolsFromTable(
|
|
1047
|
+
file.path,
|
|
1048
|
+
CodeGenState.symbolTable,
|
|
1049
|
+
);
|
|
1050
1050
|
}
|
|
1051
1051
|
}
|
|
1052
1052
|
|
|
@@ -1065,10 +1065,12 @@ class Transpiler {
|
|
|
1065
1065
|
}
|
|
1066
1066
|
|
|
1067
1067
|
// Restore symbols, struct fields, needsStructKeyword, and enumBitWidth from cache
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1068
|
+
CodeGenState.symbolTable.addSymbols(cached.symbols);
|
|
1069
|
+
CodeGenState.symbolTable.restoreStructFields(cached.structFields);
|
|
1070
|
+
CodeGenState.symbolTable.restoreNeedsStructKeyword(
|
|
1071
|
+
cached.needsStructKeyword,
|
|
1072
|
+
);
|
|
1073
|
+
CodeGenState.symbolTable.restoreEnumBitWidths(cached.enumBitWidth);
|
|
1072
1074
|
|
|
1073
1075
|
// Issue #211: Still check for C++ syntax even on cache hit
|
|
1074
1076
|
this.detectCppFromFileType(file);
|
|
@@ -1140,10 +1142,13 @@ class Transpiler {
|
|
|
1140
1142
|
private parsePureCHeader(content: string, filePath: string): void {
|
|
1141
1143
|
const { tree } = HeaderParser.parseC(content);
|
|
1142
1144
|
if (tree) {
|
|
1143
|
-
const collector = new CSymbolCollector(
|
|
1145
|
+
const collector = new CSymbolCollector(
|
|
1146
|
+
filePath,
|
|
1147
|
+
CodeGenState.symbolTable,
|
|
1148
|
+
);
|
|
1144
1149
|
const symbols = collector.collect(tree);
|
|
1145
1150
|
if (symbols.length > 0) {
|
|
1146
|
-
|
|
1151
|
+
CodeGenState.symbolTable.addSymbols(symbols);
|
|
1147
1152
|
}
|
|
1148
1153
|
}
|
|
1149
1154
|
}
|
|
@@ -1154,9 +1159,12 @@ class Transpiler {
|
|
|
1154
1159
|
private parseCppHeader(content: string, filePath: string): void {
|
|
1155
1160
|
const { tree } = HeaderParser.parseCpp(content);
|
|
1156
1161
|
if (tree) {
|
|
1157
|
-
const collector = new CppSymbolCollector(
|
|
1162
|
+
const collector = new CppSymbolCollector(
|
|
1163
|
+
filePath,
|
|
1164
|
+
CodeGenState.symbolTable,
|
|
1165
|
+
);
|
|
1158
1166
|
const symbols = collector.collect(tree);
|
|
1159
|
-
|
|
1167
|
+
CodeGenState.symbolTable.addSymbols(symbols);
|
|
1160
1168
|
}
|
|
1161
1169
|
}
|
|
1162
1170
|
|
|
@@ -1168,7 +1176,7 @@ class Transpiler {
|
|
|
1168
1176
|
* Stage 6: Generate header file for a C-Next file
|
|
1169
1177
|
*/
|
|
1170
1178
|
private generateHeader(file: IDiscoveredFile): string | null {
|
|
1171
|
-
const symbols =
|
|
1179
|
+
const symbols = CodeGenState.symbolTable.getSymbolsByFile(file.path);
|
|
1172
1180
|
const exportedSymbols = symbols.filter((s) => s.isExported);
|
|
1173
1181
|
|
|
1174
1182
|
if (exportedSymbols.length === 0) {
|
|
@@ -1199,12 +1207,12 @@ class Transpiler {
|
|
|
1199
1207
|
// Issue #497: Build mapping from external types to their C header includes
|
|
1200
1208
|
const externalTypeHeaders = ExternalTypeHeaderBuilder.build(
|
|
1201
1209
|
this.state.getAllHeaderDirectives(),
|
|
1202
|
-
|
|
1210
|
+
CodeGenState.symbolTable,
|
|
1203
1211
|
);
|
|
1204
1212
|
|
|
1205
1213
|
// Issue #502: Include symbolTable in typeInput for C++ namespace type detection
|
|
1206
1214
|
const typeInputWithSymbolTable = typeInput
|
|
1207
|
-
? { ...typeInput, symbolTable:
|
|
1215
|
+
? { ...typeInput, symbolTable: CodeGenState.symbolTable }
|
|
1208
1216
|
: undefined;
|
|
1209
1217
|
|
|
1210
1218
|
const headerContent = this.headerGenerator.generate(
|
|
@@ -1274,7 +1282,6 @@ class Transpiler {
|
|
|
1274
1282
|
private generateHeaderContent(
|
|
1275
1283
|
symbols: ISymbol[],
|
|
1276
1284
|
sourcePath: string,
|
|
1277
|
-
symbolTable: SymbolTable,
|
|
1278
1285
|
cppMode: boolean,
|
|
1279
1286
|
userIncludes: string[],
|
|
1280
1287
|
passByValueParams: Map<string, Set<string>>,
|
|
@@ -1318,12 +1325,12 @@ class Transpiler {
|
|
|
1318
1325
|
// Issue #497: Build mapping from external types to their C header includes
|
|
1319
1326
|
const externalTypeHeaders = ExternalTypeHeaderBuilder.build(
|
|
1320
1327
|
this.state.getAllHeaderDirectives(),
|
|
1321
|
-
symbolTable,
|
|
1328
|
+
CodeGenState.symbolTable,
|
|
1322
1329
|
);
|
|
1323
1330
|
|
|
1324
1331
|
// Issue #502: Include symbolTable in typeInput for C++ namespace type detection
|
|
1325
1332
|
const typeInputWithSymbolTable = typeInput
|
|
1326
|
-
? { ...typeInput, symbolTable }
|
|
1333
|
+
? { ...typeInput, symbolTable: CodeGenState.symbolTable }
|
|
1327
1334
|
: undefined;
|
|
1328
1335
|
|
|
1329
1336
|
// Issue #478: Pass all known enums for cross-file type handling
|
|
@@ -1429,7 +1436,7 @@ class Transpiler {
|
|
|
1429
1436
|
* Get the symbol table (for testing/inspection)
|
|
1430
1437
|
*/
|
|
1431
1438
|
getSymbolTable(): SymbolTable {
|
|
1432
|
-
return
|
|
1439
|
+
return CodeGenState.symbolTable;
|
|
1433
1440
|
}
|
|
1434
1441
|
|
|
1435
1442
|
/**
|
|
@@ -464,23 +464,8 @@ describe("TSymbolAdapter", () => {
|
|
|
464
464
|
});
|
|
465
465
|
});
|
|
466
466
|
|
|
467
|
-
describe("
|
|
468
|
-
it("
|
|
469
|
-
const enumSym: IEnumSymbol = {
|
|
470
|
-
kind: ESymbolKind.Enum,
|
|
471
|
-
name: "EColor",
|
|
472
|
-
sourceFile: "test.cnx",
|
|
473
|
-
sourceLine: 1,
|
|
474
|
-
sourceLanguage: ESourceLanguage.CNext,
|
|
475
|
-
isExported: true,
|
|
476
|
-
members: new Map([
|
|
477
|
-
["RED", 0],
|
|
478
|
-
["GREEN", 1],
|
|
479
|
-
["BLUE", 2],
|
|
480
|
-
["COUNT", 3],
|
|
481
|
-
]),
|
|
482
|
-
};
|
|
483
|
-
|
|
467
|
+
describe("array dimension conversion", () => {
|
|
468
|
+
it("converts qualified enum access (dots to underscores) in variable dimensions", () => {
|
|
484
469
|
const variable: IVariableSymbol = {
|
|
485
470
|
kind: ESymbolKind.Variable,
|
|
486
471
|
name: "DATA",
|
|
@@ -492,15 +477,11 @@ describe("TSymbolAdapter", () => {
|
|
|
492
477
|
isConst: true,
|
|
493
478
|
isAtomic: false,
|
|
494
479
|
isArray: true,
|
|
495
|
-
arrayDimensions: ["COUNT"],
|
|
480
|
+
arrayDimensions: ["EColor.COUNT"],
|
|
496
481
|
};
|
|
497
482
|
|
|
498
|
-
const result = TSymbolAdapter.toISymbols(
|
|
499
|
-
[enumSym, variable],
|
|
500
|
-
symbolTable,
|
|
501
|
-
);
|
|
483
|
+
const result = TSymbolAdapter.toISymbols([variable], symbolTable);
|
|
502
484
|
|
|
503
|
-
// Find the variable symbol
|
|
504
485
|
const varSym = result.find(
|
|
505
486
|
(s) => s.kind === ESymbolKind.Variable && s.name === "DATA",
|
|
506
487
|
);
|
|
@@ -508,21 +489,7 @@ describe("TSymbolAdapter", () => {
|
|
|
508
489
|
expect(varSym!.arrayDimensions).toEqual(["EColor_COUNT"]);
|
|
509
490
|
});
|
|
510
491
|
|
|
511
|
-
it("
|
|
512
|
-
const enumSym: IEnumSymbol = {
|
|
513
|
-
kind: ESymbolKind.Enum,
|
|
514
|
-
name: "Size",
|
|
515
|
-
sourceFile: "test.cnx",
|
|
516
|
-
sourceLine: 1,
|
|
517
|
-
sourceLanguage: ESourceLanguage.CNext,
|
|
518
|
-
isExported: true,
|
|
519
|
-
members: new Map([
|
|
520
|
-
["SMALL", 10],
|
|
521
|
-
["MEDIUM", 20],
|
|
522
|
-
["LARGE", 30],
|
|
523
|
-
]),
|
|
524
|
-
};
|
|
525
|
-
|
|
492
|
+
it("converts qualified enum access in function parameter dimensions", () => {
|
|
526
493
|
const funcSym: IFunctionSymbol = {
|
|
527
494
|
kind: ESymbolKind.Function,
|
|
528
495
|
name: "process",
|
|
@@ -538,14 +505,13 @@ describe("TSymbolAdapter", () => {
|
|
|
538
505
|
type: "u8",
|
|
539
506
|
isConst: false,
|
|
540
507
|
isArray: true,
|
|
541
|
-
arrayDimensions: ["MEDIUM"],
|
|
508
|
+
arrayDimensions: ["Size.MEDIUM"],
|
|
542
509
|
},
|
|
543
510
|
],
|
|
544
511
|
};
|
|
545
512
|
|
|
546
|
-
const result = TSymbolAdapter.toISymbols([
|
|
513
|
+
const result = TSymbolAdapter.toISymbols([funcSym], symbolTable);
|
|
547
514
|
|
|
548
|
-
// Find the function symbol
|
|
549
515
|
const funcResult = result.find(
|
|
550
516
|
(s) => s.kind === ESymbolKind.Function && s.name === "process",
|
|
551
517
|
);
|
|
@@ -556,29 +522,7 @@ describe("TSymbolAdapter", () => {
|
|
|
556
522
|
]);
|
|
557
523
|
});
|
|
558
524
|
|
|
559
|
-
it("
|
|
560
|
-
const enum1: IEnumSymbol = {
|
|
561
|
-
kind: ESymbolKind.Enum,
|
|
562
|
-
name: "EColor",
|
|
563
|
-
sourceFile: "test.cnx",
|
|
564
|
-
sourceLine: 1,
|
|
565
|
-
sourceLanguage: ESourceLanguage.CNext,
|
|
566
|
-
isExported: true,
|
|
567
|
-
members: new Map([["COUNT", 3]]),
|
|
568
|
-
};
|
|
569
|
-
|
|
570
|
-
const enum2: IEnumSymbol = {
|
|
571
|
-
kind: ESymbolKind.Enum,
|
|
572
|
-
name: "ESize",
|
|
573
|
-
sourceFile: "test.cnx",
|
|
574
|
-
sourceLine: 5,
|
|
575
|
-
sourceLanguage: ESourceLanguage.CNext,
|
|
576
|
-
isExported: true,
|
|
577
|
-
members: new Map([
|
|
578
|
-
["COUNT", 5], // Same member name in different enum
|
|
579
|
-
]),
|
|
580
|
-
};
|
|
581
|
-
|
|
525
|
+
it("passes through unqualified string dimensions as-is", () => {
|
|
582
526
|
const variable: IVariableSymbol = {
|
|
583
527
|
kind: ESymbolKind.Variable,
|
|
584
528
|
name: "DATA",
|
|
@@ -590,33 +534,42 @@ describe("TSymbolAdapter", () => {
|
|
|
590
534
|
isConst: true,
|
|
591
535
|
isAtomic: false,
|
|
592
536
|
isArray: true,
|
|
593
|
-
arrayDimensions: ["
|
|
537
|
+
arrayDimensions: ["DEVICE_COUNT"], // C macro passthrough
|
|
594
538
|
};
|
|
595
539
|
|
|
596
|
-
const result = TSymbolAdapter.toISymbols(
|
|
597
|
-
[enum1, enum2, variable],
|
|
598
|
-
symbolTable,
|
|
599
|
-
);
|
|
540
|
+
const result = TSymbolAdapter.toISymbols([variable], symbolTable);
|
|
600
541
|
|
|
601
|
-
// Find the variable symbol - dimension should NOT be resolved
|
|
602
542
|
const varSym = result.find(
|
|
603
543
|
(s) => s.kind === ESymbolKind.Variable && s.name === "DATA",
|
|
604
544
|
);
|
|
605
545
|
expect(varSym).toBeDefined();
|
|
606
|
-
expect(varSym!.arrayDimensions).toEqual(["
|
|
546
|
+
expect(varSym!.arrayDimensions).toEqual(["DEVICE_COUNT"]);
|
|
607
547
|
});
|
|
608
548
|
|
|
609
549
|
it("preserves numeric array dimensions", () => {
|
|
610
|
-
const
|
|
611
|
-
kind: ESymbolKind.
|
|
612
|
-
name: "
|
|
550
|
+
const variable: IVariableSymbol = {
|
|
551
|
+
kind: ESymbolKind.Variable,
|
|
552
|
+
name: "DATA",
|
|
613
553
|
sourceFile: "test.cnx",
|
|
614
|
-
sourceLine:
|
|
554
|
+
sourceLine: 10,
|
|
615
555
|
sourceLanguage: ESourceLanguage.CNext,
|
|
616
556
|
isExported: true,
|
|
617
|
-
|
|
557
|
+
type: "u8",
|
|
558
|
+
isConst: true,
|
|
559
|
+
isAtomic: false,
|
|
560
|
+
isArray: true,
|
|
561
|
+
arrayDimensions: [256],
|
|
618
562
|
};
|
|
619
563
|
|
|
564
|
+
const result = TSymbolAdapter.toISymbols([variable], symbolTable);
|
|
565
|
+
|
|
566
|
+
const varSym = result.find(
|
|
567
|
+
(s) => s.kind === ESymbolKind.Variable && s.name === "DATA",
|
|
568
|
+
);
|
|
569
|
+
expect(varSym!.arrayDimensions).toEqual(["256"]);
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
it("handles multi-dot qualified access (Motor.State.IDLE)", () => {
|
|
620
573
|
const variable: IVariableSymbol = {
|
|
621
574
|
kind: ESymbolKind.Variable,
|
|
622
575
|
name: "DATA",
|
|
@@ -628,18 +581,15 @@ describe("TSymbolAdapter", () => {
|
|
|
628
581
|
isConst: true,
|
|
629
582
|
isAtomic: false,
|
|
630
583
|
isArray: true,
|
|
631
|
-
arrayDimensions: [
|
|
584
|
+
arrayDimensions: ["Motor.State.COUNT"],
|
|
632
585
|
};
|
|
633
586
|
|
|
634
|
-
const result = TSymbolAdapter.toISymbols(
|
|
635
|
-
[enumSym, variable],
|
|
636
|
-
symbolTable,
|
|
637
|
-
);
|
|
587
|
+
const result = TSymbolAdapter.toISymbols([variable], symbolTable);
|
|
638
588
|
|
|
639
589
|
const varSym = result.find(
|
|
640
590
|
(s) => s.kind === ESymbolKind.Variable && s.name === "DATA",
|
|
641
591
|
);
|
|
642
|
-
expect(varSym!.arrayDimensions).toEqual(["
|
|
592
|
+
expect(varSym!.arrayDimensions).toEqual(["Motor_State_COUNT"]);
|
|
643
593
|
});
|
|
644
594
|
});
|
|
645
595
|
});
|
|
@@ -40,9 +40,6 @@ class TSymbolAdapter {
|
|
|
40
40
|
* @returns Array of flat ISymbol objects for Pipeline consumption
|
|
41
41
|
*/
|
|
42
42
|
static toISymbols(symbols: TSymbol[], symbolTable: SymbolTable): ISymbol[] {
|
|
43
|
-
// First pass: Build enum member lookup for array dimension resolution
|
|
44
|
-
const enumMemberLookup = TSymbolAdapter.buildEnumMemberLookup(symbols);
|
|
45
|
-
|
|
46
43
|
const result: ISymbol[] = [];
|
|
47
44
|
|
|
48
45
|
for (const symbol of symbols) {
|
|
@@ -57,12 +54,10 @@ class TSymbolAdapter {
|
|
|
57
54
|
result.push(TSymbolAdapter.convertStruct(symbol, symbolTable));
|
|
58
55
|
break;
|
|
59
56
|
case ESymbolKind.Function:
|
|
60
|
-
result.push(
|
|
61
|
-
...TSymbolAdapter.convertFunction(symbol, enumMemberLookup),
|
|
62
|
-
);
|
|
57
|
+
result.push(...TSymbolAdapter.convertFunction(symbol));
|
|
63
58
|
break;
|
|
64
59
|
case ESymbolKind.Variable:
|
|
65
|
-
result.push(TSymbolAdapter.convertVariable(symbol
|
|
60
|
+
result.push(TSymbolAdapter.convertVariable(symbol));
|
|
66
61
|
break;
|
|
67
62
|
case ESymbolKind.Register:
|
|
68
63
|
result.push(...TSymbolAdapter.convertRegister(symbol));
|
|
@@ -77,53 +72,20 @@ class TSymbolAdapter {
|
|
|
77
72
|
}
|
|
78
73
|
|
|
79
74
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* If a member name exists in multiple enums, it's marked as ambiguous (null value)
|
|
84
|
-
* and will not be resolved (the header will fail to compile, surfacing the issue).
|
|
85
|
-
*/
|
|
86
|
-
private static buildEnumMemberLookup(
|
|
87
|
-
symbols: TSymbol[],
|
|
88
|
-
): Map<string, string | null> {
|
|
89
|
-
const lookup = new Map<string, string | null>();
|
|
90
|
-
|
|
91
|
-
for (const symbol of symbols) {
|
|
92
|
-
if (symbol.kind !== ESymbolKind.Enum) continue;
|
|
93
|
-
|
|
94
|
-
for (const memberName of symbol.members.keys()) {
|
|
95
|
-
if (lookup.has(memberName)) {
|
|
96
|
-
// Ambiguous: member exists in multiple enums
|
|
97
|
-
lookup.set(memberName, null);
|
|
98
|
-
} else {
|
|
99
|
-
lookup.set(memberName, symbol.name);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return lookup;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Resolve an array dimension string, adding enum prefix if it's an unqualified enum member.
|
|
75
|
+
* Convert an array dimension to a string for header generation.
|
|
76
|
+
* Converts qualified enum access (e.g., "EColor.COUNT") to C-style ("EColor_COUNT").
|
|
109
77
|
*/
|
|
110
|
-
private static resolveArrayDimension(
|
|
111
|
-
dim: number | string,
|
|
112
|
-
enumMemberLookup: Map<string, string | null>,
|
|
113
|
-
): string {
|
|
114
|
-
// Numeric dimensions don't need resolution
|
|
78
|
+
private static resolveArrayDimension(dim: number | string): string {
|
|
115
79
|
if (typeof dim === "number") {
|
|
116
80
|
return String(dim);
|
|
117
81
|
}
|
|
118
82
|
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
// Found in exactly one enum - add the prefix
|
|
123
|
-
return `${enumName}_${dim}`;
|
|
83
|
+
// Qualified enum access (e.g., "EColor.COUNT") - convert dots to underscores
|
|
84
|
+
if (dim.includes(".")) {
|
|
85
|
+
return dim.replaceAll(".", "_");
|
|
124
86
|
}
|
|
125
87
|
|
|
126
|
-
//
|
|
88
|
+
// Pass through as-is (C macros, other identifiers)
|
|
127
89
|
return dim;
|
|
128
90
|
}
|
|
129
91
|
|
|
@@ -236,26 +198,23 @@ class TSymbolAdapter {
|
|
|
236
198
|
|
|
237
199
|
/**
|
|
238
200
|
* Convert IFunctionSymbol to ISymbol + parameter symbols for hover support.
|
|
239
|
-
*
|
|
201
|
+
* Converts qualified enum names in parameter array dimensions.
|
|
240
202
|
*/
|
|
241
|
-
private static convertFunction(
|
|
242
|
-
func: IFunctionSymbol,
|
|
243
|
-
enumMemberLookup: Map<string, string | null>,
|
|
244
|
-
): ISymbol[] {
|
|
203
|
+
private static convertFunction(func: IFunctionSymbol): ISymbol[] {
|
|
245
204
|
const result: ISymbol[] = [];
|
|
246
205
|
|
|
247
206
|
// Build parameter types for signature
|
|
248
207
|
const paramTypes = func.parameters.map((p) => p.type);
|
|
249
208
|
const signature = `${func.returnType} ${func.name}(${paramTypes.join(", ")})`;
|
|
250
209
|
|
|
251
|
-
// Build parameter info for header generation
|
|
210
|
+
// Build parameter info for header generation
|
|
252
211
|
const parameters = func.parameters.map((p) => ({
|
|
253
212
|
name: p.name,
|
|
254
213
|
type: p.type,
|
|
255
214
|
isConst: p.isConst,
|
|
256
215
|
isArray: p.isArray,
|
|
257
216
|
arrayDimensions: p.arrayDimensions?.map((dim) =>
|
|
258
|
-
TSymbolAdapter.resolveArrayDimension(dim
|
|
217
|
+
TSymbolAdapter.resolveArrayDimension(dim),
|
|
259
218
|
),
|
|
260
219
|
isAutoConst: p.isAutoConst,
|
|
261
220
|
}));
|
|
@@ -295,15 +254,12 @@ class TSymbolAdapter {
|
|
|
295
254
|
|
|
296
255
|
/**
|
|
297
256
|
* Convert IVariableSymbol to ISymbol.
|
|
298
|
-
*
|
|
257
|
+
* Converts qualified enum names in array dimensions.
|
|
299
258
|
*/
|
|
300
|
-
private static convertVariable(
|
|
301
|
-
|
|
302
|
-
enumMemberLookup: Map<string, string | null>,
|
|
303
|
-
): ISymbol {
|
|
304
|
-
// Convert dimensions to string dimensions, resolving enum member references
|
|
259
|
+
private static convertVariable(variable: IVariableSymbol): ISymbol {
|
|
260
|
+
// Convert dimensions to string dimensions
|
|
305
261
|
const arrayDimensions = variable.arrayDimensions?.map((dim) =>
|
|
306
|
-
TSymbolAdapter.resolveArrayDimension(dim
|
|
262
|
+
TSymbolAdapter.resolveArrayDimension(dim),
|
|
307
263
|
);
|
|
308
264
|
|
|
309
265
|
// Get first dimension for legacy size field (only if numeric)
|