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.
Files changed (41) hide show
  1. package/bin/cnext.js +17 -7
  2. package/dist/index.js +139830 -0
  3. package/dist/index.js.map +7 -0
  4. package/package.json +8 -4
  5. package/src/cli/Cli.ts +5 -2
  6. package/src/cli/PathNormalizer.ts +170 -0
  7. package/src/cli/PlatformIOCommand.ts +51 -3
  8. package/src/cli/__tests__/Cli.integration.test.ts +100 -0
  9. package/src/cli/__tests__/Cli.test.ts +17 -12
  10. package/src/cli/__tests__/PathNormalizer.test.ts +411 -0
  11. package/src/cli/__tests__/PlatformIOCommand.test.ts +156 -0
  12. package/src/cli/serve/__tests__/ServeCommand.test.ts +1 -1
  13. package/src/transpiler/NodeFileSystem.ts +5 -0
  14. package/src/transpiler/logic/symbols/SymbolTable.ts +17 -0
  15. package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +99 -2
  16. package/src/transpiler/logic/symbols/c/utils/__tests__/DeclaratorUtils.test.ts +128 -0
  17. package/src/transpiler/output/codegen/CodeGenerator.ts +27 -32
  18. package/src/transpiler/output/codegen/TypeResolver.ts +12 -24
  19. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +130 -5
  20. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +116 -93
  21. package/src/transpiler/output/codegen/__tests__/RequireInclude.test.ts +4 -2
  22. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +9 -13
  23. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +20 -10
  24. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +5 -2
  25. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +18 -0
  26. package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +25 -4
  27. package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +18 -0
  28. package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +51 -2
  29. package/src/transpiler/output/codegen/generators/expressions/LiteralGenerator.ts +76 -8
  30. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +23 -14
  31. package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +147 -0
  32. package/src/transpiler/output/codegen/generators/expressions/__tests__/LiteralGenerator.test.ts +116 -0
  33. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +9 -6
  34. package/src/transpiler/output/codegen/generators/statements/SwitchGenerator.ts +10 -1
  35. package/src/transpiler/output/codegen/helpers/ArrayAccessHelper.ts +6 -3
  36. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +6 -5
  37. package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +36 -22
  38. package/src/transpiler/output/codegen/helpers/__tests__/ArrayAccessHelper.test.ts +8 -6
  39. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +14 -5
  40. package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +34 -18
  41. 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 = 42;");
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 += 5;");
1011
- expect(code).toContain("x -= 3;");
1012
- expect(code).toContain("x *= 2;");
1013
- expect(code).toContain("x /= 2;");
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, 100)");
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 = 5;");
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("{1, 2, 3}");
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 * 2 - 1");
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(1, 2);");
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(5)");
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) ? 1 : 0");
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("{1, 2, 3, 4, 5}");
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("{10, 20, 30, 40}");
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 {0} for fill-all syntax
3758
- expect(code).toContain("{0}");
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("= {255, 255, 255, 255}");
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("{{1, 2, 3}, {4, 5, 6}}");
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(10, 20)");
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("{1, 2, 3, 4}");
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, 1)");
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, 1)");
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[5]");
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[0]");
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[0]");
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[5]");
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[1][2]");
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[0]");
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[0].x");
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 shadow variable and memcpy
8790
- expect(code).toContain("memcpy");
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 >> 0) & 1)");
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 > 3) ? 10 : 20");
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("{1, 2, 3, 4, 5}");
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 + 1)");
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
- // Constant expressions may be folded
10006
- expect(code).toContain("compute(8)");
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(">> 8");
10214
- // Mask is generated as ((1U << 4) - 1) for bit width 4
10215
- expect(code).toContain("((1U << 4) - 1)");
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 memcpy", () => {
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 memcpy for type punning
10762
- expect(code).toContain("memcpy");
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
- expect(code).toContain("memcpy");
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[0].x <- 10;
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 memcpy for type punning
12276
- expect(code).toContain("memcpy");
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[5]");
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
- // Constant expressions get folded
12554
- expect(code).toContain("15");
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 and memcpy", () => {
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 shadow variable pattern for float bit access
12895
+ // Should use union-based type punning (MISRA 21.15 compliant)
12882
12896
  expect(code).toContain("__bits_floatVal");
12883
- expect(code).toContain("memcpy");
12884
- expect(code).toContain("uint32_t");
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 shadow for f64
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
- // Shadow variable should only be declared once
12929
- const shadowDecls = (code.match(/uint32_t __bits_val;/g) || []).length;
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
- // But memcpy may be used only on first access
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
- // When start=0, no shift needed - just mask
12968
+ // Bit range access generates shift and mask
12953
12969
  expect(code).toContain("flags");
12954
12970
  expect(code).toContain("& 0xFF");
12955
- // Should NOT have >> 0 shift
12956
- expect(code).not.toContain(">> 0");
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[5]");
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
- expect(code).toContain("memcpy");
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
- // start=0 should NOT have >> 0 shift
13652
- expect(code).not.toContain(">> 0");
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
- // Shadow declaration should appear once
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[0].id");
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
- // Position 0 should NOT generate >> 0
14633
- expect(code).not.toContain(">> 0");
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(5, 10)");
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(5)");
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[5]");
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 memcpy", () => {
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
- expect(code).toContain("memcpy");
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
- expect(code).toContain("uint64_t __bits_dval");
15438
- expect(code).toContain("memcpy");
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
- // Expression should be constant-folded: 10 + 5 = 15
15491
- expect(code).toContain("uint8_t result = 15;");
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
- expect(result.code).toContain("#include <string.h>"); // For memcpy
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