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.
- package/grammar/CNext.g4 +9 -2
- package/package.json +1 -1
- package/src/transpiler/logic/parser/grammar/CNext.interp +2 -1
- package/src/transpiler/logic/parser/grammar/CNextListener.ts +11 -0
- package/src/transpiler/logic/parser/grammar/CNextParser.ts +992 -870
- package/src/transpiler/logic/parser/grammar/CNextVisitor.ts +7 -0
- package/src/transpiler/logic/symbols/cnext/__tests__/FunctionCollector.test.ts +6 -6
- package/src/transpiler/logic/symbols/cnext/__tests__/VariableCollector.test.ts +55 -0
- package/src/transpiler/logic/symbols/cnext/collectors/FunctionCollector.ts +9 -10
- package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +7 -1
- package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +33 -14
- package/src/transpiler/output/codegen/CodeGenerator.ts +206 -85
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +390 -22
- package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +17 -9
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +5 -3
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +12 -7
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +6 -0
- package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +4 -0
|
@@ -1568,7 +1568,7 @@ describe("CodeGenerator", () => {
|
|
|
1568
1568
|
|
|
1569
1569
|
it("should generate array parameter", () => {
|
|
1570
1570
|
const source = `
|
|
1571
|
-
void process(u32
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
12344
|
+
it("should reject C-style array parameter with multiple dimensions", () => {
|
|
12187
12345
|
const source = `
|
|
12188
|
-
void
|
|
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("
|
|
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>
|
|
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
|
|
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("
|
|
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
|
|
15489
|
+
void process(u32[10] arr) {
|
|
15122
15490
|
u32 val <- arr[0];
|
|
15123
15491
|
}
|
|
15124
15492
|
`;
|
package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts
CHANGED
|
@@ -23,18 +23,26 @@ function generateArrayTypeDimension(
|
|
|
23
23
|
return "";
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
50
|
-
|
|
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
|