c-next 0.1.49 → 0.1.50

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c-next",
3
- "version": "0.1.49",
3
+ "version": "0.1.50",
4
4
  "description": "A safer C for embedded systems development. Transpiles to clean, readable C.",
5
5
  "main": "src/index.ts",
6
6
  "bin": {
@@ -1178,6 +1178,57 @@ export default class CodeGenerator implements IOrchestrator {
1178
1178
  return this.functionParamLists;
1179
1179
  }
1180
1180
 
1181
+ /**
1182
+ * Issue #561: Analyze modifications in a parse tree without full code generation.
1183
+ * Used by Pipeline.transpileSource() to collect modification info from includes
1184
+ * for cross-file const inference (unified with Pipeline.run() behavior).
1185
+ *
1186
+ * Returns the modifications and param lists discovered in this tree.
1187
+ */
1188
+ analyzeModificationsOnly(tree: Parser.ProgramContext): {
1189
+ modifications: Map<string, Set<string>>;
1190
+ paramLists: Map<string, string[]>;
1191
+ } {
1192
+ // Save current state
1193
+ const savedModifications = new Map(this.modifiedParameters);
1194
+ const savedParamLists = new Map(this.functionParamLists);
1195
+ const savedCallGraph = new Map(this.functionCallGraph);
1196
+
1197
+ // Clear for fresh analysis
1198
+ this.modifiedParameters.clear();
1199
+ this.functionParamLists.clear();
1200
+ this.functionCallGraph.clear();
1201
+
1202
+ // Run modification analysis on the tree
1203
+ this.collectFunctionParametersAndModifications(tree);
1204
+
1205
+ // Capture results before restoring state
1206
+ const modifications = new Map<string, Set<string>>();
1207
+ for (const [funcName, params] of this.modifiedParameters) {
1208
+ modifications.set(funcName, new Set(params));
1209
+ }
1210
+ const paramLists = new Map<string, string[]>();
1211
+ for (const [funcName, params] of this.functionParamLists) {
1212
+ paramLists.set(funcName, [...params]);
1213
+ }
1214
+
1215
+ // Restore previous state by clearing and repopulating (readonly maps)
1216
+ this.modifiedParameters.clear();
1217
+ for (const [k, v] of savedModifications) {
1218
+ this.modifiedParameters.set(k, v);
1219
+ }
1220
+ this.functionParamLists.clear();
1221
+ for (const [k, v] of savedParamLists) {
1222
+ this.functionParamLists.set(k, v);
1223
+ }
1224
+ this.functionCallGraph.clear();
1225
+ for (const [k, v] of savedCallGraph) {
1226
+ this.functionCallGraph.set(k, v);
1227
+ }
1228
+
1229
+ return { modifications, paramLists };
1230
+ }
1231
+
1181
1232
  /**
1182
1233
  * Issue #268: Check if a callee function's parameter at given index is modified.
1183
1234
  * Returns true if the callee modifies that parameter (should not have const).
@@ -2473,9 +2524,17 @@ export default class CodeGenerator implements IOrchestrator {
2473
2524
  const memberNames: string[] = [];
2474
2525
 
2475
2526
  // Start with primary identifier if it's a scope name (not 'global' or 'this')
2527
+ // Issue #561: When 'this' is used, resolve to the current scope name from funcName
2476
2528
  const primaryId = primary.IDENTIFIER()?.getText();
2477
- if (primaryId && primaryId !== "global" && primaryId !== "this") {
2529
+ if (primaryId && primaryId !== "global") {
2478
2530
  memberNames.push(primaryId);
2531
+ } else if (primary.THIS()) {
2532
+ // Issue #561: 'this' keyword - resolve to current scope name from funcName
2533
+ // funcName format: "ScopeName_methodName" -> extract "ScopeName"
2534
+ const scopeName = funcName.split("_")[0];
2535
+ if (scopeName && scopeName !== funcName) {
2536
+ memberNames.push(scopeName);
2537
+ }
2479
2538
  }
2480
2539
 
2481
2540
  // Collect member access names until we hit a function call
@@ -599,6 +599,7 @@ class Pipeline {
599
599
 
600
600
  /**
601
601
  * Stage 3: Collect symbols from a C-Next file
602
+ * Issue #561: Also collects modification analysis in C++ mode for unified cross-file const inference
602
603
  */
603
604
  private collectCNextSymbols(file: IDiscoveredFile): void {
604
605
  const content = readFileSync(file.path, "utf-8");
@@ -640,6 +641,32 @@ class Pipeline {
640
641
  // This ensures enum member info is available for all files before code generation
641
642
  const symbolInfo = TSymbolInfoAdapter.convert(tSymbols);
642
643
  this.symbolInfoByFile.set(file.path, symbolInfo);
644
+
645
+ // Issue #561: Collect modification analysis in C++ mode for cross-file const inference
646
+ // This unifies behavior between run() and transpileSource() code paths
647
+ if (this.cppDetected) {
648
+ const { modifications, paramLists } =
649
+ this.codeGenerator.analyzeModificationsOnly(tree);
650
+
651
+ // Accumulate modifications
652
+ for (const [funcName, params] of modifications) {
653
+ const existing = this.accumulatedModifications.get(funcName);
654
+ if (existing) {
655
+ for (const param of params) {
656
+ existing.add(param);
657
+ }
658
+ } else {
659
+ this.accumulatedModifications.set(funcName, new Set(params));
660
+ }
661
+ }
662
+
663
+ // Accumulate param lists
664
+ for (const [funcName, params] of paramLists) {
665
+ if (!this.accumulatedParamLists.has(funcName)) {
666
+ this.accumulatedParamLists.set(funcName, [...params]);
667
+ }
668
+ }
669
+ }
643
670
  }
644
671
 
645
672
  /**
@@ -1241,6 +1268,11 @@ class Pipeline {
1241
1268
  await this.cacheManager.initialize();
1242
1269
  }
1243
1270
 
1271
+ // Issue #561: Clear cross-file modification tracking for fresh analysis
1272
+ // This ensures each transpileSource() call starts with a clean slate
1273
+ this.accumulatedModifications.clear();
1274
+ this.accumulatedParamLists.clear();
1275
+
1244
1276
  // Step 1: Build search paths using unified IncludeResolver
1245
1277
  const searchPaths = IncludeResolver.buildSearchPaths(
1246
1278
  workingDir,
@@ -1415,6 +1447,15 @@ class Pipeline {
1415
1447
  );
1416
1448
  }
1417
1449
 
1450
+ // Issue #561: Inject cross-file modification data for const inference
1451
+ // This unifies behavior with run() - both paths now share modifications from includes
1452
+ if (this.cppDetected && this.accumulatedModifications.size > 0) {
1453
+ this.codeGenerator.setCrossFileModifications(
1454
+ this.accumulatedModifications,
1455
+ this.accumulatedParamLists,
1456
+ );
1457
+ }
1458
+
1418
1459
  const code = this.codeGenerator.generate(
1419
1460
  tree,
1420
1461
  this.symbolTable,