c-next 0.1.61 → 0.1.63

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 (104) hide show
  1. package/README.md +86 -63
  2. package/grammar/CNext.g4 +3 -17
  3. package/package.json +1 -1
  4. package/src/cli/serve/ServeCommand.ts +57 -45
  5. package/src/lib/__tests__/parseCHeader.mocked.test.ts +145 -0
  6. package/src/transpiler/Transpiler.ts +603 -613
  7. package/src/transpiler/__tests__/DualCodePaths.test.ts +5 -1
  8. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +2 -99
  9. package/src/transpiler/__tests__/Transpiler.test.ts +3 -26
  10. package/src/transpiler/data/IncludeTreeWalker.ts +1 -1
  11. package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +23 -52
  12. package/src/transpiler/logic/parser/grammar/CNext.interp +1 -3
  13. package/src/transpiler/logic/parser/grammar/CNextListener.ts +0 -22
  14. package/src/transpiler/logic/parser/grammar/CNextParser.ts +665 -1084
  15. package/src/transpiler/logic/parser/grammar/CNextVisitor.ts +0 -14
  16. package/src/transpiler/logic/symbols/CppSymbolCollector.ts +67 -43
  17. package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
  18. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
  19. package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
  20. package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
  21. package/src/transpiler/output/codegen/CodeGenerator.ts +1410 -2587
  22. package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
  23. package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
  24. package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
  25. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +2082 -52
  26. package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
  27. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
  28. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
  29. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
  30. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +227 -66
  31. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +55 -58
  32. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +288 -275
  33. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
  34. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +195 -133
  35. package/src/transpiler/output/codegen/assignment/AssignmentContextBuilder.ts +24 -74
  36. package/src/transpiler/output/codegen/assignment/AssignmentKind.ts +3 -0
  37. package/src/transpiler/output/codegen/assignment/IAssignmentContext.ts +3 -0
  38. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +290 -320
  39. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +42 -0
  40. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +76 -2
  41. package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
  42. package/src/transpiler/output/codegen/generators/IOrchestrator.ts +5 -1
  43. package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
  44. package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
  45. package/src/transpiler/output/codegen/generators/declarationGenerators/RegisterGenerator.ts +11 -24
  46. package/src/transpiler/output/codegen/generators/declarationGenerators/RegisterMacroGenerator.ts +64 -0
  47. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +137 -61
  48. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopedRegisterGenerator.ts +18 -27
  49. package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
  50. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
  51. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
  52. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +5 -1
  53. package/src/transpiler/output/codegen/generators/statements/ControlFlowGenerator.ts +1 -17
  54. package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
  55. package/src/transpiler/output/codegen/helpers/ArrayAccessHelper.ts +129 -0
  56. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
  57. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +40 -44
  58. package/src/transpiler/output/codegen/helpers/AssignmentTargetExtractor.ts +17 -45
  59. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +83 -78
  60. package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
  61. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
  62. package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
  63. package/src/transpiler/output/codegen/helpers/MemberSeparatorResolver.ts +10 -3
  64. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
  65. package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +44 -0
  66. package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
  67. package/src/transpiler/output/codegen/helpers/__tests__/ArrayAccessHelper.test.ts +479 -0
  68. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
  69. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
  70. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
  71. package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
  72. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
  73. package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
  74. package/src/transpiler/output/codegen/helpers/__tests__/MemberSeparatorResolver.test.ts +1 -0
  75. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
  76. package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +201 -0
  77. package/src/transpiler/output/codegen/helpers/__tests__/TypeGenerationHelper.test.ts +50 -0
  78. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
  79. package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
  80. package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
  81. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
  82. package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
  83. package/src/transpiler/output/codegen/types/IArrayAccessDeps.ts +23 -0
  84. package/src/transpiler/output/codegen/types/IArrayAccessInfo.ts +26 -0
  85. package/src/transpiler/output/codegen/types/IMemberSeparatorDeps.ts +7 -0
  86. package/src/transpiler/output/codegen/utils/CodegenParserUtils.ts +98 -0
  87. package/src/transpiler/output/codegen/utils/ExpressionUnwrapper.ts +22 -22
  88. package/src/transpiler/output/codegen/utils/__tests__/CodegenParserUtils.test.ts +228 -0
  89. package/src/transpiler/types/IFileResult.ts +0 -4
  90. package/src/transpiler/types/IPipelineFile.ts +27 -0
  91. package/src/transpiler/types/IPipelineInput.ts +23 -0
  92. package/src/transpiler/types/TranspilerState.ts +1 -1
  93. package/src/utils/FormatUtils.ts +28 -2
  94. package/src/utils/MapUtils.ts +25 -0
  95. package/src/utils/PostfixAnalysisUtils.ts +48 -0
  96. package/src/utils/__tests__/FormatUtils.test.ts +42 -0
  97. package/src/utils/__tests__/MapUtils.test.ts +85 -0
  98. package/src/utils/constants/OperatorMappings.ts +19 -0
  99. package/src/transpiler/logic/StandaloneContextBuilder.ts +0 -150
  100. package/src/transpiler/logic/__tests__/StandaloneContextBuilder.test.ts +0 -647
  101. package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
  102. package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
  103. package/src/transpiler/types/ITranspileContext.ts +0 -49
  104. package/src/transpiler/types/ITranspileContribution.ts +0 -32
@@ -1466,7 +1466,7 @@ describe("CodeGenerator", () => {
1466
1466
  describe("Array declarations", () => {
1467
1467
  it("should generate array declaration", () => {
1468
1468
  const source = `
1469
- u32 arr[10];
1469
+ u32[10] arr;
1470
1470
  void main() { }
1471
1471
  `;
1472
1472
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -1485,7 +1485,7 @@ describe("CodeGenerator", () => {
1485
1485
 
1486
1486
  it("should generate array with initializer", () => {
1487
1487
  const source = `
1488
- u32 arr[3] <- [1, 2, 3];
1488
+ u32[3] arr <- [1, 2, 3];
1489
1489
  void main() { }
1490
1490
  `;
1491
1491
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -1505,7 +1505,7 @@ describe("CodeGenerator", () => {
1505
1505
 
1506
1506
  it("should generate multi-dimensional array", () => {
1507
1507
  const source = `
1508
- u32 matrix[3][3];
1508
+ u32[3] matrix[3];
1509
1509
  void main() { }
1510
1510
  `;
1511
1511
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -2586,7 +2586,7 @@ describe("CodeGenerator", () => {
2586
2586
  describe("Array element assignment", () => {
2587
2587
  it("should generate array element assignment", () => {
2588
2588
  const source = `
2589
- wrap u32 arr[10];
2589
+ wrap u32[10] arr;
2590
2590
  void main() {
2591
2591
  arr[0] <- 42;
2592
2592
  arr[5] <- 100;
@@ -2734,7 +2734,7 @@ describe("CodeGenerator", () => {
2734
2734
  it("should generate struct with array field", () => {
2735
2735
  const source = `
2736
2736
  struct Buffer {
2737
- u8 data[64];
2737
+ u8[64] data;
2738
2738
  u32 length;
2739
2739
  }
2740
2740
  `;
@@ -3297,7 +3297,7 @@ describe("CodeGenerator", () => {
3297
3297
  it("should generate struct with array member access", () => {
3298
3298
  const source = `
3299
3299
  struct Buffer {
3300
- u8 data[64];
3300
+ u8[64] data;
3301
3301
  }
3302
3302
  Buffer buf;
3303
3303
  void main() {
@@ -3427,7 +3427,7 @@ describe("CodeGenerator", () => {
3427
3427
  describe("Const array", () => {
3428
3428
  it("should generate const array", () => {
3429
3429
  const source = `
3430
- const u32 LOOKUP[4] <- [10, 20, 30, 40];
3430
+ const u32[4] LOOKUP <- [10, 20, 30, 40];
3431
3431
  void main() { }
3432
3432
  `;
3433
3433
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -3853,7 +3853,7 @@ describe("CodeGenerator", () => {
3853
3853
  describe("Array fill-all syntax", () => {
3854
3854
  it("should generate fill-all array [0*]", () => {
3855
3855
  const source = `
3856
- u32 data[10] <- [0*];
3856
+ u32[10] data <- [0*];
3857
3857
  `;
3858
3858
  const { tree, tokenStream } = CNextSourceParser.parse(source);
3859
3859
  const generator = new CodeGenerator();
@@ -3872,7 +3872,7 @@ describe("CodeGenerator", () => {
3872
3872
 
3873
3873
  it("should generate fill-all array with non-zero value", () => {
3874
3874
  const source = `
3875
- u8 buffer[4] <- [255*];
3875
+ u8[4] buffer <- [255*];
3876
3876
  `;
3877
3877
  const { tree, tokenStream } = CNextSourceParser.parse(source);
3878
3878
  const generator = new CodeGenerator();
@@ -3893,7 +3893,7 @@ describe("CodeGenerator", () => {
3893
3893
  describe("Nested array initializers", () => {
3894
3894
  it("should generate 2D array initializer", () => {
3895
3895
  const source = `
3896
- u32 matrix[2][3] <- [[1, 2, 3], [4, 5, 6]];
3896
+ u32[2] matrix[3] <- [[1, 2, 3], [4, 5, 6]];
3897
3897
  `;
3898
3898
  const { tree, tokenStream } = CNextSourceParser.parse(source);
3899
3899
  const generator = new CodeGenerator();
@@ -3914,7 +3914,7 @@ describe("CodeGenerator", () => {
3914
3914
  it("should generate array of struct initializers", () => {
3915
3915
  const source = `
3916
3916
  struct Point { i32 x; i32 y; }
3917
- Point points[2] <- [{x: 1, y: 2}, {x: 3, y: 4}];
3917
+ Point[2] points <- [{x: 1, y: 2}, {x: 3, y: 4}];
3918
3918
  `;
3919
3919
  const { tree, tokenStream } = CNextSourceParser.parse(source);
3920
3920
  const generator = new CodeGenerator();
@@ -4184,7 +4184,7 @@ describe("CodeGenerator", () => {
4184
4184
  it("should resolve const as array dimension at file scope", () => {
4185
4185
  const source = `
4186
4186
  const u32 SIZE <- 10;
4187
- u32 data[SIZE];
4187
+ u32[SIZE] data;
4188
4188
  `;
4189
4189
  const { tree, tokenStream } = CNextSourceParser.parse(source);
4190
4190
  const generator = new CodeGenerator();
@@ -4205,7 +4205,7 @@ describe("CodeGenerator", () => {
4205
4205
  describe("Multi-dimensional array", () => {
4206
4206
  it("should generate 3D array declaration", () => {
4207
4207
  const source = `
4208
- u8 cube[2][3][4];
4208
+ u8[2] cube[3][4];
4209
4209
  `;
4210
4210
  const { tree, tokenStream } = CNextSourceParser.parse(source);
4211
4211
  const generator = new CodeGenerator();
@@ -4686,7 +4686,7 @@ describe("CodeGenerator", () => {
4686
4686
  describe("Array indexing with expressions", () => {
4687
4687
  it("should generate array index with arithmetic", () => {
4688
4688
  const source = `
4689
- u32 data[10];
4689
+ u32[10] data;
4690
4690
  wrap u32 i <- 2;
4691
4691
  void main() {
4692
4692
  data[i * 2 + 1] <- 42;
@@ -4877,7 +4877,7 @@ describe("CodeGenerator", () => {
4877
4877
  describe("Array length", () => {
4878
4878
  it("should generate array length using sizeof", () => {
4879
4879
  const source = `
4880
- u32 data[10];
4880
+ u32[10] data;
4881
4881
  u32 len <- data.length;
4882
4882
  `;
4883
4883
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -5285,7 +5285,7 @@ describe("CodeGenerator", () => {
5285
5285
  it("should pass array without address-of operator", () => {
5286
5286
  const source = `
5287
5287
  void processData(u32 data[]) { }
5288
- u32 myData[5];
5288
+ u32[5] myData;
5289
5289
  void main() {
5290
5290
  processData(myData);
5291
5291
  }
@@ -5310,7 +5310,7 @@ describe("CodeGenerator", () => {
5310
5310
  it("should generate struct with array field", () => {
5311
5311
  const source = `
5312
5312
  struct Buffer {
5313
- u8 data[64];
5313
+ u8[64] data;
5314
5314
  u32 length;
5315
5315
  }
5316
5316
  `;
@@ -5694,7 +5694,7 @@ describe("CodeGenerator", () => {
5694
5694
  describe("Array bounds checking", () => {
5695
5695
  it("should throw error for out-of-bounds constant index", () => {
5696
5696
  const source = `
5697
- u32 data[5];
5697
+ u32[5] data;
5698
5698
  void main() {
5699
5699
  data[10] <- 1;
5700
5700
  }
@@ -5899,7 +5899,7 @@ describe("CodeGenerator", () => {
5899
5899
  describe("Sizeof variable", () => {
5900
5900
  it("should generate sizeof for variable", () => {
5901
5901
  const source = `
5902
- u32 arr[10];
5902
+ u32[10] arr;
5903
5903
  u32 size <- sizeof(arr);
5904
5904
  `;
5905
5905
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -5921,7 +5921,7 @@ describe("CodeGenerator", () => {
5921
5921
  it("should resolve const to literal for file-scope array", () => {
5922
5922
  const source = `
5923
5923
  const u32 BUFFER_SIZE <- 256;
5924
- u8 buffer[BUFFER_SIZE];
5924
+ u8[BUFFER_SIZE] buffer;
5925
5925
  `;
5926
5926
  const { tree, tokenStream } = CNextSourceParser.parse(source);
5927
5927
  const generator = new CodeGenerator();
@@ -6056,7 +6056,7 @@ describe("CodeGenerator", () => {
6056
6056
  it("should generate struct with array field access", () => {
6057
6057
  const source = `
6058
6058
  struct Message {
6059
- u8 data[8];
6059
+ u8[8] data;
6060
6060
  u8 length;
6061
6061
  }
6062
6062
  Message msg;
@@ -6166,7 +6166,7 @@ describe("CodeGenerator", () => {
6166
6166
  const source = `
6167
6167
  void setup() {
6168
6168
  const u32 SIZE <- 5;
6169
- u32 data[SIZE];
6169
+ u32[SIZE] data;
6170
6170
  }
6171
6171
  `;
6172
6172
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -6181,7 +6181,8 @@ describe("CodeGenerator", () => {
6181
6181
  });
6182
6182
 
6183
6183
  expect(code).toContain("SIZE");
6184
- expect(code).toContain("[SIZE]");
6184
+ // Const value is evaluated at compile time
6185
+ expect(code).toContain("data[5]");
6185
6186
  });
6186
6187
  });
6187
6188
 
@@ -6666,7 +6667,7 @@ describe("CodeGenerator", () => {
6666
6667
 
6667
6668
  describe("Array with literal size", () => {
6668
6669
  it("should generate array with integer literal size", () => {
6669
- const source = `u32 buffer[100];`;
6670
+ const source = `u32[100] buffer;`;
6670
6671
  const { tree, tokenStream } = CNextSourceParser.parse(source);
6671
6672
  const generator = new CodeGenerator();
6672
6673
  const symbolTable = new SymbolTable();
@@ -6793,7 +6794,7 @@ describe("CodeGenerator", () => {
6793
6794
 
6794
6795
  describe("Array initialization with values", () => {
6795
6796
  it("should generate array with initialization list", () => {
6796
- const source = `u8 data[4] <- [1, 2, 3, 4];`;
6797
+ const source = `u8[4] data <- [1, 2, 3, 4];`;
6797
6798
  const { tree, tokenStream } = CNextSourceParser.parse(source);
6798
6799
  const generator = new CodeGenerator();
6799
6800
  const symbolTable = new SymbolTable();
@@ -6814,7 +6815,7 @@ describe("CodeGenerator", () => {
6814
6815
  const source = `
6815
6816
  void process(u8 arr[]) { }
6816
6817
  void main() {
6817
- u8 local[10];
6818
+ u8[10] local;
6818
6819
  process(local);
6819
6820
  }
6820
6821
  `;
@@ -7081,7 +7082,7 @@ describe("CodeGenerator", () => {
7081
7082
  it("should initialize POD arrays to {0}", () => {
7082
7083
  const source = `
7083
7084
  void main() {
7084
- u32 values[10];
7085
+ u32[10] values;
7085
7086
  }
7086
7087
  `;
7087
7088
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -7102,7 +7103,7 @@ describe("CodeGenerator", () => {
7102
7103
  const source = `
7103
7104
  struct Point { i32 x; i32 y; }
7104
7105
  void main() {
7105
- Point points[5];
7106
+ Point[5] points;
7106
7107
  }
7107
7108
  `;
7108
7109
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -7347,7 +7348,7 @@ describe("CodeGenerator", () => {
7347
7348
  it("should generate struct array member write", () => {
7348
7349
  const source = `
7349
7350
  struct Item { u32 value; }
7350
- Item items[3];
7351
+ Item[3] items;
7351
7352
  void main() {
7352
7353
  items[0].value <- 42;
7353
7354
  }
@@ -7932,7 +7933,7 @@ describe("CodeGenerator", () => {
7932
7933
  const source = `
7933
7934
  void callee(u32 arr[10]) { }
7934
7935
  void test() {
7935
- u32 data[10];
7936
+ u32[10] data;
7936
7937
  callee(data);
7937
7938
  }
7938
7939
  `;
@@ -7976,7 +7977,7 @@ describe("CodeGenerator", () => {
7976
7977
  const source = `
7977
7978
  void callee(u32 val) { }
7978
7979
  void test() {
7979
- u32 arr[10];
7980
+ u32[10] arr;
7980
7981
  callee(arr[0]);
7981
7982
  }
7982
7983
  `;
@@ -8426,7 +8427,7 @@ describe("CodeGenerator", () => {
8426
8427
  it("should handle sizeof on variable", () => {
8427
8428
  const source = `
8428
8429
  void test() {
8429
- u32 arr[10];
8430
+ u32[10] arr;
8430
8431
  u32 size <- sizeof(arr);
8431
8432
  }
8432
8433
  `;
@@ -8491,7 +8492,7 @@ describe("CodeGenerator", () => {
8491
8492
  it("should handle single index array access", () => {
8492
8493
  const source = `
8493
8494
  void test() {
8494
- u32 arr[10];
8495
+ u32[10] arr;
8495
8496
  u32 val <- arr[5];
8496
8497
  }
8497
8498
  `;
@@ -8575,7 +8576,7 @@ describe("CodeGenerator", () => {
8575
8576
  it("should handle C++ mode array access", () => {
8576
8577
  const source = `
8577
8578
  void test() {
8578
- u32 arr[10];
8579
+ u32[10] arr;
8579
8580
  u32 val <- arr[5];
8580
8581
  }
8581
8582
  `;
@@ -8597,7 +8598,7 @@ describe("CodeGenerator", () => {
8597
8598
  it("should handle multi-dimensional array access", () => {
8598
8599
  const source = `
8599
8600
  void test() {
8600
- u32 matrix[3][3];
8601
+ u32[3] matrix[3];
8601
8602
  u32 val <- matrix[1][2];
8602
8603
  }
8603
8604
  `;
@@ -8778,7 +8779,7 @@ describe("CodeGenerator", () => {
8778
8779
  const source = `
8779
8780
  struct Point { u32 x; u32 y; }
8780
8781
  void test() {
8781
- Point points[10];
8782
+ Point[10] points;
8782
8783
  u32 x <- points[0].x;
8783
8784
  }
8784
8785
  `;
@@ -9141,7 +9142,7 @@ describe("CodeGenerator", () => {
9141
9142
  it("should resolve const values in expressions", () => {
9142
9143
  const source = `
9143
9144
  const u32 MAX_SIZE <- 100;
9144
- u32 buffer[MAX_SIZE];
9145
+ u32[MAX_SIZE] buffer;
9145
9146
  `;
9146
9147
  const { tree, tokenStream } = CNextSourceParser.parse(source);
9147
9148
  const generator = new CodeGenerator();
@@ -9210,7 +9211,7 @@ describe("CodeGenerator", () => {
9210
9211
  it("should handle array access in assignment target", () => {
9211
9212
  const source = `
9212
9213
  void test() {
9213
- u32 arr[10];
9214
+ u32[10] arr;
9214
9215
  arr[5] <- 42;
9215
9216
  }
9216
9217
  `;
@@ -9716,7 +9717,7 @@ describe("CodeGenerator", () => {
9716
9717
  it("should generate struct with array member", () => {
9717
9718
  const source = `
9718
9719
  struct Buffer {
9719
- u8 data[64];
9720
+ u8[64] data;
9720
9721
  u32 size;
9721
9722
  }
9722
9723
  Buffer buf;
@@ -9833,7 +9834,7 @@ describe("CodeGenerator", () => {
9833
9834
  it("should generate array with initializer list", () => {
9834
9835
  const source = `
9835
9836
  void test() {
9836
- u32 arr[5] <- [1, 2, 3, 4, 5];
9837
+ u32[5] arr <- [1, 2, 3, 4, 5];
9837
9838
  }
9838
9839
  `;
9839
9840
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -11130,7 +11131,7 @@ describe("CodeGenerator", () => {
11130
11131
  data[0] <- 1;
11131
11132
  }
11132
11133
  void test() {
11133
- u32 arr[10];
11134
+ u32[10] arr;
11134
11135
  process(arr);
11135
11136
  }
11136
11137
  `;
@@ -11436,7 +11437,7 @@ describe("CodeGenerator", () => {
11436
11437
  it("should handle array with size in declaration", () => {
11437
11438
  const source = `
11438
11439
  void test() {
11439
- u8 buffer[10];
11440
+ u8[10] buffer;
11440
11441
  buffer[0] <- 0xFF;
11441
11442
  }
11442
11443
  `;
@@ -11458,7 +11459,7 @@ describe("CodeGenerator", () => {
11458
11459
  const source = `
11459
11460
  const u32 BUFFER_SIZE <- 64;
11460
11461
  void test() {
11461
- u8 buffer[BUFFER_SIZE];
11462
+ u8[BUFFER_SIZE] buffer;
11462
11463
  buffer[0] <- 0;
11463
11464
  }
11464
11465
  `;
@@ -11475,6 +11476,90 @@ describe("CodeGenerator", () => {
11475
11476
 
11476
11477
  expect(code).toContain("BUFFER_SIZE");
11477
11478
  });
11479
+
11480
+ it("should reject C-style array declaration for primitive types", () => {
11481
+ const source = `
11482
+ void test() {
11483
+ u8 buffer[10];
11484
+ }
11485
+ `;
11486
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
11487
+ const generator = new CodeGenerator();
11488
+ const symbolTable = new SymbolTable();
11489
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
11490
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
11491
+
11492
+ expect(() => {
11493
+ generator.generate(tree, symbolTable, tokenStream, {
11494
+ symbolInfo: symbols,
11495
+ sourcePath: "test.cnx",
11496
+ });
11497
+ }).toThrow(/C-style array declaration is not allowed/);
11498
+ });
11499
+
11500
+ it("should reject C-style array declaration for user types", () => {
11501
+ const source = `
11502
+ struct Data {
11503
+ u32 value;
11504
+ }
11505
+ void test() {
11506
+ Data items[5];
11507
+ }
11508
+ `;
11509
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
11510
+ const generator = new CodeGenerator();
11511
+ const symbolTable = new SymbolTable();
11512
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
11513
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
11514
+
11515
+ expect(() => {
11516
+ generator.generate(tree, symbolTable, tokenStream, {
11517
+ symbolInfo: symbols,
11518
+ sourcePath: "test.cnx",
11519
+ });
11520
+ }).toThrow(/C-style array declaration is not allowed/);
11521
+ });
11522
+
11523
+ it("should allow empty brackets for size inference", () => {
11524
+ const source = `
11525
+ void test() {
11526
+ u8 data[] <- [1, 2, 3];
11527
+ }
11528
+ `;
11529
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
11530
+ const generator = new CodeGenerator();
11531
+ const symbolTable = new SymbolTable();
11532
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
11533
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
11534
+
11535
+ const code = generator.generate(tree, symbolTable, tokenStream, {
11536
+ symbolInfo: symbols,
11537
+ sourcePath: "test.cnx",
11538
+ });
11539
+
11540
+ expect(code).toContain("uint8_t data[3]");
11541
+ });
11542
+
11543
+ it("should allow multi-dimensional C-style arrays", () => {
11544
+ const source = `
11545
+ void test() {
11546
+ u8 matrix[4][4];
11547
+ matrix[0][0] <- 0;
11548
+ }
11549
+ `;
11550
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
11551
+ const generator = new CodeGenerator();
11552
+ const symbolTable = new SymbolTable();
11553
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
11554
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
11555
+
11556
+ const code = generator.generate(tree, symbolTable, tokenStream, {
11557
+ symbolInfo: symbols,
11558
+ sourcePath: "test.cnx",
11559
+ });
11560
+
11561
+ expect(code).toContain("uint8_t matrix[4][4]");
11562
+ });
11478
11563
  });
11479
11564
 
11480
11565
  describe("string expression type checking", () => {
@@ -12208,7 +12293,7 @@ describe("CodeGenerator", () => {
12208
12293
  it("should handle sizeof on local array", () => {
12209
12294
  const source = `
12210
12295
  void test() {
12211
- u8 buffer[16];
12296
+ u8[16] buffer;
12212
12297
  u32 size <- sizeof(buffer);
12213
12298
  }
12214
12299
  `;
@@ -12368,7 +12453,7 @@ describe("CodeGenerator", () => {
12368
12453
  it("should resolve array element access in expression", () => {
12369
12454
  const source = `
12370
12455
  void test() {
12371
- u32 arr[10];
12456
+ u32[10] arr;
12372
12457
  u32 val <- arr[5];
12373
12458
  }
12374
12459
  `;
@@ -12389,7 +12474,7 @@ describe("CodeGenerator", () => {
12389
12474
  it("should resolve array element with variable index", () => {
12390
12475
  const source = `
12391
12476
  void test() {
12392
- u32 arr[10];
12477
+ u32[10] arr;
12393
12478
  u32 i <- 3;
12394
12479
  u32 val <- arr[i];
12395
12480
  }
@@ -12802,7 +12887,7 @@ describe("CodeGenerator", () => {
12802
12887
  const source = `
12803
12888
  struct Item { u32 id; }
12804
12889
  void test() {
12805
- Item items[10];
12890
+ Item[10] items;
12806
12891
  items[0].id <- 42;
12807
12892
  }
12808
12893
  `;
@@ -13071,7 +13156,7 @@ describe("CodeGenerator", () => {
13071
13156
  it("should handle array type with user-defined struct", () => {
13072
13157
  const source = `
13073
13158
  struct Point { i32 x; i32 y; }
13074
- Point points[10];
13159
+ Point[10] points;
13075
13160
  `;
13076
13161
  const { tree, tokenStream } = CNextSourceParser.parse(source);
13077
13162
  const generator = new CodeGenerator();
@@ -13089,8 +13174,8 @@ describe("CodeGenerator", () => {
13089
13174
 
13090
13175
  it("should handle array type with primitive types", () => {
13091
13176
  const source = `
13092
- u8 buffer[256];
13093
- i32 numbers[10];
13177
+ u8[256] buffer;
13178
+ i32[10] numbers;
13094
13179
  `;
13095
13180
  const { tree, tokenStream } = CNextSourceParser.parse(source);
13096
13181
  const generator = new CodeGenerator();
@@ -13590,7 +13675,7 @@ describe("CodeGenerator", () => {
13590
13675
  describe("array access resolution helpers", () => {
13591
13676
  it("should resolve simple array access", () => {
13592
13677
  const source = `
13593
- u8 buffer[10];
13678
+ u8[10] buffer;
13594
13679
  void test() {
13595
13680
  u8 val <- buffer[5];
13596
13681
  }
@@ -13611,7 +13696,7 @@ describe("CodeGenerator", () => {
13611
13696
 
13612
13697
  it("should handle array access with variable index", () => {
13613
13698
  const source = `
13614
- u8 data[20];
13699
+ u8[20] data;
13615
13700
  void test() {
13616
13701
  u32 idx <- 3;
13617
13702
  u8 val <- data[idx];
@@ -13780,6 +13865,1951 @@ describe("CodeGenerator", () => {
13780
13865
 
13781
13866
  expect(code).toContain("strlen");
13782
13867
  });
13868
+
13869
+ it("should generate cache for multiple .length accesses", () => {
13870
+ const source = `
13871
+ void test() {
13872
+ string<32> s <- "hello";
13873
+ if (s.length > 0) {
13874
+ u32 x <- s.length;
13875
+ }
13876
+ }
13877
+ `;
13878
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
13879
+ const generator = new CodeGenerator();
13880
+ const symbolTable = new SymbolTable();
13881
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
13882
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
13883
+
13884
+ const code = generator.generate(tree, symbolTable, tokenStream, {
13885
+ symbolInfo: symbols,
13886
+ sourcePath: "test.cnx",
13887
+ });
13888
+
13889
+ // Should generate cache variable for repeated .length access
13890
+ expect(code).toContain("strlen");
13891
+ });
13892
+
13893
+ it("should not cache for single .length access", () => {
13894
+ const source = `
13895
+ void test() {
13896
+ string<32> s <- "hello";
13897
+ u32 len <- s.length;
13898
+ }
13899
+ `;
13900
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
13901
+ const generator = new CodeGenerator();
13902
+ const symbolTable = new SymbolTable();
13903
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
13904
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
13905
+
13906
+ const code = generator.generate(tree, symbolTable, tokenStream, {
13907
+ symbolInfo: symbols,
13908
+ sourcePath: "test.cnx",
13909
+ });
13910
+
13911
+ // Single access should just use strlen directly
13912
+ expect(code).toContain("strlen(s)");
13913
+ });
13914
+ });
13915
+
13916
+ describe("scope-qualified function resolution", () => {
13917
+ it("should resolve this.method() to CurrentScope_method", () => {
13918
+ const source = `
13919
+ enum MyEnum { A, B }
13920
+ scope Foo {
13921
+ public MyEnum bar() {
13922
+ return global.MyEnum.A;
13923
+ }
13924
+ public void test() {
13925
+ MyEnum result <- this.bar();
13926
+ }
13927
+ }
13928
+ `;
13929
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
13930
+ const generator = new CodeGenerator();
13931
+ const symbolTable = new SymbolTable();
13932
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
13933
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
13934
+
13935
+ const code = generator.generate(tree, symbolTable, tokenStream, {
13936
+ symbolInfo: symbols,
13937
+ sourcePath: "test.cnx",
13938
+ });
13939
+
13940
+ // this.bar() should become Foo_bar()
13941
+ expect(code).toContain("Foo_bar()");
13942
+ });
13943
+
13944
+ it("should resolve Scope.method() to Scope_method", () => {
13945
+ const source = `
13946
+ scope Utils {
13947
+ public u32 getValue() {
13948
+ return 42;
13949
+ }
13950
+ }
13951
+ void main() {
13952
+ u32 v <- Utils.getValue();
13953
+ }
13954
+ `;
13955
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
13956
+ const generator = new CodeGenerator();
13957
+ const symbolTable = new SymbolTable();
13958
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
13959
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
13960
+
13961
+ const code = generator.generate(tree, symbolTable, tokenStream, {
13962
+ symbolInfo: symbols,
13963
+ sourcePath: "test.cnx",
13964
+ });
13965
+
13966
+ expect(code).toContain("Utils_getValue()");
13967
+ });
13968
+
13969
+ it("should resolve global.func() to func", () => {
13970
+ const source = `
13971
+ u32 getNumber() {
13972
+ return 100;
13973
+ }
13974
+ scope Test {
13975
+ public void run() {
13976
+ u32 n <- global.getNumber();
13977
+ }
13978
+ }
13979
+ `;
13980
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
13981
+ const generator = new CodeGenerator();
13982
+ const symbolTable = new SymbolTable();
13983
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
13984
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
13985
+
13986
+ const code = generator.generate(tree, symbolTable, tokenStream, {
13987
+ symbolInfo: symbols,
13988
+ sourcePath: "test.cnx",
13989
+ });
13990
+
13991
+ // global.getNumber() should become getNumber()
13992
+ expect(code).toContain("getNumber()");
13993
+ });
13994
+
13995
+ it("should resolve global.Scope.method() to Scope_method", () => {
13996
+ const source = `
13997
+ scope Config {
13998
+ public u32 getTimeout() {
13999
+ return 1000;
14000
+ }
14001
+ }
14002
+ scope Other {
14003
+ public void test() {
14004
+ u32 t <- global.Config.getTimeout();
14005
+ }
14006
+ }
14007
+ `;
14008
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14009
+ const generator = new CodeGenerator();
14010
+ const symbolTable = new SymbolTable();
14011
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14012
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14013
+
14014
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14015
+ symbolInfo: symbols,
14016
+ sourcePath: "test.cnx",
14017
+ });
14018
+
14019
+ // global.Config.getTimeout() should become Config_getTimeout()
14020
+ expect(code).toContain("Config_getTimeout()");
14021
+ });
14022
+ });
14023
+
14024
+ describe("expression type checking", () => {
14025
+ it("should detect decimal integer literal in comparison", () => {
14026
+ const source = `
14027
+ void test() {
14028
+ u32 val <- 5;
14029
+ bool isZero <- (val = 0);
14030
+ }
14031
+ `;
14032
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14033
+ const generator = new CodeGenerator();
14034
+ const symbolTable = new SymbolTable();
14035
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14036
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14037
+
14038
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14039
+ symbolInfo: symbols,
14040
+ sourcePath: "test.cnx",
14041
+ });
14042
+
14043
+ // Integer comparison should work
14044
+ expect(code).toContain("val == 0");
14045
+ });
14046
+
14047
+ it("should detect hex literal in comparison", () => {
14048
+ const source = `
14049
+ void test() {
14050
+ u32 flags <- 0;
14051
+ bool check <- (flags = 0xFF);
14052
+ }
14053
+ `;
14054
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14055
+ const generator = new CodeGenerator();
14056
+ const symbolTable = new SymbolTable();
14057
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14058
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14059
+
14060
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14061
+ symbolInfo: symbols,
14062
+ sourcePath: "test.cnx",
14063
+ });
14064
+
14065
+ expect(code).toContain("0xFF");
14066
+ });
14067
+
14068
+ it("should detect binary literal in comparison", () => {
14069
+ const source = `
14070
+ void test() {
14071
+ u32 mode <- 0;
14072
+ bool check <- (mode = 0b1010);
14073
+ }
14074
+ `;
14075
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14076
+ const generator = new CodeGenerator();
14077
+ const symbolTable = new SymbolTable();
14078
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14079
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14080
+
14081
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14082
+ symbolInfo: symbols,
14083
+ sourcePath: "test.cnx",
14084
+ });
14085
+
14086
+ // Binary literal passes through (not converted)
14087
+ expect(code).toContain("0b1010");
14088
+ });
14089
+
14090
+ it("should detect variable of integer type", () => {
14091
+ const source = `
14092
+ void test() {
14093
+ i32 code <- 5;
14094
+ i32 limit <- 10;
14095
+ bool check <- (code = limit);
14096
+ }
14097
+ `;
14098
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14099
+ const generator = new CodeGenerator();
14100
+ const symbolTable = new SymbolTable();
14101
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14102
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14103
+
14104
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14105
+ symbolInfo: symbols,
14106
+ sourcePath: "test.cnx",
14107
+ });
14108
+
14109
+ // Comparison with integer variable
14110
+ expect(code).toContain("code == limit");
14111
+ });
14112
+
14113
+ it("should detect string literal", () => {
14114
+ const source = `
14115
+ void test() {
14116
+ string<32> s <- "hello";
14117
+ bool check <- (s = "hello");
14118
+ }
14119
+ `;
14120
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14121
+ const generator = new CodeGenerator();
14122
+ const symbolTable = new SymbolTable();
14123
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14124
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14125
+
14126
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14127
+ symbolInfo: symbols,
14128
+ sourcePath: "test.cnx",
14129
+ });
14130
+
14131
+ // String comparison should use strcmp
14132
+ expect(code).toContain("strcmp");
14133
+ });
14134
+
14135
+ it("should detect string variable", () => {
14136
+ const source = `
14137
+ void test() {
14138
+ string<32> s1 <- "hello";
14139
+ string<32> s2 <- "world";
14140
+ bool check <- (s1 = s2);
14141
+ }
14142
+ `;
14143
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14144
+ const generator = new CodeGenerator();
14145
+ const symbolTable = new SymbolTable();
14146
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14147
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14148
+
14149
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14150
+ symbolInfo: symbols,
14151
+ sourcePath: "test.cnx",
14152
+ });
14153
+
14154
+ // String comparison should use strcmp
14155
+ expect(code).toContain("strcmp");
14156
+ });
14157
+
14158
+ it("should detect array element of string array", () => {
14159
+ const source = `
14160
+ void test() {
14161
+ string<32> names[3];
14162
+ names[0] <- "Alice";
14163
+ bool check <- (names[0] = "Alice");
14164
+ }
14165
+ `;
14166
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14167
+ const generator = new CodeGenerator();
14168
+ const symbolTable = new SymbolTable();
14169
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14170
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14171
+
14172
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14173
+ symbolInfo: symbols,
14174
+ sourcePath: "test.cnx",
14175
+ });
14176
+
14177
+ // String array element comparison should use strcmp
14178
+ expect(code).toContain("strcmp");
14179
+ });
14180
+ });
14181
+
14182
+ describe("array type registration", () => {
14183
+ it("should register array type correctly", () => {
14184
+ const source = `
14185
+ void test() {
14186
+ u8[10] buffer;
14187
+ buffer[0] <- 0xFF;
14188
+ }
14189
+ `;
14190
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14191
+ const generator = new CodeGenerator();
14192
+ const symbolTable = new SymbolTable();
14193
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14194
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14195
+
14196
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14197
+ symbolInfo: symbols,
14198
+ sourcePath: "test.cnx",
14199
+ });
14200
+
14201
+ expect(code).toContain("uint8_t buffer[10]");
14202
+ });
14203
+
14204
+ it("should register multi-dimensional array", () => {
14205
+ const source = `
14206
+ void test() {
14207
+ u8[10] matrix[20];
14208
+ matrix[0][0] <- 0;
14209
+ }
14210
+ `;
14211
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14212
+ const generator = new CodeGenerator();
14213
+ const symbolTable = new SymbolTable();
14214
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14215
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14216
+
14217
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14218
+ symbolInfo: symbols,
14219
+ sourcePath: "test.cnx",
14220
+ });
14221
+
14222
+ expect(code).toContain("uint8_t matrix[10][20]");
14223
+ });
14224
+
14225
+ it("should handle i32 array type", () => {
14226
+ const source = `
14227
+ void test() {
14228
+ i32[5] values;
14229
+ values[0] <- 100;
14230
+ }
14231
+ `;
14232
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14233
+ const generator = new CodeGenerator();
14234
+ const symbolTable = new SymbolTable();
14235
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14236
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14237
+
14238
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14239
+ symbolInfo: symbols,
14240
+ sourcePath: "test.cnx",
14241
+ });
14242
+
14243
+ expect(code).toContain("int32_t values[5]");
14244
+ });
14245
+
14246
+ it("should handle const array type", () => {
14247
+ const source = `
14248
+ void test() {
14249
+ const u8[4] data <- [1, 2, 3, 4];
14250
+ }
14251
+ `;
14252
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14253
+ const generator = new CodeGenerator();
14254
+ const symbolTable = new SymbolTable();
14255
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14256
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14257
+
14258
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14259
+ symbolInfo: symbols,
14260
+ sourcePath: "test.cnx",
14261
+ });
14262
+
14263
+ expect(code).toContain("const uint8_t data[4]");
14264
+ });
14265
+
14266
+ it("should handle struct array with C-Next syntax", () => {
14267
+ const source = `
14268
+ struct Point {
14269
+ i32 x;
14270
+ i32 y;
14271
+ }
14272
+ void test() {
14273
+ Point[3] points;
14274
+ points[0].x <- 10;
14275
+ }
14276
+ `;
14277
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14278
+ const generator = new CodeGenerator();
14279
+ const symbolTable = new SymbolTable();
14280
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14281
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14282
+
14283
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14284
+ symbolInfo: symbols,
14285
+ sourcePath: "test.cnx",
14286
+ });
14287
+
14288
+ expect(code).toContain("Point points[3]");
14289
+ expect(code).toContain("points[0].x = 10");
14290
+ });
14291
+
14292
+ it("should handle bitmap array with C-Next syntax", () => {
14293
+ const source = `
14294
+ bitmap8 Flags {
14295
+ active,
14296
+ ready,
14297
+ error,
14298
+ mode[3],
14299
+ priority[2]
14300
+ }
14301
+ void test() {
14302
+ Flags[4] flags;
14303
+ flags[0].active <- true;
14304
+ }
14305
+ `;
14306
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14307
+ const generator = new CodeGenerator();
14308
+ const symbolTable = new SymbolTable();
14309
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14310
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14311
+
14312
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14313
+ symbolInfo: symbols,
14314
+ sourcePath: "test.cnx",
14315
+ });
14316
+
14317
+ expect(code).toContain("Flags flags[4]");
14318
+ // Bitmap field access should generate bit manipulation
14319
+ expect(code).toContain("flags[0]");
14320
+ });
14321
+
14322
+ it("should handle enum array with C-Next syntax", () => {
14323
+ const source = `
14324
+ enum Color {
14325
+ RED,
14326
+ GREEN,
14327
+ BLUE
14328
+ }
14329
+ void test() {
14330
+ Color[3] colors;
14331
+ colors[0] <- RED;
14332
+ }
14333
+ `;
14334
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14335
+ const generator = new CodeGenerator();
14336
+ const symbolTable = new SymbolTable();
14337
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14338
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14339
+
14340
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14341
+ symbolInfo: symbols,
14342
+ sourcePath: "test.cnx",
14343
+ });
14344
+
14345
+ expect(code).toContain("Color colors[3]");
14346
+ expect(code).toContain("colors[0] = Color_RED");
14347
+ });
14348
+
14349
+ it("should handle struct array initializer with C-Next syntax", () => {
14350
+ const source = `
14351
+ struct Item {
14352
+ u8 id;
14353
+ }
14354
+ const Item[2] items <- [{id: 1}, {id: 2}];
14355
+ `;
14356
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14357
+ const generator = new CodeGenerator();
14358
+ const symbolTable = new SymbolTable();
14359
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14360
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14361
+
14362
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14363
+ symbolInfo: symbols,
14364
+ sourcePath: "test.cnx",
14365
+ });
14366
+
14367
+ expect(code).toContain("const Item items[2]");
14368
+ expect(code).toContain(".id = 1");
14369
+ });
14370
+ });
14371
+
14372
+ describe("C++ mode member conversion", () => {
14373
+ it("should detect parameter member access needing conversion", () => {
14374
+ const source = `
14375
+ struct Config {
14376
+ u32 value;
14377
+ }
14378
+ void process(Config cfg) {
14379
+ u32 v <- cfg.value;
14380
+ }
14381
+ `;
14382
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14383
+ const generator = new CodeGenerator();
14384
+ const symbolTable = new SymbolTable();
14385
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14386
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14387
+
14388
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14389
+ symbolInfo: symbols,
14390
+ sourcePath: "test.cnx",
14391
+ cppMode: true,
14392
+ });
14393
+
14394
+ // In C++ mode, struct params use . not ->
14395
+ expect(code).toContain("cfg.value");
14396
+ });
14397
+
14398
+ it("should detect array element member access", () => {
14399
+ const source = `
14400
+ struct Item {
14401
+ u32 id;
14402
+ }
14403
+ void process() {
14404
+ Item[3] items;
14405
+ u32 first <- items[0].id;
14406
+ }
14407
+ `;
14408
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14409
+ const generator = new CodeGenerator();
14410
+ const symbolTable = new SymbolTable();
14411
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14412
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14413
+
14414
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14415
+ symbolInfo: symbols,
14416
+ sourcePath: "test.cnx",
14417
+ cppMode: true,
14418
+ });
14419
+
14420
+ // Array element member access
14421
+ expect(code).toContain("items[0].id");
14422
+ });
14423
+
14424
+ it("should use arrow for struct params in C mode", () => {
14425
+ const source = `
14426
+ struct Config {
14427
+ u32 value;
14428
+ }
14429
+ void process(Config cfg) {
14430
+ u32 v <- cfg.value;
14431
+ }
14432
+ `;
14433
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14434
+ const generator = new CodeGenerator();
14435
+ const symbolTable = new SymbolTable();
14436
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14437
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14438
+
14439
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14440
+ symbolInfo: symbols,
14441
+ sourcePath: "test.cnx",
14442
+ cppMode: false,
14443
+ });
14444
+
14445
+ // In C mode, struct params use ->
14446
+ expect(code).toContain("cfg->value");
14447
+ });
14448
+
14449
+ it("should handle const struct parameters in C++ mode", () => {
14450
+ const source = `
14451
+ struct Settings {
14452
+ u32 timeout;
14453
+ bool enabled;
14454
+ }
14455
+ void configure(const Settings s) {
14456
+ u32 t <- s.timeout;
14457
+ }
14458
+ `;
14459
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14460
+ const generator = new CodeGenerator();
14461
+ const symbolTable = new SymbolTable();
14462
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14463
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14464
+
14465
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14466
+ symbolInfo: symbols,
14467
+ sourcePath: "test.cnx",
14468
+ cppMode: true,
14469
+ });
14470
+
14471
+ // Const struct param should use reference in C++
14472
+ expect(code).toContain("const Settings&");
14473
+ expect(code).toContain("s.timeout");
14474
+ });
14475
+ });
14476
+
14477
+ describe("struct generation", () => {
14478
+ it("should generate struct typedef", () => {
14479
+ const source = `
14480
+ struct Point {
14481
+ i32 x;
14482
+ i32 y;
14483
+ }
14484
+ `;
14485
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14486
+ const generator = new CodeGenerator();
14487
+ const symbolTable = new SymbolTable();
14488
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14489
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14490
+
14491
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14492
+ symbolInfo: symbols,
14493
+ sourcePath: "test.cnx",
14494
+ });
14495
+
14496
+ expect(code).toContain("typedef struct");
14497
+ expect(code).toContain("int32_t x");
14498
+ expect(code).toContain("int32_t y");
14499
+ expect(code).toContain("} Point;");
14500
+ });
14501
+
14502
+ it("should generate struct with callback field", () => {
14503
+ const source = `
14504
+ void handler(u32 val) {}
14505
+ struct Button {
14506
+ u32 id;
14507
+ handler onClick;
14508
+ }
14509
+ `;
14510
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14511
+ const generator = new CodeGenerator();
14512
+ const symbolTable = new SymbolTable();
14513
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14514
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14515
+
14516
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14517
+ symbolInfo: symbols,
14518
+ sourcePath: "test.cnx",
14519
+ });
14520
+
14521
+ expect(code).toContain("typedef struct");
14522
+ expect(code).toContain("} Button;");
14523
+ });
14524
+ });
14525
+
14526
+ describe("register generation", () => {
14527
+ it("should generate register comment", () => {
14528
+ const source = `
14529
+ register GPIO7 @ 0x42004000 {
14530
+ rw u32 DR @ 0x00;
14531
+ }
14532
+ `;
14533
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14534
+ const generator = new CodeGenerator();
14535
+ const symbolTable = new SymbolTable();
14536
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14537
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14538
+
14539
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14540
+ symbolInfo: symbols,
14541
+ sourcePath: "test.cnx",
14542
+ });
14543
+
14544
+ // Register declaration generates a comment
14545
+ expect(code).toContain("Register: GPIO7");
14546
+ });
14547
+
14548
+ it("should generate scoped register comment", () => {
14549
+ const source = `
14550
+ scope Teensy4 {
14551
+ register GPIO7 @ 0x42004000 {
14552
+ rw u32 DR @ 0x00;
14553
+ }
14554
+ }
14555
+ `;
14556
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14557
+ const generator = new CodeGenerator();
14558
+ const symbolTable = new SymbolTable();
14559
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14560
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14561
+
14562
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14563
+ symbolInfo: symbols,
14564
+ sourcePath: "test.cnx",
14565
+ });
14566
+
14567
+ // Scoped register should show scope in output
14568
+ expect(code).toContain("Teensy4");
14569
+ expect(code).toContain("GPIO7");
14570
+ });
14571
+ });
14572
+
14573
+ describe("enum type checking in expressions", () => {
14574
+ it("should handle enum variable assignment", () => {
14575
+ const source = `
14576
+ enum Color { RED, GREEN, BLUE }
14577
+ void test() {
14578
+ Color c <- Color.RED;
14579
+ c <- Color.GREEN;
14580
+ }
14581
+ `;
14582
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14583
+ const generator = new CodeGenerator();
14584
+ const symbolTable = new SymbolTable();
14585
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14586
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14587
+
14588
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14589
+ symbolInfo: symbols,
14590
+ sourcePath: "test.cnx",
14591
+ });
14592
+
14593
+ expect(code).toContain("Color_RED");
14594
+ expect(code).toContain("Color_GREEN");
14595
+ });
14596
+
14597
+ it("should handle enum comparison", () => {
14598
+ const source = `
14599
+ enum Status { OK, ERROR }
14600
+ void test() {
14601
+ Status s <- Status.OK;
14602
+ if (s = Status.ERROR) {
14603
+ s <- Status.OK;
14604
+ }
14605
+ }
14606
+ `;
14607
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14608
+ const generator = new CodeGenerator();
14609
+ const symbolTable = new SymbolTable();
14610
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14611
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14612
+
14613
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14614
+ symbolInfo: symbols,
14615
+ sourcePath: "test.cnx",
14616
+ });
14617
+
14618
+ expect(code).toContain("s == Status_ERROR");
14619
+ });
14620
+
14621
+ it("should handle enum return from function", () => {
14622
+ const source = `
14623
+ enum Result { SUCCESS, FAILURE }
14624
+ Result getResult() {
14625
+ return Result.SUCCESS;
14626
+ }
14627
+ void test() {
14628
+ Result r <- getResult();
14629
+ }
14630
+ `;
14631
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14632
+ const generator = new CodeGenerator();
14633
+ const symbolTable = new SymbolTable();
14634
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14635
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14636
+
14637
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14638
+ symbolInfo: symbols,
14639
+ sourcePath: "test.cnx",
14640
+ });
14641
+
14642
+ expect(code).toContain("Result_SUCCESS");
14643
+ expect(code).toContain("getResult()");
14644
+ });
14645
+ });
14646
+
14647
+ describe("overflow helpers", () => {
14648
+ it("should generate clamp add helper", () => {
14649
+ const source = `
14650
+ clamp u8 val <- 250;
14651
+ void test() {
14652
+ val +<- 10;
14653
+ }
14654
+ `;
14655
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14656
+ const generator = new CodeGenerator();
14657
+ const symbolTable = new SymbolTable();
14658
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14659
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14660
+
14661
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14662
+ symbolInfo: symbols,
14663
+ sourcePath: "test.cnx",
14664
+ });
14665
+
14666
+ expect(code).toContain("cnx_clamp_add_u8");
14667
+ });
14668
+
14669
+ it("should generate clamp sub helper", () => {
14670
+ const source = `
14671
+ clamp u8 val <- 5;
14672
+ void test() {
14673
+ val -<- 10;
14674
+ }
14675
+ `;
14676
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14677
+ const generator = new CodeGenerator();
14678
+ const symbolTable = new SymbolTable();
14679
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14680
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14681
+
14682
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14683
+ symbolInfo: symbols,
14684
+ sourcePath: "test.cnx",
14685
+ });
14686
+
14687
+ expect(code).toContain("cnx_clamp_sub_u8");
14688
+ });
14689
+ });
14690
+
14691
+ describe("preprocessor directives", () => {
14692
+ it("should handle C include directive", () => {
14693
+ const source = `
14694
+ #include <stdio.h>
14695
+ void test() {}
14696
+ `;
14697
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14698
+ const generator = new CodeGenerator();
14699
+ const symbolTable = new SymbolTable();
14700
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14701
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14702
+
14703
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14704
+ symbolInfo: symbols,
14705
+ sourcePath: "test.cnx",
14706
+ });
14707
+
14708
+ expect(code).toContain("#include <stdio.h>");
14709
+ });
14710
+
14711
+ it("should handle #define without value", () => {
14712
+ const source = `
14713
+ #define DEBUG_MODE
14714
+ void test() {}
14715
+ `;
14716
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14717
+ const generator = new CodeGenerator();
14718
+ const symbolTable = new SymbolTable();
14719
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14720
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14721
+
14722
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14723
+ symbolInfo: symbols,
14724
+ sourcePath: "test.cnx",
14725
+ });
14726
+
14727
+ expect(code).toContain("#define DEBUG_MODE");
14728
+ });
14729
+ });
14730
+
14731
+ describe("bit range access", () => {
14732
+ it("should generate bit range read expression", () => {
14733
+ const source = `
14734
+ void test() {
14735
+ u32 val <- 0xFF00;
14736
+ u8 byte <- val[8, 8];
14737
+ }
14738
+ `;
14739
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14740
+ const generator = new CodeGenerator();
14741
+ const symbolTable = new SymbolTable();
14742
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14743
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14744
+
14745
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14746
+ symbolInfo: symbols,
14747
+ sourcePath: "test.cnx",
14748
+ });
14749
+
14750
+ // Bit range access generates shift and mask
14751
+ expect(code).toContain(">> 8");
14752
+ expect(code).toContain("0xFF");
14753
+ });
14754
+
14755
+ it("should generate bit range write expression", () => {
14756
+ const source = `
14757
+ void test() {
14758
+ u32 val <- 0;
14759
+ val[8, 8] <- 0xFF;
14760
+ }
14761
+ `;
14762
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14763
+ const generator = new CodeGenerator();
14764
+ const symbolTable = new SymbolTable();
14765
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14766
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14767
+
14768
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14769
+ symbolInfo: symbols,
14770
+ sourcePath: "test.cnx",
14771
+ });
14772
+
14773
+ // Bit range write should use mask-and-shift pattern
14774
+ expect(code).toContain("val");
14775
+ });
14776
+
14777
+ it("should generate single bit write", () => {
14778
+ const source = `
14779
+ void test() {
14780
+ u32 flags <- 0;
14781
+ flags[3] <- true;
14782
+ }
14783
+ `;
14784
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14785
+ const generator = new CodeGenerator();
14786
+ const symbolTable = new SymbolTable();
14787
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14788
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14789
+
14790
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14791
+ symbolInfo: symbols,
14792
+ sourcePath: "test.cnx",
14793
+ });
14794
+
14795
+ // Single bit write
14796
+ expect(code).toContain("flags");
14797
+ expect(code).toContain("1 << 3");
14798
+ });
14799
+
14800
+ it("should generate array element write", () => {
14801
+ const source = `
14802
+ void test() {
14803
+ u32[10] arr;
14804
+ arr[5] <- 42;
14805
+ }
14806
+ `;
14807
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14808
+ const generator = new CodeGenerator();
14809
+ const symbolTable = new SymbolTable();
14810
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14811
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14812
+
14813
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14814
+ symbolInfo: symbols,
14815
+ sourcePath: "test.cnx",
14816
+ });
14817
+
14818
+ expect(code).toContain("arr[5] = 42");
14819
+ });
14820
+
14821
+ it("should generate bit range at position 0", () => {
14822
+ const source = `
14823
+ void test() {
14824
+ u32 val <- 0x1234;
14825
+ u8 lowByte <- val[0, 8];
14826
+ }
14827
+ `;
14828
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14829
+ const generator = new CodeGenerator();
14830
+ const symbolTable = new SymbolTable();
14831
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14832
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14833
+
14834
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14835
+ symbolInfo: symbols,
14836
+ sourcePath: "test.cnx",
14837
+ });
14838
+
14839
+ // Position 0 should NOT generate >> 0
14840
+ expect(code).not.toContain(">> 0");
14841
+ });
14842
+
14843
+ it("should generate 64-bit mask for u64 values", () => {
14844
+ const source = `
14845
+ void test() {
14846
+ u64 val <- 0xFFFFFFFFFFFFFFFF;
14847
+ u32 upper <- val[32, 32];
14848
+ }
14849
+ `;
14850
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14851
+ const generator = new CodeGenerator();
14852
+ const symbolTable = new SymbolTable();
14853
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14854
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14855
+
14856
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14857
+ symbolInfo: symbols,
14858
+ sourcePath: "test.cnx",
14859
+ });
14860
+
14861
+ // 64-bit operations should have ULL suffix
14862
+ expect(code).toContain(">> 32");
14863
+ });
14864
+ });
14865
+
14866
+ describe("type name resolution", () => {
14867
+ it("should resolve this.Type for scoped types", () => {
14868
+ const source = `
14869
+ scope Motor {
14870
+ enum State { IDLE, RUNNING }
14871
+ public State getState() {
14872
+ return global.Motor.State.IDLE;
14873
+ }
14874
+ }
14875
+ `;
14876
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14877
+ const generator = new CodeGenerator();
14878
+ const symbolTable = new SymbolTable();
14879
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14880
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14881
+
14882
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14883
+ symbolInfo: symbols,
14884
+ sourcePath: "test.cnx",
14885
+ });
14886
+
14887
+ expect(code).toContain("Motor_State");
14888
+ });
14889
+
14890
+ it("should resolve global.Type for global types inside scope", () => {
14891
+ const source = `
14892
+ enum Color { RED, GREEN }
14893
+ scope Display {
14894
+ public void setColor(Color c) {
14895
+ Color myColor <- c;
14896
+ }
14897
+ }
14898
+ `;
14899
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14900
+ const generator = new CodeGenerator();
14901
+ const symbolTable = new SymbolTable();
14902
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14903
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14904
+
14905
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14906
+ symbolInfo: symbols,
14907
+ sourcePath: "test.cnx",
14908
+ });
14909
+
14910
+ expect(code).toContain("Color");
14911
+ });
14912
+ });
14913
+
14914
+ describe("switch statement generation", () => {
14915
+ it("should generate switch with exhaustive enum cases", () => {
14916
+ const source = `
14917
+ enum State { OFF, ON }
14918
+ void test() {
14919
+ State s <- State.OFF;
14920
+ switch (s) {
14921
+ case State.OFF { }
14922
+ case State.ON { }
14923
+ }
14924
+ }
14925
+ `;
14926
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14927
+ const generator = new CodeGenerator();
14928
+ const symbolTable = new SymbolTable();
14929
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14930
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14931
+
14932
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14933
+ symbolInfo: symbols,
14934
+ sourcePath: "test.cnx",
14935
+ });
14936
+
14937
+ expect(code).toContain("switch");
14938
+ expect(code).toContain("case State_OFF");
14939
+ expect(code).toContain("case State_ON");
14940
+ expect(code).toContain("break;");
14941
+ });
14942
+
14943
+ it("should generate switch with default case", () => {
14944
+ const source = `
14945
+ void test() {
14946
+ u32 val <- 5;
14947
+ switch (val) {
14948
+ case 1 { }
14949
+ case 2 { }
14950
+ default { }
14951
+ }
14952
+ }
14953
+ `;
14954
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14955
+ const generator = new CodeGenerator();
14956
+ const symbolTable = new SymbolTable();
14957
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14958
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14959
+
14960
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14961
+ symbolInfo: symbols,
14962
+ sourcePath: "test.cnx",
14963
+ });
14964
+
14965
+ expect(code).toContain("switch");
14966
+ expect(code).toContain("default:");
14967
+ });
14968
+ });
14969
+
14970
+ describe("while loop generation", () => {
14971
+ it("should generate while loop", () => {
14972
+ const source = `
14973
+ void test() {
14974
+ u32 i <- 0;
14975
+ while (i < 10) {
14976
+ i +<- 1;
14977
+ }
14978
+ }
14979
+ `;
14980
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
14981
+ const generator = new CodeGenerator();
14982
+ const symbolTable = new SymbolTable();
14983
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
14984
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
14985
+
14986
+ const code = generator.generate(tree, symbolTable, tokenStream, {
14987
+ symbolInfo: symbols,
14988
+ sourcePath: "test.cnx",
14989
+ });
14990
+
14991
+ expect(code).toContain("while (i < 10)");
14992
+ });
14993
+ });
14994
+
14995
+ describe("for loop generation", () => {
14996
+ it("should generate for loop", () => {
14997
+ const source = `
14998
+ void test() {
14999
+ for (u32 i <- 0; i < 10; i +<- 1) {
15000
+ u32 x <- i;
15001
+ }
15002
+ }
15003
+ `;
15004
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15005
+ const generator = new CodeGenerator();
15006
+ const symbolTable = new SymbolTable();
15007
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15008
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15009
+
15010
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15011
+ symbolInfo: symbols,
15012
+ sourcePath: "test.cnx",
15013
+ });
15014
+
15015
+ expect(code).toContain("for (");
15016
+ expect(code).toContain("uint32_t i = 0");
15017
+ expect(code).toContain("i < 10");
15018
+ });
15019
+ });
15020
+
15021
+ describe("do-while loop generation", () => {
15022
+ it("should generate do-while loop", () => {
15023
+ const source = `
15024
+ void test() {
15025
+ u32 i <- 0;
15026
+ do {
15027
+ i +<- 1;
15028
+ } while (i < 10);
15029
+ }
15030
+ `;
15031
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15032
+ const generator = new CodeGenerator();
15033
+ const symbolTable = new SymbolTable();
15034
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15035
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15036
+
15037
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15038
+ symbolInfo: symbols,
15039
+ sourcePath: "test.cnx",
15040
+ });
15041
+
15042
+ expect(code).toContain("do {");
15043
+ expect(code).toContain("} while (i < 10)");
15044
+ });
15045
+ });
15046
+
15047
+ describe("break and continue statements", () => {
15048
+ it("should generate break in loop", () => {
15049
+ const source = `
15050
+ void test() {
15051
+ while (true) {
15052
+ break;
15053
+ }
15054
+ }
15055
+ `;
15056
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15057
+ const generator = new CodeGenerator();
15058
+ const symbolTable = new SymbolTable();
15059
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15060
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15061
+
15062
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15063
+ symbolInfo: symbols,
15064
+ sourcePath: "test.cnx",
15065
+ });
15066
+
15067
+ expect(code).toContain("break;");
15068
+ });
15069
+
15070
+ it("should generate continue in loop", () => {
15071
+ const source = `
15072
+ void test() {
15073
+ u32 i <- 0;
15074
+ while (i < 10) {
15075
+ i +<- 1;
15076
+ if (i = 5) {
15077
+ continue;
15078
+ }
15079
+ }
15080
+ }
15081
+ `;
15082
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15083
+ const generator = new CodeGenerator();
15084
+ const symbolTable = new SymbolTable();
15085
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15086
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15087
+
15088
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15089
+ symbolInfo: symbols,
15090
+ sourcePath: "test.cnx",
15091
+ });
15092
+
15093
+ expect(code).toContain("continue;");
15094
+ });
15095
+ });
15096
+
15097
+ describe("function with parameters", () => {
15098
+ it("should generate function with multiple params", () => {
15099
+ const source = `
15100
+ u32 add(u32 a, u32 b) {
15101
+ return a + b;
15102
+ }
15103
+ `;
15104
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15105
+ const generator = new CodeGenerator();
15106
+ const symbolTable = new SymbolTable();
15107
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15108
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15109
+
15110
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15111
+ symbolInfo: symbols,
15112
+ sourcePath: "test.cnx",
15113
+ });
15114
+
15115
+ expect(code).toContain("uint32_t add(uint32_t a, uint32_t b)");
15116
+ expect(code).toContain("return a + b");
15117
+ });
15118
+
15119
+ it("should generate function with array parameter", () => {
15120
+ const source = `
15121
+ void process(u32 arr[10]) {
15122
+ u32 val <- arr[0];
15123
+ }
15124
+ `;
15125
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15126
+ const generator = new CodeGenerator();
15127
+ const symbolTable = new SymbolTable();
15128
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15129
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15130
+
15131
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15132
+ symbolInfo: symbols,
15133
+ sourcePath: "test.cnx",
15134
+ });
15135
+
15136
+ expect(code).toContain("uint32_t arr[10]");
15137
+ });
15138
+ });
15139
+
15140
+ describe("global variable declarations", () => {
15141
+ it("should generate global variable initialization", () => {
15142
+ const source = `
15143
+ u32 globalCounter <- 0;
15144
+ `;
15145
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15146
+ const generator = new CodeGenerator();
15147
+ const symbolTable = new SymbolTable();
15148
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15149
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15150
+
15151
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15152
+ symbolInfo: symbols,
15153
+ sourcePath: "test.cnx",
15154
+ });
15155
+
15156
+ expect(code).toContain("uint32_t globalCounter");
15157
+ expect(code).toContain("= 0");
15158
+ });
15159
+
15160
+ it("should generate const global", () => {
15161
+ const source = `
15162
+ const u32 MAX_VALUE <- 100;
15163
+ `;
15164
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15165
+ const generator = new CodeGenerator();
15166
+ const symbolTable = new SymbolTable();
15167
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15168
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15169
+
15170
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15171
+ symbolInfo: symbols,
15172
+ sourcePath: "test.cnx",
15173
+ });
15174
+
15175
+ expect(code).toContain("const uint32_t MAX_VALUE");
15176
+ expect(code).toContain("= 100");
15177
+ });
15178
+ });
15179
+
15180
+ describe("arithmetic expressions", () => {
15181
+ it("should generate modulo operation", () => {
15182
+ const source = `
15183
+ void test() {
15184
+ u32 a <- 10;
15185
+ u32 b <- a % 3;
15186
+ }
15187
+ `;
15188
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15189
+ const generator = new CodeGenerator();
15190
+ const symbolTable = new SymbolTable();
15191
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15192
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15193
+
15194
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15195
+ symbolInfo: symbols,
15196
+ sourcePath: "test.cnx",
15197
+ });
15198
+
15199
+ expect(code).toContain("a % 3");
15200
+ });
15201
+
15202
+ it("should generate bitwise operations", () => {
15203
+ const source = `
15204
+ void test() {
15205
+ u32 a <- 0xFF;
15206
+ u32 b <- a & 0x0F;
15207
+ u32 c <- a | 0xF0;
15208
+ u32 d <- a ^ 0xAA;
15209
+ u32 e <- ~a;
15210
+ }
15211
+ `;
15212
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15213
+ const generator = new CodeGenerator();
15214
+ const symbolTable = new SymbolTable();
15215
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15216
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15217
+
15218
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15219
+ symbolInfo: symbols,
15220
+ sourcePath: "test.cnx",
15221
+ });
15222
+
15223
+ expect(code).toContain("a & 0x0F");
15224
+ expect(code).toContain("a | 0xF0");
15225
+ expect(code).toContain("a ^ 0xAA");
15226
+ expect(code).toContain("~a");
15227
+ });
15228
+
15229
+ it("should generate shift operations", () => {
15230
+ const source = `
15231
+ void test() {
15232
+ u32 a <- 1;
15233
+ u32 b <- a << 4;
15234
+ u32 c <- a >> 2;
15235
+ }
15236
+ `;
15237
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15238
+ const generator = new CodeGenerator();
15239
+ const symbolTable = new SymbolTable();
15240
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15241
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15242
+
15243
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15244
+ symbolInfo: symbols,
15245
+ sourcePath: "test.cnx",
15246
+ });
15247
+
15248
+ expect(code).toContain("a << 4");
15249
+ expect(code).toContain("a >> 2");
15250
+ });
15251
+ });
15252
+
15253
+ describe("logical expressions", () => {
15254
+ it("should generate logical AND and OR", () => {
15255
+ const source = `
15256
+ void test() {
15257
+ bool a <- true;
15258
+ bool b <- false;
15259
+ bool c <- a && b;
15260
+ bool d <- a || b;
15261
+ }
15262
+ `;
15263
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15264
+ const generator = new CodeGenerator();
15265
+ const symbolTable = new SymbolTable();
15266
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15267
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15268
+
15269
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15270
+ symbolInfo: symbols,
15271
+ sourcePath: "test.cnx",
15272
+ });
15273
+
15274
+ expect(code).toContain("a && b");
15275
+ expect(code).toContain("a || b");
15276
+ });
15277
+
15278
+ it("should generate NOT operation", () => {
15279
+ const source = `
15280
+ void test() {
15281
+ bool a <- true;
15282
+ bool b <- !a;
15283
+ }
15284
+ `;
15285
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15286
+ const generator = new CodeGenerator();
15287
+ const symbolTable = new SymbolTable();
15288
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15289
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15290
+
15291
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15292
+ symbolInfo: symbols,
15293
+ sourcePath: "test.cnx",
15294
+ });
15295
+
15296
+ expect(code).toContain("!a");
15297
+ });
15298
+ });
15299
+
15300
+ describe("ternary expression", () => {
15301
+ it("should generate ternary expression", () => {
15302
+ const source = `
15303
+ void test() {
15304
+ u32 a <- 5;
15305
+ u32 b <- (a > 3) ? 10 : 20;
15306
+ }
15307
+ `;
15308
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15309
+ const generator = new CodeGenerator();
15310
+ const symbolTable = new SymbolTable();
15311
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15312
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15313
+
15314
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15315
+ symbolInfo: symbols,
15316
+ sourcePath: "test.cnx",
15317
+ });
15318
+
15319
+ expect(code).toContain("a > 3");
15320
+ expect(code).toContain("?");
15321
+ expect(code).toContain("10");
15322
+ expect(code).toContain("20");
15323
+ });
15324
+ });
15325
+
15326
+ describe("unary expressions", () => {
15327
+ it("should generate negative number", () => {
15328
+ const source = `
15329
+ void test() {
15330
+ i32 a <- 5;
15331
+ i32 b <- -a;
15332
+ }
15333
+ `;
15334
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15335
+ const generator = new CodeGenerator();
15336
+ const symbolTable = new SymbolTable();
15337
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15338
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15339
+
15340
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15341
+ symbolInfo: symbols,
15342
+ sourcePath: "test.cnx",
15343
+ });
15344
+
15345
+ expect(code).toContain("-a");
15346
+ });
15347
+
15348
+ it("should generate bitwise NOT", () => {
15349
+ const source = `
15350
+ void test() {
15351
+ u32 a <- 0xFF;
15352
+ u32 b <- ~a;
15353
+ }
15354
+ `;
15355
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15356
+ const generator = new CodeGenerator();
15357
+ const symbolTable = new SymbolTable();
15358
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15359
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15360
+
15361
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15362
+ symbolInfo: symbols,
15363
+ sourcePath: "test.cnx",
15364
+ });
15365
+
15366
+ expect(code).toContain("~a");
15367
+ });
15368
+ });
15369
+
15370
+ describe("bitmap type", () => {
15371
+ it("should generate bitmap field access", () => {
15372
+ const source = `
15373
+ bitmap8 Flags {
15374
+ bit0,
15375
+ bit1,
15376
+ bit2,
15377
+ bit3,
15378
+ bit4,
15379
+ bit5,
15380
+ bit6,
15381
+ bit7
15382
+ }
15383
+ void test() {
15384
+ Flags f <- 0;
15385
+ bool isSet <- f.bit0;
15386
+ }
15387
+ `;
15388
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15389
+ const generator = new CodeGenerator();
15390
+ const symbolTable = new SymbolTable();
15391
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15392
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15393
+
15394
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15395
+ symbolInfo: symbols,
15396
+ sourcePath: "test.cnx",
15397
+ });
15398
+
15399
+ expect(code).toContain("Flags");
15400
+ });
15401
+ });
15402
+
15403
+ describe("function call expressions", () => {
15404
+ it("should generate function call with arguments", () => {
15405
+ const source = `
15406
+ u32 multiply(u32 x, u32 y) {
15407
+ return x * y;
15408
+ }
15409
+ void test() {
15410
+ u32 result <- multiply(5, 10);
15411
+ }
15412
+ `;
15413
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15414
+ const generator = new CodeGenerator();
15415
+ const symbolTable = new SymbolTable();
15416
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15417
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15418
+
15419
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15420
+ symbolInfo: symbols,
15421
+ sourcePath: "test.cnx",
15422
+ });
15423
+
15424
+ expect(code).toContain("multiply(5, 10)");
15425
+ });
15426
+
15427
+ it("should generate scoped function call", () => {
15428
+ const source = `
15429
+ scope Math {
15430
+ public u32 square(u32 x) {
15431
+ return x * x;
15432
+ }
15433
+ }
15434
+ void test() {
15435
+ u32 result <- Math.square(5);
15436
+ }
15437
+ `;
15438
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15439
+ const generator = new CodeGenerator();
15440
+ const symbolTable = new SymbolTable();
15441
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15442
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15443
+
15444
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15445
+ symbolInfo: symbols,
15446
+ sourcePath: "test.cnx",
15447
+ });
15448
+
15449
+ expect(code).toContain("Math_square(5)");
15450
+ });
15451
+ });
15452
+
15453
+ describe("ISR declaration", () => {
15454
+ it("should generate ISR attribute", () => {
15455
+ const source = `
15456
+ isr void TIMER0_IRQ() {
15457
+ u32 x <- 1;
15458
+ }
15459
+ `;
15460
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15461
+ const generator = new CodeGenerator();
15462
+ const symbolTable = new SymbolTable();
15463
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15464
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15465
+
15466
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15467
+ symbolInfo: symbols,
15468
+ sourcePath: "test.cnx",
15469
+ });
15470
+
15471
+ // ISR functions should have special attributes
15472
+ expect(code).toContain("TIMER0_IRQ");
15473
+ });
15474
+ });
15475
+
15476
+ describe("atomic variable", () => {
15477
+ it("should generate volatile for atomic", () => {
15478
+ const source = `
15479
+ atomic u32 counter <- 0;
15480
+ void test() {
15481
+ counter <- 1;
15482
+ }
15483
+ `;
15484
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15485
+ const generator = new CodeGenerator();
15486
+ const symbolTable = new SymbolTable();
15487
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15488
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15489
+
15490
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15491
+ symbolInfo: symbols,
15492
+ sourcePath: "test.cnx",
15493
+ });
15494
+
15495
+ expect(code).toContain("volatile");
15496
+ });
15497
+ });
15498
+
15499
+ describe("wrap overflow behavior", () => {
15500
+ it("should not add helpers for wrap types", () => {
15501
+ const source = `
15502
+ wrap u8 val <- 250;
15503
+ void test() {
15504
+ val +<- 10;
15505
+ }
15506
+ `;
15507
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15508
+ const generator = new CodeGenerator();
15509
+ const symbolTable = new SymbolTable();
15510
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15511
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15512
+
15513
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15514
+ symbolInfo: symbols,
15515
+ sourcePath: "test.cnx",
15516
+ });
15517
+
15518
+ // Wrap types just use += without helper
15519
+ expect(code).toContain("+=");
15520
+ expect(code).not.toContain("cnx_");
15521
+ });
15522
+ });
15523
+
15524
+ describe("safe division", () => {
15525
+ it("should generate safe division helper", () => {
15526
+ const source = `
15527
+ void test() {
15528
+ u32 a <- 10;
15529
+ u32 b <- 0;
15530
+ u32 c <- a / b;
15531
+ }
15532
+ `;
15533
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15534
+ const generator = new CodeGenerator();
15535
+ const symbolTable = new SymbolTable();
15536
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15537
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15538
+
15539
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15540
+ symbolInfo: symbols,
15541
+ sourcePath: "test.cnx",
15542
+ });
15543
+
15544
+ // Division should work
15545
+ expect(code).toContain("a / b");
15546
+ });
15547
+ });
15548
+
15549
+ describe("parenthesized expressions", () => {
15550
+ it("should preserve parentheses in expressions", () => {
15551
+ const source = `
15552
+ void test() {
15553
+ u32 a <- 2;
15554
+ u32 b <- 3;
15555
+ u32 c <- 4;
15556
+ u32 result <- (a + b) * c;
15557
+ }
15558
+ `;
15559
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15560
+ const generator = new CodeGenerator();
15561
+ const symbolTable = new SymbolTable();
15562
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15563
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15564
+
15565
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15566
+ symbolInfo: symbols,
15567
+ sourcePath: "test.cnx",
15568
+ });
15569
+
15570
+ expect(code).toContain("(a + b) * c");
15571
+ });
15572
+ });
15573
+
15574
+ describe("array access via ArrayAccessHelper", () => {
15575
+ it("should generate single-index array access", () => {
15576
+ const source = `
15577
+ u32[10] arr;
15578
+ void test() {
15579
+ u32 val <- arr[5];
15580
+ }
15581
+ `;
15582
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15583
+ const generator = new CodeGenerator();
15584
+ const symbolTable = new SymbolTable();
15585
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15586
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15587
+
15588
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15589
+ symbolInfo: symbols,
15590
+ sourcePath: "test.cnx",
15591
+ });
15592
+
15593
+ expect(code).toContain("arr[5]");
15594
+ });
15595
+
15596
+ it("should generate array access with variable index", () => {
15597
+ const source = `
15598
+ u8[100] data;
15599
+ void test(u32 idx) {
15600
+ u8 val <- data[idx];
15601
+ }
15602
+ `;
15603
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15604
+ const generator = new CodeGenerator();
15605
+ const symbolTable = new SymbolTable();
15606
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15607
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15608
+
15609
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15610
+ symbolInfo: symbols,
15611
+ sourcePath: "test.cnx",
15612
+ });
15613
+
15614
+ expect(code).toContain("data[idx]");
15615
+ });
15616
+
15617
+ it("should generate integer bit range access", () => {
15618
+ const source = `
15619
+ void test() {
15620
+ u32 value <- 0xFF00;
15621
+ u8 byte <- value[8, 8];
15622
+ }
15623
+ `;
15624
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15625
+ const generator = new CodeGenerator();
15626
+ const symbolTable = new SymbolTable();
15627
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15628
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15629
+
15630
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15631
+ symbolInfo: symbols,
15632
+ sourcePath: "test.cnx",
15633
+ });
15634
+
15635
+ expect(code).toContain(">> 8");
15636
+ expect(code).toContain("& 0xFF");
15637
+ });
15638
+
15639
+ it("should generate float bit range access with memcpy", () => {
15640
+ const source = `
15641
+ void test() {
15642
+ f32 fval <- 1.5;
15643
+ u8 byte <- fval[0, 8];
15644
+ }
15645
+ `;
15646
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15647
+ const generator = new CodeGenerator();
15648
+ const symbolTable = new SymbolTable();
15649
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15650
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15651
+
15652
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15653
+ symbolInfo: symbols,
15654
+ sourcePath: "test.cnx",
15655
+ });
15656
+
15657
+ expect(code).toContain("memcpy");
15658
+ expect(code).toContain("__bits_fval");
15659
+ });
15660
+
15661
+ it("should generate f64 bit range access with uint64_t shadow", () => {
15662
+ const source = `
15663
+ void test() {
15664
+ f64 dval <- 1.5;
15665
+ u8 byte <- dval[0, 8];
15666
+ }
15667
+ `;
15668
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15669
+ const generator = new CodeGenerator();
15670
+ const symbolTable = new SymbolTable();
15671
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15672
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15673
+
15674
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15675
+ symbolInfo: symbols,
15676
+ sourcePath: "test.cnx",
15677
+ });
15678
+
15679
+ expect(code).toContain("uint64_t __bits_dval");
15680
+ expect(code).toContain("memcpy");
15681
+ });
15682
+ });
15683
+ });
15684
+
15685
+ describe("Issue #741: const scope members bare reference inlining", () => {
15686
+ it("should inline private const when referenced without this. prefix", () => {
15687
+ const source = `
15688
+ scope Foo {
15689
+ const u32 MY_CONSTANT <- 42;
15690
+
15691
+ public u32 getConstant() {
15692
+ return MY_CONSTANT;
15693
+ }
15694
+ }
15695
+ `;
15696
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15697
+ const generator = new CodeGenerator();
15698
+ const symbolTable = new SymbolTable();
15699
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15700
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15701
+
15702
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15703
+ symbolInfo: symbols,
15704
+ sourcePath: "test.cnx",
15705
+ });
15706
+
15707
+ // Should inline the value, not generate a reference to Foo_MY_CONSTANT
15708
+ expect(code).toContain("return 42;");
15709
+ expect(code).not.toContain("Foo_MY_CONSTANT");
15710
+ });
15711
+
15712
+ it("should inline private const in expressions without this. prefix", () => {
15713
+ const source = `
15714
+ scope Bar {
15715
+ const u8 OFFSET <- 10;
15716
+
15717
+ public u8 compute() {
15718
+ u8 result <- OFFSET + 5;
15719
+ return result;
15720
+ }
15721
+ }
15722
+ `;
15723
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15724
+ const generator = new CodeGenerator();
15725
+ const symbolTable = new SymbolTable();
15726
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15727
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15728
+
15729
+ const code = generator.generate(tree, symbolTable, tokenStream, {
15730
+ symbolInfo: symbols,
15731
+ sourcePath: "test.cnx",
15732
+ });
15733
+
15734
+ // Expression should be constant-folded: 10 + 5 = 15
15735
+ expect(code).toContain("uint8_t result = 15;");
15736
+ expect(code).not.toContain("Bar_OFFSET");
15737
+ });
15738
+ });
15739
+
15740
+ describe("Generator registration error paths", () => {
15741
+ it("throws error when struct generator is not registered", () => {
15742
+ // First call initializes the registry
15743
+ const initSource = `u8 x;`;
15744
+ const { tree: initTree, tokenStream: initTokenStream } =
15745
+ CNextSourceParser.parse(initSource);
15746
+ const generator = new CodeGenerator();
15747
+ const initSymbolTable = new SymbolTable();
15748
+ const initTSymbols = CNextResolver.resolve(initTree, "init.cnx");
15749
+ const initSymbols = TSymbolInfoAdapter.convert(initTSymbols);
15750
+ generator.generate(initTree, initSymbolTable, initTokenStream, {
15751
+ symbolInfo: initSymbols,
15752
+ sourcePath: "init.cnx",
15753
+ });
15754
+
15755
+ // Unregister the struct generator to test error path
15756
+ const registry = (
15757
+ generator as unknown as {
15758
+ registry: { unregisterDeclaration: (kind: string) => void };
15759
+ }
15760
+ ).registry;
15761
+ registry.unregisterDeclaration("struct");
15762
+
15763
+ // Second call should throw because struct generator is now missing
15764
+ const source = `struct Point { i32 x; i32 y; }`;
15765
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15766
+ const symbolTable = new SymbolTable();
15767
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15768
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15769
+
15770
+ expect(() => {
15771
+ generator.generate(tree, symbolTable, tokenStream, {
15772
+ symbolInfo: symbols,
15773
+ sourcePath: "test.cnx",
15774
+ });
15775
+ }).toThrow("Error: struct generator not registered");
15776
+ });
15777
+
15778
+ it("throws error when enum generator is not registered", () => {
15779
+ // First call initializes the registry
15780
+ const initSource = `u8 x;`;
15781
+ const { tree: initTree, tokenStream: initTokenStream } =
15782
+ CNextSourceParser.parse(initSource);
15783
+ const generator = new CodeGenerator();
15784
+ const initSymbolTable = new SymbolTable();
15785
+ const initTSymbols = CNextResolver.resolve(initTree, "init.cnx");
15786
+ const initSymbols = TSymbolInfoAdapter.convert(initTSymbols);
15787
+ generator.generate(initTree, initSymbolTable, initTokenStream, {
15788
+ symbolInfo: initSymbols,
15789
+ sourcePath: "init.cnx",
15790
+ });
15791
+
15792
+ // Unregister the enum generator to test error path
15793
+ const registry = (
15794
+ generator as unknown as {
15795
+ registry: { unregisterDeclaration: (kind: string) => void };
15796
+ }
15797
+ ).registry;
15798
+ registry.unregisterDeclaration("enum");
15799
+
15800
+ // Second call should throw because enum generator is now missing
15801
+ const source = `enum State { IDLE, RUNNING }`;
15802
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
15803
+ const symbolTable = new SymbolTable();
15804
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
15805
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
15806
+
15807
+ expect(() => {
15808
+ generator.generate(tree, symbolTable, tokenStream, {
15809
+ symbolInfo: symbols,
15810
+ sourcePath: "test.cnx",
15811
+ });
15812
+ }).toThrow("Error: enum generator not registered");
13783
15813
  });
13784
15814
  });
13785
15815
  });