c-next 0.1.38 → 0.1.39
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
CHANGED
package/src/pipeline/Pipeline.ts
CHANGED
|
@@ -75,6 +75,8 @@ class Pipeline {
|
|
|
75
75
|
> = new Map();
|
|
76
76
|
/** Issue #424: Store user includes per file for header generation */
|
|
77
77
|
private readonly userIncludesCollectors: Map<string, string[]> = new Map();
|
|
78
|
+
/** Issue #465: Store ISymbolInfo per file during stage 3 for external enum resolution */
|
|
79
|
+
private readonly symbolInfoByFile: Map<string, ISymbolInfo> = new Map();
|
|
78
80
|
|
|
79
81
|
constructor(config: IPipelineConfig) {
|
|
80
82
|
// Apply defaults
|
|
@@ -593,6 +595,54 @@ class Pipeline {
|
|
|
593
595
|
const tSymbols = CNextResolver.resolve(tree, file.path);
|
|
594
596
|
const iSymbols = TSymbolAdapter.toISymbols(tSymbols, this.symbolTable);
|
|
595
597
|
this.symbolTable.addSymbols(iSymbols);
|
|
598
|
+
|
|
599
|
+
// Issue #465: Store ISymbolInfo for external enum resolution in stage 5
|
|
600
|
+
// This ensures enum member info is available for all files before code generation
|
|
601
|
+
const symbolInfo = TSymbolInfoAdapter.convert(tSymbols);
|
|
602
|
+
this.symbolInfoByFile.set(file.path, symbolInfo);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Issue #465: Collect ISymbolInfo from all transitively included .cnx files.
|
|
607
|
+
*
|
|
608
|
+
* Recursively resolves includes to gather enum info from the entire include tree.
|
|
609
|
+
* This ensures that deeply nested enums (A includes B, B includes C with enum)
|
|
610
|
+
* are available for prefixing in the top-level file.
|
|
611
|
+
*
|
|
612
|
+
* @param filePath The file to collect transitive includes for
|
|
613
|
+
* @returns Array of ISymbolInfo from all transitively included .cnx files
|
|
614
|
+
*/
|
|
615
|
+
private collectTransitiveEnumInfo(filePath: string): ISymbolInfo[] {
|
|
616
|
+
const result: ISymbolInfo[] = [];
|
|
617
|
+
const visited = new Set<string>();
|
|
618
|
+
|
|
619
|
+
const collectRecursively = (currentPath: string): void => {
|
|
620
|
+
if (visited.has(currentPath)) return;
|
|
621
|
+
visited.add(currentPath);
|
|
622
|
+
|
|
623
|
+
// Read and parse includes from current file
|
|
624
|
+
const content = readFileSync(currentPath, "utf-8");
|
|
625
|
+
const searchPaths = IncludeResolver.buildSearchPaths(
|
|
626
|
+
dirname(currentPath),
|
|
627
|
+
this.config.includeDirs,
|
|
628
|
+
[],
|
|
629
|
+
);
|
|
630
|
+
const resolver = new IncludeResolver(searchPaths);
|
|
631
|
+
const resolved = resolver.resolve(content, currentPath);
|
|
632
|
+
|
|
633
|
+
// Process each included .cnx file
|
|
634
|
+
for (const cnxInclude of resolved.cnextIncludes) {
|
|
635
|
+
const externalInfo = this.symbolInfoByFile.get(cnxInclude.path);
|
|
636
|
+
if (externalInfo) {
|
|
637
|
+
result.push(externalInfo);
|
|
638
|
+
}
|
|
639
|
+
// Recursively collect from this include's includes
|
|
640
|
+
collectRecursively(cnxInclude.path);
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
collectRecursively(filePath);
|
|
645
|
+
return result;
|
|
596
646
|
}
|
|
597
647
|
|
|
598
648
|
/**
|
|
@@ -735,7 +785,19 @@ class Pipeline {
|
|
|
735
785
|
try {
|
|
736
786
|
// ADR-055 Phase 5: Create ISymbolInfo from TSymbol[] for CodeGenerator
|
|
737
787
|
const tSymbols = CNextResolver.resolve(tree, file.path);
|
|
738
|
-
|
|
788
|
+
let symbolInfo = TSymbolInfoAdapter.convert(tSymbols);
|
|
789
|
+
|
|
790
|
+
// Issue #465: Merge enum info from included .cnx files (including transitive)
|
|
791
|
+
// This enables external enum member references to get the correct type prefix
|
|
792
|
+
const externalEnumSources = this.collectTransitiveEnumInfo(file.path);
|
|
793
|
+
|
|
794
|
+
// Merge external enum info if any includes were found
|
|
795
|
+
if (externalEnumSources.length > 0) {
|
|
796
|
+
symbolInfo = TSymbolInfoAdapter.mergeExternalEnums(
|
|
797
|
+
symbolInfo,
|
|
798
|
+
externalEnumSources,
|
|
799
|
+
);
|
|
800
|
+
}
|
|
739
801
|
|
|
740
802
|
const code = this.codeGenerator.generate(
|
|
741
803
|
tree,
|
|
@@ -1044,15 +1106,39 @@ class Pipeline {
|
|
|
1044
1106
|
|
|
1045
1107
|
// Step 4b: Issue #294 - Parse C-Next includes to populate symbol table
|
|
1046
1108
|
// This enables cross-file scope references (e.g., decoder.getSpn() -> decoder_getSpn())
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
);
|
|
1109
|
+
// Issue #465: Recursively process transitive includes for enum info
|
|
1110
|
+
const processedCnxIncludes = new Set<string>();
|
|
1111
|
+
const processCnxIncludesRecursively = (
|
|
1112
|
+
includes: IDiscoveredFile[],
|
|
1113
|
+
): void => {
|
|
1114
|
+
for (const cnxInclude of includes) {
|
|
1115
|
+
if (processedCnxIncludes.has(cnxInclude.path)) continue;
|
|
1116
|
+
processedCnxIncludes.add(cnxInclude.path);
|
|
1117
|
+
|
|
1118
|
+
try {
|
|
1119
|
+
this.collectCNextSymbols(cnxInclude);
|
|
1120
|
+
|
|
1121
|
+
// Recursively process this include's includes
|
|
1122
|
+
const nestedContent = readFileSync(cnxInclude.path, "utf-8");
|
|
1123
|
+
const nestedSearchPaths = IncludeResolver.buildSearchPaths(
|
|
1124
|
+
dirname(cnxInclude.path),
|
|
1125
|
+
this.config.includeDirs,
|
|
1126
|
+
[],
|
|
1127
|
+
);
|
|
1128
|
+
const nestedResolver = new IncludeResolver(nestedSearchPaths);
|
|
1129
|
+
const nestedResolved = nestedResolver.resolve(
|
|
1130
|
+
nestedContent,
|
|
1131
|
+
cnxInclude.path,
|
|
1132
|
+
);
|
|
1133
|
+
processCnxIncludesRecursively(nestedResolved.cnextIncludes);
|
|
1134
|
+
} catch (err) {
|
|
1135
|
+
this.warnings.push(
|
|
1136
|
+
`Failed to process C-Next include ${cnxInclude.path}: ${err}`,
|
|
1137
|
+
);
|
|
1138
|
+
}
|
|
1054
1139
|
}
|
|
1055
|
-
}
|
|
1140
|
+
};
|
|
1141
|
+
processCnxIncludesRecursively(resolved.cnextIncludes);
|
|
1056
1142
|
|
|
1057
1143
|
// Step 5: Parse C-Next source from string
|
|
1058
1144
|
const charStream = CharStream.fromString(source);
|
|
@@ -1147,7 +1233,49 @@ class Pipeline {
|
|
|
1147
1233
|
// Step 7: Generate code with symbol table
|
|
1148
1234
|
// ADR-055 Phase 5: Create ISymbolInfo from TSymbol[] for CodeGenerator
|
|
1149
1235
|
const tSymbols = CNextResolver.resolve(tree, sourcePath);
|
|
1150
|
-
|
|
1236
|
+
let symbolInfo = TSymbolInfoAdapter.convert(tSymbols);
|
|
1237
|
+
|
|
1238
|
+
// Issue #465: Merge enum info from included .cnx files (including transitive)
|
|
1239
|
+
// This enables external enum member references to get the correct type prefix
|
|
1240
|
+
const externalEnumSources: ISymbolInfo[] = [];
|
|
1241
|
+
const visitedIncludes = new Set<string>();
|
|
1242
|
+
|
|
1243
|
+
// Recursively collect enum info from all transitive includes
|
|
1244
|
+
const collectFromIncludes = (includes: IDiscoveredFile[]): void => {
|
|
1245
|
+
for (const cnxInclude of includes) {
|
|
1246
|
+
if (visitedIncludes.has(cnxInclude.path)) continue;
|
|
1247
|
+
visitedIncludes.add(cnxInclude.path);
|
|
1248
|
+
|
|
1249
|
+
const externalInfo = this.symbolInfoByFile.get(cnxInclude.path);
|
|
1250
|
+
if (externalInfo) {
|
|
1251
|
+
externalEnumSources.push(externalInfo);
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// Recursively process this include's includes
|
|
1255
|
+
const nestedContent = readFileSync(cnxInclude.path, "utf-8");
|
|
1256
|
+
const nestedSearchPaths = IncludeResolver.buildSearchPaths(
|
|
1257
|
+
dirname(cnxInclude.path),
|
|
1258
|
+
this.config.includeDirs,
|
|
1259
|
+
[],
|
|
1260
|
+
);
|
|
1261
|
+
const nestedResolver = new IncludeResolver(nestedSearchPaths);
|
|
1262
|
+
const nestedResolved = nestedResolver.resolve(
|
|
1263
|
+
nestedContent,
|
|
1264
|
+
cnxInclude.path,
|
|
1265
|
+
);
|
|
1266
|
+
collectFromIncludes(nestedResolved.cnextIncludes);
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1269
|
+
|
|
1270
|
+
collectFromIncludes(resolved.cnextIncludes);
|
|
1271
|
+
|
|
1272
|
+
// Merge external enum info if any includes were found
|
|
1273
|
+
if (externalEnumSources.length > 0) {
|
|
1274
|
+
symbolInfo = TSymbolInfoAdapter.mergeExternalEnums(
|
|
1275
|
+
symbolInfo,
|
|
1276
|
+
externalEnumSources,
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1151
1279
|
|
|
1152
1280
|
const code = this.codeGenerator.generate(
|
|
1153
1281
|
tree,
|
|
@@ -365,6 +365,94 @@ class TSymbolInfoAdapter {
|
|
|
365
365
|
// Extract the single element from the Set (we know it exists since size === 1)
|
|
366
366
|
return [...usedIn][0];
|
|
367
367
|
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Issue #465: Merge external enum info into an existing ISymbolInfo.
|
|
371
|
+
*
|
|
372
|
+
* When a file includes other .cnx files, the enum types from those external
|
|
373
|
+
* files need to be available for code generation (enum member prefixing).
|
|
374
|
+
* This method creates a new ISymbolInfo that includes both the base symbols
|
|
375
|
+
* and merged enum info from external sources.
|
|
376
|
+
*
|
|
377
|
+
* @param base The ISymbolInfo from the current file
|
|
378
|
+
* @param externalEnumSources Array of ISymbolInfo from included .cnx files
|
|
379
|
+
* @returns New ISymbolInfo with merged enum data
|
|
380
|
+
*/
|
|
381
|
+
static mergeExternalEnums(
|
|
382
|
+
base: ISymbolInfo,
|
|
383
|
+
externalEnumSources: ISymbolInfo[],
|
|
384
|
+
): ISymbolInfo {
|
|
385
|
+
// If no external sources, return base unchanged
|
|
386
|
+
if (externalEnumSources.length === 0) {
|
|
387
|
+
return base;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Create mutable copies of enum-related data
|
|
391
|
+
const mergedKnownEnums = new Set(base.knownEnums);
|
|
392
|
+
const mergedEnumMembers = new Map<string, Map<string, number>>();
|
|
393
|
+
|
|
394
|
+
// Copy base enum members
|
|
395
|
+
for (const [enumName, members] of base.enumMembers) {
|
|
396
|
+
mergedEnumMembers.set(enumName, new Map(members));
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Merge in external enum info
|
|
400
|
+
for (const external of externalEnumSources) {
|
|
401
|
+
for (const enumName of external.knownEnums) {
|
|
402
|
+
mergedKnownEnums.add(enumName);
|
|
403
|
+
}
|
|
404
|
+
for (const [enumName, members] of external.enumMembers) {
|
|
405
|
+
// Don't overwrite if already exists (local takes precedence)
|
|
406
|
+
if (!mergedEnumMembers.has(enumName)) {
|
|
407
|
+
mergedEnumMembers.set(enumName, new Map(members));
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Return new ISymbolInfo with merged enum data
|
|
413
|
+
// All other fields remain unchanged from base
|
|
414
|
+
return {
|
|
415
|
+
// Type sets - only knownEnums is merged
|
|
416
|
+
knownScopes: base.knownScopes,
|
|
417
|
+
knownStructs: base.knownStructs,
|
|
418
|
+
knownEnums: mergedKnownEnums,
|
|
419
|
+
knownBitmaps: base.knownBitmaps,
|
|
420
|
+
knownRegisters: base.knownRegisters,
|
|
421
|
+
|
|
422
|
+
// Scope info
|
|
423
|
+
scopeMembers: base.scopeMembers,
|
|
424
|
+
scopeMemberVisibility: base.scopeMemberVisibility,
|
|
425
|
+
scopeVariableUsage: base.scopeVariableUsage,
|
|
426
|
+
|
|
427
|
+
// Struct info
|
|
428
|
+
structFields: base.structFields,
|
|
429
|
+
structFieldArrays: base.structFieldArrays,
|
|
430
|
+
structFieldDimensions: base.structFieldDimensions,
|
|
431
|
+
|
|
432
|
+
// Enum info - merged
|
|
433
|
+
enumMembers: mergedEnumMembers,
|
|
434
|
+
|
|
435
|
+
// Bitmap info
|
|
436
|
+
bitmapFields: base.bitmapFields,
|
|
437
|
+
bitmapBackingType: base.bitmapBackingType,
|
|
438
|
+
bitmapBitWidth: base.bitmapBitWidth,
|
|
439
|
+
|
|
440
|
+
// Register info
|
|
441
|
+
scopedRegisters: base.scopedRegisters,
|
|
442
|
+
registerMemberAccess: base.registerMemberAccess,
|
|
443
|
+
registerMemberTypes: base.registerMemberTypes,
|
|
444
|
+
registerBaseAddresses: base.registerBaseAddresses,
|
|
445
|
+
registerMemberOffsets: base.registerMemberOffsets,
|
|
446
|
+
registerMemberCTypes: base.registerMemberCTypes,
|
|
447
|
+
|
|
448
|
+
// Private const values
|
|
449
|
+
scopePrivateConstValues: base.scopePrivateConstValues,
|
|
450
|
+
|
|
451
|
+
// Methods - delegate to base's implementation
|
|
452
|
+
getSingleFunctionForVariable: base.getSingleFunctionForVariable,
|
|
453
|
+
hasPublicSymbols: base.hasPublicSymbols,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
368
456
|
}
|
|
369
457
|
|
|
370
458
|
export default TSymbolInfoAdapter;
|