c-next 0.2.12 → 0.2.13

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.
Files changed (66) hide show
  1. package/README.md +80 -649
  2. package/dist/index.js +7387 -6211
  3. package/dist/index.js.map +4 -4
  4. package/grammar/C.g4 +9 -3
  5. package/package.json +1 -2
  6. package/src/__tests__/index.test.ts +1 -1
  7. package/src/cli/CleanCommand.ts +8 -12
  8. package/src/cli/Cli.ts +29 -6
  9. package/src/cli/Runner.ts +42 -62
  10. package/src/cli/__tests__/CleanCommand.test.ts +10 -10
  11. package/src/cli/__tests__/Cli.test.ts +59 -7
  12. package/src/cli/__tests__/ConfigPrinter.test.ts +12 -12
  13. package/src/cli/__tests__/PathNormalizer.test.ts +5 -5
  14. package/src/cli/__tests__/Runner.test.ts +108 -82
  15. package/src/cli/serve/ServeCommand.ts +1 -1
  16. package/src/cli/types/ICliConfig.ts +2 -2
  17. package/src/lib/parseWithSymbols.ts +21 -21
  18. package/src/transpiler/Transpiler.ts +88 -43
  19. package/src/transpiler/__tests__/DualCodePaths.test.ts +29 -29
  20. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +244 -72
  21. package/src/transpiler/__tests__/Transpiler.test.ts +32 -72
  22. package/src/transpiler/__tests__/determineProjectRoot.test.ts +30 -28
  23. package/src/transpiler/__tests__/needsConditionalPreprocessing.test.ts +1 -1
  24. package/src/transpiler/data/CNextMarkerDetector.ts +34 -0
  25. package/src/transpiler/data/CppEntryPointScanner.ts +174 -0
  26. package/src/transpiler/data/FileDiscovery.ts +2 -105
  27. package/src/transpiler/data/InputExpansion.ts +37 -81
  28. package/src/transpiler/data/__tests__/CNextMarkerDetector.test.ts +62 -0
  29. package/src/transpiler/data/__tests__/CppEntryPointScanner.test.ts +239 -0
  30. package/src/transpiler/data/__tests__/FileDiscovery.test.ts +45 -191
  31. package/src/transpiler/data/__tests__/InputExpansion.test.ts +36 -204
  32. package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +2 -2
  33. package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +4 -5
  34. package/src/transpiler/logic/parser/c/grammar/C.interp +19 -1
  35. package/src/transpiler/logic/parser/c/grammar/C.tokens +231 -213
  36. package/src/transpiler/logic/parser/c/grammar/CLexer.interp +28 -1
  37. package/src/transpiler/logic/parser/c/grammar/CLexer.tokens +231 -213
  38. package/src/transpiler/logic/parser/c/grammar/CLexer.ts +654 -600
  39. package/src/transpiler/logic/parser/c/grammar/CParser.ts +1175 -1099
  40. package/src/transpiler/logic/symbols/SymbolTable.ts +19 -7
  41. package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +78 -0
  42. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolInfoAdapter.test.ts +6 -6
  43. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolInfoAdapter.ts +28 -27
  44. package/src/transpiler/logic/symbols/cnext/index.ts +4 -4
  45. package/src/transpiler/logic/symbols/cnext/utils/SymbolNameUtils.ts +5 -5
  46. package/src/transpiler/output/codegen/CodeGenerator.ts +7 -1
  47. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +15 -0
  48. package/src/transpiler/output/codegen/__tests__/ExpressionWalker.test.ts +3 -3
  49. package/src/transpiler/output/codegen/__tests__/RequireInclude.test.ts +14 -14
  50. package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +2 -2
  51. package/src/transpiler/output/codegen/utils/QualifiedNameGenerator.ts +7 -7
  52. package/src/transpiler/output/codegen/utils/__tests__/QualifiedNameGenerator.test.ts +3 -3
  53. package/src/transpiler/output/headers/BaseHeaderGenerator.ts +10 -1
  54. package/src/transpiler/output/headers/HeaderGenerator.ts +3 -0
  55. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +6 -2
  56. package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +16 -0
  57. package/src/transpiler/output/headers/adapters/HeaderSymbolAdapter.ts +19 -19
  58. package/src/transpiler/output/headers/adapters/__tests__/HeaderSymbolAdapter.test.ts +5 -5
  59. package/src/transpiler/state/SymbolRegistry.ts +10 -12
  60. package/src/transpiler/state/__tests__/SymbolRegistry.test.ts +11 -13
  61. package/src/transpiler/types/IPipelineFile.ts +3 -0
  62. package/src/transpiler/types/ITranspilerConfig.ts +2 -2
  63. package/src/transpiler/types/symbols/IScopeSymbol.ts +1 -1
  64. package/src/utils/FunctionUtils.ts +3 -3
  65. package/src/utils/__tests__/FunctionUtils.test.ts +6 -4
  66. package/src/transpiler/data/types/IDiscoveryOptions.ts +0 -15
@@ -157,7 +157,7 @@ class SymbolTable {
157
157
  * Called automatically when adding struct symbols.
158
158
  */
159
159
  private registerStructFields(struct: IStructSymbol): void {
160
- const mangledName = SymbolNameUtils.getMangledName(struct);
160
+ const cName = SymbolNameUtils.getTranspiledCName(struct);
161
161
 
162
162
  for (const [fieldName, fieldInfo] of struct.fields) {
163
163
  // Convert TType to string for structFields map
@@ -169,7 +169,7 @@ class SymbolTable {
169
169
  );
170
170
 
171
171
  this.addStructField(
172
- mangledName,
172
+ cName,
173
173
  fieldName,
174
174
  typeString,
175
175
  numericDims && numericDims.length > 0 ? numericDims : undefined,
@@ -651,17 +651,29 @@ class SymbolTable {
651
651
  (s) => s.sourceLanguage === ESourceLanguage.Cpp,
652
652
  );
653
653
 
654
- if (cnextDefs.length > 0 && (cDefs.length > 0 || cppDefs.length > 0)) {
655
- const locations = globalDefinitions.map(
654
+ // Issue #967: Only global-scope C-Next symbols can conflict with C/C++ symbols.
655
+ // Scoped symbols (e.g., Touch.read) live in a namespace and don't compete
656
+ // with C's global symbols (e.g., POSIX read()).
657
+ const conflictingCnextDefs = cnextDefs.filter((s) => {
658
+ const tSymbol = s as TSymbol;
659
+ return tSymbol.scope.name === "";
660
+ });
661
+
662
+ if (
663
+ conflictingCnextDefs.length > 0 &&
664
+ (cDefs.length > 0 || cppDefs.length > 0)
665
+ ) {
666
+ const conflictingDefs = [...conflictingCnextDefs, ...cDefs, ...cppDefs];
667
+ const locations = conflictingDefs.map(
656
668
  (s) =>
657
669
  `${s.sourceLanguage.toUpperCase()} (${s.sourceFile}:${s.sourceLine})`,
658
670
  );
659
671
 
660
672
  return {
661
- symbolName: globalDefinitions[0].name,
662
- definitions: globalDefinitions,
673
+ symbolName: conflictingDefs[0].name,
674
+ definitions: conflictingDefs,
663
675
  severity: "error",
664
- message: `Symbol conflict: '${globalDefinitions[0].name}' is defined in multiple languages:\n ${locations.join("\n ")}\nRename the C-Next symbol to resolve.`,
676
+ message: `Symbol conflict: '${conflictingDefs[0].name}' is defined in multiple languages:\n ${locations.join("\n ")}\nRename the C-Next symbol to resolve.`,
665
677
  };
666
678
  }
667
679
 
@@ -478,6 +478,84 @@ describe("SymbolTable", () => {
478
478
  // Two globals with same name IS a conflict
479
479
  expect(symbolTable.hasConflict("globalVar")).toBe(true);
480
480
  });
481
+
482
+ // Issue #967: Scoped C-Next symbols live in a namespace and don't conflict
483
+ // with C's global symbols. Only global-scope C-Next symbols can conflict.
484
+ it("should NOT detect conflict for scoped C-Next method vs C function with same bare name", () => {
485
+ const globalScope = TestScopeUtils.createMockGlobalScope();
486
+ const touchScope = TestScopeUtils.createMockScope("Touch", globalScope);
487
+
488
+ // Add C-Next scoped function 'read' in scope 'Touch'
489
+ // This transpiles to Touch_read()
490
+ symbolTable.addTSymbol({
491
+ kind: "function",
492
+ name: "read",
493
+ sourceFile: "touch.cnx",
494
+ sourceLine: 28,
495
+ sourceLanguage: ESourceLanguage.CNext,
496
+ isExported: true,
497
+ returnType: TTypeUtils.createPrimitive("u8"),
498
+ parameters: [],
499
+ scope: touchScope,
500
+ visibility: "public",
501
+ body: null,
502
+ } as IFunctionSymbol);
503
+
504
+ // Add C function 'read' from POSIX headers
505
+ // This stays as read()
506
+ symbolTable.addCSymbol({
507
+ kind: "function",
508
+ name: "read",
509
+ sourceFile: "lv_pthread.h",
510
+ sourceLine: 80,
511
+ sourceLanguage: ESourceLanguage.C,
512
+ isExported: true,
513
+ type: "ssize_t",
514
+ parameters: [
515
+ { name: "fd", type: "int", isConst: false, isArray: false },
516
+ { name: "buf", type: "void*", isConst: false, isArray: false },
517
+ { name: "count", type: "size_t", isConst: false, isArray: false },
518
+ ],
519
+ });
520
+
521
+ // Touch.read() is in a namespace — does NOT conflict with C's global read()
522
+ expect(symbolTable.hasConflict("read")).toBe(false);
523
+ });
524
+
525
+ // Issue #967: Global C-Next functions SHOULD still conflict with C functions
526
+ it("should detect conflict for global C-Next function vs C function", () => {
527
+ const globalScope = TestScopeUtils.createMockGlobalScope();
528
+
529
+ // Add global C-Next function 'read'
530
+ symbolTable.addTSymbol({
531
+ kind: "function",
532
+ name: "read",
533
+ sourceFile: "utils.cnx",
534
+ sourceLine: 5,
535
+ sourceLanguage: ESourceLanguage.CNext,
536
+ isExported: true,
537
+ returnType: TTypeUtils.createPrimitive("u8"),
538
+ parameters: [],
539
+ scope: globalScope,
540
+ visibility: "public",
541
+ body: null,
542
+ } as IFunctionSymbol);
543
+
544
+ // Add C function 'read'
545
+ symbolTable.addCSymbol({
546
+ kind: "function",
547
+ name: "read",
548
+ sourceFile: "unistd.h",
549
+ sourceLine: 100,
550
+ sourceLanguage: ESourceLanguage.C,
551
+ isExported: true,
552
+ type: "ssize_t",
553
+ parameters: [],
554
+ });
555
+
556
+ // Global C-Next read() DOES conflict with C's read()
557
+ expect(symbolTable.hasConflict("read")).toBe(true);
558
+ });
481
559
  });
482
560
 
483
561
  // ========================================================================
@@ -466,7 +466,7 @@ describe("TSymbolInfoAdapter", () => {
466
466
  const motorScope = TestScopeUtils.createMockScope("Motor");
467
467
  const variable: IVariableSymbol = {
468
468
  kind: "variable",
469
- name: "MAX_SPEED", // Bare name - adapter computes mangled name
469
+ name: "MAX_SPEED", // Bare name - adapter computes transpiled C name
470
470
  scope: motorScope,
471
471
  sourceFile: "test.cnx",
472
472
  sourceLine: 1,
@@ -481,7 +481,7 @@ describe("TSymbolInfoAdapter", () => {
481
481
 
482
482
  const info = TSymbolInfoAdapter.convert([variable]);
483
483
 
484
- // Adapter stores using mangled name (scope + bare name)
484
+ // Adapter stores using transpiled C name (scope + bare name)
485
485
  expect(info.scopePrivateConstValues.get("Motor_MAX_SPEED")).toBe("255");
486
486
  });
487
487
 
@@ -489,7 +489,7 @@ describe("TSymbolInfoAdapter", () => {
489
489
  const motorScope = TestScopeUtils.createMockScope("Motor");
490
490
  const variable: IVariableSymbol = {
491
491
  kind: "variable",
492
- name: "PUBLIC_CONST", // Bare name - adapter computes mangled name
492
+ name: "PUBLIC_CONST", // Bare name - adapter computes transpiled C name
493
493
  scope: motorScope,
494
494
  sourceFile: "test.cnx",
495
495
  sourceLine: 1,
@@ -513,7 +513,7 @@ describe("TSymbolInfoAdapter", () => {
513
513
  const motorScope = TestScopeUtils.createMockScope("Motor");
514
514
  const variable: IVariableSymbol = {
515
515
  kind: "variable",
516
- name: "counter", // Bare name - adapter computes mangled name
516
+ name: "counter", // Bare name - adapter computes transpiled C name
517
517
  scope: motorScope,
518
518
  sourceFile: "test.cnx",
519
519
  sourceLine: 1,
@@ -535,7 +535,7 @@ describe("TSymbolInfoAdapter", () => {
535
535
  const motorScope = TestScopeUtils.createMockScope("Motor");
536
536
  const variable: IVariableSymbol = {
537
537
  kind: "variable",
538
- name: "LOOKUP_TABLE", // Bare name - adapter computes mangled name
538
+ name: "LOOKUP_TABLE", // Bare name - adapter computes transpiled C name
539
539
  scope: motorScope,
540
540
  sourceFile: "test.cnx",
541
541
  sourceLine: 1,
@@ -562,7 +562,7 @@ describe("TSymbolInfoAdapter", () => {
562
562
  const motorScope = TestScopeUtils.createMockScope("Motor");
563
563
  const variable: IVariableSymbol = {
564
564
  kind: "variable",
565
- name: "MATRIX", // Bare name - adapter computes mangled name
565
+ name: "MATRIX", // Bare name - adapter computes transpiled C name
566
566
  scope: motorScope,
567
567
  sourceFile: "test.cnx",
568
568
  sourceLine: 1,
@@ -239,8 +239,9 @@ class TSymbolInfoAdapter {
239
239
 
240
240
  // === Private Processing Methods ===
241
241
 
242
- // Use shared utility for name mangling
243
- private static readonly getMangledName = SymbolNameUtils.getMangledName;
242
+ // Use shared utility for transpiled C names
243
+ private static readonly getTranspiledCName =
244
+ SymbolNameUtils.getTranspiledCName;
244
245
 
245
246
  private static processStruct(
246
247
  struct: IStructSymbol,
@@ -249,9 +250,9 @@ class TSymbolInfoAdapter {
249
250
  structFieldArrays: Map<string, Set<string>>,
250
251
  structFieldDimensions: Map<string, Map<string, number[]>>,
251
252
  ): void {
252
- // Use mangled name for lookups (e.g., "Geometry_Point")
253
- const mangledName = TSymbolInfoAdapter.getMangledName(struct);
254
- knownStructs.add(mangledName);
253
+ // Use transpiled C name for lookups (e.g., "Geometry_Point")
254
+ const cName = TSymbolInfoAdapter.getTranspiledCName(struct);
255
+ knownStructs.add(cName);
255
256
 
256
257
  const fields = new Map<string, string>();
257
258
  const arrayFields = new Set<string>();
@@ -277,10 +278,10 @@ class TSymbolInfoAdapter {
277
278
  }
278
279
  }
279
280
 
280
- structFields.set(mangledName, fields);
281
- structFieldArrays.set(mangledName, arrayFields);
281
+ structFields.set(cName, fields);
282
+ structFieldArrays.set(cName, arrayFields);
282
283
  if (dimensions.size > 0) {
283
- structFieldDimensions.set(mangledName, dimensions);
284
+ structFieldDimensions.set(cName, dimensions);
284
285
  }
285
286
  }
286
287
 
@@ -289,9 +290,9 @@ class TSymbolInfoAdapter {
289
290
  knownEnums: Set<string>,
290
291
  enumMembers: Map<string, Map<string, number>>,
291
292
  ): void {
292
- const mangledName = TSymbolInfoAdapter.getMangledName(enumSym);
293
- knownEnums.add(mangledName);
294
- enumMembers.set(mangledName, new Map(enumSym.members));
293
+ const cName = TSymbolInfoAdapter.getTranspiledCName(enumSym);
294
+ knownEnums.add(cName);
295
+ enumMembers.set(cName, new Map(enumSym.members));
295
296
  }
296
297
 
297
298
  private static processBitmap(
@@ -301,10 +302,10 @@ class TSymbolInfoAdapter {
301
302
  bitmapBackingType: Map<string, string>,
302
303
  bitmapBitWidth: Map<string, number>,
303
304
  ): void {
304
- const mangledName = TSymbolInfoAdapter.getMangledName(bitmap);
305
- knownBitmaps.add(mangledName);
306
- bitmapBackingType.set(mangledName, bitmap.backingType);
307
- bitmapBitWidth.set(mangledName, bitmap.bitWidth);
305
+ const cName = TSymbolInfoAdapter.getTranspiledCName(bitmap);
306
+ knownBitmaps.add(cName);
307
+ bitmapBackingType.set(cName, bitmap.backingType);
308
+ bitmapBitWidth.set(cName, bitmap.bitWidth);
308
309
 
309
310
  const fields = new Map<string, { offset: number; width: number }>();
310
311
  for (const [fieldName, fieldInfo] of bitmap.fields) {
@@ -313,7 +314,7 @@ class TSymbolInfoAdapter {
313
314
  width: fieldInfo.width,
314
315
  });
315
316
  }
316
- bitmapFields.set(mangledName, fields);
317
+ bitmapFields.set(cName, fields);
317
318
  }
318
319
 
319
320
  private static processScope(
@@ -338,18 +339,18 @@ class TSymbolInfoAdapter {
338
339
  knownBitmaps: Set<string>,
339
340
  maps: IRegisterMaps,
340
341
  ): void {
341
- const mangledName = TSymbolInfoAdapter.getMangledName(register);
342
- maps.knownRegisters.add(mangledName);
343
- maps.registerBaseAddresses.set(mangledName, register.baseAddress);
342
+ const cName = TSymbolInfoAdapter.getTranspiledCName(register);
343
+ maps.knownRegisters.add(cName);
344
+ maps.registerBaseAddresses.set(cName, register.baseAddress);
344
345
 
345
346
  // Check if this is a scoped register (has non-global scope)
346
347
  const isScoped = register.scope.name !== "";
347
348
  if (isScoped) {
348
- maps.scopedRegisters.set(mangledName, register.baseAddress);
349
+ maps.scopedRegisters.set(cName, register.baseAddress);
349
350
  }
350
351
 
351
352
  for (const [memberName, memberInfo] of register.members) {
352
- const fullName = `${mangledName}_${memberName}`;
353
+ const fullName = `${cName}_${memberName}`;
353
354
 
354
355
  maps.registerMemberAccess.set(fullName, memberInfo.access);
355
356
  maps.registerMemberOffsets.set(fullName, memberInfo.offset);
@@ -370,7 +371,7 @@ class TSymbolInfoAdapter {
370
371
  scopeMembers: Map<string, Set<string>>,
371
372
  scopePrivateConstValues: Map<string, string>,
372
373
  ): void {
373
- const mangledName = TSymbolInfoAdapter.getMangledName(variable);
374
+ const cName = TSymbolInfoAdapter.getTranspiledCName(variable);
374
375
  const scopeName = variable.scope.name;
375
376
  const isScoped = scopeName !== "";
376
377
 
@@ -381,7 +382,7 @@ class TSymbolInfoAdapter {
381
382
  members = new Set<string>();
382
383
  scopeMembers.set(scopeName, members);
383
384
  }
384
- members.add(variable.name); // Add local name (e.g., "value"), not mangled
385
+ members.add(variable.name); // Add local name (e.g., "value"), not transpiled C name
385
386
  }
386
387
 
387
388
  // Issue #282: Track private const values for inlining
@@ -395,7 +396,7 @@ class TSymbolInfoAdapter {
395
396
  variable.initialValue &&
396
397
  !variable.isArray
397
398
  ) {
398
- scopePrivateConstValues.set(mangledName, variable.initialValue);
399
+ scopePrivateConstValues.set(cName, variable.initialValue);
399
400
  }
400
401
  }
401
402
 
@@ -405,10 +406,10 @@ class TSymbolInfoAdapter {
405
406
  ): void {
406
407
  // Track function return types for enum validation in assignments
407
408
  // This enables recognizing that Motor.getMode() returns Motor_EMode
408
- // Use mangled name (e.g., "Motor_getMode") for lookup consistency
409
- const mangledName = TSymbolInfoAdapter.getMangledName(func);
409
+ // Use transpiled C name (e.g., "Motor_getMode") for lookup consistency
410
+ const cName = TSymbolInfoAdapter.getTranspiledCName(func);
410
411
  const returnTypeStr = TypeResolver.getTypeName(func.returnType);
411
- functionReturnTypes.set(mangledName, returnTypeStr);
412
+ functionReturnTypes.set(cName, returnTypeStr);
412
413
  }
413
414
 
414
415
  private static cnextTypeToCType(typeName: string): string {
@@ -164,7 +164,7 @@ class CNextResolver {
164
164
  globalScope,
165
165
  );
166
166
  symbols.push(symbol);
167
- // Use mangled name (global bitmaps have no scope prefix)
167
+ // Use transpiled C name (global bitmaps have no scope prefix)
168
168
  knownBitmaps.add(symbol.name);
169
169
  }
170
170
 
@@ -200,9 +200,9 @@ class CNextResolver {
200
200
  const bitmapCtx = member.bitmapDeclaration()!;
201
201
  const symbol = BitmapCollector.collect(bitmapCtx, sourceFile, scope);
202
202
  symbols.push(symbol);
203
- // Use mangled name (e.g., "Timer_ControlBits") for scoped bitmaps
204
- const mangledName = `${scopeName}_${symbol.name}`;
205
- knownBitmaps.add(mangledName);
203
+ // Use transpiled C name (e.g., "Timer_ControlBits") for scoped bitmaps
204
+ const cName = `${scopeName}_${symbol.name}`;
205
+ knownBitmaps.add(cName);
206
206
  }
207
207
 
208
208
  // Collect structs early so they're available as types
@@ -3,13 +3,13 @@
3
3
  */
4
4
 
5
5
  /**
6
- * Get the C-mangled name for a symbol (e.g., "Geometry_Point" for Point in Geometry scope).
7
- * Works with any symbol that has a name and scope reference.
6
+ * Get the transpiled C name for a symbol (e.g., "Geometry_Point" for Point in Geometry scope).
7
+ * Use only at the output layer for C code generation, not for input-side logic.
8
8
  *
9
9
  * @param symbol Object with name and scope.name properties
10
- * @returns The mangled name (e.g., "Motor_init") or bare name if global scope
10
+ * @returns The C output name (e.g., "Motor_init") or bare name if global scope
11
11
  */
12
- function getMangledName(symbol: {
12
+ function getTranspiledCName(symbol: {
13
13
  name: string;
14
14
  scope: { name: string };
15
15
  }): string {
@@ -21,7 +21,7 @@ function getMangledName(symbol: {
21
21
  }
22
22
 
23
23
  class SymbolNameUtils {
24
- static readonly getMangledName = getMangledName;
24
+ static readonly getTranspiledCName = getTranspiledCName;
25
25
  }
26
26
 
27
27
  export default SymbolNameUtils;
@@ -3,6 +3,7 @@
3
3
  * Transforms C-Next AST to clean, readable C code
4
4
  */
5
5
 
6
+ import { basename } from "node:path";
6
7
  import { CommonTokenStream, ParserRuleContext } from "antlr4ng";
7
8
  import * as Parser from "../../logic/parser/grammar/CNextParser";
8
9
 
@@ -2225,9 +2226,14 @@ export default class CodeGenerator implements IOrchestrator {
2225
2226
  const output: string[] = [];
2226
2227
  const symbols = CodeGenState.symbols!;
2227
2228
  // Add header comment
2229
+ const sourcePath = CodeGenState.sourcePath;
2230
+ const generatedLine = sourcePath
2231
+ ? ` * Generated by C-Next Transpiler from: ${basename(sourcePath)}`
2232
+ : " * Generated by C-Next Transpiler";
2233
+
2228
2234
  output.push(
2229
2235
  "/**",
2230
- " * Generated by C-Next Transpiler",
2236
+ generatedLine,
2231
2237
  " * A safer C for embedded systems",
2232
2238
  " */",
2233
2239
  "",
@@ -164,6 +164,21 @@ describe("CodeGenerator", () => {
164
164
 
165
165
  expect(code).toContain("void foo");
166
166
  });
167
+
168
+ it("should include source path in generation comment", () => {
169
+ const source = `void test() { }`;
170
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
171
+ const generator = new CodeGenerator();
172
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
173
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
174
+
175
+ const code = generator.generate(tree, tokenStream, {
176
+ symbolInfo: symbols,
177
+ sourcePath: "led.cnx",
178
+ });
179
+
180
+ expect(code).toContain("Generated by C-Next Transpiler from: led.cnx");
181
+ });
167
182
  });
168
183
 
169
184
  describe("IOrchestrator interface", () => {
@@ -311,7 +311,7 @@ describe("ExpressionWalker - const inference integration", () => {
311
311
  caller(val);
312
312
  }
313
313
  `;
314
- const transpiler = new Transpiler({ inputs: [] });
314
+ const transpiler = new Transpiler({ input: "" });
315
315
  const transpileResult = (
316
316
  await transpiler.transpile({ kind: "source", source: source })
317
317
  ).files[0];
@@ -341,7 +341,7 @@ describe("ExpressionWalker - const inference integration", () => {
341
341
  caller(val);
342
342
  }
343
343
  `;
344
- const transpiler = new Transpiler({ inputs: [] });
344
+ const transpiler = new Transpiler({ input: "" });
345
345
  const transpileResult = (
346
346
  await transpiler.transpile({ kind: "source", source: source })
347
347
  ).files[0];
@@ -370,7 +370,7 @@ describe("ExpressionWalker - const inference integration", () => {
370
370
  caller(val);
371
371
  }
372
372
  `;
373
- const transpiler = new Transpiler({ inputs: [] });
373
+ const transpiler = new Transpiler({ input: "" });
374
374
  const transpileResult = (
375
375
  await transpiler.transpile({ kind: "source", source: source })
376
376
  ).files[0];
@@ -18,7 +18,7 @@ describe("CodeGenerator requireInclude", () => {
18
18
 
19
19
  describe("stdint includes", () => {
20
20
  it("includes stdint.h for u8 type", async () => {
21
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
21
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
22
22
 
23
23
  const result = (
24
24
  await transpiler.transpile({ kind: "source", source: "u8 value <- 0;" })
@@ -29,7 +29,7 @@ describe("CodeGenerator requireInclude", () => {
29
29
  });
30
30
 
31
31
  it("includes stdint.h for u16 type", async () => {
32
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
32
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
33
33
 
34
34
  const result = (
35
35
  await transpiler.transpile({
@@ -43,7 +43,7 @@ describe("CodeGenerator requireInclude", () => {
43
43
  });
44
44
 
45
45
  it("includes stdint.h for u32 type", async () => {
46
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
46
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
47
47
 
48
48
  const result = (
49
49
  await transpiler.transpile({
@@ -57,7 +57,7 @@ describe("CodeGenerator requireInclude", () => {
57
57
  });
58
58
 
59
59
  it("includes stdint.h for i32 type", async () => {
60
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
60
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
61
61
 
62
62
  const result = (
63
63
  await transpiler.transpile({
@@ -71,7 +71,7 @@ describe("CodeGenerator requireInclude", () => {
71
71
  });
72
72
 
73
73
  it("includes stdint.h for bitmap types", async () => {
74
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
74
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
75
75
 
76
76
  const result = (
77
77
  await transpiler.transpile({
@@ -94,7 +94,7 @@ describe("CodeGenerator requireInclude", () => {
94
94
 
95
95
  describe("stdbool includes", () => {
96
96
  it("includes stdbool.h for bool type", async () => {
97
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
97
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
98
98
 
99
99
  const result = (
100
100
  await transpiler.transpile({
@@ -110,7 +110,7 @@ describe("CodeGenerator requireInclude", () => {
110
110
 
111
111
  describe("string includes", () => {
112
112
  it("includes string.h for bounded string type", async () => {
113
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
113
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
114
114
 
115
115
  const result = (
116
116
  await transpiler.transpile({
@@ -124,7 +124,7 @@ describe("CodeGenerator requireInclude", () => {
124
124
  });
125
125
 
126
126
  it("includes string.h for const string inference", async () => {
127
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
127
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
128
128
 
129
129
  const result = (
130
130
  await transpiler.transpile({
@@ -140,7 +140,7 @@ describe("CodeGenerator requireInclude", () => {
140
140
 
141
141
  describe("isr includes", () => {
142
142
  it("generates ISR typedef for ISR type", async () => {
143
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
143
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
144
144
 
145
145
  const result = (
146
146
  await transpiler.transpile({
@@ -156,7 +156,7 @@ describe("CodeGenerator requireInclude", () => {
156
156
 
157
157
  describe("float static assert includes", () => {
158
158
  it("generates static assert for float bit indexing write", async () => {
159
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
159
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
160
160
 
161
161
  const result = (
162
162
  await transpiler.transpile({
@@ -177,7 +177,7 @@ describe("CodeGenerator requireInclude", () => {
177
177
  });
178
178
 
179
179
  it("generates static assert for float bit indexing read (no string.h)", async () => {
180
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
180
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
181
181
 
182
182
  const result = (
183
183
  await transpiler.transpile({
@@ -201,7 +201,7 @@ describe("CodeGenerator requireInclude", () => {
201
201
 
202
202
  describe("limits includes", () => {
203
203
  it("includes limits.h for float-to-int clamp cast", async () => {
204
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
204
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
205
205
 
206
206
  const result = (
207
207
  await transpiler.transpile({
@@ -221,7 +221,7 @@ describe("CodeGenerator requireInclude", () => {
221
221
 
222
222
  describe("multiple includes", () => {
223
223
  it("includes multiple headers when needed", async () => {
224
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
224
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
225
225
 
226
226
  const result = (
227
227
  await transpiler.transpile({
@@ -241,7 +241,7 @@ describe("CodeGenerator requireInclude", () => {
241
241
  });
242
242
 
243
243
  it("does not include unused headers", async () => {
244
- const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
244
+ const transpiler = new Transpiler({ input: "", noCache: true }, mockFs);
245
245
 
246
246
  const result = (
247
247
  await transpiler.transpile({
@@ -11,7 +11,7 @@ import Transpiler from "../../../Transpiler";
11
11
  * Helper to transpile C-Next source and return the C output
12
12
  */
13
13
  async function transpileSource(source: string): Promise<string> {
14
- const transpiler = new Transpiler({ inputs: [] });
14
+ const transpiler = new Transpiler({ input: "" });
15
15
  const result = (
16
16
  await transpiler.transpile({ kind: "source", source: source })
17
17
  ).files[0];
@@ -130,7 +130,7 @@ describe("trackVariableTypeWithName helpers", () => {
130
130
  }
131
131
  `;
132
132
  const code = await transpileSource(source);
133
- // Scoped type should be mangled to Motor_State
133
+ // Scoped type should be transpiled to Motor_State
134
134
  expect(code).toContain("Motor_State");
135
135
  });
136
136
 
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * QualifiedNameGenerator - C-style name generation for C-Next symbols
3
3
  *
4
- * Provides C-style mangled name generation for use in the output layer.
5
- * Delegates to FunctionUtils.getCMangledName() for the actual implementation
4
+ * Provides transpiled C name generation for use in the output layer.
5
+ * Delegates to FunctionUtils.getTranspiledCName() for the actual implementation
6
6
  * to avoid duplication with the types layer.
7
7
  *
8
8
  * Design decisions:
@@ -24,16 +24,16 @@ class QualifiedNameGenerator {
24
24
  // ============================================================================
25
25
 
26
26
  /**
27
- * Generate the C-style mangled name for a function.
27
+ * Generate the transpiled C name for a function.
28
28
  *
29
29
  * For global scope functions, returns the bare name (e.g., "main").
30
30
  * For scoped functions, returns "Scope_name" (e.g., "Test_fillData").
31
31
  * For nested scopes, returns "Outer_Inner_name" (e.g., "Outer_Inner_deepFunc").
32
32
  *
33
- * Delegates to FunctionUtils.getCMangledName() to avoid duplication.
33
+ * Delegates to FunctionUtils.getTranspiledCName() to avoid duplication.
34
34
  */
35
35
  static forFunction(func: IFunctionSymbol): string {
36
- return FunctionUtils.getCMangledName(func);
36
+ return FunctionUtils.getTranspiledCName(func);
37
37
  }
38
38
 
39
39
  /**
@@ -61,7 +61,7 @@ class QualifiedNameGenerator {
61
61
  *
62
62
  * @param scopeName Scope name (e.g., "Test", "Outer.Inner") or undefined for global
63
63
  * @param funcName Bare function name (e.g., "fillData")
64
- * @returns C-mangled name (e.g., "Test_fillData")
64
+ * @returns Transpiled C name (e.g., "Test_fillData")
65
65
  */
66
66
  static forFunctionStrings(
67
67
  scopeName: string | undefined,
@@ -100,7 +100,7 @@ class QualifiedNameGenerator {
100
100
  *
101
101
  * @param scopeName Scope name or undefined for global
102
102
  * @param memberName Member name
103
- * @returns C-mangled name
103
+ * @returns Transpiled C name
104
104
  */
105
105
  static forMember(scopeName: string | undefined, memberName: string): string {
106
106
  if (!scopeName) {