c-next 0.2.1 → 0.2.3
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 +139830 -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/transpiler/NodeFileSystem.ts +5 -0
- package/src/transpiler/logic/symbols/SymbolTable.ts +17 -0
- package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +99 -2
- package/src/transpiler/logic/symbols/c/utils/__tests__/DeclaratorUtils.test.ts +128 -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 +116 -93
- package/src/transpiler/output/codegen/__tests__/RequireInclude.test.ts +4 -2
- 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/PostfixExpressionGenerator.ts +23 -14
- 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/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +9 -6
- package/src/transpiler/output/codegen/generators/statements/SwitchGenerator.ts +10 -1
- package/src/transpiler/output/codegen/helpers/ArrayAccessHelper.ts +6 -3
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +6 -5
- package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +36 -22
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayAccessHelper.test.ts +8 -6
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +14 -5
- package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +34 -18
- 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", () => {
|
|
@@ -8769,7 +8776,7 @@ describe("CodeGenerator", () => {
|
|
|
8769
8776
|
expect(code).toContain(">> 4");
|
|
8770
8777
|
});
|
|
8771
8778
|
|
|
8772
|
-
it("should generate float bit range read with shadow variable", () => {
|
|
8779
|
+
it("should generate float bit range read with union shadow variable", () => {
|
|
8773
8780
|
const source = `
|
|
8774
8781
|
void test() {
|
|
8775
8782
|
f32 value <- 3.14;
|
|
@@ -8786,8 +8793,9 @@ describe("CodeGenerator", () => {
|
|
|
8786
8793
|
sourcePath: "test.cnx",
|
|
8787
8794
|
});
|
|
8788
8795
|
|
|
8789
|
-
// Float bit access uses
|
|
8790
|
-
expect(code).toContain("
|
|
8796
|
+
// Float bit access uses union-based type punning (MISRA 21.15 compliant)
|
|
8797
|
+
expect(code).toContain("union { float f; uint32_t u; }");
|
|
8798
|
+
expect(code).not.toContain("memcpy");
|
|
8791
8799
|
});
|
|
8792
8800
|
});
|
|
8793
8801
|
|
|
@@ -9105,8 +9113,8 @@ describe("CodeGenerator", () => {
|
|
|
9105
9113
|
sourcePath: "test.cnx",
|
|
9106
9114
|
});
|
|
9107
9115
|
|
|
9108
|
-
// Bitmap indexing generates bit extraction
|
|
9109
|
-
expect(code).toContain("((flags >>
|
|
9116
|
+
// Bitmap indexing generates bit extraction with U suffix
|
|
9117
|
+
expect(code).toContain("((flags >> 0U) & 1)");
|
|
9110
9118
|
});
|
|
9111
9119
|
});
|
|
9112
9120
|
|
|
@@ -9368,7 +9376,7 @@ describe("CodeGenerator", () => {
|
|
|
9368
9376
|
sourcePath: "test.cnx",
|
|
9369
9377
|
});
|
|
9370
9378
|
|
|
9371
|
-
expect(code).toContain("(x >
|
|
9379
|
+
expect(code).toContain("(x > 3U) ? 10U : 20U");
|
|
9372
9380
|
});
|
|
9373
9381
|
});
|
|
9374
9382
|
|
|
@@ -9632,7 +9640,7 @@ describe("CodeGenerator", () => {
|
|
|
9632
9640
|
sourcePath: "test.cnx",
|
|
9633
9641
|
});
|
|
9634
9642
|
|
|
9635
|
-
expect(code).toContain("{
|
|
9643
|
+
expect(code).toContain("{1U, 2U, 3U, 4U, 5U}");
|
|
9636
9644
|
});
|
|
9637
9645
|
});
|
|
9638
9646
|
|
|
@@ -9890,7 +9898,7 @@ describe("CodeGenerator", () => {
|
|
|
9890
9898
|
sourcePath: "test.cnx",
|
|
9891
9899
|
});
|
|
9892
9900
|
|
|
9893
|
-
expect(code).toContain("sizeof(x +
|
|
9901
|
+
expect(code).toContain("sizeof(x + 1U)");
|
|
9894
9902
|
});
|
|
9895
9903
|
});
|
|
9896
9904
|
|
|
@@ -9936,6 +9944,7 @@ describe("CodeGenerator", () => {
|
|
|
9936
9944
|
cppMode: true,
|
|
9937
9945
|
});
|
|
9938
9946
|
|
|
9947
|
+
// Array element assignments don't get U suffix yet
|
|
9939
9948
|
expect(code).toContain("c.points[0].x = 5");
|
|
9940
9949
|
});
|
|
9941
9950
|
});
|
|
@@ -10002,8 +10011,8 @@ describe("CodeGenerator", () => {
|
|
|
10002
10011
|
sourcePath: "test.cnx",
|
|
10003
10012
|
});
|
|
10004
10013
|
|
|
10005
|
-
//
|
|
10006
|
-
expect(code).toContain("compute(
|
|
10014
|
+
// Literals get U suffix per MISRA Rule 7.2
|
|
10015
|
+
expect(code).toContain("compute(5U + 3U)");
|
|
10007
10016
|
});
|
|
10008
10017
|
});
|
|
10009
10018
|
|
|
@@ -10210,9 +10219,9 @@ describe("CodeGenerator", () => {
|
|
|
10210
10219
|
sourcePath: "test.cnx",
|
|
10211
10220
|
});
|
|
10212
10221
|
|
|
10213
|
-
expect(code).toContain(">>
|
|
10214
|
-
// Mask is generated as ((1U <<
|
|
10215
|
-
expect(code).toContain("((1U <<
|
|
10222
|
+
expect(code).toContain(">> 8U");
|
|
10223
|
+
// Mask is generated as ((1U << 4U) - 1) for bit width 4
|
|
10224
|
+
expect(code).toContain("((1U << 4U) - 1)");
|
|
10216
10225
|
});
|
|
10217
10226
|
});
|
|
10218
10227
|
|
|
@@ -10694,6 +10703,7 @@ describe("CodeGenerator", () => {
|
|
|
10694
10703
|
});
|
|
10695
10704
|
|
|
10696
10705
|
// Array params don't need dereference
|
|
10706
|
+
// Array element access doesn't get U suffix yet
|
|
10697
10707
|
expect(code).toContain("arr[5]");
|
|
10698
10708
|
expect(code).not.toContain("(*arr)");
|
|
10699
10709
|
});
|
|
@@ -10741,7 +10751,7 @@ describe("CodeGenerator", () => {
|
|
|
10741
10751
|
});
|
|
10742
10752
|
|
|
10743
10753
|
describe("float bit range access helpers", () => {
|
|
10744
|
-
it("should generate float bit range read with
|
|
10754
|
+
it("should generate float bit range read with union", () => {
|
|
10745
10755
|
const source = `
|
|
10746
10756
|
void test() {
|
|
10747
10757
|
f32 value <- 3.14;
|
|
@@ -10758,11 +10768,12 @@ describe("CodeGenerator", () => {
|
|
|
10758
10768
|
sourcePath: "test.cnx",
|
|
10759
10769
|
});
|
|
10760
10770
|
|
|
10761
|
-
// Float bit access uses
|
|
10762
|
-
expect(code).toContain("
|
|
10771
|
+
// Float bit access uses union-based type punning (MISRA 21.15 compliant)
|
|
10772
|
+
expect(code).toContain("union { float f; uint32_t u; }");
|
|
10773
|
+
expect(code).not.toContain("memcpy");
|
|
10763
10774
|
});
|
|
10764
10775
|
|
|
10765
|
-
it("should generate f64 bit range read", () => {
|
|
10776
|
+
it("should generate f64 bit range read with union", () => {
|
|
10766
10777
|
const source = `
|
|
10767
10778
|
void test() {
|
|
10768
10779
|
f64 value <- 3.14159;
|
|
@@ -10779,7 +10790,9 @@ describe("CodeGenerator", () => {
|
|
|
10779
10790
|
sourcePath: "test.cnx",
|
|
10780
10791
|
});
|
|
10781
10792
|
|
|
10782
|
-
|
|
10793
|
+
// f64 uses double/uint64_t union
|
|
10794
|
+
expect(code).toContain("union { double f; uint64_t u; }");
|
|
10795
|
+
expect(code).not.toContain("memcpy");
|
|
10783
10796
|
});
|
|
10784
10797
|
});
|
|
10785
10798
|
|
|
@@ -11952,7 +11965,7 @@ describe("CodeGenerator", () => {
|
|
|
11952
11965
|
const source = `
|
|
11953
11966
|
struct Point { i32 x; i32 y; }
|
|
11954
11967
|
void processPoints(Point[4] points) {
|
|
11955
|
-
points[
|
|
11968
|
+
points[0U].x <- 10;
|
|
11956
11969
|
}
|
|
11957
11970
|
`;
|
|
11958
11971
|
const { tree, tokenStream } = CNextSourceParser.parse(source);
|
|
@@ -12255,7 +12268,7 @@ describe("CodeGenerator", () => {
|
|
|
12255
12268
|
expect(code).toContain("flags");
|
|
12256
12269
|
});
|
|
12257
12270
|
|
|
12258
|
-
it("should handle float bit punning", () => {
|
|
12271
|
+
it("should handle float bit punning with union", () => {
|
|
12259
12272
|
const source = `
|
|
12260
12273
|
void test() {
|
|
12261
12274
|
f32 val <- 3.14;
|
|
@@ -12272,8 +12285,9 @@ describe("CodeGenerator", () => {
|
|
|
12272
12285
|
sourcePath: "test.cnx",
|
|
12273
12286
|
});
|
|
12274
12287
|
|
|
12275
|
-
// Float bit access uses
|
|
12276
|
-
expect(code).toContain("
|
|
12288
|
+
// Float bit access uses union-based type punning (MISRA 21.15 compliant)
|
|
12289
|
+
expect(code).toContain("union { float f; uint32_t u; }");
|
|
12290
|
+
expect(code).not.toContain("memcpy");
|
|
12277
12291
|
});
|
|
12278
12292
|
});
|
|
12279
12293
|
|
|
@@ -12361,7 +12375,7 @@ describe("CodeGenerator", () => {
|
|
|
12361
12375
|
sourcePath: "test.cnx",
|
|
12362
12376
|
});
|
|
12363
12377
|
|
|
12364
|
-
expect(code).toContain("arr[
|
|
12378
|
+
expect(code).toContain("arr[5U]");
|
|
12365
12379
|
});
|
|
12366
12380
|
|
|
12367
12381
|
it("should resolve array element with variable index", () => {
|
|
@@ -12550,8 +12564,8 @@ describe("CodeGenerator", () => {
|
|
|
12550
12564
|
sourcePath: "test.cnx",
|
|
12551
12565
|
});
|
|
12552
12566
|
|
|
12553
|
-
//
|
|
12554
|
-
expect(code).toContain("
|
|
12567
|
+
// Literals get U suffix per MISRA Rule 7.2
|
|
12568
|
+
expect(code).toContain("10U + 5U");
|
|
12555
12569
|
});
|
|
12556
12570
|
});
|
|
12557
12571
|
|
|
@@ -12861,7 +12875,7 @@ describe("CodeGenerator", () => {
|
|
|
12861
12875
|
|
|
12862
12876
|
describe("refactored helper methods", () => {
|
|
12863
12877
|
describe("float bit range access (PR #715 coverage)", () => {
|
|
12864
|
-
it("should generate f32 bit range read with shadow
|
|
12878
|
+
it("should generate f32 bit range read with union shadow", () => {
|
|
12865
12879
|
const source = `
|
|
12866
12880
|
void test() {
|
|
12867
12881
|
f32 floatVal <- 1.5;
|
|
@@ -12878,13 +12892,13 @@ describe("CodeGenerator", () => {
|
|
|
12878
12892
|
sourcePath: "test.cnx",
|
|
12879
12893
|
});
|
|
12880
12894
|
|
|
12881
|
-
// Should use
|
|
12895
|
+
// Should use union-based type punning (MISRA 21.15 compliant)
|
|
12882
12896
|
expect(code).toContain("__bits_floatVal");
|
|
12883
|
-
expect(code).toContain("
|
|
12884
|
-
expect(code).toContain("
|
|
12897
|
+
expect(code).toContain("union { float f; uint32_t u; }");
|
|
12898
|
+
expect(code).not.toContain("memcpy");
|
|
12885
12899
|
});
|
|
12886
12900
|
|
|
12887
|
-
it("should generate f64 bit range read with 64-bit shadow", () => {
|
|
12901
|
+
it("should generate f64 bit range read with 64-bit union shadow", () => {
|
|
12888
12902
|
const source = `
|
|
12889
12903
|
void test() {
|
|
12890
12904
|
f64 doubleVal <- 2.718;
|
|
@@ -12901,10 +12915,10 @@ describe("CodeGenerator", () => {
|
|
|
12901
12915
|
sourcePath: "test.cnx",
|
|
12902
12916
|
});
|
|
12903
12917
|
|
|
12904
|
-
// Should use 64-bit
|
|
12918
|
+
// Should use 64-bit union for f64 (MISRA 21.15 compliant)
|
|
12905
12919
|
expect(code).toContain("__bits_doubleVal");
|
|
12906
|
-
expect(code).toContain("uint64_t");
|
|
12907
|
-
expect(code).toContain("memcpy");
|
|
12920
|
+
expect(code).toContain("union { double f; uint64_t u; }");
|
|
12921
|
+
expect(code).not.toContain("memcpy");
|
|
12908
12922
|
});
|
|
12909
12923
|
|
|
12910
12924
|
it("should reuse shadow variable for repeated float bit reads", () => {
|
|
@@ -12925,11 +12939,13 @@ describe("CodeGenerator", () => {
|
|
|
12925
12939
|
sourcePath: "test.cnx",
|
|
12926
12940
|
});
|
|
12927
12941
|
|
|
12928
|
-
//
|
|
12929
|
-
const shadowDecls = (
|
|
12942
|
+
// Union shadow should only be declared once
|
|
12943
|
+
const shadowDecls = (
|
|
12944
|
+
code.match(/union { float f; uint32_t u; } __bits_val;/g) || []
|
|
12945
|
+
).length;
|
|
12930
12946
|
expect(shadowDecls).toBe(1);
|
|
12931
|
-
//
|
|
12932
|
-
expect(code).toContain("__bits_val");
|
|
12947
|
+
// Uses union member .u for bit access
|
|
12948
|
+
expect(code).toContain("__bits_val.u");
|
|
12933
12949
|
});
|
|
12934
12950
|
|
|
12935
12951
|
it("should generate integer bit range with start=0 optimization", () => {
|
|
@@ -12949,11 +12965,11 @@ describe("CodeGenerator", () => {
|
|
|
12949
12965
|
sourcePath: "test.cnx",
|
|
12950
12966
|
});
|
|
12951
12967
|
|
|
12952
|
-
//
|
|
12968
|
+
// Bit range access generates shift and mask
|
|
12953
12969
|
expect(code).toContain("flags");
|
|
12954
12970
|
expect(code).toContain("& 0xFF");
|
|
12955
|
-
//
|
|
12956
|
-
expect(code).
|
|
12971
|
+
// MISRA Rule 7.2: shift amount gets U suffix
|
|
12972
|
+
expect(code).toContain(">> 0U");
|
|
12957
12973
|
});
|
|
12958
12974
|
|
|
12959
12975
|
it("should generate integer bit range with shift for non-zero start", () => {
|
|
@@ -13532,7 +13548,7 @@ describe("CodeGenerator", () => {
|
|
|
13532
13548
|
sourcePath: "test.cnx",
|
|
13533
13549
|
});
|
|
13534
13550
|
|
|
13535
|
-
expect(code).toContain("buffer[
|
|
13551
|
+
expect(code).toContain("buffer[5U]");
|
|
13536
13552
|
});
|
|
13537
13553
|
|
|
13538
13554
|
it("should handle array access with variable index", () => {
|
|
@@ -13608,7 +13624,7 @@ describe("CodeGenerator", () => {
|
|
|
13608
13624
|
});
|
|
13609
13625
|
|
|
13610
13626
|
describe("float bit range edge cases", () => {
|
|
13611
|
-
it("should generate f32 bit range with non-zero start position", () => {
|
|
13627
|
+
it("should generate f32 bit range with non-zero start position using union", () => {
|
|
13612
13628
|
const source = `
|
|
13613
13629
|
void test() {
|
|
13614
13630
|
f32 value <- 3.14;
|
|
@@ -13627,7 +13643,9 @@ describe("CodeGenerator", () => {
|
|
|
13627
13643
|
|
|
13628
13644
|
expect(code).toContain("__bits_value");
|
|
13629
13645
|
expect(code).toContain(">> 8");
|
|
13630
|
-
|
|
13646
|
+
// Uses union, not memcpy (MISRA 21.15 compliant)
|
|
13647
|
+
expect(code).toContain("union { float f; uint32_t u; }");
|
|
13648
|
+
expect(code).not.toContain("memcpy");
|
|
13631
13649
|
});
|
|
13632
13650
|
|
|
13633
13651
|
it("should generate f32 bit range with start=0", () => {
|
|
@@ -13648,11 +13666,11 @@ describe("CodeGenerator", () => {
|
|
|
13648
13666
|
});
|
|
13649
13667
|
|
|
13650
13668
|
expect(code).toContain("__bits_val");
|
|
13651
|
-
//
|
|
13652
|
-
expect(code).
|
|
13669
|
+
// MISRA Rule 7.2: shift amount gets U suffix
|
|
13670
|
+
expect(code).toContain(">> 0U");
|
|
13653
13671
|
});
|
|
13654
13672
|
|
|
13655
|
-
it("should handle multiple reads from same float reusing shadow", () => {
|
|
13673
|
+
it("should handle multiple reads from same float reusing union shadow", () => {
|
|
13656
13674
|
const source = `
|
|
13657
13675
|
void test() {
|
|
13658
13676
|
f32 data <- 2.5;
|
|
@@ -13671,10 +13689,10 @@ describe("CodeGenerator", () => {
|
|
|
13671
13689
|
sourcePath: "test.cnx",
|
|
13672
13690
|
});
|
|
13673
13691
|
|
|
13674
|
-
//
|
|
13675
|
-
expect(code).toContain("uint32_t __bits_data");
|
|
13676
|
-
// Multiple reads should work
|
|
13677
|
-
expect(code).toContain("__bits_data");
|
|
13692
|
+
// Union shadow declaration should appear once
|
|
13693
|
+
expect(code).toContain("union { float f; uint32_t u; } __bits_data;");
|
|
13694
|
+
// Multiple reads should work via union member
|
|
13695
|
+
expect(code).toContain("__bits_data.u");
|
|
13678
13696
|
});
|
|
13679
13697
|
});
|
|
13680
13698
|
|
|
@@ -14102,6 +14120,7 @@ describe("CodeGenerator", () => {
|
|
|
14102
14120
|
});
|
|
14103
14121
|
|
|
14104
14122
|
expect(code).toContain("Point points[3]");
|
|
14123
|
+
// Array element assignments don't get U suffix yet
|
|
14105
14124
|
expect(code).toContain("points[0].x = 10");
|
|
14106
14125
|
});
|
|
14107
14126
|
|
|
@@ -14229,7 +14248,7 @@ describe("CodeGenerator", () => {
|
|
|
14229
14248
|
});
|
|
14230
14249
|
|
|
14231
14250
|
// Array element member access
|
|
14232
|
-
expect(code).toContain("items[
|
|
14251
|
+
expect(code).toContain("items[0U].id");
|
|
14233
14252
|
});
|
|
14234
14253
|
|
|
14235
14254
|
it("should use arrow for struct params in C mode", () => {
|
|
@@ -14629,8 +14648,8 @@ describe("CodeGenerator", () => {
|
|
|
14629
14648
|
sourcePath: "test.cnx",
|
|
14630
14649
|
});
|
|
14631
14650
|
|
|
14632
|
-
//
|
|
14633
|
-
expect(code).
|
|
14651
|
+
// MISRA Rule 7.2: shift amount gets U suffix
|
|
14652
|
+
expect(code).toContain(">> 0U");
|
|
14634
14653
|
});
|
|
14635
14654
|
|
|
14636
14655
|
it("should generate 64-bit mask for u64 values", () => {
|
|
@@ -15190,7 +15209,7 @@ describe("CodeGenerator", () => {
|
|
|
15190
15209
|
sourcePath: "test.cnx",
|
|
15191
15210
|
});
|
|
15192
15211
|
|
|
15193
|
-
expect(code).toContain("multiply(
|
|
15212
|
+
expect(code).toContain("multiply(5U, 10U)");
|
|
15194
15213
|
});
|
|
15195
15214
|
|
|
15196
15215
|
it("should generate scoped function call", () => {
|
|
@@ -15214,7 +15233,7 @@ describe("CodeGenerator", () => {
|
|
|
15214
15233
|
sourcePath: "test.cnx",
|
|
15215
15234
|
});
|
|
15216
15235
|
|
|
15217
|
-
expect(code).toContain("Math_square(
|
|
15236
|
+
expect(code).toContain("Math_square(5U)");
|
|
15218
15237
|
});
|
|
15219
15238
|
});
|
|
15220
15239
|
|
|
@@ -15352,7 +15371,7 @@ describe("CodeGenerator", () => {
|
|
|
15352
15371
|
sourcePath: "test.cnx",
|
|
15353
15372
|
});
|
|
15354
15373
|
|
|
15355
|
-
expect(code).toContain("arr[
|
|
15374
|
+
expect(code).toContain("arr[5U]");
|
|
15356
15375
|
});
|
|
15357
15376
|
|
|
15358
15377
|
it("should generate array access with variable index", () => {
|
|
@@ -15396,7 +15415,7 @@ describe("CodeGenerator", () => {
|
|
|
15396
15415
|
expect(code).toContain("& 0xFF");
|
|
15397
15416
|
});
|
|
15398
15417
|
|
|
15399
|
-
it("should generate float bit range access with
|
|
15418
|
+
it("should generate float bit range access with union", () => {
|
|
15400
15419
|
const source = `
|
|
15401
15420
|
void test() {
|
|
15402
15421
|
f32 fval <- 1.5;
|
|
@@ -15413,11 +15432,13 @@ describe("CodeGenerator", () => {
|
|
|
15413
15432
|
sourcePath: "test.cnx",
|
|
15414
15433
|
});
|
|
15415
15434
|
|
|
15416
|
-
|
|
15417
|
-
expect(code).toContain("__bits_fval");
|
|
15435
|
+
// Uses union, not memcpy (MISRA 21.15 compliant)
|
|
15436
|
+
expect(code).toContain("union { float f; uint32_t u; } __bits_fval;");
|
|
15437
|
+
expect(code).toContain("__bits_fval.u");
|
|
15438
|
+
expect(code).not.toContain("memcpy");
|
|
15418
15439
|
});
|
|
15419
15440
|
|
|
15420
|
-
it("should generate f64 bit range access with uint64_t shadow", () => {
|
|
15441
|
+
it("should generate f64 bit range access with uint64_t union shadow", () => {
|
|
15421
15442
|
const source = `
|
|
15422
15443
|
void test() {
|
|
15423
15444
|
f64 dval <- 1.5;
|
|
@@ -15434,8 +15455,10 @@ describe("CodeGenerator", () => {
|
|
|
15434
15455
|
sourcePath: "test.cnx",
|
|
15435
15456
|
});
|
|
15436
15457
|
|
|
15437
|
-
|
|
15438
|
-
expect(code).toContain("
|
|
15458
|
+
// Uses union, not memcpy (MISRA 21.15 compliant)
|
|
15459
|
+
expect(code).toContain("union { double f; uint64_t u; } __bits_dval;");
|
|
15460
|
+
expect(code).toContain("__bits_dval.u");
|
|
15461
|
+
expect(code).not.toContain("memcpy");
|
|
15439
15462
|
});
|
|
15440
15463
|
});
|
|
15441
15464
|
});
|
|
@@ -15487,8 +15510,8 @@ describe("CodeGenerator", () => {
|
|
|
15487
15510
|
sourcePath: "test.cnx",
|
|
15488
15511
|
});
|
|
15489
15512
|
|
|
15490
|
-
//
|
|
15491
|
-
expect(code).toContain("uint8_t result =
|
|
15513
|
+
// Const values are inlined, 5 gets U suffix per MISRA Rule 7.2
|
|
15514
|
+
expect(code).toContain("uint8_t result = 10 + 5U;");
|
|
15492
15515
|
expect(code).not.toContain("Bar_OFFSET");
|
|
15493
15516
|
});
|
|
15494
15517
|
});
|
|
@@ -133,7 +133,7 @@ describe("CodeGenerator requireInclude", () => {
|
|
|
133
133
|
expect(result.code).toContain("sizeof(float)");
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
-
it("generates static assert for float bit indexing read", async () => {
|
|
136
|
+
it("generates static assert for float bit indexing read (no string.h)", async () => {
|
|
137
137
|
const transpiler = new Transpiler({ inputs: [], noCache: true }, mockFs);
|
|
138
138
|
|
|
139
139
|
const result = await transpiler.transpileSource(`
|
|
@@ -145,7 +145,9 @@ describe("CodeGenerator requireInclude", () => {
|
|
|
145
145
|
|
|
146
146
|
expect(result.success).toBe(true);
|
|
147
147
|
expect(result.code).toContain("_Static_assert");
|
|
148
|
-
|
|
148
|
+
// Uses union-based type punning, no memcpy needed (MISRA 21.15 compliant)
|
|
149
|
+
expect(result.code).not.toContain("#include <string.h>");
|
|
150
|
+
expect(result.code).toContain("union { float f; uint32_t u; }");
|
|
149
151
|
});
|
|
150
152
|
});
|
|
151
153
|
|