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.
@@ -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 buffer[256]) {
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 matrix[4][4]) {
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
- const arrayDims = p.arrayDimension();
74
- const isArray = arrayDims.length > 0;
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 as strings (can contain expressions like SIZE)
77
+ // Extract array dimensions from arrayType syntax (supports multi-dimensional)
77
78
  const arrayDimensions: string[] = [];
78
- if (isArray) {
79
- for (const dim of arrayDims) {
80
- const text = dim.getText();
81
- const regex = /\[([^\]]*)\]/;
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
- const sizeExpr = arrayTypeCtx.expression();
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 dimension from arrayType syntax (u16[8] arr)
139
+ // Collect dimensions from arrayType syntax (u16[8] arr, u16[4][4] arr, u16[] arr)
114
140
  if (hasArrayTypeSyntax) {
115
- const sizeExpr = arrayTypeCtx.expression();
116
- if (sizeExpr) {
117
- const dimText = sizeExpr.getText();
118
- const literalSize = LiteralUtils.parseIntegerLiteral(dimText);
119
- if (literalSize !== undefined) {
120
- arrayDimensions.push(literalSize);
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
- const sizeExpr = arrayTypeCtx.expression();
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 dimension from array type syntax
3600
- const sizeExpr = arrayTypeCtx.expression();
3601
- if (sizeExpr) {
3602
- const size = Number.parseInt(sizeExpr.getText(), 10);
3603
- if (!Number.isNaN(size)) {
3604
- arrayDimensions.push(size);
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
- const isArray = param.arrayDimension().length > 0;
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 = isArray
3798
- ? ArrayDimensionParser.parseForParameters(param.arrayDimension())
3799
- : [];
3869
+ const arrayDimensions = this._extractParamArrayDimensions(
3870
+ param,
3871
+ typeCtx,
3872
+ isArray,
3873
+ );
3800
3874
 
3801
- // Get string capacity if applicable
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 || !typeCtx.stringType()) return undefined;
3834
- const intLiteral = typeCtx.stringType()!.INTEGER_LITERAL();
3835
- if (!intLiteral) return undefined;
3836
- return Number.parseInt(intLiteral.getText(), 10);
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
- const isArray = param.arrayDimension().length > 0;
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 isArray = dims.length > 0;
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
- const arrayDims = isArray
3926
- ? dims.map((d) => this.generateArrayDimension(d)).join("")
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
- // Try special cases first
5185
- const stringArrayResult = this._tryGenerateStringArrayParam(
5186
- ctx,
5187
- constMod,
5188
- name,
5189
- dims,
5190
- );
5191
- if (stringArrayResult) return stringArrayResult;
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
- const arrayResult = this._tryGenerateArrayParam(constMod, type, name, dims);
5194
- if (arrayResult) return arrayResult;
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 sizeExpr = typeCtx.arrayType()!.expression();
5508
- if (!sizeExpr) {
5509
- return "[]";
5510
- }
5511
- // Try to evaluate as constant first (required for C file-scope arrays)
5512
- const constValue = this.tryEvaluateConstant(sizeExpr);
5513
- if (constValue !== undefined) {
5514
- return `[${constValue}]`;
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
- // Fall back to expression text (for macros, enums, etc.)
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 sizeExpr = typeCtx.arrayType()!.expression();
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
- if (/^\d+$/.exec(sizeText)) {
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 "{}";