c-next 0.2.0 → 0.2.2
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/bin/cnext.js +17 -7
- package/dist/index.js +139747 -0
- package/dist/index.js.map +7 -0
- package/package.json +8 -4
- package/src/cli/Cli.ts +5 -2
- package/src/cli/PathNormalizer.ts +170 -0
- package/src/cli/PlatformIOCommand.ts +51 -3
- package/src/cli/__tests__/Cli.integration.test.ts +100 -0
- package/src/cli/__tests__/Cli.test.ts +17 -12
- package/src/cli/__tests__/PathNormalizer.test.ts +411 -0
- package/src/cli/__tests__/PlatformIOCommand.test.ts +156 -0
- package/src/cli/serve/__tests__/ServeCommand.test.ts +1 -1
- package/src/lib/__tests__/parseWithSymbols.test.ts +228 -0
- package/src/lib/parseCHeader.ts +5 -1
- package/src/lib/parseWithSymbols.ts +62 -5
- package/src/lib/types/ISymbolInfo.ts +4 -0
- package/src/lib/utils/SymbolPathUtils.ts +87 -0
- package/src/lib/utils/__tests__/SymbolPathUtils.test.ts +123 -0
- package/src/transpiler/NodeFileSystem.ts +5 -0
- package/src/transpiler/logic/symbols/SymbolTable.ts +17 -0
- package/src/transpiler/output/codegen/CodeGenerator.ts +27 -32
- package/src/transpiler/output/codegen/TypeResolver.ts +12 -24
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +130 -5
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +67 -57
- package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +9 -13
- package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +20 -10
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +5 -2
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +18 -0
- package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +25 -4
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +18 -0
- package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +51 -2
- package/src/transpiler/output/codegen/generators/expressions/LiteralGenerator.ts +76 -8
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +147 -0
- package/src/transpiler/output/codegen/generators/expressions/__tests__/LiteralGenerator.test.ts +116 -0
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +6 -5
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +14 -5
- package/src/transpiler/types/IFileSystem.ts +8 -0
|
@@ -29,6 +29,8 @@ function setupGenerator(source: string): {
|
|
|
29
29
|
|
|
30
30
|
const symbolTable = new SymbolTable();
|
|
31
31
|
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
32
|
+
// Issue #831: Register TSymbols in SymbolTable (single source of truth)
|
|
33
|
+
symbolTable.addTSymbols(tSymbols);
|
|
32
34
|
const symbols = TSymbolInfoAdapter.convert(tSymbols);
|
|
33
35
|
|
|
34
36
|
const generator = new CodeGenerator();
|
|
@@ -982,7 +984,7 @@ describe("CodeGenerator", () => {
|
|
|
982
984
|
sourcePath: "test.cnx",
|
|
983
985
|
});
|
|
984
986
|
|
|
985
|
-
expect(code).toContain("x =
|
|
987
|
+
expect(code).toContain("x = 42U;");
|
|
986
988
|
});
|
|
987
989
|
|
|
988
990
|
it("should translate compound assignment operators", () => {
|
|
@@ -1007,10 +1009,10 @@ describe("CodeGenerator", () => {
|
|
|
1007
1009
|
sourcePath: "test.cnx",
|
|
1008
1010
|
});
|
|
1009
1011
|
|
|
1010
|
-
expect(code).toContain("x +=
|
|
1011
|
-
expect(code).toContain("x -=
|
|
1012
|
-
expect(code).toContain("x *=
|
|
1013
|
-
expect(code).toContain("x /=
|
|
1012
|
+
expect(code).toContain("x += 5U;");
|
|
1013
|
+
expect(code).toContain("x -= 3U;");
|
|
1014
|
+
expect(code).toContain("x *= 2U;");
|
|
1015
|
+
expect(code).toContain("x /= 2U;");
|
|
1014
1016
|
});
|
|
1015
1017
|
});
|
|
1016
1018
|
|
|
@@ -1159,7 +1161,7 @@ describe("CodeGenerator", () => {
|
|
|
1159
1161
|
});
|
|
1160
1162
|
|
|
1161
1163
|
expect(code).toContain("cnx_clamp_add_u8");
|
|
1162
|
-
expect(code).toContain("cnx_clamp_add_u8(value,
|
|
1164
|
+
expect(code).toContain("cnx_clamp_add_u8(value, 100U)");
|
|
1163
1165
|
});
|
|
1164
1166
|
});
|
|
1165
1167
|
|
|
@@ -1302,7 +1304,7 @@ describe("CodeGenerator", () => {
|
|
|
1302
1304
|
});
|
|
1303
1305
|
|
|
1304
1306
|
expect(code).toContain("if (x == 10)");
|
|
1305
|
-
expect(code).toContain("x =
|
|
1307
|
+
expect(code).toContain("x = 5U;");
|
|
1306
1308
|
});
|
|
1307
1309
|
|
|
1308
1310
|
it("should generate if-else statement", () => {
|
|
@@ -1482,7 +1484,7 @@ describe("CodeGenerator", () => {
|
|
|
1482
1484
|
});
|
|
1483
1485
|
|
|
1484
1486
|
expect(code).toContain("arr[3]");
|
|
1485
|
-
expect(code).toContain("{
|
|
1487
|
+
expect(code).toContain("{1U, 2U, 3U}");
|
|
1486
1488
|
});
|
|
1487
1489
|
|
|
1488
1490
|
it("should generate multi-dimensional array", () => {
|
|
@@ -1583,7 +1585,7 @@ describe("CodeGenerator", () => {
|
|
|
1583
1585
|
sourcePath: "test.cnx",
|
|
1584
1586
|
});
|
|
1585
1587
|
|
|
1586
|
-
expect(code).toContain("a + b *
|
|
1588
|
+
expect(code).toContain("a + b * 2U - 1U");
|
|
1587
1589
|
});
|
|
1588
1590
|
|
|
1589
1591
|
it("should generate comparison expressions", () => {
|
|
@@ -1868,7 +1870,7 @@ describe("CodeGenerator", () => {
|
|
|
1868
1870
|
sourcePath: "test.cnx",
|
|
1869
1871
|
});
|
|
1870
1872
|
|
|
1871
|
-
expect(code).toContain("result = add(
|
|
1873
|
+
expect(code).toContain("result = add(1U, 2U);");
|
|
1872
1874
|
});
|
|
1873
1875
|
|
|
1874
1876
|
it("should generate scope function call", () => {
|
|
@@ -1893,7 +1895,7 @@ describe("CodeGenerator", () => {
|
|
|
1893
1895
|
sourcePath: "test.cnx",
|
|
1894
1896
|
});
|
|
1895
1897
|
|
|
1896
|
-
expect(code).toContain("Math_square(
|
|
1898
|
+
expect(code).toContain("Math_square(5U)");
|
|
1897
1899
|
});
|
|
1898
1900
|
});
|
|
1899
1901
|
|
|
@@ -2145,7 +2147,7 @@ describe("CodeGenerator", () => {
|
|
|
2145
2147
|
sourcePath: "test.cnx",
|
|
2146
2148
|
});
|
|
2147
2149
|
|
|
2148
|
-
expect(code).toContain("(a > b) ?
|
|
2150
|
+
expect(code).toContain("(a > b) ? 1U : 0U");
|
|
2149
2151
|
});
|
|
2150
2152
|
});
|
|
2151
2153
|
|
|
@@ -2940,7 +2942,7 @@ describe("CodeGenerator", () => {
|
|
|
2940
2942
|
});
|
|
2941
2943
|
|
|
2942
2944
|
expect(code).toContain("values[5]"); // Size inferred from initializer
|
|
2943
|
-
expect(code).toContain("{
|
|
2945
|
+
expect(code).toContain("{1U, 2U, 3U, 4U, 5U}");
|
|
2944
2946
|
});
|
|
2945
2947
|
});
|
|
2946
2948
|
|
|
@@ -3347,7 +3349,7 @@ describe("CodeGenerator", () => {
|
|
|
3347
3349
|
});
|
|
3348
3350
|
|
|
3349
3351
|
expect(code).toContain("const uint32_t LOOKUP[4]");
|
|
3350
|
-
expect(code).toContain("{
|
|
3352
|
+
expect(code).toContain("{10U, 20U, 30U, 40U}");
|
|
3351
3353
|
});
|
|
3352
3354
|
});
|
|
3353
3355
|
|
|
@@ -3754,8 +3756,8 @@ describe("CodeGenerator", () => {
|
|
|
3754
3756
|
sourcePath: "test.cnx",
|
|
3755
3757
|
});
|
|
3756
3758
|
|
|
3757
|
-
// Should generate
|
|
3758
|
-
expect(code).toContain("{
|
|
3759
|
+
// Should generate all zeros with U suffix for unsigned fill-all
|
|
3760
|
+
expect(code).toContain("{0U, 0U");
|
|
3759
3761
|
});
|
|
3760
3762
|
|
|
3761
3763
|
it("should generate fill-all array with non-zero value", () => {
|
|
@@ -3773,7 +3775,7 @@ describe("CodeGenerator", () => {
|
|
|
3773
3775
|
});
|
|
3774
3776
|
|
|
3775
3777
|
// Non-zero fill-all expands to all elements
|
|
3776
|
-
expect(code).toContain("= {
|
|
3778
|
+
expect(code).toContain("= {255U, 255U, 255U, 255U}");
|
|
3777
3779
|
});
|
|
3778
3780
|
});
|
|
3779
3781
|
|
|
@@ -3792,7 +3794,7 @@ describe("CodeGenerator", () => {
|
|
|
3792
3794
|
sourcePath: "test.cnx",
|
|
3793
3795
|
});
|
|
3794
3796
|
|
|
3795
|
-
expect(code).toContain("{{
|
|
3797
|
+
expect(code).toContain("{{1U, 2U, 3U}, {4U, 5U, 6U}}");
|
|
3796
3798
|
});
|
|
3797
3799
|
});
|
|
3798
3800
|
|
|
@@ -5079,7 +5081,7 @@ describe("CodeGenerator", () => {
|
|
|
5079
5081
|
sourcePath: "test.cnx",
|
|
5080
5082
|
});
|
|
5081
5083
|
|
|
5082
|
-
expect(code).toContain("add(
|
|
5084
|
+
expect(code).toContain("add(10U, 20U)");
|
|
5083
5085
|
});
|
|
5084
5086
|
});
|
|
5085
5087
|
|
|
@@ -5751,6 +5753,7 @@ describe("CodeGenerator", () => {
|
|
|
5751
5753
|
sourcePath: "test.cnx",
|
|
5752
5754
|
});
|
|
5753
5755
|
|
|
5756
|
+
// Array element assignments don't get U suffix yet
|
|
5754
5757
|
expect(code).toContain("output[0]");
|
|
5755
5758
|
expect(code).toContain("output[1]");
|
|
5756
5759
|
});
|
|
@@ -6562,7 +6565,7 @@ describe("CodeGenerator", () => {
|
|
|
6562
6565
|
sourcePath: "test.cnx",
|
|
6563
6566
|
});
|
|
6564
6567
|
|
|
6565
|
-
expect(code).toContain("{
|
|
6568
|
+
expect(code).toContain("{1U, 2U, 3U, 4U}");
|
|
6566
6569
|
});
|
|
6567
6570
|
});
|
|
6568
6571
|
|
|
@@ -7655,7 +7658,7 @@ describe("CodeGenerator", () => {
|
|
|
7655
7658
|
});
|
|
7656
7659
|
|
|
7657
7660
|
expect(code).toContain("while (i < 10)");
|
|
7658
|
-
expect(code).toContain("cnx_clamp_add_u32(i,
|
|
7661
|
+
expect(code).toContain("cnx_clamp_add_u32(i, 1U)");
|
|
7659
7662
|
});
|
|
7660
7663
|
|
|
7661
7664
|
it("should handle for loop with block", () => {
|
|
@@ -7723,7 +7726,7 @@ describe("CodeGenerator", () => {
|
|
|
7723
7726
|
});
|
|
7724
7727
|
|
|
7725
7728
|
expect(code).toContain("__cnx_disable_irq()");
|
|
7726
|
-
expect(code).toContain("cnx_clamp_add_u32(counter,
|
|
7729
|
+
expect(code).toContain("cnx_clamp_add_u32(counter, 1U)");
|
|
7727
7730
|
expect(code).toContain("__cnx_set_PRIMASK");
|
|
7728
7731
|
});
|
|
7729
7732
|
|
|
@@ -8349,7 +8352,7 @@ describe("CodeGenerator", () => {
|
|
|
8349
8352
|
sourcePath: "test.cnx",
|
|
8350
8353
|
});
|
|
8351
8354
|
|
|
8352
|
-
expect(code).toContain("arr[
|
|
8355
|
+
expect(code).toContain("arr[5U]");
|
|
8353
8356
|
});
|
|
8354
8357
|
|
|
8355
8358
|
it("should handle bit range access on integer", () => {
|
|
@@ -8389,7 +8392,7 @@ describe("CodeGenerator", () => {
|
|
|
8389
8392
|
sourcePath: "test.cnx",
|
|
8390
8393
|
});
|
|
8391
8394
|
|
|
8392
|
-
expect(code).toContain("arr[
|
|
8395
|
+
expect(code).toContain("arr[0U]");
|
|
8393
8396
|
});
|
|
8394
8397
|
|
|
8395
8398
|
it("should handle struct member array element access", () => {
|
|
@@ -8409,7 +8412,7 @@ describe("CodeGenerator", () => {
|
|
|
8409
8412
|
sourcePath: "test.cnx",
|
|
8410
8413
|
});
|
|
8411
8414
|
|
|
8412
|
-
expect(code).toContain("d->values[
|
|
8415
|
+
expect(code).toContain("d->values[0U]");
|
|
8413
8416
|
});
|
|
8414
8417
|
|
|
8415
8418
|
it("should handle C++ mode array access", () => {
|
|
@@ -8430,7 +8433,7 @@ describe("CodeGenerator", () => {
|
|
|
8430
8433
|
cppMode: true,
|
|
8431
8434
|
});
|
|
8432
8435
|
|
|
8433
|
-
expect(code).toContain("arr[
|
|
8436
|
+
expect(code).toContain("arr[5U]");
|
|
8434
8437
|
});
|
|
8435
8438
|
|
|
8436
8439
|
it("should handle multi-dimensional array access", () => {
|
|
@@ -8450,7 +8453,7 @@ describe("CodeGenerator", () => {
|
|
|
8450
8453
|
sourcePath: "test.cnx",
|
|
8451
8454
|
});
|
|
8452
8455
|
|
|
8453
|
-
expect(code).toContain("matrix[
|
|
8456
|
+
expect(code).toContain("matrix[1U][2U]");
|
|
8454
8457
|
});
|
|
8455
8458
|
});
|
|
8456
8459
|
|
|
@@ -8594,6 +8597,10 @@ describe("CodeGenerator", () => {
|
|
|
8594
8597
|
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
8595
8598
|
const generator = new CodeGenerator();
|
|
8596
8599
|
const tSymbols = CNextResolver.resolve(tree, "test.cnx");
|
|
8600
|
+
// Issue #831: Register TSymbols in SymbolTable (single source of truth)
|
|
8601
|
+
const symbolTable = new SymbolTable();
|
|
8602
|
+
symbolTable.addTSymbols(tSymbols);
|
|
8603
|
+
CodeGenState.symbolTable = symbolTable;
|
|
8597
8604
|
const symbols = TSymbolInfoAdapter.convert(tSymbols);
|
|
8598
8605
|
|
|
8599
8606
|
const code = generator.generate(tree, tokenStream, {
|
|
@@ -8602,7 +8609,7 @@ describe("CodeGenerator", () => {
|
|
|
8602
8609
|
cppMode: true,
|
|
8603
8610
|
});
|
|
8604
8611
|
|
|
8605
|
-
expect(code).toContain("d.values[
|
|
8612
|
+
expect(code).toContain("d.values[0U]");
|
|
8606
8613
|
});
|
|
8607
8614
|
|
|
8608
8615
|
it("should handle struct array element member access", () => {
|
|
@@ -8623,7 +8630,7 @@ describe("CodeGenerator", () => {
|
|
|
8623
8630
|
sourcePath: "test.cnx",
|
|
8624
8631
|
});
|
|
8625
8632
|
|
|
8626
|
-
expect(code).toContain("points[
|
|
8633
|
+
expect(code).toContain("points[0U].x");
|
|
8627
8634
|
});
|
|
8628
8635
|
|
|
8629
8636
|
it("should handle function return member access pattern", () => {
|
|
@@ -9105,8 +9112,8 @@ describe("CodeGenerator", () => {
|
|
|
9105
9112
|
sourcePath: "test.cnx",
|
|
9106
9113
|
});
|
|
9107
9114
|
|
|
9108
|
-
// Bitmap indexing generates bit extraction
|
|
9109
|
-
expect(code).toContain("((flags >>
|
|
9115
|
+
// Bitmap indexing generates bit extraction with U suffix
|
|
9116
|
+
expect(code).toContain("((flags >> 0U) & 1)");
|
|
9110
9117
|
});
|
|
9111
9118
|
});
|
|
9112
9119
|
|
|
@@ -9368,7 +9375,7 @@ describe("CodeGenerator", () => {
|
|
|
9368
9375
|
sourcePath: "test.cnx",
|
|
9369
9376
|
});
|
|
9370
9377
|
|
|
9371
|
-
expect(code).toContain("(x >
|
|
9378
|
+
expect(code).toContain("(x > 3U) ? 10U : 20U");
|
|
9372
9379
|
});
|
|
9373
9380
|
});
|
|
9374
9381
|
|
|
@@ -9632,7 +9639,7 @@ describe("CodeGenerator", () => {
|
|
|
9632
9639
|
sourcePath: "test.cnx",
|
|
9633
9640
|
});
|
|
9634
9641
|
|
|
9635
|
-
expect(code).toContain("{
|
|
9642
|
+
expect(code).toContain("{1U, 2U, 3U, 4U, 5U}");
|
|
9636
9643
|
});
|
|
9637
9644
|
});
|
|
9638
9645
|
|
|
@@ -9890,7 +9897,7 @@ describe("CodeGenerator", () => {
|
|
|
9890
9897
|
sourcePath: "test.cnx",
|
|
9891
9898
|
});
|
|
9892
9899
|
|
|
9893
|
-
expect(code).toContain("sizeof(x +
|
|
9900
|
+
expect(code).toContain("sizeof(x + 1U)");
|
|
9894
9901
|
});
|
|
9895
9902
|
});
|
|
9896
9903
|
|
|
@@ -9936,6 +9943,7 @@ describe("CodeGenerator", () => {
|
|
|
9936
9943
|
cppMode: true,
|
|
9937
9944
|
});
|
|
9938
9945
|
|
|
9946
|
+
// Array element assignments don't get U suffix yet
|
|
9939
9947
|
expect(code).toContain("c.points[0].x = 5");
|
|
9940
9948
|
});
|
|
9941
9949
|
});
|
|
@@ -10002,8 +10010,8 @@ describe("CodeGenerator", () => {
|
|
|
10002
10010
|
sourcePath: "test.cnx",
|
|
10003
10011
|
});
|
|
10004
10012
|
|
|
10005
|
-
//
|
|
10006
|
-
expect(code).toContain("compute(
|
|
10013
|
+
// Literals get U suffix per MISRA Rule 7.2
|
|
10014
|
+
expect(code).toContain("compute(5U + 3U)");
|
|
10007
10015
|
});
|
|
10008
10016
|
});
|
|
10009
10017
|
|
|
@@ -10210,9 +10218,9 @@ describe("CodeGenerator", () => {
|
|
|
10210
10218
|
sourcePath: "test.cnx",
|
|
10211
10219
|
});
|
|
10212
10220
|
|
|
10213
|
-
expect(code).toContain(">>
|
|
10214
|
-
// Mask is generated as ((1U <<
|
|
10215
|
-
expect(code).toContain("((1U <<
|
|
10221
|
+
expect(code).toContain(">> 8U");
|
|
10222
|
+
// Mask is generated as ((1U << 4U) - 1) for bit width 4
|
|
10223
|
+
expect(code).toContain("((1U << 4U) - 1)");
|
|
10216
10224
|
});
|
|
10217
10225
|
});
|
|
10218
10226
|
|
|
@@ -10694,6 +10702,7 @@ describe("CodeGenerator", () => {
|
|
|
10694
10702
|
});
|
|
10695
10703
|
|
|
10696
10704
|
// Array params don't need dereference
|
|
10705
|
+
// Array element access doesn't get U suffix yet
|
|
10697
10706
|
expect(code).toContain("arr[5]");
|
|
10698
10707
|
expect(code).not.toContain("(*arr)");
|
|
10699
10708
|
});
|
|
@@ -11952,7 +11961,7 @@ describe("CodeGenerator", () => {
|
|
|
11952
11961
|
const source = `
|
|
11953
11962
|
struct Point { i32 x; i32 y; }
|
|
11954
11963
|
void processPoints(Point[4] points) {
|
|
11955
|
-
points[
|
|
11964
|
+
points[0U].x <- 10;
|
|
11956
11965
|
}
|
|
11957
11966
|
`;
|
|
11958
11967
|
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
@@ -12361,7 +12370,7 @@ describe("CodeGenerator", () => {
|
|
|
12361
12370
|
sourcePath: "test.cnx",
|
|
12362
12371
|
});
|
|
12363
12372
|
|
|
12364
|
-
expect(code).toContain("arr[
|
|
12373
|
+
expect(code).toContain("arr[5U]");
|
|
12365
12374
|
});
|
|
12366
12375
|
|
|
12367
12376
|
it("should resolve array element with variable index", () => {
|
|
@@ -12550,8 +12559,8 @@ describe("CodeGenerator", () => {
|
|
|
12550
12559
|
sourcePath: "test.cnx",
|
|
12551
12560
|
});
|
|
12552
12561
|
|
|
12553
|
-
//
|
|
12554
|
-
expect(code).toContain("
|
|
12562
|
+
// Literals get U suffix per MISRA Rule 7.2
|
|
12563
|
+
expect(code).toContain("10U + 5U");
|
|
12555
12564
|
});
|
|
12556
12565
|
});
|
|
12557
12566
|
|
|
@@ -12949,11 +12958,11 @@ describe("CodeGenerator", () => {
|
|
|
12949
12958
|
sourcePath: "test.cnx",
|
|
12950
12959
|
});
|
|
12951
12960
|
|
|
12952
|
-
//
|
|
12961
|
+
// Bit range access generates shift and mask
|
|
12953
12962
|
expect(code).toContain("flags");
|
|
12954
12963
|
expect(code).toContain("& 0xFF");
|
|
12955
|
-
//
|
|
12956
|
-
expect(code).
|
|
12964
|
+
// MISRA Rule 7.2: shift amount gets U suffix
|
|
12965
|
+
expect(code).toContain(">> 0U");
|
|
12957
12966
|
});
|
|
12958
12967
|
|
|
12959
12968
|
it("should generate integer bit range with shift for non-zero start", () => {
|
|
@@ -13532,7 +13541,7 @@ describe("CodeGenerator", () => {
|
|
|
13532
13541
|
sourcePath: "test.cnx",
|
|
13533
13542
|
});
|
|
13534
13543
|
|
|
13535
|
-
expect(code).toContain("buffer[
|
|
13544
|
+
expect(code).toContain("buffer[5U]");
|
|
13536
13545
|
});
|
|
13537
13546
|
|
|
13538
13547
|
it("should handle array access with variable index", () => {
|
|
@@ -13648,8 +13657,8 @@ describe("CodeGenerator", () => {
|
|
|
13648
13657
|
});
|
|
13649
13658
|
|
|
13650
13659
|
expect(code).toContain("__bits_val");
|
|
13651
|
-
//
|
|
13652
|
-
expect(code).
|
|
13660
|
+
// MISRA Rule 7.2: shift amount gets U suffix
|
|
13661
|
+
expect(code).toContain(">> 0U");
|
|
13653
13662
|
});
|
|
13654
13663
|
|
|
13655
13664
|
it("should handle multiple reads from same float reusing shadow", () => {
|
|
@@ -14102,6 +14111,7 @@ describe("CodeGenerator", () => {
|
|
|
14102
14111
|
});
|
|
14103
14112
|
|
|
14104
14113
|
expect(code).toContain("Point points[3]");
|
|
14114
|
+
// Array element assignments don't get U suffix yet
|
|
14105
14115
|
expect(code).toContain("points[0].x = 10");
|
|
14106
14116
|
});
|
|
14107
14117
|
|
|
@@ -14229,7 +14239,7 @@ describe("CodeGenerator", () => {
|
|
|
14229
14239
|
});
|
|
14230
14240
|
|
|
14231
14241
|
// Array element member access
|
|
14232
|
-
expect(code).toContain("items[
|
|
14242
|
+
expect(code).toContain("items[0U].id");
|
|
14233
14243
|
});
|
|
14234
14244
|
|
|
14235
14245
|
it("should use arrow for struct params in C mode", () => {
|
|
@@ -14629,8 +14639,8 @@ describe("CodeGenerator", () => {
|
|
|
14629
14639
|
sourcePath: "test.cnx",
|
|
14630
14640
|
});
|
|
14631
14641
|
|
|
14632
|
-
//
|
|
14633
|
-
expect(code).
|
|
14642
|
+
// MISRA Rule 7.2: shift amount gets U suffix
|
|
14643
|
+
expect(code).toContain(">> 0U");
|
|
14634
14644
|
});
|
|
14635
14645
|
|
|
14636
14646
|
it("should generate 64-bit mask for u64 values", () => {
|
|
@@ -15190,7 +15200,7 @@ describe("CodeGenerator", () => {
|
|
|
15190
15200
|
sourcePath: "test.cnx",
|
|
15191
15201
|
});
|
|
15192
15202
|
|
|
15193
|
-
expect(code).toContain("multiply(
|
|
15203
|
+
expect(code).toContain("multiply(5U, 10U)");
|
|
15194
15204
|
});
|
|
15195
15205
|
|
|
15196
15206
|
it("should generate scoped function call", () => {
|
|
@@ -15214,7 +15224,7 @@ describe("CodeGenerator", () => {
|
|
|
15214
15224
|
sourcePath: "test.cnx",
|
|
15215
15225
|
});
|
|
15216
15226
|
|
|
15217
|
-
expect(code).toContain("Math_square(
|
|
15227
|
+
expect(code).toContain("Math_square(5U)");
|
|
15218
15228
|
});
|
|
15219
15229
|
});
|
|
15220
15230
|
|
|
@@ -15352,7 +15362,7 @@ describe("CodeGenerator", () => {
|
|
|
15352
15362
|
sourcePath: "test.cnx",
|
|
15353
15363
|
});
|
|
15354
15364
|
|
|
15355
|
-
expect(code).toContain("arr[
|
|
15365
|
+
expect(code).toContain("arr[5U]");
|
|
15356
15366
|
});
|
|
15357
15367
|
|
|
15358
15368
|
it("should generate array access with variable index", () => {
|
|
@@ -15487,8 +15497,8 @@ describe("CodeGenerator", () => {
|
|
|
15487
15497
|
sourcePath: "test.cnx",
|
|
15488
15498
|
});
|
|
15489
15499
|
|
|
15490
|
-
//
|
|
15491
|
-
expect(code).toContain("uint8_t result =
|
|
15500
|
+
// Const values are inlined, 5 gets U suffix per MISRA Rule 7.2
|
|
15501
|
+
expect(code).toContain("uint8_t result = 10 + 5U;");
|
|
15492
15502
|
expect(code).not.toContain("Bar_OFFSET");
|
|
15493
15503
|
});
|
|
15494
15504
|
});
|
|
@@ -171,25 +171,21 @@ class MemberChainAnalyzer {
|
|
|
171
171
|
return false;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
|
|
174
|
+
// Issue #831: Use SymbolTable as single source of truth for struct fields
|
|
175
|
+
const fieldInfo = CodeGenState.symbolTable?.getStructFieldInfo(
|
|
175
176
|
state.currentStructType,
|
|
177
|
+
fieldName,
|
|
176
178
|
);
|
|
177
|
-
if (!
|
|
179
|
+
if (!fieldInfo) {
|
|
178
180
|
return false;
|
|
179
181
|
}
|
|
180
182
|
|
|
181
|
-
|
|
182
|
-
if (!fieldType) {
|
|
183
|
-
return false;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
state.currentType = fieldType;
|
|
183
|
+
state.currentType = fieldInfo.type;
|
|
187
184
|
|
|
188
|
-
// Check if this field is an array
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
state.isCurrentArray = arrayFields?.has(fieldName) ?? false;
|
|
185
|
+
// Check if this field is an array (has array dimensions)
|
|
186
|
+
state.isCurrentArray =
|
|
187
|
+
fieldInfo.arrayDimensions !== undefined &&
|
|
188
|
+
fieldInfo.arrayDimensions.length > 0;
|
|
193
189
|
|
|
194
190
|
// If the field type is a struct, update currentStructType
|
|
195
191
|
state.currentStructType = CodeGenState.isKnownStruct(state.currentType)
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { describe, it, expect, beforeEach } from "vitest";
|
|
10
10
|
import MemberChainAnalyzer from "../MemberChainAnalyzer.js";
|
|
11
11
|
import CodeGenState from "../../../../state/CodeGenState.js";
|
|
12
|
+
import SymbolTable from "../../../../logic/symbols/SymbolTable.js";
|
|
12
13
|
import type * as Parser from "../../../../logic/parser/grammar/CNextParser.js";
|
|
13
14
|
|
|
14
15
|
/** Mock type for PostfixTargetOpContext */
|
|
@@ -70,14 +71,31 @@ describe("MemberChainAnalyzer", () => {
|
|
|
70
71
|
});
|
|
71
72
|
|
|
72
73
|
/**
|
|
73
|
-
* Helper to set up struct fields in CodeGenState.
|
|
74
|
+
* Helper to set up struct fields in CodeGenState.symbolTable
|
|
75
|
+
* Issue #831: SymbolTable is now the single source of truth for struct fields
|
|
74
76
|
*/
|
|
75
77
|
function setupStructFields(
|
|
76
78
|
structName: string,
|
|
77
79
|
fields: Map<string, string>,
|
|
78
80
|
arrayFields: Set<string> = new Set(),
|
|
79
81
|
): void {
|
|
80
|
-
// Initialize
|
|
82
|
+
// Initialize symbolTable if not set
|
|
83
|
+
if (!CodeGenState.symbolTable) {
|
|
84
|
+
CodeGenState.symbolTable = new SymbolTable();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Register struct fields in SymbolTable
|
|
88
|
+
for (const [fieldName, fieldType] of fields) {
|
|
89
|
+
const isArray = arrayFields.has(fieldName);
|
|
90
|
+
CodeGenState.symbolTable.addStructField(
|
|
91
|
+
structName,
|
|
92
|
+
fieldName,
|
|
93
|
+
fieldType,
|
|
94
|
+
isArray ? [10] : undefined, // Use realistic dimension for arrays
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Also mark struct as known (for isKnownStruct checks)
|
|
81
99
|
if (!CodeGenState.symbols) {
|
|
82
100
|
CodeGenState.symbols = {
|
|
83
101
|
knownStructs: new Set(),
|
|
@@ -108,14 +126,6 @@ describe("MemberChainAnalyzer", () => {
|
|
|
108
126
|
};
|
|
109
127
|
}
|
|
110
128
|
(CodeGenState.symbols.knownStructs as Set<string>).add(structName);
|
|
111
|
-
(CodeGenState.symbols.structFields as Map<string, Map<string, string>>).set(
|
|
112
|
-
structName,
|
|
113
|
-
fields,
|
|
114
|
-
);
|
|
115
|
-
(CodeGenState.symbols.structFieldArrays as Map<string, Set<string>>).set(
|
|
116
|
-
structName,
|
|
117
|
-
arrayFields,
|
|
118
|
-
);
|
|
119
129
|
}
|
|
120
130
|
|
|
121
131
|
describe("analyze", () => {
|
|
@@ -669,8 +669,11 @@ class AssignmentClassifier {
|
|
|
669
669
|
if (!structType) {
|
|
670
670
|
return null;
|
|
671
671
|
}
|
|
672
|
-
|
|
673
|
-
const fieldType =
|
|
672
|
+
// Issue #831: Use SymbolTable as single source of truth for struct fields
|
|
673
|
+
const fieldType = CodeGenState.symbolTable?.getStructFieldType(
|
|
674
|
+
structType,
|
|
675
|
+
structFieldNames.fieldName,
|
|
676
|
+
);
|
|
674
677
|
return { structType, fieldType };
|
|
675
678
|
}
|
|
676
679
|
|
|
@@ -3,6 +3,7 @@ import AssignmentClassifier from "../AssignmentClassifier";
|
|
|
3
3
|
import AssignmentKind from "../AssignmentKind";
|
|
4
4
|
import IAssignmentContext from "../IAssignmentContext";
|
|
5
5
|
import CodeGenState from "../../../../state/CodeGenState";
|
|
6
|
+
import SymbolTable from "../../../../logic/symbols/SymbolTable";
|
|
6
7
|
import TTypeInfo from "../../types/TTypeInfo";
|
|
7
8
|
|
|
8
9
|
// ========================================================================
|
|
@@ -64,6 +65,7 @@ function createTypeInfo(overrides: Partial<TTypeInfo> = {}): TTypeInfo {
|
|
|
64
65
|
|
|
65
66
|
/**
|
|
66
67
|
* Helper to set up CodeGenState.symbols with minimal fields.
|
|
68
|
+
* Issue #831: Also registers struct fields in SymbolTable (single source of truth).
|
|
67
69
|
*/
|
|
68
70
|
function setupSymbols(
|
|
69
71
|
overrides: {
|
|
@@ -77,6 +79,22 @@ function setupSymbols(
|
|
|
77
79
|
structFieldDimensions?: Map<string, Map<string, readonly number[]>>;
|
|
78
80
|
} = {},
|
|
79
81
|
): void {
|
|
82
|
+
// Initialize symbolTable for struct field lookups
|
|
83
|
+
CodeGenState.symbolTable = new SymbolTable();
|
|
84
|
+
|
|
85
|
+
// Register struct fields in SymbolTable
|
|
86
|
+
if (overrides.structFields) {
|
|
87
|
+
for (const [structName, fields] of overrides.structFields) {
|
|
88
|
+
for (const [fieldName, fieldType] of fields) {
|
|
89
|
+
CodeGenState.symbolTable.addStructField(
|
|
90
|
+
structName,
|
|
91
|
+
fieldName,
|
|
92
|
+
fieldType,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
80
98
|
CodeGenState.symbols = {
|
|
81
99
|
knownScopes: overrides.knownScopes ?? new Set(),
|
|
82
100
|
knownStructs: overrides.knownStructs ?? new Set(),
|
|
@@ -57,10 +57,26 @@ function handleSimpleStringAssignment(ctx: IAssignmentContext): string {
|
|
|
57
57
|
* Shared helper for struct field string handlers.
|
|
58
58
|
*/
|
|
59
59
|
function getStructFieldType(structName: string, fieldName: string): string {
|
|
60
|
+
// Issue #831: Use SymbolTable as single source of truth for struct fields
|
|
60
61
|
const structTypeInfo = CodeGenState.getVariableTypeInfo(structName);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
if (!structTypeInfo) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`Error: Unknown struct variable '${structName}' in string assignment`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const structType = structTypeInfo.baseType;
|
|
69
|
+
const fieldType = CodeGenState.symbolTable?.getStructFieldType(
|
|
70
|
+
structType,
|
|
71
|
+
fieldName,
|
|
72
|
+
);
|
|
73
|
+
if (!fieldType) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Error: Unknown field '${fieldName}' on struct '${structType}' in string assignment`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return fieldType;
|
|
64
80
|
}
|
|
65
81
|
|
|
66
82
|
/**
|
|
@@ -70,7 +86,12 @@ function getStructFieldType(structName: string, fieldName: string): string {
|
|
|
70
86
|
*/
|
|
71
87
|
function getStructType(structName: string): string {
|
|
72
88
|
const structTypeInfo = CodeGenState.getVariableTypeInfo(structName);
|
|
73
|
-
|
|
89
|
+
if (!structTypeInfo) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`Error: Unknown struct variable '${structName}' in string assignment`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return structTypeInfo.baseType;
|
|
74
95
|
}
|
|
75
96
|
|
|
76
97
|
/**
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { vi } from "vitest";
|
|
7
7
|
import CodeGenState from "../../../../../state/CodeGenState";
|
|
8
|
+
import SymbolTable from "../../../../../logic/symbols/SymbolTable";
|
|
8
9
|
import type ICodeGenApi from "../../../types/ICodeGenApi";
|
|
9
10
|
import type ICodeGenSymbols from "../../../../../types/ICodeGenSymbols";
|
|
10
11
|
import type TTypeInfo from "../../../types/TTypeInfo";
|
|
@@ -63,12 +64,29 @@ function createDefaultMockSymbols(): ICodeGenSymbols {
|
|
|
63
64
|
/**
|
|
64
65
|
* Set up mock symbols on CodeGenState.
|
|
65
66
|
* Provides comprehensive defaults that can be overridden.
|
|
67
|
+
* Issue #831: Also registers struct fields in SymbolTable for single source of truth.
|
|
66
68
|
*/
|
|
67
69
|
function setupMockSymbols(overrides: Partial<ICodeGenSymbols> = {}): void {
|
|
68
70
|
CodeGenState.symbols = {
|
|
69
71
|
...createDefaultMockSymbols(),
|
|
70
72
|
...overrides,
|
|
71
73
|
};
|
|
74
|
+
|
|
75
|
+
// Also register struct fields in SymbolTable (single source of truth)
|
|
76
|
+
if (overrides.structFields) {
|
|
77
|
+
if (!CodeGenState.symbolTable) {
|
|
78
|
+
CodeGenState.symbolTable = new SymbolTable();
|
|
79
|
+
}
|
|
80
|
+
for (const [structName, fields] of overrides.structFields) {
|
|
81
|
+
for (const [fieldName, fieldType] of fields) {
|
|
82
|
+
CodeGenState.symbolTable.addStructField(
|
|
83
|
+
structName,
|
|
84
|
+
fieldName,
|
|
85
|
+
fieldType,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
72
90
|
}
|
|
73
91
|
|
|
74
92
|
/**
|