c-next 0.1.71 → 0.2.0
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
|
@@ -271,8 +271,8 @@ class Transpiler {
|
|
|
271
271
|
// Stage 3b: Resolve external const array dimensions
|
|
272
272
|
CodeGenState.symbolTable.resolveExternalArrayDimensions();
|
|
273
273
|
|
|
274
|
-
// Stage 4: Check for symbol conflicts
|
|
275
|
-
if (!
|
|
274
|
+
// Stage 4: Check for symbol conflicts
|
|
275
|
+
if (!this._checkSymbolConflicts(result)) {
|
|
276
276
|
return;
|
|
277
277
|
}
|
|
278
278
|
|
|
@@ -581,7 +581,6 @@ class Transpiler {
|
|
|
581
581
|
cnextFiles: [...cnextIncludeFiles, mainFile],
|
|
582
582
|
headerFiles: allHeaders,
|
|
583
583
|
writeOutputToDisk: false,
|
|
584
|
-
skipConflictCheck: true,
|
|
585
584
|
};
|
|
586
585
|
}
|
|
587
586
|
|
|
@@ -1283,9 +1282,14 @@ class Transpiler {
|
|
|
1283
1282
|
? { ...typeInput, symbolTable: CodeGenState.symbolTable }
|
|
1284
1283
|
: undefined;
|
|
1285
1284
|
|
|
1286
|
-
// ADR-055 Phase 7: Convert TSymbol to IHeaderSymbol
|
|
1287
|
-
//
|
|
1288
|
-
const
|
|
1285
|
+
// ADR-055 Phase 7: Convert TSymbol to IHeaderSymbol with auto-const info
|
|
1286
|
+
// Issue #817: Apply auto-const info same as generateHeaderContent() does
|
|
1287
|
+
const unmodifiedParams = this.codeGenerator.getFunctionUnmodifiedParams();
|
|
1288
|
+
const headerSymbols = this.convertToHeaderSymbols(
|
|
1289
|
+
exportedSymbols,
|
|
1290
|
+
unmodifiedParams,
|
|
1291
|
+
allKnownEnums,
|
|
1292
|
+
);
|
|
1289
1293
|
|
|
1290
1294
|
const headerContent = this.headerGenerator.generate(
|
|
1291
1295
|
headerSymbols,
|
|
@@ -627,14 +627,30 @@ class SymbolTable {
|
|
|
627
627
|
}
|
|
628
628
|
|
|
629
629
|
// Multiple definitions in same language (excluding overloads) = ERROR
|
|
630
|
+
// Issue #817: Group by scope AND kind - symbols in different scopes don't conflict,
|
|
631
|
+
// and symbols with different kinds (variable vs scope) don't conflict either
|
|
630
632
|
if (cnextDefs.length > 1) {
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
633
|
+
const byScopeAndKind = this.groupCNextSymbolsByScopeAndKind(cnextDefs);
|
|
634
|
+
|
|
635
|
+
// Check each scope+kind group for conflicts (multiple symbols in same scope with same kind)
|
|
636
|
+
for (const symbols of byScopeAndKind.values()) {
|
|
637
|
+
if (symbols.length > 1) {
|
|
638
|
+
const locations = symbols.map(
|
|
639
|
+
(s) => `${s.sourceFile}:${s.sourceLine}`,
|
|
640
|
+
);
|
|
641
|
+
const scopeName = symbols[0].scope.name;
|
|
642
|
+
const displayName =
|
|
643
|
+
scopeName === ""
|
|
644
|
+
? symbols[0].name
|
|
645
|
+
: `${scopeName}.${symbols[0].name}`;
|
|
646
|
+
return {
|
|
647
|
+
symbolName: displayName,
|
|
648
|
+
definitions: symbols,
|
|
649
|
+
severity: "error",
|
|
650
|
+
message: `Symbol conflict: '${displayName}' is defined multiple times in C-Next:\n ${locations.join("\n ")}`,
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
}
|
|
638
654
|
}
|
|
639
655
|
|
|
640
656
|
// Same symbol in C and C++ - typically OK (same symbol)
|
|
@@ -645,6 +661,36 @@ class SymbolTable {
|
|
|
645
661
|
return null;
|
|
646
662
|
}
|
|
647
663
|
|
|
664
|
+
/**
|
|
665
|
+
* Issue #817: Group C-Next symbols by scope name and kind.
|
|
666
|
+
*
|
|
667
|
+
* Symbols in different scopes don't conflict (Foo.enabled vs Bar.enabled
|
|
668
|
+
* generate Foo_enabled and Bar_enabled). Symbols with different kinds also
|
|
669
|
+
* don't conflict (variable LED vs scope LED are distinct).
|
|
670
|
+
*
|
|
671
|
+
* @param symbols C-Next symbols to group (must all be TSymbol)
|
|
672
|
+
* @returns Map from "scopeName:kind" key to array of symbols
|
|
673
|
+
*/
|
|
674
|
+
private groupCNextSymbolsByScopeAndKind(
|
|
675
|
+
symbols: TAnySymbol[],
|
|
676
|
+
): Map<string, TSymbol[]> {
|
|
677
|
+
const byScopeAndKind = new Map<string, TSymbol[]>();
|
|
678
|
+
|
|
679
|
+
for (const def of symbols) {
|
|
680
|
+
const tSymbol = def as TSymbol;
|
|
681
|
+
const scopeName = tSymbol.scope.name;
|
|
682
|
+
const key = `${scopeName}:${tSymbol.kind}`;
|
|
683
|
+
const existing = byScopeAndKind.get(key);
|
|
684
|
+
if (existing) {
|
|
685
|
+
existing.push(tSymbol);
|
|
686
|
+
} else {
|
|
687
|
+
byScopeAndKind.set(key, [tSymbol]);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
return byScopeAndKind;
|
|
692
|
+
}
|
|
693
|
+
|
|
648
694
|
// ========================================================================
|
|
649
695
|
// Struct Field Information
|
|
650
696
|
// ========================================================================
|
|
@@ -322,6 +322,162 @@ describe("SymbolTable", () => {
|
|
|
322
322
|
|
|
323
323
|
expect(symbolTable.hasConflict("overloaded")).toBe(false);
|
|
324
324
|
});
|
|
325
|
+
|
|
326
|
+
// Issue #817: Scope-private members should NOT conflict across scopes
|
|
327
|
+
it("should NOT detect conflict for same-named members in different scopes", () => {
|
|
328
|
+
// Create two different named scopes
|
|
329
|
+
const globalScope = TestScopeUtils.createMockGlobalScope();
|
|
330
|
+
const fooScope = TestScopeUtils.createMockScope("Foo", globalScope);
|
|
331
|
+
const barScope = TestScopeUtils.createMockScope("Bar", globalScope);
|
|
332
|
+
|
|
333
|
+
// Add 'enabled' variable in scope Foo
|
|
334
|
+
symbolTable.addTSymbol({
|
|
335
|
+
kind: "variable",
|
|
336
|
+
name: "enabled",
|
|
337
|
+
sourceFile: "test.cnx",
|
|
338
|
+
sourceLine: 2,
|
|
339
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
340
|
+
isExported: false,
|
|
341
|
+
type: TTypeUtils.createPrimitive("bool"),
|
|
342
|
+
isArray: false,
|
|
343
|
+
isConst: false,
|
|
344
|
+
isAtomic: false,
|
|
345
|
+
scope: fooScope,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Add 'enabled' variable in scope Bar
|
|
349
|
+
symbolTable.addTSymbol({
|
|
350
|
+
kind: "variable",
|
|
351
|
+
name: "enabled",
|
|
352
|
+
sourceFile: "test.cnx",
|
|
353
|
+
sourceLine: 10,
|
|
354
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
355
|
+
isExported: false,
|
|
356
|
+
type: TTypeUtils.createPrimitive("bool"),
|
|
357
|
+
isArray: false,
|
|
358
|
+
isConst: false,
|
|
359
|
+
isAtomic: false,
|
|
360
|
+
scope: barScope,
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// These are NOT conflicts - they generate Foo_enabled and Bar_enabled
|
|
364
|
+
expect(symbolTable.hasConflict("enabled")).toBe(false);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
// Issue #817: Same-named functions in different scopes are not conflicts
|
|
368
|
+
it("should NOT detect conflict for same-named functions in different scopes", () => {
|
|
369
|
+
const globalScope = TestScopeUtils.createMockGlobalScope();
|
|
370
|
+
const fooScope = TestScopeUtils.createMockScope("Foo", globalScope);
|
|
371
|
+
const barScope = TestScopeUtils.createMockScope("Bar", globalScope);
|
|
372
|
+
|
|
373
|
+
// Add 'initialize' function in scope Foo
|
|
374
|
+
symbolTable.addTSymbol({
|
|
375
|
+
kind: "function",
|
|
376
|
+
name: "initialize",
|
|
377
|
+
sourceFile: "test.cnx",
|
|
378
|
+
sourceLine: 4,
|
|
379
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
380
|
+
isExported: true,
|
|
381
|
+
returnType: TTypeUtils.createPrimitive("void"),
|
|
382
|
+
parameters: [],
|
|
383
|
+
scope: fooScope,
|
|
384
|
+
visibility: "public",
|
|
385
|
+
body: null,
|
|
386
|
+
} as IFunctionSymbol);
|
|
387
|
+
|
|
388
|
+
// Add 'initialize' function in scope Bar
|
|
389
|
+
symbolTable.addTSymbol({
|
|
390
|
+
kind: "function",
|
|
391
|
+
name: "initialize",
|
|
392
|
+
sourceFile: "test.cnx",
|
|
393
|
+
sourceLine: 12,
|
|
394
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
395
|
+
isExported: true,
|
|
396
|
+
returnType: TTypeUtils.createPrimitive("void"),
|
|
397
|
+
parameters: [],
|
|
398
|
+
scope: barScope,
|
|
399
|
+
visibility: "public",
|
|
400
|
+
body: null,
|
|
401
|
+
} as IFunctionSymbol);
|
|
402
|
+
|
|
403
|
+
// These generate Foo_initialize and Bar_initialize - no conflict
|
|
404
|
+
expect(symbolTable.hasConflict("initialize")).toBe(false);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// True conflicts: same name in same scope should still be detected
|
|
408
|
+
it("should detect conflict for same-named symbols in same scope", () => {
|
|
409
|
+
const globalScope = TestScopeUtils.createMockGlobalScope();
|
|
410
|
+
const fooScope = TestScopeUtils.createMockScope("Foo", globalScope);
|
|
411
|
+
|
|
412
|
+
// Add 'duplicate' variable in scope Foo twice
|
|
413
|
+
symbolTable.addTSymbol({
|
|
414
|
+
kind: "variable",
|
|
415
|
+
name: "duplicate",
|
|
416
|
+
sourceFile: "test.cnx",
|
|
417
|
+
sourceLine: 2,
|
|
418
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
419
|
+
isExported: false,
|
|
420
|
+
type: TTypeUtils.createPrimitive("bool"),
|
|
421
|
+
isArray: false,
|
|
422
|
+
isConst: false,
|
|
423
|
+
isAtomic: false,
|
|
424
|
+
scope: fooScope,
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
symbolTable.addTSymbol({
|
|
428
|
+
kind: "variable",
|
|
429
|
+
name: "duplicate",
|
|
430
|
+
sourceFile: "test.cnx",
|
|
431
|
+
sourceLine: 5,
|
|
432
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
433
|
+
isExported: false,
|
|
434
|
+
type: TTypeUtils.createPrimitive("bool"),
|
|
435
|
+
isArray: false,
|
|
436
|
+
isConst: false,
|
|
437
|
+
isAtomic: false,
|
|
438
|
+
scope: fooScope,
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// Same name in SAME scope IS a conflict
|
|
442
|
+
expect(symbolTable.hasConflict("duplicate")).toBe(true);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
// Global scope conflicts should still be detected
|
|
446
|
+
it("should detect conflict for same-named globals", () => {
|
|
447
|
+
const globalScope = TestScopeUtils.createMockGlobalScope();
|
|
448
|
+
|
|
449
|
+
// Add two global variables with same name
|
|
450
|
+
symbolTable.addTSymbol({
|
|
451
|
+
kind: "variable",
|
|
452
|
+
name: "globalVar",
|
|
453
|
+
sourceFile: "first.cnx",
|
|
454
|
+
sourceLine: 1,
|
|
455
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
456
|
+
isExported: true,
|
|
457
|
+
type: TTypeUtils.createPrimitive("u32"),
|
|
458
|
+
isArray: false,
|
|
459
|
+
isConst: false,
|
|
460
|
+
isAtomic: false,
|
|
461
|
+
scope: globalScope,
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
symbolTable.addTSymbol({
|
|
465
|
+
kind: "variable",
|
|
466
|
+
name: "globalVar",
|
|
467
|
+
sourceFile: "second.cnx",
|
|
468
|
+
sourceLine: 1,
|
|
469
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
470
|
+
isExported: true,
|
|
471
|
+
type: TTypeUtils.createPrimitive("u32"),
|
|
472
|
+
isArray: false,
|
|
473
|
+
isConst: false,
|
|
474
|
+
isAtomic: false,
|
|
475
|
+
scope: globalScope,
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
// Two globals with same name IS a conflict
|
|
479
|
+
expect(symbolTable.hasConflict("globalVar")).toBe(true);
|
|
480
|
+
});
|
|
325
481
|
});
|
|
326
482
|
|
|
327
483
|
// ========================================================================
|
|
@@ -15,9 +15,6 @@ interface IPipelineInput {
|
|
|
15
15
|
|
|
16
16
|
/** Whether to write generated output to disk */
|
|
17
17
|
readonly writeOutputToDisk: boolean;
|
|
18
|
-
|
|
19
|
-
/** Skip Stage 4 (symbol conflict check) — standalone mode doesn't need it */
|
|
20
|
-
readonly skipConflictCheck?: boolean;
|
|
21
18
|
}
|
|
22
19
|
|
|
23
20
|
export default IPipelineInput;
|