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
|
@@ -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
|
/**
|
|
@@ -3870,7 +3959,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3870
3959
|
const paramName = param.IDENTIFIER().getText();
|
|
3871
3960
|
const isConst = param.constModifier() !== null;
|
|
3872
3961
|
// arrayDimension() returns an array (due to grammar's *), so check length
|
|
3873
|
-
|
|
3962
|
+
// Also check C-Next style array type (e.g., u8[8] param)
|
|
3963
|
+
const isArray =
|
|
3964
|
+
param.arrayDimension().length > 0 ||
|
|
3965
|
+
param.type().arrayType() !== null;
|
|
3874
3966
|
const baseType = this.getTypeName(param.type());
|
|
3875
3967
|
parameters.push({ name: paramName, baseType, isConst, isArray });
|
|
3876
3968
|
}
|
|
@@ -3903,7 +3995,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3903
3995
|
const typeName = this.getTypeName(param.type());
|
|
3904
3996
|
const isConst = param.constModifier() !== null;
|
|
3905
3997
|
const dims = param.arrayDimension();
|
|
3906
|
-
const
|
|
3998
|
+
const arrayTypeCtx = param.type().arrayType();
|
|
3999
|
+
const isArray = dims.length > 0 || arrayTypeCtx !== null;
|
|
3907
4000
|
|
|
3908
4001
|
// ADR-029: Check if parameter type is itself a callback type
|
|
3909
4002
|
const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
|
|
@@ -3922,9 +4015,21 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3922
4015
|
isPointer = !isArray;
|
|
3923
4016
|
}
|
|
3924
4017
|
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
4018
|
+
let arrayDims: string;
|
|
4019
|
+
if (dims.length > 0) {
|
|
4020
|
+
arrayDims = dims.map((d) => this.generateArrayDimension(d)).join("");
|
|
4021
|
+
} else if (arrayTypeCtx) {
|
|
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("");
|
|
4030
|
+
} else {
|
|
4031
|
+
arrayDims = "";
|
|
4032
|
+
}
|
|
3928
4033
|
parameters.push({
|
|
3929
4034
|
name: paramName,
|
|
3930
4035
|
type: paramType,
|
|
@@ -5173,6 +5278,22 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5173
5278
|
const name = ctx.IDENTIFIER().getText();
|
|
5174
5279
|
const dims = ctx.arrayDimension();
|
|
5175
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
|
+
|
|
5176
5297
|
// ADR-029: Check if this is a callback type parameter
|
|
5177
5298
|
if (CodeGenState.callbackTypes.has(typeName)) {
|
|
5178
5299
|
const callbackInfo = CodeGenState.callbackTypes.get(typeName)!;
|
|
@@ -5181,17 +5302,40 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5181
5302
|
|
|
5182
5303
|
const type = this.generateType(ctx.type());
|
|
5183
5304
|
|
|
5184
|
-
//
|
|
5185
|
-
const
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5305
|
+
// Handle C-Next style array type in parameter (e.g., u8[8] param, u8[4][4] param, string<32>[5] param)
|
|
5306
|
+
const arrayTypeCtx = ctx.type().arrayType();
|
|
5307
|
+
if (arrayTypeCtx) {
|
|
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
|
+
}
|
|
5192
5319
|
|
|
5193
|
-
|
|
5194
|
-
|
|
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
|
+
}
|
|
5335
|
+
const wasModified = this._isCurrentParameterModified(name);
|
|
5336
|
+
const autoConst = !wasModified && !constMod ? "const " : "";
|
|
5337
|
+
return `${autoConst}${constMod}${type} ${name}${dims}`;
|
|
5338
|
+
}
|
|
5195
5339
|
|
|
5196
5340
|
// Pass-by-value types
|
|
5197
5341
|
if (this._isPassByValueType(typeName, name)) {
|
|
@@ -5215,46 +5359,6 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5215
5359
|
return `${constMod}${type} ${name}`;
|
|
5216
5360
|
}
|
|
5217
5361
|
|
|
5218
|
-
/**
|
|
5219
|
-
* Try to generate string array parameter: string<N>[] -> char arr[n][N+1]
|
|
5220
|
-
*/
|
|
5221
|
-
private _tryGenerateStringArrayParam(
|
|
5222
|
-
ctx: Parser.ParameterContext,
|
|
5223
|
-
constMod: string,
|
|
5224
|
-
name: string,
|
|
5225
|
-
dims: Parser.ArrayDimensionContext[],
|
|
5226
|
-
): string | null {
|
|
5227
|
-
if (!ctx.type().stringType() || dims.length === 0) {
|
|
5228
|
-
return null;
|
|
5229
|
-
}
|
|
5230
|
-
|
|
5231
|
-
const stringType = ctx.type().stringType()!;
|
|
5232
|
-
const capacity = stringType.INTEGER_LITERAL()
|
|
5233
|
-
? Number.parseInt(stringType.INTEGER_LITERAL()!.getText(), 10)
|
|
5234
|
-
: 256;
|
|
5235
|
-
const dimStr = dims.map((d) => this.generateArrayDimension(d)).join("");
|
|
5236
|
-
return `${constMod}char ${name}${dimStr}[${capacity + 1}]`;
|
|
5237
|
-
}
|
|
5238
|
-
|
|
5239
|
-
/**
|
|
5240
|
-
* Try to generate array parameter with auto-const
|
|
5241
|
-
*/
|
|
5242
|
-
private _tryGenerateArrayParam(
|
|
5243
|
-
constMod: string,
|
|
5244
|
-
type: string,
|
|
5245
|
-
name: string,
|
|
5246
|
-
dims: Parser.ArrayDimensionContext[],
|
|
5247
|
-
): string | null {
|
|
5248
|
-
if (dims.length === 0) {
|
|
5249
|
-
return null;
|
|
5250
|
-
}
|
|
5251
|
-
|
|
5252
|
-
const dimStr = dims.map((d) => this.generateArrayDimension(d)).join("");
|
|
5253
|
-
const wasModified = this._isCurrentParameterModified(name);
|
|
5254
|
-
const autoConst = !wasModified && !constMod ? "const " : "";
|
|
5255
|
-
return `${autoConst}${constMod}${type} ${name}${dimStr}`;
|
|
5256
|
-
}
|
|
5257
|
-
|
|
5258
5362
|
/**
|
|
5259
5363
|
* Check if type should use pass-by-value semantics
|
|
5260
5364
|
*/
|
|
@@ -5497,39 +5601,48 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5497
5601
|
}
|
|
5498
5602
|
|
|
5499
5603
|
/**
|
|
5500
|
-
* 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]").
|
|
5501
5605
|
* Evaluates const expressions to their numeric values for C compatibility.
|
|
5502
5606
|
*/
|
|
5503
5607
|
private _getArrayTypeDimension(typeCtx: Parser.TypeContext): string {
|
|
5504
5608
|
if (!typeCtx.arrayType()) {
|
|
5505
5609
|
return "";
|
|
5506
5610
|
}
|
|
5507
|
-
const
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
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}]`;
|
|
5515
5624
|
}
|
|
5516
|
-
|
|
5517
|
-
return `[${this.generateExpression(sizeExpr)}]`;
|
|
5625
|
+
return result;
|
|
5518
5626
|
}
|
|
5519
5627
|
|
|
5520
5628
|
/**
|
|
5521
|
-
* Parse array dimension from arrayType syntax for size validation.
|
|
5629
|
+
* Parse first array dimension from arrayType syntax for size validation.
|
|
5522
5630
|
*/
|
|
5523
5631
|
private _parseArrayTypeDimension(typeCtx: Parser.TypeContext): number | null {
|
|
5524
5632
|
if (!typeCtx.arrayType()) {
|
|
5525
5633
|
return null;
|
|
5526
5634
|
}
|
|
5527
|
-
const
|
|
5635
|
+
const dims = typeCtx.arrayType()!.arrayTypeDimension();
|
|
5636
|
+
if (dims.length === 0) {
|
|
5637
|
+
return null;
|
|
5638
|
+
}
|
|
5639
|
+
const sizeExpr = dims[0].expression();
|
|
5528
5640
|
if (!sizeExpr) {
|
|
5529
5641
|
return null;
|
|
5530
5642
|
}
|
|
5531
5643
|
const sizeText = sizeExpr.getText();
|
|
5532
|
-
|
|
5644
|
+
const digitRegex = /^\d+$/;
|
|
5645
|
+
if (digitRegex.exec(sizeText)) {
|
|
5533
5646
|
return Number.parseInt(sizeText, 10);
|
|
5534
5647
|
}
|
|
5535
5648
|
return null;
|
|
@@ -5814,6 +5927,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5814
5927
|
return "{}";
|
|
5815
5928
|
}
|
|
5816
5929
|
}
|
|
5930
|
+
// Also check C-Next style array type (e.g., CppClass[4]) where
|
|
5931
|
+
// the userType is nested inside arrayType.
|
|
5932
|
+
if (typeCtx.arrayType()?.userType()) {
|
|
5933
|
+
const typeName = typeCtx.arrayType()!.userType()!.getText();
|
|
5934
|
+
if (this._needsEmptyBraceInit(typeName)) {
|
|
5935
|
+
return "{}";
|
|
5936
|
+
}
|
|
5937
|
+
}
|
|
5817
5938
|
// Template types are always C++ classes
|
|
5818
5939
|
if (typeCtx.templateType()) {
|
|
5819
5940
|
return "{}";
|