c-next 0.1.65 → 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 +5 -1
- package/src/transpiler/Transpiler.ts +49 -42
- package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +129 -0
- package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +27 -3
- package/src/transpiler/output/codegen/CodeGenerator.ts +131 -186
- 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 +1087 -0
- 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 +618 -12
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +819 -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/ParameterInputAdapter.ts +337 -0
- package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +135 -0
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/VariableDeclarationFormatter.ts +118 -0
- 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__/ParameterInputAdapter.test.ts +426 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +315 -0
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclarationFormatter.test.ts +333 -0
- 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/types/IParameterInput.ts +58 -0
- package/src/transpiler/output/codegen/types/IVariableFormatInput.ts +51 -0
- package/src/transpiler/output/headers/BaseHeaderGenerator.ts +20 -35
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +21 -48
- package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +0 -64
- 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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "c-next",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.67",
|
|
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",
|
|
@@ -118,5 +118,9 @@
|
|
|
118
118
|
"*.ts": [
|
|
119
119
|
"oxlint --fix"
|
|
120
120
|
]
|
|
121
|
+
},
|
|
122
|
+
"volta": {
|
|
123
|
+
"node": "24.13.1",
|
|
124
|
+
"npm": "11.8.0"
|
|
121
125
|
}
|
|
122
126
|
}
|
|
@@ -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
|
/**
|
|
@@ -463,4 +463,133 @@ describe("TSymbolAdapter", () => {
|
|
|
463
463
|
expect(symbolTable.getStructFieldType("Point", "x")).toBe("i32");
|
|
464
464
|
});
|
|
465
465
|
});
|
|
466
|
+
|
|
467
|
+
describe("array dimension conversion", () => {
|
|
468
|
+
it("converts qualified enum access (dots to underscores) in variable dimensions", () => {
|
|
469
|
+
const variable: IVariableSymbol = {
|
|
470
|
+
kind: ESymbolKind.Variable,
|
|
471
|
+
name: "DATA",
|
|
472
|
+
sourceFile: "test.cnx",
|
|
473
|
+
sourceLine: 10,
|
|
474
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
475
|
+
isExported: true,
|
|
476
|
+
type: "u8",
|
|
477
|
+
isConst: true,
|
|
478
|
+
isAtomic: false,
|
|
479
|
+
isArray: true,
|
|
480
|
+
arrayDimensions: ["EColor.COUNT"],
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
const result = TSymbolAdapter.toISymbols([variable], symbolTable);
|
|
484
|
+
|
|
485
|
+
const varSym = result.find(
|
|
486
|
+
(s) => s.kind === ESymbolKind.Variable && s.name === "DATA",
|
|
487
|
+
);
|
|
488
|
+
expect(varSym).toBeDefined();
|
|
489
|
+
expect(varSym!.arrayDimensions).toEqual(["EColor_COUNT"]);
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
it("converts qualified enum access in function parameter dimensions", () => {
|
|
493
|
+
const funcSym: IFunctionSymbol = {
|
|
494
|
+
kind: ESymbolKind.Function,
|
|
495
|
+
name: "process",
|
|
496
|
+
sourceFile: "test.cnx",
|
|
497
|
+
sourceLine: 5,
|
|
498
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
499
|
+
isExported: true,
|
|
500
|
+
returnType: "void",
|
|
501
|
+
visibility: "public",
|
|
502
|
+
parameters: [
|
|
503
|
+
{
|
|
504
|
+
name: "buffer",
|
|
505
|
+
type: "u8",
|
|
506
|
+
isConst: false,
|
|
507
|
+
isArray: true,
|
|
508
|
+
arrayDimensions: ["Size.MEDIUM"],
|
|
509
|
+
},
|
|
510
|
+
],
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
const result = TSymbolAdapter.toISymbols([funcSym], symbolTable);
|
|
514
|
+
|
|
515
|
+
const funcResult = result.find(
|
|
516
|
+
(s) => s.kind === ESymbolKind.Function && s.name === "process",
|
|
517
|
+
);
|
|
518
|
+
expect(funcResult).toBeDefined();
|
|
519
|
+
expect(funcResult!.parameters).toBeDefined();
|
|
520
|
+
expect(funcResult!.parameters![0].arrayDimensions).toEqual([
|
|
521
|
+
"Size_MEDIUM",
|
|
522
|
+
]);
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
it("passes through unqualified string dimensions as-is", () => {
|
|
526
|
+
const variable: IVariableSymbol = {
|
|
527
|
+
kind: ESymbolKind.Variable,
|
|
528
|
+
name: "DATA",
|
|
529
|
+
sourceFile: "test.cnx",
|
|
530
|
+
sourceLine: 10,
|
|
531
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
532
|
+
isExported: true,
|
|
533
|
+
type: "u8",
|
|
534
|
+
isConst: true,
|
|
535
|
+
isAtomic: false,
|
|
536
|
+
isArray: true,
|
|
537
|
+
arrayDimensions: ["DEVICE_COUNT"], // C macro passthrough
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
const result = TSymbolAdapter.toISymbols([variable], symbolTable);
|
|
541
|
+
|
|
542
|
+
const varSym = result.find(
|
|
543
|
+
(s) => s.kind === ESymbolKind.Variable && s.name === "DATA",
|
|
544
|
+
);
|
|
545
|
+
expect(varSym).toBeDefined();
|
|
546
|
+
expect(varSym!.arrayDimensions).toEqual(["DEVICE_COUNT"]);
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
it("preserves numeric array dimensions", () => {
|
|
550
|
+
const variable: IVariableSymbol = {
|
|
551
|
+
kind: ESymbolKind.Variable,
|
|
552
|
+
name: "DATA",
|
|
553
|
+
sourceFile: "test.cnx",
|
|
554
|
+
sourceLine: 10,
|
|
555
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
556
|
+
isExported: true,
|
|
557
|
+
type: "u8",
|
|
558
|
+
isConst: true,
|
|
559
|
+
isAtomic: false,
|
|
560
|
+
isArray: true,
|
|
561
|
+
arrayDimensions: [256],
|
|
562
|
+
};
|
|
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)", () => {
|
|
573
|
+
const variable: IVariableSymbol = {
|
|
574
|
+
kind: ESymbolKind.Variable,
|
|
575
|
+
name: "DATA",
|
|
576
|
+
sourceFile: "test.cnx",
|
|
577
|
+
sourceLine: 10,
|
|
578
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
579
|
+
isExported: true,
|
|
580
|
+
type: "u8",
|
|
581
|
+
isConst: true,
|
|
582
|
+
isAtomic: false,
|
|
583
|
+
isArray: true,
|
|
584
|
+
arrayDimensions: ["Motor.State.COUNT"],
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
const result = TSymbolAdapter.toISymbols([variable], symbolTable);
|
|
588
|
+
|
|
589
|
+
const varSym = result.find(
|
|
590
|
+
(s) => s.kind === ESymbolKind.Variable && s.name === "DATA",
|
|
591
|
+
);
|
|
592
|
+
expect(varSym!.arrayDimensions).toEqual(["Motor_State_COUNT"]);
|
|
593
|
+
});
|
|
594
|
+
});
|
|
466
595
|
});
|
|
@@ -71,6 +71,24 @@ class TSymbolAdapter {
|
|
|
71
71
|
return result;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
/**
|
|
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").
|
|
77
|
+
*/
|
|
78
|
+
private static resolveArrayDimension(dim: number | string): string {
|
|
79
|
+
if (typeof dim === "number") {
|
|
80
|
+
return String(dim);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Qualified enum access (e.g., "EColor.COUNT") - convert dots to underscores
|
|
84
|
+
if (dim.includes(".")) {
|
|
85
|
+
return dim.replaceAll(".", "_");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Pass through as-is (C macros, other identifiers)
|
|
89
|
+
return dim;
|
|
90
|
+
}
|
|
91
|
+
|
|
74
92
|
/**
|
|
75
93
|
* Convert IBitmapSymbol to ISymbol + BitmapField symbols.
|
|
76
94
|
*/
|
|
@@ -180,6 +198,7 @@ class TSymbolAdapter {
|
|
|
180
198
|
|
|
181
199
|
/**
|
|
182
200
|
* Convert IFunctionSymbol to ISymbol + parameter symbols for hover support.
|
|
201
|
+
* Converts qualified enum names in parameter array dimensions.
|
|
183
202
|
*/
|
|
184
203
|
private static convertFunction(func: IFunctionSymbol): ISymbol[] {
|
|
185
204
|
const result: ISymbol[] = [];
|
|
@@ -194,7 +213,9 @@ class TSymbolAdapter {
|
|
|
194
213
|
type: p.type,
|
|
195
214
|
isConst: p.isConst,
|
|
196
215
|
isArray: p.isArray,
|
|
197
|
-
arrayDimensions: p.arrayDimensions
|
|
216
|
+
arrayDimensions: p.arrayDimensions?.map((dim) =>
|
|
217
|
+
TSymbolAdapter.resolveArrayDimension(dim),
|
|
218
|
+
),
|
|
198
219
|
isAutoConst: p.isAutoConst,
|
|
199
220
|
}));
|
|
200
221
|
|
|
@@ -233,10 +254,13 @@ class TSymbolAdapter {
|
|
|
233
254
|
|
|
234
255
|
/**
|
|
235
256
|
* Convert IVariableSymbol to ISymbol.
|
|
257
|
+
* Converts qualified enum names in array dimensions.
|
|
236
258
|
*/
|
|
237
259
|
private static convertVariable(variable: IVariableSymbol): ISymbol {
|
|
238
|
-
// Convert dimensions to string dimensions
|
|
239
|
-
const arrayDimensions = variable.arrayDimensions?.map(
|
|
260
|
+
// Convert dimensions to string dimensions
|
|
261
|
+
const arrayDimensions = variable.arrayDimensions?.map((dim) =>
|
|
262
|
+
TSymbolAdapter.resolveArrayDimension(dim),
|
|
263
|
+
);
|
|
240
264
|
|
|
241
265
|
// Get first dimension for legacy size field (only if numeric)
|
|
242
266
|
const firstDim = variable.arrayDimensions?.[0];
|