c-next 0.1.64 → 0.1.66

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.
Files changed (33) hide show
  1. package/grammar/CNext.g4 +9 -2
  2. package/package.json +5 -1
  3. package/src/transpiler/logic/parser/grammar/CNext.interp +2 -1
  4. package/src/transpiler/logic/parser/grammar/CNextListener.ts +11 -0
  5. package/src/transpiler/logic/parser/grammar/CNextParser.ts +992 -870
  6. package/src/transpiler/logic/parser/grammar/CNextVisitor.ts +7 -0
  7. package/src/transpiler/logic/symbols/cnext/__tests__/FunctionCollector.test.ts +6 -6
  8. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +179 -0
  9. package/src/transpiler/logic/symbols/cnext/__tests__/VariableCollector.test.ts +55 -0
  10. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +76 -8
  11. package/src/transpiler/logic/symbols/cnext/collectors/FunctionCollector.ts +9 -10
  12. package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +7 -1
  13. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +33 -14
  14. package/src/transpiler/output/codegen/CodeGenerator.ts +243 -166
  15. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +1086 -0
  16. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +254 -22
  17. package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +17 -9
  18. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +5 -3
  19. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +12 -7
  20. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +624 -12
  21. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +819 -0
  22. package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +337 -0
  23. package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +135 -0
  24. package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +4 -0
  25. package/src/transpiler/output/codegen/helpers/VariableDeclarationFormatter.ts +118 -0
  26. package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +426 -0
  27. package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +315 -0
  28. package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclarationFormatter.test.ts +333 -0
  29. package/src/transpiler/output/codegen/types/IParameterInput.ts +58 -0
  30. package/src/transpiler/output/codegen/types/IVariableFormatInput.ts +51 -0
  31. package/src/transpiler/output/headers/BaseHeaderGenerator.ts +20 -35
  32. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +21 -48
  33. package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +0 -64
@@ -134,6 +134,9 @@ import TypeGenerationHelper from "./helpers/TypeGenerationHelper";
134
134
  import CastValidator from "./helpers/CastValidator";
135
135
  // Global state for code generation (simplifies debugging, eliminates DI complexity)
136
136
  import CodeGenState from "./CodeGenState";
137
+ // Unified parameter generation (Phase 1)
138
+ import ParameterInputAdapter from "./helpers/ParameterInputAdapter";
139
+ import ParameterSignatureBuilder from "./helpers/ParameterSignatureBuilder";
137
140
  // Extracted resolvers that use CodeGenState
138
141
  import SizeofResolver from "./resolution/SizeofResolver";
139
142
  import EnumTypeResolver from "./resolution/EnumTypeResolver";
@@ -802,30 +805,54 @@ export default class CodeGenerator implements IOrchestrator {
802
805
  }
803
806
 
804
807
  // Issue #137: Check for array element access (e.g., names[0], arr[i])
808
+ return this._isArrayAccessStringExpression(text);
809
+ }
810
+
811
+ /**
812
+ * Check if array access expression evaluates to a string.
813
+ * Extracted from isStringExpression to reduce cognitive complexity.
814
+ */
815
+ private _isArrayAccessStringExpression(text: string): boolean {
805
816
  // Pattern: identifier[expression] or identifier[expression][expression]...
806
817
  // BUT NOT if accessing .length/.capacity/.size (those return numbers, not strings)
807
818
  const arrayAccessMatch = /^([a-zA-Z_]\w*)\[/.exec(text);
808
- if (arrayAccessMatch) {
809
- // ADR-045: String properties return numeric values, not strings
810
- if (
811
- text.endsWith(".length") ||
812
- text.endsWith(".capacity") ||
813
- text.endsWith(".size")
814
- ) {
815
- return false;
816
- }
817
- const arrayName = arrayAccessMatch[1];
818
- const typeInfo = CodeGenState.typeRegistry.get(arrayName);
819
- // Check if base type is a string type
820
- if (
821
- typeInfo?.isString ||
822
- (typeInfo?.baseType && TypeCheckUtils.isString(typeInfo.baseType))
823
- ) {
824
- return true;
825
- }
819
+ if (!arrayAccessMatch) {
820
+ return false;
826
821
  }
827
822
 
828
- return false;
823
+ // ADR-045: String properties return numeric values, not strings
824
+ if (
825
+ text.endsWith(".length") ||
826
+ text.endsWith(".capacity") ||
827
+ text.endsWith(".size")
828
+ ) {
829
+ return false;
830
+ }
831
+
832
+ const arrayName = arrayAccessMatch[1];
833
+ const typeInfo = CodeGenState.typeRegistry.get(arrayName);
834
+ if (!typeInfo) {
835
+ return false;
836
+ }
837
+
838
+ // Check if it's an ARRAY OF STRINGS (not a single string being indexed)
839
+ // A single string<50> has arrayDimensions=[51] (just the char buffer)
840
+ // An array of strings string<50>[10] has arrayDimensions=[10, 51]
841
+ // Single string indexing (e.g., userName[i]) returns a char, not a string
842
+ // Array of strings indexing (e.g., names[0]) returns a string
843
+ if (typeInfo.isString) {
844
+ // For strings, only treat as string expression if it's an array of strings
845
+ // (arrayDimensions.length > 1 means it's string<N>[M], not just string<N>)
846
+ const dims = typeInfo.arrayDimensions;
847
+ return Array.isArray(dims) && dims.length > 1;
848
+ }
849
+
850
+ // Non-string array with string base type
851
+ return Boolean(
852
+ typeInfo.isArray &&
853
+ typeInfo.baseType &&
854
+ TypeCheckUtils.isString(typeInfo.baseType),
855
+ );
829
856
  }
830
857
 
831
858
  /**
@@ -1505,7 +1532,9 @@ export default class CodeGenerator implements IOrchestrator {
1505
1532
  return `${constMod}${p.type} ${p.name}${p.arrayDims}`;
1506
1533
  } else if (p.isPointer) {
1507
1534
  // ADR-006: Non-array, non-callback parameters become pointers
1508
- return `${constMod}${p.type}*`;
1535
+ // In C++ mode, use reference (&) instead of pointer (*)
1536
+ const ptrOrRef = this.isCppMode() ? "&" : "*";
1537
+ return `${constMod}${p.type}${ptrOrRef}`;
1509
1538
  } else {
1510
1539
  // ADR-029: Callback parameters are already function pointers
1511
1540
  return `${p.type}`;
@@ -2373,9 +2402,13 @@ export default class CodeGenerator implements IOrchestrator {
2373
2402
  */
2374
2403
  private addGeneratedHelpers(output: string[]): void {
2375
2404
  if (CodeGenState.needsFloatStaticAssert) {
2405
+ // Use static_assert for C++ (standard), _Static_assert for C11
2406
+ const assertKeyword = this.isCppMode()
2407
+ ? "static_assert"
2408
+ : "_Static_assert";
2376
2409
  output.push(
2377
- '_Static_assert(sizeof(float) == 4, "Float bit indexing requires 32-bit float");',
2378
- '_Static_assert(sizeof(double) == 8, "Float bit indexing requires 64-bit double");',
2410
+ `${assertKeyword}(sizeof(float) == 4, "Float bit indexing requires 32-bit float");`,
2411
+ `${assertKeyword}(sizeof(double) == 8, "Float bit indexing requires 64-bit double");`,
2379
2412
  "",
2380
2413
  );
2381
2414
  }
@@ -3579,7 +3612,12 @@ export default class CodeGenerator implements IOrchestrator {
3579
3612
  private _parseArrayTypeDimensionFromCtx(
3580
3613
  arrayTypeCtx: Parser.ArrayTypeContext,
3581
3614
  ): number | undefined {
3582
- const sizeExpr = arrayTypeCtx.expression();
3615
+ // Get first dimension for backwards compatibility
3616
+ const dims = arrayTypeCtx.arrayTypeDimension();
3617
+ if (dims.length === 0) {
3618
+ return undefined;
3619
+ }
3620
+ const sizeExpr = dims[0].expression();
3583
3621
  if (!sizeExpr) {
3584
3622
  return undefined;
3585
3623
  }
@@ -3596,12 +3634,14 @@ export default class CodeGenerator implements IOrchestrator {
3596
3634
  ): number[] {
3597
3635
  const arrayDimensions: number[] = [];
3598
3636
 
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);
3637
+ // Get all dimensions from array type syntax (supports multi-dimensional)
3638
+ for (const dim of arrayTypeCtx.arrayTypeDimension()) {
3639
+ const sizeExpr = dim.expression();
3640
+ if (sizeExpr) {
3641
+ const size = Number.parseInt(sizeExpr.getText(), 10);
3642
+ if (!Number.isNaN(size)) {
3643
+ arrayDimensions.push(size);
3644
+ }
3605
3645
  }
3606
3646
  }
3607
3647
 
@@ -3671,7 +3711,9 @@ export default class CodeGenerator implements IOrchestrator {
3671
3711
  */
3672
3712
  private _processParameter(param: Parser.ParameterContext): void {
3673
3713
  const name = param.IDENTIFIER().getText();
3674
- const isArray = param.arrayDimension().length > 0;
3714
+ // Check both C-Next style (u8[8] param) and legacy style (u8 param[8])
3715
+ const isArray =
3716
+ param.arrayDimension().length > 0 || param.type().arrayType() !== null;
3675
3717
  const isConst = param.constModifier() !== null;
3676
3718
  const typeCtx = param.type();
3677
3719
 
@@ -3768,6 +3810,38 @@ export default class CodeGenerator implements IOrchestrator {
3768
3810
  };
3769
3811
  }
3770
3812
 
3813
+ // Handle C-Next style array type (u8[8] param) - extract base type
3814
+ if (typeCtx.arrayType()) {
3815
+ const arrayTypeCtx = typeCtx.arrayType()!;
3816
+ if (arrayTypeCtx.primitiveType()) {
3817
+ return {
3818
+ typeName: arrayTypeCtx.primitiveType()!.getText(),
3819
+ isStruct: false,
3820
+ isCallback: false,
3821
+ isString: false,
3822
+ };
3823
+ }
3824
+ if (arrayTypeCtx.userType()) {
3825
+ const typeName = arrayTypeCtx.userType()!.getText();
3826
+ return {
3827
+ typeName,
3828
+ isStruct: this.isStructType(typeName),
3829
+ isCallback: CodeGenState.callbackTypes.has(typeName),
3830
+ isString: false,
3831
+ };
3832
+ }
3833
+ // Handle string array type (string<32>[5] param)
3834
+ if (arrayTypeCtx.stringType()) {
3835
+ const stringCtx = arrayTypeCtx.stringType()!;
3836
+ return {
3837
+ typeName: stringCtx.getText(), // "string<32>"
3838
+ isStruct: false,
3839
+ isCallback: false,
3840
+ isString: true,
3841
+ };
3842
+ }
3843
+ }
3844
+
3771
3845
  // Fallback
3772
3846
  return {
3773
3847
  typeName: typeCtx.getText(),
@@ -3777,6 +3851,37 @@ export default class CodeGenerator implements IOrchestrator {
3777
3851
  };
3778
3852
  }
3779
3853
 
3854
+ /**
3855
+ * Extract array dimensions from parameter (C-style or C-Next style).
3856
+ */
3857
+ private _extractParamArrayDimensions(
3858
+ param: Parser.ParameterContext,
3859
+ typeCtx: Parser.TypeContext,
3860
+ isArray: boolean,
3861
+ ): number[] {
3862
+ if (!isArray) return [];
3863
+
3864
+ // Try C-style first (param.arrayDimension())
3865
+ if (param.arrayDimension().length > 0) {
3866
+ return ArrayDimensionParser.parseForParameters(param.arrayDimension());
3867
+ }
3868
+
3869
+ // C-Next style: get dimensions from arrayType
3870
+ const arrayTypeCtx = typeCtx.arrayType();
3871
+ if (!arrayTypeCtx) return [];
3872
+
3873
+ const dimensions: number[] = [];
3874
+ for (const dim of arrayTypeCtx.arrayTypeDimension()) {
3875
+ const expr = dim.expression();
3876
+ if (!expr) continue;
3877
+ const size = Number.parseInt(expr.getText(), 10);
3878
+ if (!Number.isNaN(size)) {
3879
+ dimensions.push(size);
3880
+ }
3881
+ }
3882
+ return dimensions;
3883
+ }
3884
+
3780
3885
  /**
3781
3886
  * Register a parameter in the type registry
3782
3887
  */
@@ -3794,11 +3899,13 @@ export default class CodeGenerator implements IOrchestrator {
3794
3899
  const isBitmap = CodeGenState.symbols!.knownBitmaps.has(typeName);
3795
3900
 
3796
3901
  // Extract array dimensions
3797
- const arrayDimensions = isArray
3798
- ? ArrayDimensionParser.parseForParameters(param.arrayDimension())
3799
- : [];
3902
+ const arrayDimensions = this._extractParamArrayDimensions(
3903
+ param,
3904
+ typeCtx,
3905
+ isArray,
3906
+ );
3800
3907
 
3801
- // Get string capacity if applicable
3908
+ // Add string capacity dimension if applicable
3802
3909
  const stringCapacity = this._getStringCapacity(typeCtx, isString);
3803
3910
  if (isArray && stringCapacity !== undefined) {
3804
3911
  arrayDimensions.push(stringCapacity + 1);
@@ -3830,10 +3937,25 @@ export default class CodeGenerator implements IOrchestrator {
3830
3937
  typeCtx: Parser.TypeContext,
3831
3938
  isString: boolean,
3832
3939
  ): 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);
3940
+ if (!isString) return undefined;
3941
+
3942
+ // Check direct stringType (e.g., string<32> param)
3943
+ if (typeCtx.stringType()) {
3944
+ const intLiteral = typeCtx.stringType()!.INTEGER_LITERAL();
3945
+ if (intLiteral) {
3946
+ return Number.parseInt(intLiteral.getText(), 10);
3947
+ }
3948
+ }
3949
+
3950
+ // Check arrayType with stringType (e.g., string<32>[5] param)
3951
+ if (typeCtx.arrayType()?.stringType()) {
3952
+ const intLiteral = typeCtx.arrayType()!.stringType()!.INTEGER_LITERAL();
3953
+ if (intLiteral) {
3954
+ return Number.parseInt(intLiteral.getText(), 10);
3955
+ }
3956
+ }
3957
+
3958
+ return undefined;
3837
3959
  }
3838
3960
 
3839
3961
  /**
@@ -3930,7 +4052,14 @@ export default class CodeGenerator implements IOrchestrator {
3930
4052
  if (dims.length > 0) {
3931
4053
  arrayDims = dims.map((d) => this.generateArrayDimension(d)).join("");
3932
4054
  } else if (arrayTypeCtx) {
3933
- arrayDims = `[${this.generateExpression(arrayTypeCtx.expression())}]`;
4055
+ // Generate all dimensions from arrayType (supports multi-dimensional)
4056
+ arrayDims = arrayTypeCtx
4057
+ .arrayTypeDimension()
4058
+ .map((d) => {
4059
+ const expr = d.expression();
4060
+ return expr ? `[${this.generateExpression(expr)}]` : "[]";
4061
+ })
4062
+ .join("");
3934
4063
  } else {
3935
4064
  arrayDims = "";
3936
4065
  }
@@ -5177,100 +5306,76 @@ export default class CodeGenerator implements IOrchestrator {
5177
5306
  }
5178
5307
 
5179
5308
  private generateParameter(ctx: Parser.ParameterContext): string {
5180
- const constMod = ctx.constModifier() ? "const " : "";
5181
5309
  const typeName = this.getTypeName(ctx.type());
5182
5310
  const name = ctx.IDENTIFIER().getText();
5183
- const dims = ctx.arrayDimension();
5184
-
5185
- // ADR-029: Check if this is a callback type parameter
5186
- if (CodeGenState.callbackTypes.has(typeName)) {
5187
- const callbackInfo = CodeGenState.callbackTypes.get(typeName)!;
5188
- return `${callbackInfo.typedefName} ${name}`;
5189
- }
5190
-
5191
- const type = this.generateType(ctx.type());
5192
5311
 
5193
- // Handle C-Next style array type in parameter (e.g., u8[8] param)
5194
- const arrayTypeCtx = ctx.type().arrayType();
5195
- if (arrayTypeCtx) {
5196
- const dimExpr = this.generateExpression(arrayTypeCtx.expression());
5197
- const wasModified = this._isCurrentParameterModified(name);
5198
- const autoConst = !wasModified && !constMod ? "const " : "";
5199
- return `${autoConst}${constMod}${type} ${name}[${dimExpr}]`;
5200
- }
5312
+ // Validate: Reject C-style array parameters
5313
+ this._validateCStyleArrayParam(ctx, typeName, name);
5201
5314
 
5202
- // Try special cases first
5203
- const stringArrayResult = this._tryGenerateStringArrayParam(
5204
- ctx,
5205
- constMod,
5206
- name,
5207
- dims,
5208
- );
5209
- if (stringArrayResult) return stringArrayResult;
5315
+ // Validate: Reject unbounded array dimensions
5316
+ this._validateUnboundedArrayParam(ctx);
5210
5317
 
5211
- const arrayResult = this._tryGenerateArrayParam(constMod, type, name, dims);
5212
- if (arrayResult) return arrayResult;
5318
+ // Pre-compute CodeGenState-dependent values
5319
+ const isModified = this._isCurrentParameterModified(name);
5320
+ const isPassByValue = this._isPassByValueType(typeName, name);
5213
5321
 
5214
- // Pass-by-value types
5215
- if (this._isPassByValueType(typeName, name)) {
5216
- return `${constMod}${type} ${name}`;
5217
- }
5218
-
5219
- // Non-array string parameters
5220
- const stringResult = this._tryGenerateStringParam(
5221
- ctx,
5222
- constMod,
5223
- name,
5224
- dims,
5225
- );
5226
- if (stringResult) return stringResult;
5227
-
5228
- // Pass-by-reference types
5229
- const refResult = this._tryGenerateRefParam(constMod, type, typeName, name);
5230
- if (refResult) return refResult;
5322
+ // Build normalized input using adapter
5323
+ const input = ParameterInputAdapter.fromAST(ctx, {
5324
+ getTypeName: (t) => this.getTypeName(t),
5325
+ generateType: (t) => this.generateType(t),
5326
+ generateExpression: (e) => this.generateExpression(e),
5327
+ callbackTypes: CodeGenState.callbackTypes,
5328
+ isKnownStruct: (t) => this.isKnownStruct(t),
5329
+ typeMap: TYPE_MAP,
5330
+ isModified,
5331
+ isPassByValue,
5332
+ });
5231
5333
 
5232
- // Unknown types use pass-by-value (standard C semantics)
5233
- return `${constMod}${type} ${name}`;
5334
+ // Use shared builder with C/C++ mode
5335
+ return ParameterSignatureBuilder.build(input, CppModeHelper.refOrPtr());
5234
5336
  }
5235
5337
 
5236
5338
  /**
5237
- * Try to generate string array parameter: string<N>[] -> char arr[n][N+1]
5339
+ * Validate: Reject C-style array parameters
5340
+ * C-style: u8 data[8], u8 data[4][4], u8 data[]
5341
+ * C-Next: u8[8] data, u8[4][4] data, u8[] data
5238
5342
  */
5239
- private _tryGenerateStringArrayParam(
5343
+ private _validateCStyleArrayParam(
5240
5344
  ctx: Parser.ParameterContext,
5241
- constMod: string,
5345
+ typeName: string,
5242
5346
  name: string,
5243
- dims: Parser.ArrayDimensionContext[],
5244
- ): string | null {
5245
- if (!ctx.type().stringType() || dims.length === 0) {
5246
- return null;
5347
+ ): void {
5348
+ const dims = ctx.arrayDimension();
5349
+ if (dims.length > 0) {
5350
+ const dimensions = dims
5351
+ .map((dim) => `[${dim.expression()?.getText() ?? ""}]`)
5352
+ .join("");
5353
+ const line = ctx.start?.line ?? 0;
5354
+ const col = ctx.start?.column ?? 0;
5355
+ throw new Error(
5356
+ `${line}:${col} C-style array parameter is not allowed. ` +
5357
+ `Use '${typeName}${dimensions} ${name}' instead of '${typeName} ${name}${dimensions}'`,
5358
+ );
5247
5359
  }
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
5360
  }
5256
5361
 
5257
5362
  /**
5258
- * Try to generate array parameter with auto-const
5363
+ * Validate: Reject unbounded array dimensions for memory safety
5259
5364
  */
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
- }
5365
+ private _validateUnboundedArrayParam(ctx: Parser.ParameterContext): void {
5366
+ const arrayTypeCtx = ctx.type().arrayType();
5367
+ if (!arrayTypeCtx) return;
5269
5368
 
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}`;
5369
+ const allDims = arrayTypeCtx.arrayTypeDimension();
5370
+ const hasUnboundedDim = allDims.some((d) => !d.expression());
5371
+ if (hasUnboundedDim) {
5372
+ const line = ctx.start?.line ?? 0;
5373
+ const col = ctx.start?.column ?? 0;
5374
+ throw new Error(
5375
+ `${line}:${col} Unbounded array parameters are not allowed. ` +
5376
+ `All dimensions must have explicit sizes for memory safety.`,
5377
+ );
5378
+ }
5274
5379
  }
5275
5380
 
5276
5381
  /**
@@ -5280,7 +5385,7 @@ export default class CodeGenerator implements IOrchestrator {
5280
5385
  // ISR, float, enum types
5281
5386
  if (typeName === "ISR") return true;
5282
5387
  if (this._isFloatType(typeName)) return true;
5283
- if (CodeGenState.symbols!.knownEnums.has(typeName)) return true;
5388
+ if (CodeGenState.symbols?.knownEnums.has(typeName)) return true;
5284
5389
 
5285
5390
  // Small unmodified primitives
5286
5391
  if (
@@ -5293,43 +5398,6 @@ export default class CodeGenerator implements IOrchestrator {
5293
5398
  return false;
5294
5399
  }
5295
5400
 
5296
- /**
5297
- * Try to generate non-array string parameter: string<N> -> char*
5298
- */
5299
- private _tryGenerateStringParam(
5300
- ctx: Parser.ParameterContext,
5301
- constMod: string,
5302
- name: string,
5303
- dims: Parser.ArrayDimensionContext[],
5304
- ): string | null {
5305
- if (!ctx.type().stringType() || dims.length !== 0) {
5306
- return null;
5307
- }
5308
-
5309
- const wasModified = this._isCurrentParameterModified(name);
5310
- const autoConst = !wasModified && !constMod ? "const " : "";
5311
- return `${autoConst}${constMod}char* ${name}`;
5312
- }
5313
-
5314
- /**
5315
- * Try to generate pass-by-reference parameter for known types
5316
- */
5317
- private _tryGenerateRefParam(
5318
- constMod: string,
5319
- type: string,
5320
- typeName: string,
5321
- name: string,
5322
- ): string | null {
5323
- if (!this.isKnownStruct(typeName) && !this._isKnownPrimitive(typeName)) {
5324
- return null;
5325
- }
5326
-
5327
- const wasModified = this._isCurrentParameterModified(name);
5328
- const autoConst = !wasModified && !constMod ? "const " : "";
5329
- const refOrPtr = CppModeHelper.refOrPtr();
5330
- return `${autoConst}${constMod}${type}${refOrPtr} ${name}`;
5331
- }
5332
-
5333
5401
  // ========================================================================
5334
5402
  // Variables
5335
5403
  // ========================================================================
@@ -5515,39 +5583,48 @@ export default class CodeGenerator implements IOrchestrator {
5515
5583
  }
5516
5584
 
5517
5585
  /**
5518
- * Get array dimension string from arrayType syntax (u16[8] -> "[8]").
5586
+ * Get array dimension string from arrayType syntax (u16[8] -> "[8]", u16[4][4] -> "[4][4]").
5519
5587
  * Evaluates const expressions to their numeric values for C compatibility.
5520
5588
  */
5521
5589
  private _getArrayTypeDimension(typeCtx: Parser.TypeContext): string {
5522
5590
  if (!typeCtx.arrayType()) {
5523
5591
  return "";
5524
5592
  }
5525
- const sizeExpr = typeCtx.arrayType()!.expression();
5526
- if (!sizeExpr) {
5527
- return "[]";
5528
- }
5529
- // Try to evaluate as constant first (required for C file-scope arrays)
5530
- const constValue = this.tryEvaluateConstant(sizeExpr);
5531
- if (constValue !== undefined) {
5532
- return `[${constValue}]`;
5593
+ const dims = typeCtx.arrayType()!.arrayTypeDimension();
5594
+ let result = "";
5595
+ for (const dim of dims) {
5596
+ const sizeExpr = dim.expression();
5597
+ if (!sizeExpr) {
5598
+ result += "[]";
5599
+ continue;
5600
+ }
5601
+ // Try to evaluate as constant first (required for C file-scope arrays)
5602
+ // Fall back to expression text for macros, enums, etc.
5603
+ const dimValue =
5604
+ this.tryEvaluateConstant(sizeExpr) ?? this.generateExpression(sizeExpr);
5605
+ result += `[${dimValue}]`;
5533
5606
  }
5534
- // Fall back to expression text (for macros, enums, etc.)
5535
- return `[${this.generateExpression(sizeExpr)}]`;
5607
+ return result;
5536
5608
  }
5537
5609
 
5538
5610
  /**
5539
- * Parse array dimension from arrayType syntax for size validation.
5611
+ * Parse first array dimension from arrayType syntax for size validation.
5540
5612
  */
5541
5613
  private _parseArrayTypeDimension(typeCtx: Parser.TypeContext): number | null {
5542
5614
  if (!typeCtx.arrayType()) {
5543
5615
  return null;
5544
5616
  }
5545
- const sizeExpr = typeCtx.arrayType()!.expression();
5617
+ const dims = typeCtx.arrayType()!.arrayTypeDimension();
5618
+ if (dims.length === 0) {
5619
+ return null;
5620
+ }
5621
+ const sizeExpr = dims[0].expression();
5546
5622
  if (!sizeExpr) {
5547
5623
  return null;
5548
5624
  }
5549
5625
  const sizeText = sizeExpr.getText();
5550
- if (/^\d+$/.exec(sizeText)) {
5626
+ const digitRegex = /^\d+$/;
5627
+ if (digitRegex.exec(sizeText)) {
5551
5628
  return Number.parseInt(sizeText, 10);
5552
5629
  }
5553
5630
  return null;