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.
- package/grammar/CNext.g4 +9 -2
- package/package.json +5 -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__/TSymbolAdapter.test.ts +179 -0
- package/src/transpiler/logic/symbols/cnext/__tests__/VariableCollector.test.ts +55 -0
- package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +76 -8
- 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 +243 -166
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +1086 -0
- 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 +624 -12
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +819 -0
- package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +337 -0
- package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +135 -0
- package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +4 -0
- package/src/transpiler/output/codegen/helpers/VariableDeclarationFormatter.ts +118 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +426 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +315 -0
- package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclarationFormatter.test.ts +333 -0
- package/src/transpiler/output/codegen/types/IParameterInput.ts +58 -0
- package/src/transpiler/output/codegen/types/IVariableFormatInput.ts +51 -0
- package/src/transpiler/output/headers/BaseHeaderGenerator.ts +20 -35
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +21 -48
- 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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
2378
|
-
|
|
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
|
-
|
|
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
|
|
3600
|
-
const
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
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
|
-
|
|
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 =
|
|
3798
|
-
|
|
3799
|
-
|
|
3902
|
+
const arrayDimensions = this._extractParamArrayDimensions(
|
|
3903
|
+
param,
|
|
3904
|
+
typeCtx,
|
|
3905
|
+
isArray,
|
|
3906
|
+
);
|
|
3800
3907
|
|
|
3801
|
-
//
|
|
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
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
5194
|
-
|
|
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
|
-
//
|
|
5203
|
-
|
|
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
|
-
|
|
5212
|
-
|
|
5318
|
+
// Pre-compute CodeGenState-dependent values
|
|
5319
|
+
const isModified = this._isCurrentParameterModified(name);
|
|
5320
|
+
const isPassByValue = this._isPassByValueType(typeName, name);
|
|
5213
5321
|
|
|
5214
|
-
//
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
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
|
-
//
|
|
5233
|
-
return
|
|
5334
|
+
// Use shared builder with C/C++ mode
|
|
5335
|
+
return ParameterSignatureBuilder.build(input, CppModeHelper.refOrPtr());
|
|
5234
5336
|
}
|
|
5235
5337
|
|
|
5236
5338
|
/**
|
|
5237
|
-
*
|
|
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
|
|
5343
|
+
private _validateCStyleArrayParam(
|
|
5240
5344
|
ctx: Parser.ParameterContext,
|
|
5241
|
-
|
|
5345
|
+
typeName: string,
|
|
5242
5346
|
name: string,
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
if (
|
|
5246
|
-
|
|
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
|
-
*
|
|
5363
|
+
* Validate: Reject unbounded array dimensions for memory safety
|
|
5259
5364
|
*/
|
|
5260
|
-
private
|
|
5261
|
-
|
|
5262
|
-
|
|
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
|
|
5271
|
-
const
|
|
5272
|
-
|
|
5273
|
-
|
|
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
|
|
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
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
5626
|
+
const digitRegex = /^\d+$/;
|
|
5627
|
+
if (digitRegex.exec(sizeText)) {
|
|
5551
5628
|
return Number.parseInt(sizeText, 10);
|
|
5552
5629
|
}
|
|
5553
5630
|
return null;
|