c-next 0.1.63 → 0.1.65

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.
@@ -1568,7 +1568,7 @@ describe("CodeGenerator", () => {
1568
1568
 
1569
1569
  it("should generate array parameter", () => {
1570
1570
  const source = `
1571
- void process(u32 arr[10]) { }
1571
+ void process(u32[10] arr) { }
1572
1572
  `;
1573
1573
  const { tree, tokenStream } = CNextSourceParser.parse(source);
1574
1574
  const generator = new CodeGenerator();
@@ -5284,7 +5284,7 @@ describe("CodeGenerator", () => {
5284
5284
  describe("Array passed to function", () => {
5285
5285
  it("should pass array without address-of operator", () => {
5286
5286
  const source = `
5287
- void processData(u32 data[]) { }
5287
+ void processData(u32[5] data) { }
5288
5288
  u32[5] myData;
5289
5289
  void main() {
5290
5290
  processData(myData);
@@ -5942,7 +5942,7 @@ describe("CodeGenerator", () => {
5942
5942
  describe("Function with array return type simulation", () => {
5943
5943
  it("should handle function returning via output parameter", () => {
5944
5944
  const source = `
5945
- void getData(u8 output[]) {
5945
+ void getData(u8[2] output) {
5946
5946
  output[0] <- 1;
5947
5947
  output[1] <- 2;
5948
5948
  }
@@ -6285,7 +6285,7 @@ describe("CodeGenerator", () => {
6285
6285
  describe("Array parameter bounds", () => {
6286
6286
  it("should handle sized array parameter", () => {
6287
6287
  const source = `
6288
- void process(u32 arr[10]) {
6288
+ void process(u32[10] arr) {
6289
6289
  arr[0] <- 1;
6290
6290
  }
6291
6291
  `;
@@ -6813,7 +6813,7 @@ describe("CodeGenerator", () => {
6813
6813
  describe("Local array tracking", () => {
6814
6814
  it("should track local arrays for function arguments", () => {
6815
6815
  const source = `
6816
- void process(u8 arr[]) { }
6816
+ void process(u8[10] arr) { }
6817
6817
  void main() {
6818
6818
  u8[10] local;
6819
6819
  process(local);
@@ -7169,6 +7169,142 @@ describe("CodeGenerator", () => {
7169
7169
 
7170
7170
  // Note: Template type tests skipped - template argument transformation
7171
7171
  // (i32 -> int32_t) is a separate issue to be addressed in another PR
7172
+
7173
+ it("should generate C-Next style array params with dimensions in C++ mode", () => {
7174
+ const source = `
7175
+ void fill(u8[8] buf) {
7176
+ buf[0] <- 0xFF;
7177
+ }
7178
+ `;
7179
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
7180
+ const generator = new CodeGenerator();
7181
+ const symbolTable = new SymbolTable();
7182
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
7183
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
7184
+
7185
+ const code = generator.generate(tree, symbolTable, tokenStream, {
7186
+ symbolInfo: symbols,
7187
+ sourcePath: "test.cnx",
7188
+ cppMode: true,
7189
+ });
7190
+
7191
+ // C-Next style u8[8] param should generate uint8_t buf[8], not uint8_t& buf
7192
+ expect(code).toContain("uint8_t buf[8]");
7193
+ expect(code).not.toContain("uint8_t& buf");
7194
+ expect(code).not.toContain("uint8_t& buf");
7195
+ });
7196
+
7197
+ it("should generate const C-Next style array params in C++ mode", () => {
7198
+ const source = `
7199
+ u8 read(const u8[4] data) {
7200
+ return data[0];
7201
+ }
7202
+ `;
7203
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
7204
+ const generator = new CodeGenerator();
7205
+ const symbolTable = new SymbolTable();
7206
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
7207
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
7208
+
7209
+ const code = generator.generate(tree, symbolTable, tokenStream, {
7210
+ symbolInfo: symbols,
7211
+ sourcePath: "test.cnx",
7212
+ cppMode: true,
7213
+ });
7214
+
7215
+ // Const C-Next style array param should retain dimension
7216
+ expect(code).toContain("const uint8_t data[4]");
7217
+ expect(code).not.toContain("const uint8_t& data");
7218
+ });
7219
+
7220
+ it("should generate C-Next style array params in C mode too", () => {
7221
+ const source = `
7222
+ void fill(u8[8] buf) {
7223
+ buf[0] <- 0xFF;
7224
+ }
7225
+ `;
7226
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
7227
+ const generator = new CodeGenerator();
7228
+ const symbolTable = new SymbolTable();
7229
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
7230
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
7231
+
7232
+ const code = generator.generate(tree, symbolTable, tokenStream, {
7233
+ symbolInfo: symbols,
7234
+ sourcePath: "test.cnx",
7235
+ });
7236
+
7237
+ // C mode should also generate uint8_t buf[8]
7238
+ expect(code).toContain("uint8_t buf[8]");
7239
+ expect(code).not.toContain("uint8_t* buf");
7240
+ });
7241
+
7242
+ it("should generate primitive C-Next style arrays with {0} in C++ mode", () => {
7243
+ const source = `
7244
+ void main() {
7245
+ u32[8] counters;
7246
+ }
7247
+ `;
7248
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
7249
+ const generator = new CodeGenerator();
7250
+ const symbolTable = new SymbolTable();
7251
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
7252
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
7253
+
7254
+ const code = generator.generate(tree, symbolTable, tokenStream, {
7255
+ symbolInfo: symbols,
7256
+ sourcePath: "test.cnx",
7257
+ cppMode: true,
7258
+ });
7259
+
7260
+ // Primitive type arrays should still use {0}
7261
+ expect(code).toContain("uint32_t counters[8] = {0}");
7262
+ });
7263
+
7264
+ it("should generate unknown user type C-Next style arrays with {} in C++ mode", () => {
7265
+ const source = `
7266
+ void main() {
7267
+ UnknownType[4] items;
7268
+ }
7269
+ `;
7270
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
7271
+ const generator = new CodeGenerator();
7272
+ const symbolTable = new SymbolTable();
7273
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
7274
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
7275
+
7276
+ const code = generator.generate(tree, symbolTable, tokenStream, {
7277
+ symbolInfo: symbols,
7278
+ sourcePath: "test.cnx",
7279
+ cppMode: true,
7280
+ });
7281
+
7282
+ // Unknown types in C++ mode use {} (may have non-trivial constructors)
7283
+ expect(code).toContain("UnknownType items[4] = {}");
7284
+ });
7285
+
7286
+ it("should generate known C-Next struct arrays with {0} in C++ mode", () => {
7287
+ const source = `
7288
+ struct Point { i32 x; i32 y; }
7289
+ void main() {
7290
+ Point[3] pts;
7291
+ }
7292
+ `;
7293
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
7294
+ const generator = new CodeGenerator();
7295
+ const symbolTable = new SymbolTable();
7296
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
7297
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
7298
+
7299
+ const code = generator.generate(tree, symbolTable, tokenStream, {
7300
+ symbolInfo: symbols,
7301
+ sourcePath: "test.cnx",
7302
+ cppMode: true,
7303
+ });
7304
+
7305
+ // Known C-Next structs are POD types, {0} is correct
7306
+ expect(code).toContain("Point pts[3] = {0}");
7307
+ });
7172
7308
  });
7173
7309
  });
7174
7310
 
@@ -7931,7 +8067,7 @@ describe("CodeGenerator", () => {
7931
8067
 
7932
8068
  it("should handle identifier argument (array)", () => {
7933
8069
  const source = `
7934
- void callee(u32 arr[10]) { }
8070
+ void callee(u32[10] arr) { }
7935
8071
  void test() {
7936
8072
  u32[10] data;
7937
8073
  callee(data);
@@ -8045,7 +8181,7 @@ describe("CodeGenerator", () => {
8045
8181
  it("should handle struct field array argument", () => {
8046
8182
  const source = `
8047
8183
  struct Data { u32 values[10]; }
8048
- void callee(u32 arr[10]) { }
8184
+ void callee(u32[10] arr) { }
8049
8185
  void test(Data d) {
8050
8186
  callee(d.values);
8051
8187
  }
@@ -8110,7 +8246,7 @@ describe("CodeGenerator", () => {
8110
8246
  it("should handle struct member array as argument (array decay)", () => {
8111
8247
  const source = `
8112
8248
  struct Config { u8 data[16]; }
8113
- void processData(u8 buffer[16]) { }
8249
+ void processData(u8[16] buffer) { }
8114
8250
  void test() {
8115
8251
  Config cfg;
8116
8252
  processData(cfg.data);
@@ -8241,7 +8377,7 @@ describe("CodeGenerator", () => {
8241
8377
 
8242
8378
  it("should process array parameter type", () => {
8243
8379
  const source = `
8244
- void test(u32 arr[10]) {
8380
+ void test(u32[10] arr) {
8245
8381
  u32 x <- arr[0];
8246
8382
  }
8247
8383
  `;
@@ -8447,7 +8583,7 @@ describe("CodeGenerator", () => {
8447
8583
 
8448
8584
  it("should error on sizeof of array parameter", () => {
8449
8585
  const source = `
8450
- void test(u32 arr[10]) {
8586
+ void test(u32[10] arr) {
8451
8587
  u32 size <- sizeof(arr);
8452
8588
  }
8453
8589
  `;
@@ -8534,7 +8670,7 @@ describe("CodeGenerator", () => {
8534
8670
 
8535
8671
  it("should handle parameter array access", () => {
8536
8672
  const source = `
8537
- void test(u32 arr[10]) {
8673
+ void test(u32[10] arr) {
8538
8674
  u32 val <- arr[0];
8539
8675
  }
8540
8676
  `;
@@ -9896,7 +10032,7 @@ describe("CodeGenerator", () => {
9896
10032
 
9897
10033
  it("should resolve array parameter", () => {
9898
10034
  const source = `
9899
- void test(u32 arr[10]) {
10035
+ void test(u32[10] arr) {
9900
10036
  arr[0] <- 1;
9901
10037
  }
9902
10038
  `;
@@ -10942,7 +11078,7 @@ describe("CodeGenerator", () => {
10942
11078
 
10943
11079
  it("should not dereference array parameter for index access", () => {
10944
11080
  const source = `
10945
- u32 getElement(u32 arr[10]) {
11081
+ u32 getElement(u32[10] arr) {
10946
11082
  return arr[5];
10947
11083
  }
10948
11084
  `;
@@ -11127,7 +11263,7 @@ describe("CodeGenerator", () => {
11127
11263
  describe("function call argument generation", () => {
11128
11264
  it("should handle array argument passed to function", () => {
11129
11265
  const source = `
11130
- void process(u32 data[10]) {
11266
+ void process(u32[10] data) {
11131
11267
  data[0] <- 1;
11132
11268
  }
11133
11269
  void test() {
@@ -12165,7 +12301,7 @@ describe("CodeGenerator", () => {
12165
12301
  describe("array parameter dimensions", () => {
12166
12302
  it("should handle multi-dimensional array parameter", () => {
12167
12303
  const source = `
12168
- void processMatrix(u32 matrix[3][3]) {
12304
+ void processMatrix(u32[3][3] matrix) {
12169
12305
  matrix[0][0] <- 1;
12170
12306
  }
12171
12307
  `;
@@ -12182,10 +12318,52 @@ describe("CodeGenerator", () => {
12182
12318
 
12183
12319
  expect(code).toContain("uint32_t matrix[3][3]");
12184
12320
  });
12321
+ });
12322
+
12323
+ describe("C-style array parameter rejection", () => {
12324
+ it("should reject C-style array parameter with single dimension", () => {
12325
+ const source = `
12326
+ void process(u8 data[8]) {
12327
+ data[0] <- 0xFF;
12328
+ }
12329
+ `;
12330
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
12331
+ const generator = new CodeGenerator();
12332
+ const symbolTable = new SymbolTable();
12333
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
12334
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
12335
+
12336
+ expect(() => {
12337
+ generator.generate(tree, symbolTable, tokenStream, {
12338
+ symbolInfo: symbols,
12339
+ sourcePath: "test.cnx",
12340
+ });
12341
+ }).toThrow(/C-style array parameter is not allowed/);
12342
+ });
12185
12343
 
12186
- it("should handle unsized array parameter", () => {
12344
+ it("should reject C-style array parameter with multiple dimensions", () => {
12187
12345
  const source = `
12188
- void processData(u8 data[], u32 len) {
12346
+ void process(u32 matrix[3][3]) {
12347
+ matrix[0][0] <- 1;
12348
+ }
12349
+ `;
12350
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
12351
+ const generator = new CodeGenerator();
12352
+ const symbolTable = new SymbolTable();
12353
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
12354
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
12355
+
12356
+ expect(() => {
12357
+ generator.generate(tree, symbolTable, tokenStream, {
12358
+ symbolInfo: symbols,
12359
+ sourcePath: "test.cnx",
12360
+ });
12361
+ }).toThrow(/C-style array parameter is not allowed/);
12362
+ });
12363
+
12364
+ it("should reject C-style unsized array parameter", () => {
12365
+ const source = `
12366
+ void process(u8 data[]) {
12189
12367
  data[0] <- 0xFF;
12190
12368
  }
12191
12369
  `;
@@ -12195,12 +12373,202 @@ describe("CodeGenerator", () => {
12195
12373
  const tSymbols = CNextResolver.resolve(tree, "test.cnx");
12196
12374
  const symbols = TSymbolInfoAdapter.convert(tSymbols);
12197
12375
 
12376
+ expect(() => {
12377
+ generator.generate(tree, symbolTable, tokenStream, {
12378
+ symbolInfo: symbols,
12379
+ sourcePath: "test.cnx",
12380
+ });
12381
+ }).toThrow(/C-style array parameter is not allowed/);
12382
+ });
12383
+
12384
+ it("should suggest correct C-Next style syntax in error message", () => {
12385
+ const source = `
12386
+ void process(i32 values[10]) {
12387
+ values[0] <- 1;
12388
+ }
12389
+ `;
12390
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
12391
+ const generator = new CodeGenerator();
12392
+ const symbolTable = new SymbolTable();
12393
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
12394
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
12395
+
12396
+ expect(() => {
12397
+ generator.generate(tree, symbolTable, tokenStream, {
12398
+ symbolInfo: symbols,
12399
+ sourcePath: "test.cnx",
12400
+ });
12401
+ }).toThrow(/Use 'i32\[10\] values' instead of 'i32 values\[10\]'/);
12402
+ });
12403
+ });
12404
+
12405
+ describe("user type array parameters", () => {
12406
+ it("should handle struct array parameter with C-Next style", () => {
12407
+ const source = `
12408
+ struct Point { i32 x; i32 y; }
12409
+ void processPoints(Point[4] points) {
12410
+ points[0].x <- 10;
12411
+ }
12412
+ `;
12413
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
12414
+ const generator = new CodeGenerator();
12415
+ const symbolTable = new SymbolTable();
12416
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
12417
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
12418
+
12419
+ const code = generator.generate(tree, symbolTable, tokenStream, {
12420
+ symbolInfo: symbols,
12421
+ sourcePath: "test.cnx",
12422
+ });
12423
+
12424
+ expect(code).toContain("Point points[4]");
12425
+ });
12426
+
12427
+ it("should detect struct type in arrayType for parameter", () => {
12428
+ const source = `
12429
+ struct Data { u32 value; }
12430
+ void process(Data[8] items) {
12431
+ items[0].value <- 42;
12432
+ }
12433
+ `;
12434
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
12435
+ const generator = new CodeGenerator();
12436
+ const symbolTable = new SymbolTable();
12437
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
12438
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
12439
+
12198
12440
  const code = generator.generate(tree, symbolTable, tokenStream, {
12199
12441
  symbolInfo: symbols,
12200
12442
  sourcePath: "test.cnx",
12201
12443
  });
12202
12444
 
12203
- expect(code).toContain("uint8_t data[]");
12445
+ expect(code).toContain("Data items[8]");
12446
+ expect(code).toContain("items[0].value = 42");
12447
+ });
12448
+ });
12449
+
12450
+ describe("multi-dimensional C-Next style array parameters", () => {
12451
+ it("should handle 2D array parameter", () => {
12452
+ const source = `
12453
+ void processMatrix(i32[4][4] matrix) {
12454
+ matrix[0][0] <- 1;
12455
+ }
12456
+ `;
12457
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
12458
+ const generator = new CodeGenerator();
12459
+ const symbolTable = new SymbolTable();
12460
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
12461
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
12462
+
12463
+ const code = generator.generate(tree, symbolTable, tokenStream, {
12464
+ symbolInfo: symbols,
12465
+ sourcePath: "test.cnx",
12466
+ });
12467
+
12468
+ expect(code).toContain("int32_t matrix[4][4]");
12469
+ });
12470
+
12471
+ it("should handle 3D array parameter", () => {
12472
+ const source = `
12473
+ void processCube(u8[2][3][4] cube) {
12474
+ cube[0][0][0] <- 0xFF;
12475
+ }
12476
+ `;
12477
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
12478
+ const generator = new CodeGenerator();
12479
+ const symbolTable = new SymbolTable();
12480
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
12481
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
12482
+
12483
+ const code = generator.generate(tree, symbolTable, tokenStream, {
12484
+ symbolInfo: symbols,
12485
+ sourcePath: "test.cnx",
12486
+ });
12487
+
12488
+ expect(code).toContain("uint8_t cube[2][3][4]");
12489
+ });
12490
+
12491
+ it("should reject unbounded array parameter for memory safety", () => {
12492
+ const source = `
12493
+ void processRows(u32[][4] rows, u32 count) {
12494
+ rows[0][0] <- 1;
12495
+ }
12496
+ `;
12497
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
12498
+ const generator = new CodeGenerator();
12499
+ const symbolTable = new SymbolTable();
12500
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
12501
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
12502
+
12503
+ expect(() => {
12504
+ generator.generate(tree, symbolTable, tokenStream, {
12505
+ symbolInfo: symbols,
12506
+ sourcePath: "test.cnx",
12507
+ });
12508
+ }).toThrow(/Unbounded array parameters are not allowed/);
12509
+ });
12510
+
12511
+ it("should reject simple unbounded array parameter", () => {
12512
+ const source = `
12513
+ void process(u8[] data) {
12514
+ data[0] <- 0xFF;
12515
+ }
12516
+ `;
12517
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
12518
+ const generator = new CodeGenerator();
12519
+ const symbolTable = new SymbolTable();
12520
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
12521
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
12522
+
12523
+ expect(() => {
12524
+ generator.generate(tree, symbolTable, tokenStream, {
12525
+ symbolInfo: symbols,
12526
+ sourcePath: "test.cnx",
12527
+ });
12528
+ }).toThrow(/Unbounded array parameters are not allowed/);
12529
+ });
12530
+ });
12531
+
12532
+ describe("string array parameter capacity", () => {
12533
+ it("should add capacity dimension for string array parameter", () => {
12534
+ const source = `
12535
+ void processNames(string<16>[5] names) {
12536
+ names[0] <- "test";
12537
+ }
12538
+ `;
12539
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
12540
+ const generator = new CodeGenerator();
12541
+ const symbolTable = new SymbolTable();
12542
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
12543
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
12544
+
12545
+ const code = generator.generate(tree, symbolTable, tokenStream, {
12546
+ symbolInfo: symbols,
12547
+ sourcePath: "test.cnx",
12548
+ });
12549
+
12550
+ // string<16>[5] -> char[5][17] (capacity + 1 for null terminator)
12551
+ expect(code).toContain("char names[5][17]");
12552
+ });
12553
+
12554
+ it("should handle string array with larger capacity", () => {
12555
+ const source = `
12556
+ void logMessages(string<128>[10] messages) {
12557
+ messages[0] <- "hello";
12558
+ }
12559
+ `;
12560
+ const { tree, tokenStream } = CNextSourceParser.parse(source);
12561
+ const generator = new CodeGenerator();
12562
+ const symbolTable = new SymbolTable();
12563
+ const tSymbols = CNextResolver.resolve(tree, "test.cnx");
12564
+ const symbols = TSymbolInfoAdapter.convert(tSymbols);
12565
+
12566
+ const code = generator.generate(tree, symbolTable, tokenStream, {
12567
+ symbolInfo: symbols,
12568
+ sourcePath: "test.cnx",
12569
+ });
12570
+
12571
+ expect(code).toContain("char messages[10][129]");
12204
12572
  });
12205
12573
  });
12206
12574
 
@@ -12497,7 +12865,7 @@ describe("CodeGenerator", () => {
12497
12865
  describe("string array parameters", () => {
12498
12866
  it("should handle string array parameter with capacity", () => {
12499
12867
  const source = `
12500
- void processNames(string<32> names[10]) {
12868
+ void processNames(string<32>[10] names) {
12501
12869
  string<32> first <- names[0];
12502
12870
  }
12503
12871
  `;
@@ -13363,7 +13731,7 @@ describe("CodeGenerator", () => {
13363
13731
 
13364
13732
  it("should handle array parameters", () => {
13365
13733
  const source = `
13366
- void sum(u32 values[], u32 count) {
13734
+ void sum(u32[10] values) {
13367
13735
  u32 total <- 0;
13368
13736
  }
13369
13737
  `;
@@ -13379,7 +13747,7 @@ describe("CodeGenerator", () => {
13379
13747
  });
13380
13748
 
13381
13749
  expect(code).toContain("values");
13382
- expect(code).toContain("count");
13750
+ expect(code).toContain("uint32_t values[10]");
13383
13751
  });
13384
13752
  });
13385
13753
 
@@ -15118,7 +15486,7 @@ describe("CodeGenerator", () => {
15118
15486
 
15119
15487
  it("should generate function with array parameter", () => {
15120
15488
  const source = `
15121
- void process(u32 arr[10]) {
15489
+ void process(u32[10] arr) {
15122
15490
  u32 val <- arr[0];
15123
15491
  }
15124
15492
  `;
@@ -23,18 +23,26 @@ function generateArrayTypeDimension(
23
23
  return "";
24
24
  }
25
25
 
26
- const sizeExpr = arrayTypeCtx.expression();
27
- if (!sizeExpr) {
28
- return "[]";
29
- }
26
+ // Handle all dimensions from arrayType (supports u8[4][4], u8[], etc.)
27
+ const dims = arrayTypeCtx.arrayTypeDimension();
28
+ let result = "";
29
+ for (const dim of dims) {
30
+ const sizeExpr = dim.expression();
31
+ if (!sizeExpr) {
32
+ result += "[]";
33
+ continue;
34
+ }
30
35
 
31
- const constValue = orchestrator.tryEvaluateConstant(sizeExpr);
32
- if (constValue === undefined) {
33
- // Fall back to expression generation for macros, enums, etc.
34
- return `[${orchestrator.generateExpression(sizeExpr)}]`;
36
+ const constValue = orchestrator.tryEvaluateConstant(sizeExpr);
37
+ if (constValue === undefined) {
38
+ // Fall back to expression generation for macros, enums, etc.
39
+ result += `[${orchestrator.generateExpression(sizeExpr)}]`;
40
+ } else {
41
+ result += `[${constValue}]`;
42
+ }
35
43
  }
36
44
 
37
- return `[${constValue}]`;
45
+ return result;
38
46
  }
39
47
 
40
48
  /**
@@ -26,7 +26,7 @@ describe("ArrayDimensionUtils", () => {
26
26
  it("returns [] for context with no expression", () => {
27
27
  const orchestrator = createMockOrchestrator();
28
28
  const ctx = {
29
- expression: () => null,
29
+ arrayTypeDimension: () => [{ expression: () => null }],
30
30
  };
31
31
  const result = ArrayDimensionUtils.generateArrayTypeDimension(
32
32
  ctx as never,
@@ -38,7 +38,9 @@ describe("ArrayDimensionUtils", () => {
38
38
  it("returns constant dimension when evaluable", () => {
39
39
  const orchestrator = createMockOrchestrator(16);
40
40
  const ctx = {
41
- expression: () => ({ getText: () => "16" }),
41
+ arrayTypeDimension: () => [
42
+ { expression: () => ({ getText: () => "16" }) },
43
+ ],
42
44
  };
43
45
  const result = ArrayDimensionUtils.generateArrayTypeDimension(
44
46
  ctx as never,
@@ -52,7 +54,7 @@ describe("ArrayDimensionUtils", () => {
52
54
  const orchestrator = createMockOrchestrator(undefined, "BUFFER_SIZE");
53
55
  const mockExpr = { getText: () => "BUFFER_SIZE" };
54
56
  const ctx = {
55
- expression: () => mockExpr,
57
+ arrayTypeDimension: () => [{ expression: () => mockExpr }],
56
58
  };
57
59
  const result = ArrayDimensionUtils.generateArrayTypeDimension(
58
60
  ctx as never,
@@ -44,15 +44,11 @@ function createMockConstModifier(
44
44
 
45
45
  /**
46
46
  * Create a mock array type context.
47
+ * Updated for new grammar: arrayType has arrayTypeDimension() which returns dimensions
47
48
  */
48
49
  function createMockArrayType(sizeExpr?: string | null) {
49
- if (sizeExpr === null) {
50
- // Empty brackets - no expression
51
- return {
52
- expression: () => null,
53
- };
54
- }
55
- return {
50
+ // Create a single dimension with optional expression
51
+ const mockDimension = {
56
52
  expression: () =>
57
53
  sizeExpr
58
54
  ? {
@@ -61,6 +57,15 @@ function createMockArrayType(sizeExpr?: string | null) {
61
57
  }
62
58
  : null,
63
59
  };
60
+
61
+ return {
62
+ // New grammar: arrayTypeDimension() returns array of dimensions
63
+ arrayTypeDimension: () => [mockDimension],
64
+ // Keep primitiveType for base type extraction
65
+ primitiveType: () => null,
66
+ userType: () => null,
67
+ stringType: () => null,
68
+ };
64
69
  }
65
70
 
66
71
  /**
@@ -704,6 +704,12 @@ const generateStringLength = (
704
704
  return subscriptDepth === 0 ? String(dims[0]) : `strlen(${result})`;
705
705
  }
706
706
 
707
+ // String array with subscript - use result which contains arr[index]
708
+ // This handles string<32>[5] parameters where subscriptDepth=1 after arr[index]
709
+ if (subscriptDepth > 0) {
710
+ return `strlen(${result})`;
711
+ }
712
+
707
713
  // Simple string: check length cache first, then use strlen
708
714
  if (resolvedIdentifier && state.lengthCache?.has(resolvedIdentifier)) {
709
715
  return state.lengthCache.get(resolvedIdentifier)!;
@@ -208,6 +208,10 @@ class TypeGenerationHelper {
208
208
  // Array type
209
209
  if (ctx.arrayType()) {
210
210
  const arrCtx = ctx.arrayType()!;
211
+ // String arrays have base type "char"
212
+ if (arrCtx.stringType()) {
213
+ return "char";
214
+ }
211
215
  const primitiveText = arrCtx.primitiveType()?.getText() ?? null;
212
216
  const userTypeName = arrCtx.userType()?.getText() ?? null;
213
217
  const needsStruct = userTypeName