c-next 0.1.64 → 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 +181 -86
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +254 -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
|
@@ -89,6 +89,7 @@ import { TemplateArgumentListContext } from "./CNextParser.js";
|
|
|
89
89
|
import { TemplateArgumentContext } from "./CNextParser.js";
|
|
90
90
|
import { StringTypeContext } from "./CNextParser.js";
|
|
91
91
|
import { ArrayTypeContext } from "./CNextParser.js";
|
|
92
|
+
import { ArrayTypeDimensionContext } from "./CNextParser.js";
|
|
92
93
|
import { LiteralContext } from "./CNextParser.js";
|
|
93
94
|
|
|
94
95
|
|
|
@@ -616,6 +617,12 @@ export class CNextVisitor<Result> extends AbstractParseTreeVisitor<Result> {
|
|
|
616
617
|
* @return the visitor result
|
|
617
618
|
*/
|
|
618
619
|
visitArrayType?: (ctx: ArrayTypeContext) => Result;
|
|
620
|
+
/**
|
|
621
|
+
* Visit a parse tree produced by `CNextParser.arrayTypeDimension`.
|
|
622
|
+
* @param ctx the parse tree
|
|
623
|
+
* @return the visitor result
|
|
624
|
+
*/
|
|
625
|
+
visitArrayTypeDimension?: (ctx: ArrayTypeDimensionContext) => Result;
|
|
619
626
|
/**
|
|
620
627
|
* Visit a parse tree produced by `CNextParser.literal`.
|
|
621
628
|
* @param ctx the parse tree
|
|
@@ -77,9 +77,9 @@ describe("FunctionCollector", () => {
|
|
|
77
77
|
expect(symbol.parameters[0].isConst).toBe(true);
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
it("handles array parameters", () => {
|
|
80
|
+
it("handles array parameters (C-Next style)", () => {
|
|
81
81
|
const code = `
|
|
82
|
-
void processArray(u8 data
|
|
82
|
+
void processArray(u8[] data) {
|
|
83
83
|
}
|
|
84
84
|
`;
|
|
85
85
|
const tree = parse(code);
|
|
@@ -90,9 +90,9 @@ describe("FunctionCollector", () => {
|
|
|
90
90
|
expect(symbol.parameters[0].arrayDimensions).toEqual([""]);
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
it("handles sized array parameters", () => {
|
|
93
|
+
it("handles sized array parameters (C-Next style)", () => {
|
|
94
94
|
const code = `
|
|
95
|
-
void processBuffer(u8
|
|
95
|
+
void processBuffer(u8[256] buffer) {
|
|
96
96
|
}
|
|
97
97
|
`;
|
|
98
98
|
const tree = parse(code);
|
|
@@ -103,9 +103,9 @@ describe("FunctionCollector", () => {
|
|
|
103
103
|
expect(symbol.parameters[0].arrayDimensions).toEqual(["256"]);
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
-
it("handles multi-dimensional array parameters", () => {
|
|
106
|
+
it("handles multi-dimensional array parameters (C-Next style)", () => {
|
|
107
107
|
const code = `
|
|
108
|
-
void processMatrix(f32
|
|
108
|
+
void processMatrix(f32[4][4] matrix) {
|
|
109
109
|
}
|
|
110
110
|
`;
|
|
111
111
|
const tree = parse(code);
|
|
@@ -156,6 +156,61 @@ describe("VariableCollector", () => {
|
|
|
156
156
|
expect(symbol.isArray).toBe(true);
|
|
157
157
|
expect(symbol.arrayDimensions).toEqual([10, 20]);
|
|
158
158
|
});
|
|
159
|
+
|
|
160
|
+
it("collects C-Next style array with dimensions in type (u8[8] arr)", () => {
|
|
161
|
+
const code = `
|
|
162
|
+
u8[8] buffer;
|
|
163
|
+
`;
|
|
164
|
+
const tree = parse(code);
|
|
165
|
+
const varCtx = tree.declaration(0)!.variableDeclaration()!;
|
|
166
|
+
const symbol = VariableCollector.collect(varCtx, "test.cnx");
|
|
167
|
+
|
|
168
|
+
expect(symbol.isArray).toBe(true);
|
|
169
|
+
expect(symbol.arrayDimensions).toEqual([8]);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("collects C-Next style multi-dimensional array (u8[4][4] arr)", () => {
|
|
173
|
+
const code = `
|
|
174
|
+
u8[4][4] matrix;
|
|
175
|
+
`;
|
|
176
|
+
const tree = parse(code);
|
|
177
|
+
const varCtx = tree.declaration(0)!.variableDeclaration()!;
|
|
178
|
+
const symbol = VariableCollector.collect(varCtx, "test.cnx");
|
|
179
|
+
|
|
180
|
+
expect(symbol.isArray).toBe(true);
|
|
181
|
+
expect(symbol.arrayDimensions).toEqual([4, 4]);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("collects C-Next style array with const reference dimension", () => {
|
|
185
|
+
const code = `
|
|
186
|
+
u8[SIZE] buffer;
|
|
187
|
+
`;
|
|
188
|
+
const tree = parse(code);
|
|
189
|
+
const varCtx = tree.declaration(0)!.variableDeclaration()!;
|
|
190
|
+
const constValues = new Map<string, number>([["SIZE", 16]]);
|
|
191
|
+
const symbol = VariableCollector.collect(
|
|
192
|
+
varCtx,
|
|
193
|
+
"test.cnx",
|
|
194
|
+
undefined,
|
|
195
|
+
true,
|
|
196
|
+
constValues,
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
expect(symbol.isArray).toBe(true);
|
|
200
|
+
expect(symbol.arrayDimensions).toEqual([16]);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("preserves unresolved macro as string in C-Next style array", () => {
|
|
204
|
+
const code = `
|
|
205
|
+
u8[BUFFER_SIZE] buffer;
|
|
206
|
+
`;
|
|
207
|
+
const tree = parse(code);
|
|
208
|
+
const varCtx = tree.declaration(0)!.variableDeclaration()!;
|
|
209
|
+
const symbol = VariableCollector.collect(varCtx, "test.cnx");
|
|
210
|
+
|
|
211
|
+
expect(symbol.isArray).toBe(true);
|
|
212
|
+
expect(symbol.arrayDimensions).toEqual(["BUFFER_SIZE"]);
|
|
213
|
+
});
|
|
159
214
|
});
|
|
160
215
|
|
|
161
216
|
describe("scoped variables", () => {
|
|
@@ -70,17 +70,16 @@ class FunctionCollector {
|
|
|
70
70
|
const type = TypeUtils.getTypeName(typeCtx, scopeName);
|
|
71
71
|
const isConst = p.constModifier() !== null;
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
const
|
|
73
|
+
// Check for C-Next style array type (u8[8] param, u8[4][4] param, u8[] param)
|
|
74
|
+
const arrayTypeCtx = typeCtx.arrayType();
|
|
75
|
+
const hasArrayType = arrayTypeCtx !== null;
|
|
75
76
|
|
|
76
|
-
// Extract array dimensions
|
|
77
|
+
// Extract array dimensions from arrayType syntax (supports multi-dimensional)
|
|
77
78
|
const arrayDimensions: string[] = [];
|
|
78
|
-
if (
|
|
79
|
-
for (const dim of
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
const match = regex.exec(text);
|
|
83
|
-
arrayDimensions.push(match ? match[1] : ""); // "" means unbounded
|
|
79
|
+
if (hasArrayType) {
|
|
80
|
+
for (const dim of arrayTypeCtx.arrayTypeDimension()) {
|
|
81
|
+
const sizeExpr = dim.expression();
|
|
82
|
+
arrayDimensions.push(sizeExpr ? sizeExpr.getText() : "");
|
|
84
83
|
}
|
|
85
84
|
}
|
|
86
85
|
|
|
@@ -88,7 +87,7 @@ class FunctionCollector {
|
|
|
88
87
|
name,
|
|
89
88
|
type,
|
|
90
89
|
isConst,
|
|
91
|
-
isArray,
|
|
90
|
+
isArray: hasArrayType,
|
|
92
91
|
};
|
|
93
92
|
|
|
94
93
|
if (arrayDimensions.length > 0) {
|
|
@@ -30,7 +30,13 @@ function processArrayTypeSyntax(
|
|
|
30
30
|
return { isArray: false, dimension: undefined };
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
// Get the first dimension (for backwards compatibility with single-dimension code)
|
|
34
|
+
const dims = arrayTypeCtx.arrayTypeDimension();
|
|
35
|
+
if (dims.length === 0) {
|
|
36
|
+
return { isArray: true, dimension: undefined };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const sizeExpr = dims[0].expression();
|
|
34
40
|
if (!sizeExpr) {
|
|
35
41
|
return { isArray: true, dimension: undefined };
|
|
36
42
|
}
|
|
@@ -71,6 +71,32 @@ class VariableCollector {
|
|
|
71
71
|
return dimensions;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Collect dimensions from C-Next style arrayType syntax (u16[8] arr, u16[4][4] arr).
|
|
76
|
+
*/
|
|
77
|
+
private static collectArrayTypeDimensions(
|
|
78
|
+
arrayTypeCtx: Parser.ArrayTypeContext,
|
|
79
|
+
constValues: Map<string, number> | undefined,
|
|
80
|
+
): (number | string)[] {
|
|
81
|
+
const dimensions: (number | string)[] = [];
|
|
82
|
+
for (const dim of arrayTypeCtx.arrayTypeDimension()) {
|
|
83
|
+
const sizeExpr = dim.expression();
|
|
84
|
+
if (!sizeExpr) continue;
|
|
85
|
+
|
|
86
|
+
const dimText = sizeExpr.getText();
|
|
87
|
+
const literalSize = LiteralUtils.parseIntegerLiteral(dimText);
|
|
88
|
+
if (literalSize !== undefined) {
|
|
89
|
+
dimensions.push(literalSize);
|
|
90
|
+
} else if (constValues?.has(dimText)) {
|
|
91
|
+
dimensions.push(constValues.get(dimText)!);
|
|
92
|
+
} else {
|
|
93
|
+
// Keep as string for macro/enum references
|
|
94
|
+
dimensions.push(dimText);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return dimensions;
|
|
98
|
+
}
|
|
99
|
+
|
|
74
100
|
/**
|
|
75
101
|
* Collect a variable declaration and return an IVariableSymbol.
|
|
76
102
|
*
|
|
@@ -110,21 +136,14 @@ class VariableCollector {
|
|
|
110
136
|
const initExpr = ctx.expression();
|
|
111
137
|
const arrayDimensions: (number | string)[] = [];
|
|
112
138
|
|
|
113
|
-
// Collect
|
|
139
|
+
// Collect dimensions from arrayType syntax (u16[8] arr, u16[4][4] arr, u16[] arr)
|
|
114
140
|
if (hasArrayTypeSyntax) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
} else if (constValues?.has(dimText)) {
|
|
122
|
-
arrayDimensions.push(constValues.get(dimText)!);
|
|
123
|
-
} else {
|
|
124
|
-
// Keep as string for macro/enum references
|
|
125
|
-
arrayDimensions.push(dimText);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
141
|
+
arrayDimensions.push(
|
|
142
|
+
...VariableCollector.collectArrayTypeDimensions(
|
|
143
|
+
arrayTypeCtx,
|
|
144
|
+
constValues,
|
|
145
|
+
),
|
|
146
|
+
);
|
|
128
147
|
}
|
|
129
148
|
|
|
130
149
|
// Collect additional dimensions from arrayDimension syntax
|
|
@@ -3579,7 +3579,12 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3579
3579
|
private _parseArrayTypeDimensionFromCtx(
|
|
3580
3580
|
arrayTypeCtx: Parser.ArrayTypeContext,
|
|
3581
3581
|
): number | undefined {
|
|
3582
|
-
|
|
3582
|
+
// Get first dimension for backwards compatibility
|
|
3583
|
+
const dims = arrayTypeCtx.arrayTypeDimension();
|
|
3584
|
+
if (dims.length === 0) {
|
|
3585
|
+
return undefined;
|
|
3586
|
+
}
|
|
3587
|
+
const sizeExpr = dims[0].expression();
|
|
3583
3588
|
if (!sizeExpr) {
|
|
3584
3589
|
return undefined;
|
|
3585
3590
|
}
|
|
@@ -3596,12 +3601,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3596
3601
|
): number[] {
|
|
3597
3602
|
const arrayDimensions: number[] = [];
|
|
3598
3603
|
|
|
3599
|
-
// Get
|
|
3600
|
-
const
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3604
|
+
// Get all dimensions from array type syntax (supports multi-dimensional)
|
|
3605
|
+
for (const dim of arrayTypeCtx.arrayTypeDimension()) {
|
|
3606
|
+
const sizeExpr = dim.expression();
|
|
3607
|
+
if (sizeExpr) {
|
|
3608
|
+
const size = Number.parseInt(sizeExpr.getText(), 10);
|
|
3609
|
+
if (!Number.isNaN(size)) {
|
|
3610
|
+
arrayDimensions.push(size);
|
|
3611
|
+
}
|
|
3605
3612
|
}
|
|
3606
3613
|
}
|
|
3607
3614
|
|
|
@@ -3671,7 +3678,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3671
3678
|
*/
|
|
3672
3679
|
private _processParameter(param: Parser.ParameterContext): void {
|
|
3673
3680
|
const name = param.IDENTIFIER().getText();
|
|
3674
|
-
|
|
3681
|
+
// Check both C-Next style (u8[8] param) and legacy style (u8 param[8])
|
|
3682
|
+
const isArray =
|
|
3683
|
+
param.arrayDimension().length > 0 || param.type().arrayType() !== null;
|
|
3675
3684
|
const isConst = param.constModifier() !== null;
|
|
3676
3685
|
const typeCtx = param.type();
|
|
3677
3686
|
|
|
@@ -3768,6 +3777,38 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3768
3777
|
};
|
|
3769
3778
|
}
|
|
3770
3779
|
|
|
3780
|
+
// Handle C-Next style array type (u8[8] param) - extract base type
|
|
3781
|
+
if (typeCtx.arrayType()) {
|
|
3782
|
+
const arrayTypeCtx = typeCtx.arrayType()!;
|
|
3783
|
+
if (arrayTypeCtx.primitiveType()) {
|
|
3784
|
+
return {
|
|
3785
|
+
typeName: arrayTypeCtx.primitiveType()!.getText(),
|
|
3786
|
+
isStruct: false,
|
|
3787
|
+
isCallback: false,
|
|
3788
|
+
isString: false,
|
|
3789
|
+
};
|
|
3790
|
+
}
|
|
3791
|
+
if (arrayTypeCtx.userType()) {
|
|
3792
|
+
const typeName = arrayTypeCtx.userType()!.getText();
|
|
3793
|
+
return {
|
|
3794
|
+
typeName,
|
|
3795
|
+
isStruct: this.isStructType(typeName),
|
|
3796
|
+
isCallback: CodeGenState.callbackTypes.has(typeName),
|
|
3797
|
+
isString: false,
|
|
3798
|
+
};
|
|
3799
|
+
}
|
|
3800
|
+
// Handle string array type (string<32>[5] param)
|
|
3801
|
+
if (arrayTypeCtx.stringType()) {
|
|
3802
|
+
const stringCtx = arrayTypeCtx.stringType()!;
|
|
3803
|
+
return {
|
|
3804
|
+
typeName: stringCtx.getText(), // "string<32>"
|
|
3805
|
+
isStruct: false,
|
|
3806
|
+
isCallback: false,
|
|
3807
|
+
isString: true,
|
|
3808
|
+
};
|
|
3809
|
+
}
|
|
3810
|
+
}
|
|
3811
|
+
|
|
3771
3812
|
// Fallback
|
|
3772
3813
|
return {
|
|
3773
3814
|
typeName: typeCtx.getText(),
|
|
@@ -3777,6 +3818,37 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3777
3818
|
};
|
|
3778
3819
|
}
|
|
3779
3820
|
|
|
3821
|
+
/**
|
|
3822
|
+
* Extract array dimensions from parameter (C-style or C-Next style).
|
|
3823
|
+
*/
|
|
3824
|
+
private _extractParamArrayDimensions(
|
|
3825
|
+
param: Parser.ParameterContext,
|
|
3826
|
+
typeCtx: Parser.TypeContext,
|
|
3827
|
+
isArray: boolean,
|
|
3828
|
+
): number[] {
|
|
3829
|
+
if (!isArray) return [];
|
|
3830
|
+
|
|
3831
|
+
// Try C-style first (param.arrayDimension())
|
|
3832
|
+
if (param.arrayDimension().length > 0) {
|
|
3833
|
+
return ArrayDimensionParser.parseForParameters(param.arrayDimension());
|
|
3834
|
+
}
|
|
3835
|
+
|
|
3836
|
+
// C-Next style: get dimensions from arrayType
|
|
3837
|
+
const arrayTypeCtx = typeCtx.arrayType();
|
|
3838
|
+
if (!arrayTypeCtx) return [];
|
|
3839
|
+
|
|
3840
|
+
const dimensions: number[] = [];
|
|
3841
|
+
for (const dim of arrayTypeCtx.arrayTypeDimension()) {
|
|
3842
|
+
const expr = dim.expression();
|
|
3843
|
+
if (!expr) continue;
|
|
3844
|
+
const size = Number.parseInt(expr.getText(), 10);
|
|
3845
|
+
if (!Number.isNaN(size)) {
|
|
3846
|
+
dimensions.push(size);
|
|
3847
|
+
}
|
|
3848
|
+
}
|
|
3849
|
+
return dimensions;
|
|
3850
|
+
}
|
|
3851
|
+
|
|
3780
3852
|
/**
|
|
3781
3853
|
* Register a parameter in the type registry
|
|
3782
3854
|
*/
|
|
@@ -3794,11 +3866,13 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3794
3866
|
const isBitmap = CodeGenState.symbols!.knownBitmaps.has(typeName);
|
|
3795
3867
|
|
|
3796
3868
|
// Extract array dimensions
|
|
3797
|
-
const arrayDimensions =
|
|
3798
|
-
|
|
3799
|
-
|
|
3869
|
+
const arrayDimensions = this._extractParamArrayDimensions(
|
|
3870
|
+
param,
|
|
3871
|
+
typeCtx,
|
|
3872
|
+
isArray,
|
|
3873
|
+
);
|
|
3800
3874
|
|
|
3801
|
-
//
|
|
3875
|
+
// Add string capacity dimension if applicable
|
|
3802
3876
|
const stringCapacity = this._getStringCapacity(typeCtx, isString);
|
|
3803
3877
|
if (isArray && stringCapacity !== undefined) {
|
|
3804
3878
|
arrayDimensions.push(stringCapacity + 1);
|
|
@@ -3830,10 +3904,25 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3830
3904
|
typeCtx: Parser.TypeContext,
|
|
3831
3905
|
isString: boolean,
|
|
3832
3906
|
): number | undefined {
|
|
3833
|
-
if (!isString
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3907
|
+
if (!isString) return undefined;
|
|
3908
|
+
|
|
3909
|
+
// Check direct stringType (e.g., string<32> param)
|
|
3910
|
+
if (typeCtx.stringType()) {
|
|
3911
|
+
const intLiteral = typeCtx.stringType()!.INTEGER_LITERAL();
|
|
3912
|
+
if (intLiteral) {
|
|
3913
|
+
return Number.parseInt(intLiteral.getText(), 10);
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
|
|
3917
|
+
// Check arrayType with stringType (e.g., string<32>[5] param)
|
|
3918
|
+
if (typeCtx.arrayType()?.stringType()) {
|
|
3919
|
+
const intLiteral = typeCtx.arrayType()!.stringType()!.INTEGER_LITERAL();
|
|
3920
|
+
if (intLiteral) {
|
|
3921
|
+
return Number.parseInt(intLiteral.getText(), 10);
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
|
|
3925
|
+
return undefined;
|
|
3837
3926
|
}
|
|
3838
3927
|
|
|
3839
3928
|
/**
|
|
@@ -3930,7 +4019,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3930
4019
|
if (dims.length > 0) {
|
|
3931
4020
|
arrayDims = dims.map((d) => this.generateArrayDimension(d)).join("");
|
|
3932
4021
|
} else if (arrayTypeCtx) {
|
|
3933
|
-
|
|
4022
|
+
// Generate all dimensions from arrayType (supports multi-dimensional)
|
|
4023
|
+
arrayDims = arrayTypeCtx
|
|
4024
|
+
.arrayTypeDimension()
|
|
4025
|
+
.map((d) => {
|
|
4026
|
+
const expr = d.expression();
|
|
4027
|
+
return expr ? `[${this.generateExpression(expr)}]` : "[]";
|
|
4028
|
+
})
|
|
4029
|
+
.join("");
|
|
3934
4030
|
} else {
|
|
3935
4031
|
arrayDims = "";
|
|
3936
4032
|
}
|
|
@@ -5182,6 +5278,22 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5182
5278
|
const name = ctx.IDENTIFIER().getText();
|
|
5183
5279
|
const dims = ctx.arrayDimension();
|
|
5184
5280
|
|
|
5281
|
+
// Reject ALL C-style array parameters - require C-Next style (dimensions in type)
|
|
5282
|
+
// C-style: u8 data[8], u8 data[4][4], u8 data[]
|
|
5283
|
+
// C-Next: u8[8] data, u8[4][4] data, u8[] data
|
|
5284
|
+
if (dims.length > 0) {
|
|
5285
|
+
const baseType = typeName;
|
|
5286
|
+
const dimensions = dims
|
|
5287
|
+
.map((dim) => `[${dim.expression()?.getText() ?? ""}]`)
|
|
5288
|
+
.join("");
|
|
5289
|
+
const line = ctx.start?.line ?? 0;
|
|
5290
|
+
const col = ctx.start?.column ?? 0;
|
|
5291
|
+
throw new Error(
|
|
5292
|
+
`${line}:${col} C-style array parameter is not allowed. ` +
|
|
5293
|
+
`Use '${baseType}${dimensions} ${name}' instead of '${baseType} ${name}${dimensions}'`,
|
|
5294
|
+
);
|
|
5295
|
+
}
|
|
5296
|
+
|
|
5185
5297
|
// ADR-029: Check if this is a callback type parameter
|
|
5186
5298
|
if (CodeGenState.callbackTypes.has(typeName)) {
|
|
5187
5299
|
const callbackInfo = CodeGenState.callbackTypes.get(typeName)!;
|
|
@@ -5190,27 +5302,41 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5190
5302
|
|
|
5191
5303
|
const type = this.generateType(ctx.type());
|
|
5192
5304
|
|
|
5193
|
-
// Handle C-Next style array type in parameter (e.g., u8[8] param)
|
|
5305
|
+
// Handle C-Next style array type in parameter (e.g., u8[8] param, u8[4][4] param, string<32>[5] param)
|
|
5194
5306
|
const arrayTypeCtx = ctx.type().arrayType();
|
|
5195
5307
|
if (arrayTypeCtx) {
|
|
5196
|
-
|
|
5308
|
+
// Check for unbounded dimensions - reject for memory safety
|
|
5309
|
+
const allDims = arrayTypeCtx.arrayTypeDimension();
|
|
5310
|
+
const hasUnboundedDim = allDims.some((d) => !d.expression());
|
|
5311
|
+
if (hasUnboundedDim) {
|
|
5312
|
+
const line = ctx.start?.line ?? 0;
|
|
5313
|
+
const col = ctx.start?.column ?? 0;
|
|
5314
|
+
throw new Error(
|
|
5315
|
+
`${line}:${col} Unbounded array parameters are not allowed. ` +
|
|
5316
|
+
`All dimensions must have explicit sizes for memory safety.`,
|
|
5317
|
+
);
|
|
5318
|
+
}
|
|
5319
|
+
|
|
5320
|
+
let dims = allDims
|
|
5321
|
+
.map((d) => {
|
|
5322
|
+
const expr = d.expression();
|
|
5323
|
+
return expr ? `[${this.generateExpression(expr)}]` : "[]";
|
|
5324
|
+
})
|
|
5325
|
+
.join("");
|
|
5326
|
+
// For string arrays, add the string capacity dimension (string<32>[5] -> char[5][33])
|
|
5327
|
+
if (arrayTypeCtx.stringType()) {
|
|
5328
|
+
const stringCtx = arrayTypeCtx.stringType()!;
|
|
5329
|
+
const intLiteral = stringCtx.INTEGER_LITERAL();
|
|
5330
|
+
if (intLiteral) {
|
|
5331
|
+
const capacity = Number.parseInt(intLiteral.getText(), 10);
|
|
5332
|
+
dims += `[${capacity + 1}]`;
|
|
5333
|
+
}
|
|
5334
|
+
}
|
|
5197
5335
|
const wasModified = this._isCurrentParameterModified(name);
|
|
5198
5336
|
const autoConst = !wasModified && !constMod ? "const " : "";
|
|
5199
|
-
return `${autoConst}${constMod}${type} ${name}
|
|
5337
|
+
return `${autoConst}${constMod}${type} ${name}${dims}`;
|
|
5200
5338
|
}
|
|
5201
5339
|
|
|
5202
|
-
// Try special cases first
|
|
5203
|
-
const stringArrayResult = this._tryGenerateStringArrayParam(
|
|
5204
|
-
ctx,
|
|
5205
|
-
constMod,
|
|
5206
|
-
name,
|
|
5207
|
-
dims,
|
|
5208
|
-
);
|
|
5209
|
-
if (stringArrayResult) return stringArrayResult;
|
|
5210
|
-
|
|
5211
|
-
const arrayResult = this._tryGenerateArrayParam(constMod, type, name, dims);
|
|
5212
|
-
if (arrayResult) return arrayResult;
|
|
5213
|
-
|
|
5214
5340
|
// Pass-by-value types
|
|
5215
5341
|
if (this._isPassByValueType(typeName, name)) {
|
|
5216
5342
|
return `${constMod}${type} ${name}`;
|
|
@@ -5233,46 +5359,6 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5233
5359
|
return `${constMod}${type} ${name}`;
|
|
5234
5360
|
}
|
|
5235
5361
|
|
|
5236
|
-
/**
|
|
5237
|
-
* Try to generate string array parameter: string<N>[] -> char arr[n][N+1]
|
|
5238
|
-
*/
|
|
5239
|
-
private _tryGenerateStringArrayParam(
|
|
5240
|
-
ctx: Parser.ParameterContext,
|
|
5241
|
-
constMod: string,
|
|
5242
|
-
name: string,
|
|
5243
|
-
dims: Parser.ArrayDimensionContext[],
|
|
5244
|
-
): string | null {
|
|
5245
|
-
if (!ctx.type().stringType() || dims.length === 0) {
|
|
5246
|
-
return null;
|
|
5247
|
-
}
|
|
5248
|
-
|
|
5249
|
-
const stringType = ctx.type().stringType()!;
|
|
5250
|
-
const capacity = stringType.INTEGER_LITERAL()
|
|
5251
|
-
? Number.parseInt(stringType.INTEGER_LITERAL()!.getText(), 10)
|
|
5252
|
-
: 256;
|
|
5253
|
-
const dimStr = dims.map((d) => this.generateArrayDimension(d)).join("");
|
|
5254
|
-
return `${constMod}char ${name}${dimStr}[${capacity + 1}]`;
|
|
5255
|
-
}
|
|
5256
|
-
|
|
5257
|
-
/**
|
|
5258
|
-
* Try to generate array parameter with auto-const
|
|
5259
|
-
*/
|
|
5260
|
-
private _tryGenerateArrayParam(
|
|
5261
|
-
constMod: string,
|
|
5262
|
-
type: string,
|
|
5263
|
-
name: string,
|
|
5264
|
-
dims: Parser.ArrayDimensionContext[],
|
|
5265
|
-
): string | null {
|
|
5266
|
-
if (dims.length === 0) {
|
|
5267
|
-
return null;
|
|
5268
|
-
}
|
|
5269
|
-
|
|
5270
|
-
const dimStr = dims.map((d) => this.generateArrayDimension(d)).join("");
|
|
5271
|
-
const wasModified = this._isCurrentParameterModified(name);
|
|
5272
|
-
const autoConst = !wasModified && !constMod ? "const " : "";
|
|
5273
|
-
return `${autoConst}${constMod}${type} ${name}${dimStr}`;
|
|
5274
|
-
}
|
|
5275
|
-
|
|
5276
5362
|
/**
|
|
5277
5363
|
* Check if type should use pass-by-value semantics
|
|
5278
5364
|
*/
|
|
@@ -5515,39 +5601,48 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5515
5601
|
}
|
|
5516
5602
|
|
|
5517
5603
|
/**
|
|
5518
|
-
* Get array dimension string from arrayType syntax (u16[8] -> "[8]").
|
|
5604
|
+
* Get array dimension string from arrayType syntax (u16[8] -> "[8]", u16[4][4] -> "[4][4]").
|
|
5519
5605
|
* Evaluates const expressions to their numeric values for C compatibility.
|
|
5520
5606
|
*/
|
|
5521
5607
|
private _getArrayTypeDimension(typeCtx: Parser.TypeContext): string {
|
|
5522
5608
|
if (!typeCtx.arrayType()) {
|
|
5523
5609
|
return "";
|
|
5524
5610
|
}
|
|
5525
|
-
const
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5611
|
+
const dims = typeCtx.arrayType()!.arrayTypeDimension();
|
|
5612
|
+
let result = "";
|
|
5613
|
+
for (const dim of dims) {
|
|
5614
|
+
const sizeExpr = dim.expression();
|
|
5615
|
+
if (!sizeExpr) {
|
|
5616
|
+
result += "[]";
|
|
5617
|
+
continue;
|
|
5618
|
+
}
|
|
5619
|
+
// Try to evaluate as constant first (required for C file-scope arrays)
|
|
5620
|
+
// Fall back to expression text for macros, enums, etc.
|
|
5621
|
+
const dimValue =
|
|
5622
|
+
this.tryEvaluateConstant(sizeExpr) ?? this.generateExpression(sizeExpr);
|
|
5623
|
+
result += `[${dimValue}]`;
|
|
5533
5624
|
}
|
|
5534
|
-
|
|
5535
|
-
return `[${this.generateExpression(sizeExpr)}]`;
|
|
5625
|
+
return result;
|
|
5536
5626
|
}
|
|
5537
5627
|
|
|
5538
5628
|
/**
|
|
5539
|
-
* Parse array dimension from arrayType syntax for size validation.
|
|
5629
|
+
* Parse first array dimension from arrayType syntax for size validation.
|
|
5540
5630
|
*/
|
|
5541
5631
|
private _parseArrayTypeDimension(typeCtx: Parser.TypeContext): number | null {
|
|
5542
5632
|
if (!typeCtx.arrayType()) {
|
|
5543
5633
|
return null;
|
|
5544
5634
|
}
|
|
5545
|
-
const
|
|
5635
|
+
const dims = typeCtx.arrayType()!.arrayTypeDimension();
|
|
5636
|
+
if (dims.length === 0) {
|
|
5637
|
+
return null;
|
|
5638
|
+
}
|
|
5639
|
+
const sizeExpr = dims[0].expression();
|
|
5546
5640
|
if (!sizeExpr) {
|
|
5547
5641
|
return null;
|
|
5548
5642
|
}
|
|
5549
5643
|
const sizeText = sizeExpr.getText();
|
|
5550
|
-
|
|
5644
|
+
const digitRegex = /^\d+$/;
|
|
5645
|
+
if (digitRegex.exec(sizeText)) {
|
|
5551
5646
|
return Number.parseInt(sizeText, 10);
|
|
5552
5647
|
}
|
|
5553
5648
|
return null;
|