c-next 0.2.16 → 0.2.18
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/README.md +18 -2
- package/dist/index.js +8897 -6260
- package/dist/index.js.map +4 -4
- package/grammar/CNext.g4 +12 -0
- package/package.json +4 -2
- package/src/transpiler/Transpiler.ts +376 -48
- package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
- package/src/transpiler/__tests__/compileCommandsDiscovery.integration.test.ts +94 -0
- package/src/transpiler/__tests__/externalSymbolRecovery.integration.test.ts +215 -0
- package/src/transpiler/logic/__tests__/detectAssemblySyntax.test.ts +116 -0
- package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +65 -10
- package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +186 -14
- package/src/transpiler/logic/analysis/MixedTypeCategoryAnalyzer.ts +408 -0
- package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +16 -97
- package/src/transpiler/logic/analysis/ReturnPathAnalyzer.ts +171 -0
- package/src/transpiler/logic/analysis/SignedShiftAnalyzer.ts +124 -12
- package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +200 -0
- package/src/transpiler/logic/analysis/__tests__/InitializationAnalyzer.test.ts +386 -1
- package/src/transpiler/logic/analysis/__tests__/MixedTypeCategoryAnalyzer.test.ts +346 -0
- package/src/transpiler/logic/analysis/__tests__/ReturnPathAnalyzer.test.ts +232 -0
- package/src/transpiler/logic/analysis/__tests__/SignedShiftAnalyzer.test.ts +211 -0
- package/src/transpiler/logic/analysis/runAnalyzers.ts +23 -2
- package/src/transpiler/logic/analysis/types/IMixedTypeCategoryError.ts +17 -0
- package/src/transpiler/logic/analysis/types/IReturnPathError.ts +12 -0
- package/src/transpiler/logic/detectAssemblySyntax.ts +80 -0
- package/src/transpiler/logic/parser/grammar/CNext.interp +4 -1
- package/src/transpiler/logic/parser/grammar/CNext.tokens +169 -167
- package/src/transpiler/logic/parser/grammar/CNextLexer.interp +4 -1
- package/src/transpiler/logic/parser/grammar/CNextLexer.tokens +169 -167
- package/src/transpiler/logic/parser/grammar/CNextLexer.ts +545 -541
- package/src/transpiler/logic/parser/grammar/CNextListener.ts +11 -0
- package/src/transpiler/logic/parser/grammar/CNextParser.ts +1318 -1178
- package/src/transpiler/logic/parser/grammar/CNextVisitor.ts +7 -0
- package/src/transpiler/logic/preprocessor/CompileCommandsReader.ts +332 -0
- package/src/transpiler/logic/preprocessor/ExternalDeclarationOracle.ts +202 -0
- package/src/transpiler/logic/preprocessor/Preprocessor.ts +24 -6
- package/src/transpiler/logic/preprocessor/ToolchainDetector.ts +42 -1
- package/src/transpiler/logic/preprocessor/__tests__/CompileCommandsReader.test.ts +216 -0
- package/src/transpiler/logic/preprocessor/__tests__/ExternalDeclarationOracle.test.ts +153 -0
- package/src/transpiler/logic/preprocessor/__tests__/Preprocessor.test.ts +43 -18
- package/src/transpiler/logic/preprocessor/__tests__/ToolchainDetector.crossCompiler.test.ts +75 -0
- package/src/transpiler/logic/preprocessor/__tests__/fixtures/oracle/dependent.h +7 -0
- package/src/transpiler/logic/preprocessor/__tests__/fixtures/oracle/predecessor.h +5 -0
- package/src/transpiler/logic/preprocessor/types/ICompileCommandsResult.ts +14 -0
- package/src/transpiler/logic/preprocessor/types/IPreprocessOptions.ts +17 -0
- package/src/transpiler/logic/symbols/SymbolTable.ts +62 -2
- package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +55 -4
- package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +15 -2
- package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +64 -50
- package/src/transpiler/output/MisraSuppressionUtils.ts +52 -0
- package/src/transpiler/output/__tests__/MisraSuppressionUtils.test.ts +67 -0
- package/src/transpiler/output/codegen/CodeGenerator.ts +196 -98
- package/src/transpiler/output/codegen/TypeResolver.ts +148 -0
- package/src/transpiler/output/codegen/TypeValidator.ts +179 -81
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +165 -17
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +163 -35
- package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +2 -2
- package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +93 -0
- package/src/transpiler/output/codegen/__tests__/TypeValidator.alwaysTrueLoop.test.ts +91 -0
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +97 -14
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +13 -0
- package/src/transpiler/output/codegen/assignment/AssignmentKind.ts +1 -1
- package/src/transpiler/output/codegen/assignment/handlers/AccessPatternHandlers.ts +20 -12
- package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +424 -22
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +31 -18
- package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +7 -8
- package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +6 -8
- package/src/transpiler/output/codegen/assignment/handlers/RegisterUtils.ts +12 -10
- package/src/transpiler/output/codegen/assignment/handlers/SimpleHandler.ts +3 -7
- package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +7 -9
- package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +12 -10
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +479 -11
- package/src/transpiler/output/codegen/generators/IOrchestrator.ts +3 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +26 -7
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +86 -0
- package/src/transpiler/output/codegen/generators/expressions/BinaryExprGenerator.ts +43 -24
- package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +76 -58
- package/src/transpiler/output/codegen/generators/expressions/ExpressionGenerator.ts +9 -2
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +26 -13
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +44 -0
- package/src/transpiler/output/codegen/generators/expressions/__tests__/ExpressionGenerator.test.ts +82 -1
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +129 -1
- package/src/transpiler/output/codegen/generators/statements/ControlFlowGenerator.ts +64 -8
- package/src/transpiler/output/codegen/generators/statements/__tests__/ControlFlowGenerator.test.ts +8 -5
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +30 -2
- package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +17 -3
- package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +17 -4
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +240 -42
- package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +0 -21
- package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +60 -39
- package/src/transpiler/output/codegen/helpers/TypeRegistrationEngine.ts +170 -36
- package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +37 -39
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +19 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +117 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +94 -2
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +322 -9
- package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +0 -64
- package/src/transpiler/output/codegen/helpers/__tests__/TypeRegistrationEngine.test.ts +101 -0
- package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclHelper.test.ts +29 -5
- package/src/transpiler/output/codegen/subscript/SubscriptClassifier.ts +30 -11
- package/src/transpiler/output/codegen/subscript/TSubscriptKind.ts +1 -1
- package/src/transpiler/output/codegen/subscript/__tests__/SubscriptClassifier.test.ts +38 -6
- package/src/transpiler/output/codegen/types/ICallbackTypeInfo.ts +2 -1
- package/src/transpiler/output/codegen/types/IParameterInput.ts +7 -0
- package/src/transpiler/output/headers/BaseHeaderGenerator.ts +8 -0
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +140 -24
- package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +280 -0
- package/src/transpiler/output/headers/generators/IHeaderTypeInput.ts +13 -0
- package/src/transpiler/output/headers/generators/generateStructHeader.ts +48 -28
- package/src/transpiler/state/CodeGenState.ts +91 -22
- package/src/transpiler/state/__tests__/CodeGenState.test.ts +253 -11
- package/src/transpiler/types/ICachedFileEntry.ts +7 -0
- package/src/utils/LiteralUtils.ts +23 -0
- package/src/utils/__tests__/LiteralUtils.test.ts +101 -0
- package/src/utils/cache/CacheManager.ts +13 -2
- package/src/utils/cache/__tests__/CacheManager.test.ts +18 -1
- package/src/utils/constants/TypeConstants.ts +13 -0
- package/src/utils/types/IParameterSymbol.ts +1 -0
|
@@ -648,12 +648,15 @@ describe("CodeGenerator Coverage Tests", () => {
|
|
|
648
648
|
// Issue #834: generateStructInitializer with named struct tags
|
|
649
649
|
// ==========================================================================
|
|
650
650
|
describe("generateStructInitializer() with named struct tags", () => {
|
|
651
|
-
it("should include struct keyword in compound literal for named struct tags", () => {
|
|
652
|
-
// Test the fix for issue #834: named struct tags need 'struct' prefix in cast
|
|
651
|
+
it("should include struct keyword in compound literal for named struct tags (assignment context)", () => {
|
|
652
|
+
// Test the fix for issue #834: named struct tags need 'struct' prefix in cast.
|
|
653
|
+
// In declaration context, no compound literal is emitted.
|
|
654
|
+
// In assignment (expression) context, the struct keyword must be present.
|
|
653
655
|
const source = `
|
|
654
656
|
struct NamedPoint { i32 x; i32 y; }
|
|
655
657
|
void test() {
|
|
656
|
-
NamedPoint p <- {x:
|
|
658
|
+
NamedPoint p <- {x: 0, y: 0};
|
|
659
|
+
p <- {x: 10, y: 20};
|
|
657
660
|
}
|
|
658
661
|
`;
|
|
659
662
|
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
@@ -673,10 +676,10 @@ describe("CodeGenerator Coverage Tests", () => {
|
|
|
673
676
|
cppMode: false,
|
|
674
677
|
});
|
|
675
678
|
|
|
676
|
-
//
|
|
677
|
-
expect(code).toContain("
|
|
678
|
-
|
|
679
|
-
expect(code).toContain(".y = 20");
|
|
679
|
+
// Declaration uses plain designated initializer (no compound literal)
|
|
680
|
+
expect(code).toContain("p = { .x = 0, .y = 0 }");
|
|
681
|
+
// Assignment (expression context) must keep compound literal with struct keyword
|
|
682
|
+
expect(code).toContain("(struct NamedPoint){ .x = 10, .y = 20 }");
|
|
680
683
|
});
|
|
681
684
|
|
|
682
685
|
it("should include struct keyword in empty initializer via return statement", () => {
|
|
@@ -708,12 +711,14 @@ describe("CodeGenerator Coverage Tests", () => {
|
|
|
708
711
|
expect(code).toContain("(struct ReturnStruct){ 0 }");
|
|
709
712
|
});
|
|
710
713
|
|
|
711
|
-
it("should NOT include struct keyword for typedef'd structs in
|
|
712
|
-
// This tests the branch where checkNeedsStructKeyword returns false
|
|
714
|
+
it("should NOT include struct keyword for typedef'd structs in assignment context", () => {
|
|
715
|
+
// This tests the branch where checkNeedsStructKeyword returns false.
|
|
716
|
+
// Compound literals (expression context) for typedef'd structs must NOT have 'struct'.
|
|
713
717
|
const source = `
|
|
714
718
|
struct TypedefPoint { i32 x; i32 y; }
|
|
715
719
|
void test() {
|
|
716
|
-
TypedefPoint p <- {x:
|
|
720
|
+
TypedefPoint p <- {x: 0, y: 0};
|
|
721
|
+
p <- {x: 1, y: 2};
|
|
717
722
|
}
|
|
718
723
|
`;
|
|
719
724
|
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
@@ -732,22 +737,23 @@ describe("CodeGenerator Coverage Tests", () => {
|
|
|
732
737
|
cppMode: false,
|
|
733
738
|
});
|
|
734
739
|
|
|
735
|
-
//
|
|
740
|
+
// Assignment (expression context) should use plain type, no 'struct' keyword
|
|
736
741
|
expect(code).not.toContain("(struct TypedefPoint)");
|
|
737
|
-
expect(code).toContain("(TypedefPoint)");
|
|
742
|
+
expect(code).toContain("(TypedefPoint){ .x = 1, .y = 2 }");
|
|
738
743
|
});
|
|
739
744
|
|
|
740
|
-
it("should NOT include struct keyword in C++ mode", () => {
|
|
745
|
+
it("should NOT include struct keyword in C++ mode (assignment context)", () => {
|
|
746
|
+
// Even if marked, C++ mode should not use struct keyword in compound literals.
|
|
741
747
|
const source = `
|
|
742
748
|
struct CppPoint { i32 x; i32 y; }
|
|
743
749
|
void test() {
|
|
744
|
-
CppPoint p <- {x:
|
|
750
|
+
CppPoint p <- {x: 0, y: 0};
|
|
751
|
+
p <- {x: 5, y: 10};
|
|
745
752
|
}
|
|
746
753
|
`;
|
|
747
754
|
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
748
755
|
|
|
749
756
|
const symbolTable = new SymbolTable();
|
|
750
|
-
// Even if marked, C++ mode should not use struct keyword
|
|
751
757
|
symbolTable.markNeedsStructKeyword("CppPoint");
|
|
752
758
|
|
|
753
759
|
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
@@ -761,9 +767,9 @@ describe("CodeGenerator Coverage Tests", () => {
|
|
|
761
767
|
cppMode: true,
|
|
762
768
|
});
|
|
763
769
|
|
|
764
|
-
//
|
|
770
|
+
// Assignment (expression context) in C++ mode must not use 'struct' keyword
|
|
765
771
|
expect(code).not.toContain("(struct CppPoint)");
|
|
766
|
-
expect(code).toContain("(CppPoint)");
|
|
772
|
+
expect(code).toContain("(CppPoint){ .x = 5, .y = 10 }");
|
|
767
773
|
});
|
|
768
774
|
});
|
|
769
775
|
|
|
@@ -1339,4 +1345,146 @@ describe("CodeGenerator Coverage Tests", () => {
|
|
|
1339
1345
|
expect(code).not.toContain("widget_t* w");
|
|
1340
1346
|
});
|
|
1341
1347
|
});
|
|
1348
|
+
|
|
1349
|
+
// ==========================================================================
|
|
1350
|
+
// PR: _generateScopeVariable with struct initializer (line 3214)
|
|
1351
|
+
// Covers withDeclarationInit wrapping in scope variable declarations
|
|
1352
|
+
// ==========================================================================
|
|
1353
|
+
describe("_generateScopeVariable() with struct initializer", () => {
|
|
1354
|
+
it("should use plain designated initializer for scope struct variable", () => {
|
|
1355
|
+
const source = `
|
|
1356
|
+
struct Settings { i32 timeout; i32 retries; }
|
|
1357
|
+
scope Config {
|
|
1358
|
+
public Settings defaults <- {timeout: 30, retries: 3};
|
|
1359
|
+
}
|
|
1360
|
+
`;
|
|
1361
|
+
const { code } = setupGenerator(source);
|
|
1362
|
+
// Scope variable initializer uses withDeclarationInit, producing plain designated init
|
|
1363
|
+
expect(code).toContain(".timeout = 30");
|
|
1364
|
+
expect(code).toContain(".retries = 3");
|
|
1365
|
+
// Should NOT have compound literal prefix in declaration context
|
|
1366
|
+
expect(code).not.toContain("(Settings){ .timeout");
|
|
1367
|
+
});
|
|
1368
|
+
|
|
1369
|
+
it("should use plain designated initializer for private scope struct variable", () => {
|
|
1370
|
+
const source = `
|
|
1371
|
+
struct Point { i32 x; i32 y; }
|
|
1372
|
+
scope Drawing {
|
|
1373
|
+
Point origin <- {x: 0, y: 0};
|
|
1374
|
+
}
|
|
1375
|
+
`;
|
|
1376
|
+
const { code } = setupGenerator(source);
|
|
1377
|
+
expect(code).toContain(
|
|
1378
|
+
"static Point Drawing_origin = { .x = 0, .y = 0 }",
|
|
1379
|
+
);
|
|
1380
|
+
});
|
|
1381
|
+
});
|
|
1382
|
+
|
|
1383
|
+
// ==========================================================================
|
|
1384
|
+
// PR: formatStructInitializer with inDeclarationInit (line 3544)
|
|
1385
|
+
// Covers the plain designated initializer path in declaration context
|
|
1386
|
+
// ==========================================================================
|
|
1387
|
+
describe("formatStructInitializer() in declaration context", () => {
|
|
1388
|
+
it("should use plain designated init (no compound literal) for global struct variable", () => {
|
|
1389
|
+
const source = `
|
|
1390
|
+
struct Point { i32 x; i32 y; }
|
|
1391
|
+
Point origin <- {x: 0, y: 0};
|
|
1392
|
+
`;
|
|
1393
|
+
const { code } = setupGenerator(source);
|
|
1394
|
+
// Global declaration: plain designated init, no compound literal prefix
|
|
1395
|
+
expect(code).toContain("Point origin = { .x = 0, .y = 0 }");
|
|
1396
|
+
expect(code).not.toContain("(Point){ .x");
|
|
1397
|
+
});
|
|
1398
|
+
|
|
1399
|
+
it("should use compound literal for struct in assignment context", () => {
|
|
1400
|
+
const source = `
|
|
1401
|
+
struct Point { i32 x; i32 y; }
|
|
1402
|
+
void main() {
|
|
1403
|
+
Point p <- {x: 0, y: 0};
|
|
1404
|
+
p <- {x: 10, y: 20};
|
|
1405
|
+
}
|
|
1406
|
+
`;
|
|
1407
|
+
const { code } = setupGenerator(source);
|
|
1408
|
+
// Declaration: plain init
|
|
1409
|
+
expect(code).toContain("Point p = { .x = 0, .y = 0 }");
|
|
1410
|
+
// Assignment: compound literal with type cast
|
|
1411
|
+
expect(code).toContain("(Point){ .x = 10, .y = 20 }");
|
|
1412
|
+
});
|
|
1413
|
+
});
|
|
1414
|
+
|
|
1415
|
+
// ==========================================================================
|
|
1416
|
+
// PR: _resolveFieldType with underscore field types (lines 3577-3581)
|
|
1417
|
+
// Covers the C++ underscore-to-:: conversion path
|
|
1418
|
+
// ==========================================================================
|
|
1419
|
+
describe("_resolveFieldType() with underscore types", () => {
|
|
1420
|
+
it("should convert underscore type to :: when first part is a C++ namespace", () => {
|
|
1421
|
+
const source = `
|
|
1422
|
+
struct Outer { i32 dummy; }
|
|
1423
|
+
void main() {
|
|
1424
|
+
Outer o <- {dummy: 1};
|
|
1425
|
+
}
|
|
1426
|
+
`;
|
|
1427
|
+
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
1428
|
+
|
|
1429
|
+
const symbolTable = new SymbolTable();
|
|
1430
|
+
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
1431
|
+
symbolTable.addTSymbols(tSymbols);
|
|
1432
|
+
const symbols = TSymbolInfoAdapter.convert(tSymbols);
|
|
1433
|
+
|
|
1434
|
+
// Register a C++ namespace so isCppScopeSymbol("SeaDash") returns true
|
|
1435
|
+
symbolTable.addCppSymbol({
|
|
1436
|
+
kind: "namespace",
|
|
1437
|
+
name: "SeaDash",
|
|
1438
|
+
sourceFile: "SeaDash.h",
|
|
1439
|
+
sourceLine: 1,
|
|
1440
|
+
sourceLanguage: ESourceLanguage.Cpp,
|
|
1441
|
+
isExported: true,
|
|
1442
|
+
});
|
|
1443
|
+
|
|
1444
|
+
// Register struct field type with underscore (simulates C++ imported struct)
|
|
1445
|
+
symbolTable.addStructField("Outer", "dummy", "SeaDash_Parse_Result");
|
|
1446
|
+
|
|
1447
|
+
const generator = new CodeGenerator();
|
|
1448
|
+
CodeGenState.symbolTable = symbolTable;
|
|
1449
|
+
const code = generator.generate(tree, tokenStream, {
|
|
1450
|
+
symbolInfo: symbols,
|
|
1451
|
+
sourcePath: "test.cnx",
|
|
1452
|
+
cppMode: false,
|
|
1453
|
+
});
|
|
1454
|
+
|
|
1455
|
+
// The field type should be converted from SeaDash_Parse_Result to SeaDash::Parse::Result
|
|
1456
|
+
// This exercises _resolveFieldType lines 3577-3579
|
|
1457
|
+
expect(code).toBeDefined();
|
|
1458
|
+
});
|
|
1459
|
+
|
|
1460
|
+
it("should keep underscore type when first part is not a C++ namespace", () => {
|
|
1461
|
+
const source = `
|
|
1462
|
+
struct Data { i32 value; }
|
|
1463
|
+
void main() {
|
|
1464
|
+
Data d <- {value: 42};
|
|
1465
|
+
}
|
|
1466
|
+
`;
|
|
1467
|
+
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
1468
|
+
|
|
1469
|
+
const symbolTable = new SymbolTable();
|
|
1470
|
+
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
1471
|
+
symbolTable.addTSymbols(tSymbols);
|
|
1472
|
+
const symbols = TSymbolInfoAdapter.convert(tSymbols);
|
|
1473
|
+
|
|
1474
|
+
// Register struct field type with underscore but NOT a C++ namespace
|
|
1475
|
+
symbolTable.addStructField("Data", "value", "some_plain_type");
|
|
1476
|
+
|
|
1477
|
+
const generator = new CodeGenerator();
|
|
1478
|
+
CodeGenState.symbolTable = symbolTable;
|
|
1479
|
+
const code = generator.generate(tree, tokenStream, {
|
|
1480
|
+
symbolInfo: symbols,
|
|
1481
|
+
sourcePath: "test.cnx",
|
|
1482
|
+
cppMode: false,
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1485
|
+
// The field type should remain unchanged (not a C++ namespace)
|
|
1486
|
+
// This exercises _resolveFieldType line 3581
|
|
1487
|
+
expect(code).toBeDefined();
|
|
1488
|
+
});
|
|
1489
|
+
});
|
|
1342
1490
|
});
|
|
@@ -1504,7 +1504,7 @@ describe("CodeGenerator", () => {
|
|
|
1504
1504
|
|
|
1505
1505
|
it("should generate multi-dimensional array", () => {
|
|
1506
1506
|
const source = `
|
|
1507
|
-
u32[3]
|
|
1507
|
+
u32[3][3] matrix;
|
|
1508
1508
|
void main() { }
|
|
1509
1509
|
`;
|
|
1510
1510
|
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
@@ -2944,7 +2944,7 @@ describe("CodeGenerator", () => {
|
|
|
2944
2944
|
describe("Inferred array size", () => {
|
|
2945
2945
|
it("should generate array with inferred size from initializer", () => {
|
|
2946
2946
|
const source = `
|
|
2947
|
-
u32
|
|
2947
|
+
u32[] values <- [1, 2, 3, 4, 5];
|
|
2948
2948
|
void main() { }
|
|
2949
2949
|
`;
|
|
2950
2950
|
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
@@ -3799,7 +3799,7 @@ describe("CodeGenerator", () => {
|
|
|
3799
3799
|
describe("Nested array initializers", () => {
|
|
3800
3800
|
it("should generate 2D array initializer", () => {
|
|
3801
3801
|
const source = `
|
|
3802
|
-
u32[2]
|
|
3802
|
+
u32[2][3] matrix <- [[1, 2, 3], [4, 5, 6]];
|
|
3803
3803
|
`;
|
|
3804
3804
|
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
3805
3805
|
const generator = new CodeGenerator();
|
|
@@ -4097,7 +4097,7 @@ describe("CodeGenerator", () => {
|
|
|
4097
4097
|
describe("Multi-dimensional array", () => {
|
|
4098
4098
|
it("should generate 3D array declaration", () => {
|
|
4099
4099
|
const source = `
|
|
4100
|
-
u8[2]
|
|
4100
|
+
u8[2][3][4] cube;
|
|
4101
4101
|
`;
|
|
4102
4102
|
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
4103
4103
|
const generator = new CodeGenerator();
|
|
@@ -6932,7 +6932,7 @@ describe("CodeGenerator", () => {
|
|
|
6932
6932
|
expect(code).toContain("ExternalClass obj = {}");
|
|
6933
6933
|
});
|
|
6934
6934
|
|
|
6935
|
-
it("should initialize known structs to {
|
|
6935
|
+
it("should initialize known structs to {} in C++ mode (Issue #1004)", () => {
|
|
6936
6936
|
const source = `
|
|
6937
6937
|
struct Point { i32 x; i32 y; }
|
|
6938
6938
|
void main() {
|
|
@@ -6950,8 +6950,10 @@ describe("CodeGenerator", () => {
|
|
|
6950
6950
|
cppMode: true,
|
|
6951
6951
|
});
|
|
6952
6952
|
|
|
6953
|
-
//
|
|
6954
|
-
|
|
6953
|
+
// Issue #1004: C++ value-initialization ({}) is valid for any struct,
|
|
6954
|
+
// including ones whose first field is an enum where {0} would be an
|
|
6955
|
+
// invalid int->enum narrowing.
|
|
6956
|
+
expect(code).toContain("Point p = {}");
|
|
6955
6957
|
});
|
|
6956
6958
|
|
|
6957
6959
|
// Note: Template type tests skipped - template argument transformation
|
|
@@ -7023,7 +7025,7 @@ describe("CodeGenerator", () => {
|
|
|
7023
7025
|
expect(code).not.toContain("uint8_t* buf");
|
|
7024
7026
|
});
|
|
7025
7027
|
|
|
7026
|
-
it("should generate primitive C-Next style arrays with {
|
|
7028
|
+
it("should generate primitive C-Next style arrays with {} in C++ mode (Issue #1004)", () => {
|
|
7027
7029
|
const source = `
|
|
7028
7030
|
void main() {
|
|
7029
7031
|
u32[8] counters;
|
|
@@ -7040,8 +7042,9 @@ describe("CodeGenerator", () => {
|
|
|
7040
7042
|
cppMode: true,
|
|
7041
7043
|
});
|
|
7042
7044
|
|
|
7043
|
-
//
|
|
7044
|
-
|
|
7045
|
+
// Issue #1004: C++ arrays value-initialize with {} regardless of
|
|
7046
|
+
// element type (one unified aggregate zero-init rule).
|
|
7047
|
+
expect(code).toContain("uint32_t counters[8] = {}");
|
|
7045
7048
|
});
|
|
7046
7049
|
|
|
7047
7050
|
it("should generate unknown user type C-Next style arrays with {} in C++ mode", () => {
|
|
@@ -7065,7 +7068,7 @@ describe("CodeGenerator", () => {
|
|
|
7065
7068
|
expect(code).toContain("UnknownType items[4] = {}");
|
|
7066
7069
|
});
|
|
7067
7070
|
|
|
7068
|
-
it("should generate known C-Next struct arrays with {
|
|
7071
|
+
it("should generate known C-Next struct arrays with {} in C++ mode (Issue #1004)", () => {
|
|
7069
7072
|
const source = `
|
|
7070
7073
|
struct Point { i32 x; i32 y; }
|
|
7071
7074
|
void main() {
|
|
@@ -7083,8 +7086,9 @@ describe("CodeGenerator", () => {
|
|
|
7083
7086
|
cppMode: true,
|
|
7084
7087
|
});
|
|
7085
7088
|
|
|
7086
|
-
//
|
|
7087
|
-
|
|
7089
|
+
// Issue #1004: C++ struct arrays value-initialize with {}, valid even
|
|
7090
|
+
// when the struct's first field is an enum.
|
|
7091
|
+
expect(code).toContain("Point pts[3] = {}");
|
|
7088
7092
|
});
|
|
7089
7093
|
});
|
|
7090
7094
|
});
|
|
@@ -8450,6 +8454,17 @@ describe("CodeGenerator", () => {
|
|
|
8450
8454
|
const generator = new CodeGenerator();
|
|
8451
8455
|
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
8452
8456
|
const symbols = TSymbolInfoAdapter.convert(tSymbols);
|
|
8457
|
+
// Issue #1100: SymbolTable must be wired up (as the real Transpiler
|
|
8458
|
+
// pipeline always does, see setupGenerator() above) so
|
|
8459
|
+
// getMemberTypeInfo() can resolve struct field array-ness. Without
|
|
8460
|
+
// this, getStructFieldInfo() always returns null and the struct
|
|
8461
|
+
// field's array-ness is never determined via the correct path — this
|
|
8462
|
+
// test was previously passing only because a since-removed blanket
|
|
8463
|
+
// "parameter -> array access" rule (Issue #579) coincidentally
|
|
8464
|
+
// produced the right output for the wrong reason.
|
|
8465
|
+
const symbolTable = new SymbolTable();
|
|
8466
|
+
symbolTable.addTSymbols(tSymbols);
|
|
8467
|
+
CodeGenState.symbolTable = symbolTable;
|
|
8453
8468
|
|
|
8454
8469
|
const code = generator.generate(tree, tokenStream, {
|
|
8455
8470
|
symbolInfo: symbols,
|
|
@@ -8483,7 +8498,7 @@ describe("CodeGenerator", () => {
|
|
|
8483
8498
|
it("should handle multi-dimensional array access", () => {
|
|
8484
8499
|
const source = `
|
|
8485
8500
|
void test() {
|
|
8486
|
-
u32[3]
|
|
8501
|
+
u32[3][3] matrix;
|
|
8487
8502
|
u32 val <- matrix[1][2];
|
|
8488
8503
|
}
|
|
8489
8504
|
`;
|
|
@@ -9420,7 +9435,9 @@ describe("CodeGenerator", () => {
|
|
|
9420
9435
|
sourcePath: "test.cnx",
|
|
9421
9436
|
});
|
|
9422
9437
|
|
|
9423
|
-
|
|
9438
|
+
// Issue #1032: Comparison operands don't get U suffix (would change semantics)
|
|
9439
|
+
// but ternary arms do (they're assigned to u32 result)
|
|
9440
|
+
expect(code).toContain("(x > 3) ? 10U : 20U");
|
|
9424
9441
|
});
|
|
9425
9442
|
});
|
|
9426
9443
|
|
|
@@ -11293,7 +11310,7 @@ describe("CodeGenerator", () => {
|
|
|
11293
11310
|
it("should allow empty brackets for size inference", () => {
|
|
11294
11311
|
const source = `
|
|
11295
11312
|
void test() {
|
|
11296
|
-
u8
|
|
11313
|
+
u8[] data <- [1, 2, 3];
|
|
11297
11314
|
}
|
|
11298
11315
|
`;
|
|
11299
11316
|
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
@@ -11309,7 +11326,7 @@ describe("CodeGenerator", () => {
|
|
|
11309
11326
|
expect(code).toContain("uint8_t data[3]");
|
|
11310
11327
|
});
|
|
11311
11328
|
|
|
11312
|
-
it("should
|
|
11329
|
+
it("should reject multi-dimensional C-style arrays (Issue #1014)", () => {
|
|
11313
11330
|
const source = `
|
|
11314
11331
|
void test() {
|
|
11315
11332
|
u8 matrix[4][4];
|
|
@@ -11321,6 +11338,26 @@ describe("CodeGenerator", () => {
|
|
|
11321
11338
|
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
11322
11339
|
const symbols = TSymbolInfoAdapter.convert(tSymbols);
|
|
11323
11340
|
|
|
11341
|
+
expect(() =>
|
|
11342
|
+
generator.generate(tree, tokenStream, {
|
|
11343
|
+
symbolInfo: symbols,
|
|
11344
|
+
sourcePath: "test.cnx",
|
|
11345
|
+
}),
|
|
11346
|
+
).toThrow("C-style array declaration is not allowed");
|
|
11347
|
+
});
|
|
11348
|
+
|
|
11349
|
+
it("should allow multi-dimensional C-Next style arrays", () => {
|
|
11350
|
+
const source = `
|
|
11351
|
+
void test() {
|
|
11352
|
+
u8[4][4] matrix;
|
|
11353
|
+
matrix[0][0] <- 0;
|
|
11354
|
+
}
|
|
11355
|
+
`;
|
|
11356
|
+
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
11357
|
+
const generator = new CodeGenerator();
|
|
11358
|
+
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
11359
|
+
const symbols = TSymbolInfoAdapter.convert(tSymbols);
|
|
11360
|
+
|
|
11324
11361
|
const code = generator.generate(tree, tokenStream, {
|
|
11325
11362
|
symbolInfo: symbols,
|
|
11326
11363
|
sourcePath: "test.cnx",
|
|
@@ -14042,7 +14079,7 @@ describe("CodeGenerator", () => {
|
|
|
14042
14079
|
it("should detect array element of string array", () => {
|
|
14043
14080
|
const source = `
|
|
14044
14081
|
void test() {
|
|
14045
|
-
string<32>
|
|
14082
|
+
string<32>[3] names;
|
|
14046
14083
|
names[0] <- "Alice";
|
|
14047
14084
|
bool check <- (names[0] = "Alice");
|
|
14048
14085
|
}
|
|
@@ -14086,7 +14123,7 @@ describe("CodeGenerator", () => {
|
|
|
14086
14123
|
it("should register multi-dimensional array", () => {
|
|
14087
14124
|
const source = `
|
|
14088
14125
|
void test() {
|
|
14089
|
-
u8[10]
|
|
14126
|
+
u8[10][20] matrix;
|
|
14090
14127
|
matrix[0][0] <- 0;
|
|
14091
14128
|
}
|
|
14092
14129
|
`;
|
|
@@ -14892,11 +14929,12 @@ describe("CodeGenerator", () => {
|
|
|
14892
14929
|
});
|
|
14893
14930
|
});
|
|
14894
14931
|
|
|
14895
|
-
describe("break and continue
|
|
14896
|
-
it("should
|
|
14932
|
+
describe("break and continue rejection (Issue #1011)", () => {
|
|
14933
|
+
it("should reject break - not part of C-Next spec", () => {
|
|
14897
14934
|
const source = `
|
|
14898
14935
|
void test() {
|
|
14899
|
-
|
|
14936
|
+
u32 i <- 0;
|
|
14937
|
+
while (i < 10) {
|
|
14900
14938
|
break;
|
|
14901
14939
|
}
|
|
14902
14940
|
}
|
|
@@ -14906,15 +14944,15 @@ describe("CodeGenerator", () => {
|
|
|
14906
14944
|
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
14907
14945
|
const symbols = TSymbolInfoAdapter.convert(tSymbols);
|
|
14908
14946
|
|
|
14909
|
-
|
|
14910
|
-
|
|
14911
|
-
|
|
14912
|
-
|
|
14913
|
-
|
|
14914
|
-
|
|
14947
|
+
expect(() =>
|
|
14948
|
+
generator.generate(tree, tokenStream, {
|
|
14949
|
+
symbolInfo: symbols,
|
|
14950
|
+
sourcePath: "test.cnx",
|
|
14951
|
+
}),
|
|
14952
|
+
).toThrow("'break' is not supported in C-Next");
|
|
14915
14953
|
});
|
|
14916
14954
|
|
|
14917
|
-
it("should
|
|
14955
|
+
it("should reject continue - not part of C-Next spec", () => {
|
|
14918
14956
|
const source = `
|
|
14919
14957
|
void test() {
|
|
14920
14958
|
u32 i <- 0;
|
|
@@ -14931,12 +14969,12 @@ describe("CodeGenerator", () => {
|
|
|
14931
14969
|
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
14932
14970
|
const symbols = TSymbolInfoAdapter.convert(tSymbols);
|
|
14933
14971
|
|
|
14934
|
-
|
|
14935
|
-
|
|
14936
|
-
|
|
14937
|
-
|
|
14938
|
-
|
|
14939
|
-
|
|
14972
|
+
expect(() =>
|
|
14973
|
+
generator.generate(tree, tokenStream, {
|
|
14974
|
+
symbolInfo: symbols,
|
|
14975
|
+
sourcePath: "test.cnx",
|
|
14976
|
+
}),
|
|
14977
|
+
).toThrow("'continue' is not supported in C-Next");
|
|
14940
14978
|
});
|
|
14941
14979
|
});
|
|
14942
14980
|
|
|
@@ -15632,4 +15670,94 @@ describe("CodeGenerator", () => {
|
|
|
15632
15670
|
}).toThrow("Error: enum generator not registered");
|
|
15633
15671
|
});
|
|
15634
15672
|
});
|
|
15673
|
+
|
|
15674
|
+
describe("struct initializer — declaration vs expression context", () => {
|
|
15675
|
+
it("should use designated initializer without type cast for global struct declaration", () => {
|
|
15676
|
+
const source = `
|
|
15677
|
+
struct Point { i32 x; i32 y; }
|
|
15678
|
+
Point origin <- {x: 0, y: 0};
|
|
15679
|
+
`;
|
|
15680
|
+
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
15681
|
+
const generator = new CodeGenerator();
|
|
15682
|
+
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
15683
|
+
const symbols = TSymbolInfoAdapter.convert(tSymbols);
|
|
15684
|
+
|
|
15685
|
+
const code = generator.generate(tree, tokenStream, {
|
|
15686
|
+
symbolInfo: symbols,
|
|
15687
|
+
sourcePath: "test.cnx",
|
|
15688
|
+
});
|
|
15689
|
+
|
|
15690
|
+
// Must use plain designated initializer — (Point){...} is not a C99 constant expression
|
|
15691
|
+
// and fails to compile at file scope on GCC < 13
|
|
15692
|
+
expect(code).toContain("origin = { .x = 0, .y = 0 }");
|
|
15693
|
+
expect(code).not.toContain("(Point)");
|
|
15694
|
+
});
|
|
15695
|
+
|
|
15696
|
+
it("should use designated initializer without type cast for local struct declaration", () => {
|
|
15697
|
+
const source = `
|
|
15698
|
+
struct Point { i32 x; i32 y; }
|
|
15699
|
+
void foo() {
|
|
15700
|
+
Point p <- {x: 10, y: 20};
|
|
15701
|
+
}
|
|
15702
|
+
`;
|
|
15703
|
+
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
15704
|
+
const generator = new CodeGenerator();
|
|
15705
|
+
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
15706
|
+
const symbols = TSymbolInfoAdapter.convert(tSymbols);
|
|
15707
|
+
|
|
15708
|
+
const code = generator.generate(tree, tokenStream, {
|
|
15709
|
+
symbolInfo: symbols,
|
|
15710
|
+
sourcePath: "test.cnx",
|
|
15711
|
+
});
|
|
15712
|
+
|
|
15713
|
+
expect(code).toContain("p = { .x = 10, .y = 20 }");
|
|
15714
|
+
expect(code).not.toContain("(Point)");
|
|
15715
|
+
});
|
|
15716
|
+
|
|
15717
|
+
it("should use designated initializer for nested struct literals in declaration", () => {
|
|
15718
|
+
const source = `
|
|
15719
|
+
struct Point { i32 x; i32 y; }
|
|
15720
|
+
struct Line { Point start; Point end; }
|
|
15721
|
+
Line seg <- {start: {x: 0, y: 0}, end: {x: 100, y: 100}};
|
|
15722
|
+
`;
|
|
15723
|
+
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
15724
|
+
const generator = new CodeGenerator();
|
|
15725
|
+
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
15726
|
+
const symbols = TSymbolInfoAdapter.convert(tSymbols);
|
|
15727
|
+
|
|
15728
|
+
const code = generator.generate(tree, tokenStream, {
|
|
15729
|
+
symbolInfo: symbols,
|
|
15730
|
+
sourcePath: "test.cnx",
|
|
15731
|
+
});
|
|
15732
|
+
|
|
15733
|
+
// Neither outer nor inner initializer should have a type cast prefix
|
|
15734
|
+
expect(code).toContain(
|
|
15735
|
+
"{ .start = { .x = 0, .y = 0 }, .end = { .x = 100, .y = 100 } }",
|
|
15736
|
+
);
|
|
15737
|
+
expect(code).not.toContain("(Line)");
|
|
15738
|
+
expect(code).not.toContain("(Point)");
|
|
15739
|
+
});
|
|
15740
|
+
|
|
15741
|
+
it("should keep compound literal type cast for struct re-assignment (expression context)", () => {
|
|
15742
|
+
const source = `
|
|
15743
|
+
struct Point { i32 x; i32 y; }
|
|
15744
|
+
void foo() {
|
|
15745
|
+
Point p <- {x: 0, y: 0};
|
|
15746
|
+
p <- {x: 10, y: 20};
|
|
15747
|
+
}
|
|
15748
|
+
`;
|
|
15749
|
+
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
15750
|
+
const generator = new CodeGenerator();
|
|
15751
|
+
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
15752
|
+
const symbols = TSymbolInfoAdapter.convert(tSymbols);
|
|
15753
|
+
|
|
15754
|
+
const code = generator.generate(tree, tokenStream, {
|
|
15755
|
+
symbolInfo: symbols,
|
|
15756
|
+
sourcePath: "test.cnx",
|
|
15757
|
+
});
|
|
15758
|
+
|
|
15759
|
+
// Re-assignment must use compound literal — plain { } is not valid as an expression
|
|
15760
|
+
expect(code).toContain("p = (Point){ .x = 10, .y = 20 }");
|
|
15761
|
+
});
|
|
15762
|
+
});
|
|
15635
15763
|
});
|
|
@@ -27,7 +27,7 @@ describe("trackVariableTypeWithName helpers", () => {
|
|
|
27
27
|
describe("extractArrayDimensionsSimple", () => {
|
|
28
28
|
it("handles string array with single dimension", async () => {
|
|
29
29
|
const source = `
|
|
30
|
-
string<32>
|
|
30
|
+
string<32>[4] messages;
|
|
31
31
|
void main() {
|
|
32
32
|
messages[0] <- "Hello";
|
|
33
33
|
}
|
|
@@ -39,7 +39,7 @@ describe("trackVariableTypeWithName helpers", () => {
|
|
|
39
39
|
|
|
40
40
|
it("handles string array with multiple dimensions", async () => {
|
|
41
41
|
const source = `
|
|
42
|
-
string<16>
|
|
42
|
+
string<16>[2][3] grid;
|
|
43
43
|
void main() {
|
|
44
44
|
grid[0][0] <- "test";
|
|
45
45
|
}
|