c-next 0.1.62 → 0.1.63
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/README.md +86 -63
- package/package.json +1 -1
- package/src/transpiler/Transpiler.ts +3 -2
- package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
- package/src/transpiler/__tests__/Transpiler.coverage.test.ts +1 -1
- package/src/transpiler/__tests__/Transpiler.test.ts +0 -23
- package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
- package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
- package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
- package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
- package/src/transpiler/output/codegen/CodeGenerator.ts +817 -1377
- package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
- package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
- package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +326 -60
- package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
- package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
- package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +39 -43
- package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +52 -55
- package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +122 -62
- package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +143 -126
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +287 -320
- package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
- package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
- package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +121 -51
- package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
- package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
- package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +21 -30
- package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +56 -53
- package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
- package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
- package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
- package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
- package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
- package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
- package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
- package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
- package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
- package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
- package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
- package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
- package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
|
@@ -9,29 +9,18 @@
|
|
|
9
9
|
* 2. memcpy float → shadow (if not already current)
|
|
10
10
|
* 3. Modify shadow bits
|
|
11
11
|
* 4. memcpy shadow → float
|
|
12
|
+
*
|
|
13
|
+
* Migrated to use CodeGenState instead of constructor DI.
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
16
|
import TTypeInfo from "../types/TTypeInfo.js";
|
|
15
17
|
import TIncludeHeader from "../generators/TIncludeHeader.js";
|
|
18
|
+
import CodeGenState from "../CodeGenState.js";
|
|
16
19
|
|
|
17
20
|
/**
|
|
18
|
-
*
|
|
19
|
-
*/
|
|
20
|
-
interface IFloatBitState {
|
|
21
|
-
/** Shadow variables already declared in current scope */
|
|
22
|
-
floatBitShadows: Set<string>;
|
|
23
|
-
/** Shadows that currently hold the float's value (skip redundant memcpy read) */
|
|
24
|
-
floatShadowCurrent: Set<string>;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Dependencies required for float bit write generation.
|
|
21
|
+
* Callback types for code generation operations.
|
|
29
22
|
*/
|
|
30
|
-
interface
|
|
31
|
-
/** Whether we're generating C++ code */
|
|
32
|
-
cppMode: boolean;
|
|
33
|
-
/** Float bit shadow tracking state */
|
|
34
|
-
state: IFloatBitState;
|
|
23
|
+
interface IFloatBitCallbacks {
|
|
35
24
|
/** Generate a bit mask expression */
|
|
36
25
|
generateBitMask: (width: string, is64Bit?: boolean) => string;
|
|
37
26
|
/** Fold boolean expressions to 0/1 integer */
|
|
@@ -47,12 +36,6 @@ interface IFloatBitHelperDeps {
|
|
|
47
36
|
* For bit range: width is provided, uses bitIndex as start position
|
|
48
37
|
*/
|
|
49
38
|
class FloatBitHelper {
|
|
50
|
-
private readonly deps: IFloatBitHelperDeps;
|
|
51
|
-
|
|
52
|
-
constructor(deps: IFloatBitHelperDeps) {
|
|
53
|
-
this.deps = deps;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
39
|
/**
|
|
57
40
|
* Generate float bit write using shadow variable + memcpy.
|
|
58
41
|
* Returns null if typeInfo is not a float type.
|
|
@@ -62,14 +45,16 @@ class FloatBitHelper {
|
|
|
62
45
|
* @param bitIndex - Bit index expression (start position)
|
|
63
46
|
* @param width - Bit width expression (null for single bit)
|
|
64
47
|
* @param value - Value to write
|
|
48
|
+
* @param callbacks - Code generation callbacks
|
|
65
49
|
* @returns Generated C code, or null if not a float type
|
|
66
50
|
*/
|
|
67
|
-
generateFloatBitWrite(
|
|
51
|
+
static generateFloatBitWrite(
|
|
68
52
|
name: string,
|
|
69
53
|
typeInfo: TTypeInfo,
|
|
70
54
|
bitIndex: string,
|
|
71
55
|
width: string | null,
|
|
72
56
|
value: string,
|
|
57
|
+
callbacks: IFloatBitCallbacks,
|
|
73
58
|
): string | null {
|
|
74
59
|
const isFloatType =
|
|
75
60
|
typeInfo.baseType === "f32" || typeInfo.baseType === "f64";
|
|
@@ -77,8 +62,8 @@ class FloatBitHelper {
|
|
|
77
62
|
return null;
|
|
78
63
|
}
|
|
79
64
|
|
|
80
|
-
|
|
81
|
-
|
|
65
|
+
callbacks.requireInclude("string"); // For memcpy
|
|
66
|
+
callbacks.requireInclude("float_static_assert"); // For size verification
|
|
82
67
|
|
|
83
68
|
const isF64 = typeInfo.baseType === "f64";
|
|
84
69
|
const shadowType = isF64 ? "uint64_t" : "uint32_t";
|
|
@@ -86,13 +71,13 @@ class FloatBitHelper {
|
|
|
86
71
|
const maskSuffix = isF64 ? "ULL" : "U";
|
|
87
72
|
|
|
88
73
|
// Check if shadow variable needs declaration
|
|
89
|
-
const needsDeclaration = !
|
|
74
|
+
const needsDeclaration = !CodeGenState.floatBitShadows.has(shadowName);
|
|
90
75
|
if (needsDeclaration) {
|
|
91
|
-
|
|
76
|
+
CodeGenState.floatBitShadows.add(shadowName);
|
|
92
77
|
}
|
|
93
78
|
|
|
94
79
|
// Check if shadow already has current value (skip redundant memcpy read)
|
|
95
|
-
const shadowIsCurrent =
|
|
80
|
+
const shadowIsCurrent = CodeGenState.floatShadowCurrent.has(shadowName);
|
|
96
81
|
|
|
97
82
|
const decl = needsDeclaration ? `${shadowType} ${shadowName}; ` : "";
|
|
98
83
|
const readMemcpy = shadowIsCurrent
|
|
@@ -100,18 +85,18 @@ class FloatBitHelper {
|
|
|
100
85
|
: `memcpy(&${shadowName}, &${name}, sizeof(${name})); `;
|
|
101
86
|
|
|
102
87
|
// Mark shadow as current after this write
|
|
103
|
-
|
|
88
|
+
CodeGenState.floatShadowCurrent.add(shadowName);
|
|
104
89
|
|
|
105
90
|
if (width === null) {
|
|
106
91
|
// Single bit assignment: floatVar[3] <- true
|
|
107
92
|
return (
|
|
108
93
|
`${decl}${readMemcpy}` +
|
|
109
|
-
`${shadowName} = (${shadowName} & ~(1${maskSuffix} << ${bitIndex})) | ((${shadowType})${
|
|
94
|
+
`${shadowName} = (${shadowName} & ~(1${maskSuffix} << ${bitIndex})) | ((${shadowType})${callbacks.foldBooleanToInt(value)} << ${bitIndex}); ` +
|
|
110
95
|
`memcpy(&${name}, &${shadowName}, sizeof(${name}));`
|
|
111
96
|
);
|
|
112
97
|
} else {
|
|
113
98
|
// Bit range assignment: floatVar[0, 8] <- b0
|
|
114
|
-
const mask =
|
|
99
|
+
const mask = callbacks.generateBitMask(width, isF64);
|
|
115
100
|
return (
|
|
116
101
|
`${decl}${readMemcpy}` +
|
|
117
102
|
`${shadowName} = (${shadowName} & ~(${mask} << ${bitIndex})) | (((${shadowType})${value} & ${mask}) << ${bitIndex}); ` +
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* StringDeclHelper - Generates string variable declarations
|
|
3
3
|
*
|
|
4
4
|
* Issue #644: Extracted from CodeGenerator to reduce file size.
|
|
5
|
+
* Migrated to use CodeGenState instead of constructor DI.
|
|
5
6
|
*
|
|
6
7
|
* Handles all string-related declaration patterns:
|
|
7
8
|
* - Bounded strings: string<64> name
|
|
@@ -13,7 +14,8 @@
|
|
|
13
14
|
|
|
14
15
|
import * as Parser from "../../../logic/parser/grammar/CNextParser.js";
|
|
15
16
|
import FormatUtils from "../../../../utils/FormatUtils.js";
|
|
16
|
-
import
|
|
17
|
+
import StringUtils from "../../../../utils/StringUtils.js";
|
|
18
|
+
import CodeGenState from "../CodeGenState.js";
|
|
17
19
|
|
|
18
20
|
/** C null terminator character literal for generated code */
|
|
19
21
|
const C_NULL_CHAR = String.raw`'\0'`;
|
|
@@ -39,27 +41,30 @@ interface ISubstringOps {
|
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
/**
|
|
42
|
-
*
|
|
44
|
+
* Declaration modifiers for string variable declarations.
|
|
43
45
|
*/
|
|
44
|
-
interface
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
interface IStringDeclModifiers {
|
|
47
|
+
extern: string;
|
|
48
|
+
const: string;
|
|
49
|
+
atomic: string;
|
|
50
|
+
volatile: string;
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
/**
|
|
50
|
-
*
|
|
54
|
+
* Result from generating a string declaration.
|
|
51
55
|
*/
|
|
52
|
-
interface
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
interface IStringDeclResult {
|
|
57
|
+
/** The generated C code */
|
|
58
|
+
code: string;
|
|
59
|
+
/** Whether the declaration was handled (false = not a string type) */
|
|
60
|
+
handled: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Callbacks required for string declaration generation.
|
|
65
|
+
* These need CodeGenerator context and cannot be replaced with static state.
|
|
66
|
+
*/
|
|
67
|
+
interface IStringDeclCallbacks {
|
|
63
68
|
/** Generate expression code */
|
|
64
69
|
generateExpression: (ctx: Parser.ExpressionContext) => string;
|
|
65
70
|
/** Generate array dimensions */
|
|
@@ -70,55 +75,28 @@ interface IStringDeclHelperDeps {
|
|
|
70
75
|
) => IStringConcatOps | null;
|
|
71
76
|
/** Get substring extraction operands */
|
|
72
77
|
getSubstringOperands: (ctx: Parser.ExpressionContext) => ISubstringOps | null;
|
|
73
|
-
/** Get string literal length */
|
|
74
|
-
getStringLiteralLength: (literal: string) => number;
|
|
75
78
|
/** Get string expression capacity */
|
|
76
79
|
getStringExprCapacity: (exprCode: string) => number | null;
|
|
77
80
|
/** Request string include */
|
|
78
81
|
requireStringInclude: () => void;
|
|
79
82
|
}
|
|
80
83
|
|
|
81
|
-
/**
|
|
82
|
-
* Declaration modifiers for string variable declarations.
|
|
83
|
-
*/
|
|
84
|
-
interface IStringDeclModifiers {
|
|
85
|
-
extern: string;
|
|
86
|
-
const: string;
|
|
87
|
-
atomic: string;
|
|
88
|
-
volatile: string;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Result from generating a string declaration.
|
|
93
|
-
*/
|
|
94
|
-
interface IStringDeclResult {
|
|
95
|
-
/** The generated C code */
|
|
96
|
-
code: string;
|
|
97
|
-
/** Whether the declaration was handled (false = not a string type) */
|
|
98
|
-
handled: boolean;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
84
|
/**
|
|
102
85
|
* Generates string variable declarations in C.
|
|
103
86
|
*/
|
|
104
87
|
class StringDeclHelper {
|
|
105
|
-
private readonly deps: IStringDeclHelperDeps;
|
|
106
|
-
|
|
107
|
-
constructor(deps: IStringDeclHelperDeps) {
|
|
108
|
-
this.deps = deps;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
88
|
/**
|
|
112
89
|
* Generate string declaration if the type is a string type.
|
|
113
90
|
* Returns { handled: false } if not a string type.
|
|
114
91
|
*/
|
|
115
|
-
generateStringDecl(
|
|
92
|
+
static generateStringDecl(
|
|
116
93
|
typeCtx: Parser.TypeContext,
|
|
117
94
|
name: string,
|
|
118
95
|
expression: Parser.ExpressionContext | null,
|
|
119
96
|
arrayDims: Parser.ArrayDimensionContext[],
|
|
120
97
|
modifiers: IStringDeclModifiers,
|
|
121
98
|
isConst: boolean,
|
|
99
|
+
callbacks: IStringDeclCallbacks,
|
|
122
100
|
): IStringDeclResult {
|
|
123
101
|
const stringCtx = typeCtx.stringType();
|
|
124
102
|
if (!stringCtx) {
|
|
@@ -130,21 +108,23 @@ class StringDeclHelper {
|
|
|
130
108
|
if (intLiteral) {
|
|
131
109
|
// Bounded string with explicit capacity
|
|
132
110
|
const capacity = Number.parseInt(intLiteral.getText(), 10);
|
|
133
|
-
return
|
|
111
|
+
return StringDeclHelper._generateBoundedStringDecl(
|
|
134
112
|
name,
|
|
135
113
|
capacity,
|
|
136
114
|
expression,
|
|
137
115
|
arrayDims,
|
|
138
116
|
modifiers,
|
|
139
117
|
isConst,
|
|
118
|
+
callbacks,
|
|
140
119
|
);
|
|
141
120
|
} else {
|
|
142
121
|
// Unsized string - requires const and literal
|
|
143
|
-
return
|
|
122
|
+
return StringDeclHelper._generateUnsizedStringDecl(
|
|
144
123
|
name,
|
|
145
124
|
expression,
|
|
146
125
|
modifiers,
|
|
147
126
|
isConst,
|
|
127
|
+
callbacks,
|
|
148
128
|
);
|
|
149
129
|
}
|
|
150
130
|
}
|
|
@@ -152,25 +132,27 @@ class StringDeclHelper {
|
|
|
152
132
|
/**
|
|
153
133
|
* Generate bounded string declaration (string<N>).
|
|
154
134
|
*/
|
|
155
|
-
private
|
|
135
|
+
private static _generateBoundedStringDecl(
|
|
156
136
|
name: string,
|
|
157
137
|
capacity: number,
|
|
158
138
|
expression: Parser.ExpressionContext | null,
|
|
159
139
|
arrayDims: Parser.ArrayDimensionContext[],
|
|
160
140
|
modifiers: IStringDeclModifiers,
|
|
161
141
|
isConst: boolean,
|
|
142
|
+
callbacks: IStringDeclCallbacks,
|
|
162
143
|
): IStringDeclResult {
|
|
163
144
|
const { extern, const: constMod } = modifiers;
|
|
164
145
|
|
|
165
146
|
// String arrays: string<64> arr[4] -> char arr[4][65] = {0};
|
|
166
147
|
if (arrayDims.length > 0) {
|
|
167
|
-
return
|
|
148
|
+
return StringDeclHelper._generateStringArrayDecl(
|
|
168
149
|
name,
|
|
169
150
|
capacity,
|
|
170
151
|
expression,
|
|
171
152
|
arrayDims,
|
|
172
153
|
modifiers,
|
|
173
154
|
isConst,
|
|
155
|
+
callbacks,
|
|
174
156
|
);
|
|
175
157
|
}
|
|
176
158
|
|
|
@@ -182,50 +164,70 @@ class StringDeclHelper {
|
|
|
182
164
|
};
|
|
183
165
|
}
|
|
184
166
|
|
|
185
|
-
return
|
|
167
|
+
return StringDeclHelper._generateBoundedStringWithInit(
|
|
186
168
|
name,
|
|
187
169
|
capacity,
|
|
188
170
|
expression,
|
|
189
171
|
extern,
|
|
190
172
|
constMod,
|
|
173
|
+
callbacks,
|
|
191
174
|
);
|
|
192
175
|
}
|
|
193
176
|
|
|
194
177
|
/**
|
|
195
178
|
* Generate bounded string with initializer expression
|
|
196
179
|
*/
|
|
197
|
-
private _generateBoundedStringWithInit(
|
|
180
|
+
private static _generateBoundedStringWithInit(
|
|
198
181
|
name: string,
|
|
199
182
|
capacity: number,
|
|
200
183
|
expression: Parser.ExpressionContext,
|
|
201
184
|
extern: string,
|
|
202
185
|
constMod: string,
|
|
186
|
+
callbacks: IStringDeclCallbacks,
|
|
203
187
|
): IStringDeclResult {
|
|
204
188
|
// Check for string concatenation
|
|
205
|
-
const concatOps =
|
|
189
|
+
const concatOps = callbacks.getStringConcatOperands(expression);
|
|
206
190
|
if (concatOps) {
|
|
207
|
-
return
|
|
191
|
+
return StringDeclHelper._generateConcatDecl(
|
|
192
|
+
name,
|
|
193
|
+
capacity,
|
|
194
|
+
concatOps,
|
|
195
|
+
constMod,
|
|
196
|
+
);
|
|
208
197
|
}
|
|
209
198
|
|
|
210
199
|
// Check for substring extraction
|
|
211
|
-
const substringOps =
|
|
200
|
+
const substringOps = callbacks.getSubstringOperands(expression);
|
|
212
201
|
if (substringOps) {
|
|
213
|
-
return
|
|
202
|
+
return StringDeclHelper._generateSubstringDecl(
|
|
203
|
+
name,
|
|
204
|
+
capacity,
|
|
205
|
+
substringOps,
|
|
206
|
+
constMod,
|
|
207
|
+
);
|
|
214
208
|
}
|
|
215
209
|
|
|
216
210
|
// Validate and generate simple assignment
|
|
217
|
-
|
|
218
|
-
|
|
211
|
+
StringDeclHelper._validateStringInit(
|
|
212
|
+
expression.getText(),
|
|
213
|
+
capacity,
|
|
214
|
+
callbacks,
|
|
215
|
+
);
|
|
216
|
+
const code = `${extern}${constMod}char ${name}[${capacity + 1}] = ${callbacks.generateExpression(expression)};`;
|
|
219
217
|
return { code, handled: true };
|
|
220
218
|
}
|
|
221
219
|
|
|
222
220
|
/**
|
|
223
221
|
* Validate string initialization (literal length and variable capacity)
|
|
224
222
|
*/
|
|
225
|
-
private _validateStringInit(
|
|
223
|
+
private static _validateStringInit(
|
|
224
|
+
exprText: string,
|
|
225
|
+
capacity: number,
|
|
226
|
+
callbacks: IStringDeclCallbacks,
|
|
227
|
+
): void {
|
|
226
228
|
// Validate string literal fits capacity
|
|
227
229
|
if (exprText.startsWith('"') && exprText.endsWith('"')) {
|
|
228
|
-
const content =
|
|
230
|
+
const content = StringUtils.literalLength(exprText);
|
|
229
231
|
if (content > capacity) {
|
|
230
232
|
throw new Error(
|
|
231
233
|
`Error: String literal (${content} chars) exceeds string<${capacity}> capacity`,
|
|
@@ -234,7 +236,7 @@ class StringDeclHelper {
|
|
|
234
236
|
}
|
|
235
237
|
|
|
236
238
|
// Check for string variable assignment
|
|
237
|
-
const srcCapacity =
|
|
239
|
+
const srcCapacity = callbacks.getStringExprCapacity(exprText);
|
|
238
240
|
if (srcCapacity !== null && srcCapacity > capacity) {
|
|
239
241
|
throw new Error(
|
|
240
242
|
`Error: Cannot assign string<${srcCapacity}> to string<${capacity}> (potential truncation)`,
|
|
@@ -245,13 +247,14 @@ class StringDeclHelper {
|
|
|
245
247
|
/**
|
|
246
248
|
* Generate string array declaration.
|
|
247
249
|
*/
|
|
248
|
-
private
|
|
250
|
+
private static _generateStringArrayDecl(
|
|
249
251
|
name: string,
|
|
250
252
|
capacity: number,
|
|
251
253
|
expression: Parser.ExpressionContext | null,
|
|
252
254
|
arrayDims: Parser.ArrayDimensionContext[],
|
|
253
255
|
modifiers: IStringDeclModifiers,
|
|
254
256
|
isConst: boolean,
|
|
257
|
+
callbacks: IStringDeclCallbacks,
|
|
255
258
|
): IStringDeclResult {
|
|
256
259
|
const {
|
|
257
260
|
extern,
|
|
@@ -263,20 +266,20 @@ class StringDeclHelper {
|
|
|
263
266
|
|
|
264
267
|
// No initializer - zero-initialize
|
|
265
268
|
if (!expression) {
|
|
266
|
-
decl +=
|
|
269
|
+
decl += callbacks.generateArrayDimensions(arrayDims);
|
|
267
270
|
decl += `[${capacity + 1}]`;
|
|
268
271
|
return { code: `${decl} = {0};`, handled: true };
|
|
269
272
|
}
|
|
270
273
|
|
|
271
274
|
// Reset array init tracking and generate initializer
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
const initValue =
|
|
275
|
+
CodeGenState.lastArrayInitCount = 0;
|
|
276
|
+
CodeGenState.lastArrayFillValue = undefined;
|
|
277
|
+
const initValue = callbacks.generateExpression(expression);
|
|
275
278
|
|
|
276
279
|
// Check if it was an array initializer
|
|
277
280
|
const isArrayInit =
|
|
278
|
-
|
|
279
|
-
|
|
281
|
+
CodeGenState.lastArrayInitCount > 0 ||
|
|
282
|
+
CodeGenState.lastArrayFillValue !== undefined;
|
|
280
283
|
|
|
281
284
|
if (!isArrayInit) {
|
|
282
285
|
throw new Error(
|
|
@@ -285,18 +288,21 @@ class StringDeclHelper {
|
|
|
285
288
|
}
|
|
286
289
|
|
|
287
290
|
// Track as local array
|
|
288
|
-
|
|
291
|
+
CodeGenState.localArrays.add(name);
|
|
289
292
|
|
|
290
293
|
const hasEmptyArrayDim = arrayDims.some((dim) => !dim.expression());
|
|
291
294
|
if (hasEmptyArrayDim) {
|
|
292
|
-
decl +=
|
|
295
|
+
decl += StringDeclHelper._handleSizeInference(name, capacity, isConst);
|
|
293
296
|
} else {
|
|
294
|
-
decl +=
|
|
297
|
+
decl += StringDeclHelper._handleExplicitSize(arrayDims, callbacks);
|
|
295
298
|
}
|
|
296
299
|
|
|
297
300
|
decl += `[${capacity + 1}]`; // String capacity + null terminator
|
|
298
301
|
|
|
299
|
-
const finalInitValue =
|
|
302
|
+
const finalInitValue = StringDeclHelper._expandFillAllIfNeeded(
|
|
303
|
+
initValue,
|
|
304
|
+
arrayDims,
|
|
305
|
+
);
|
|
300
306
|
return { code: `${decl} = ${finalInitValue};`, handled: true };
|
|
301
307
|
}
|
|
302
308
|
|
|
@@ -304,22 +310,22 @@ class StringDeclHelper {
|
|
|
304
310
|
* Handle size inference for empty array dimension.
|
|
305
311
|
* Returns the dimension string to append to declaration.
|
|
306
312
|
*/
|
|
307
|
-
private _handleSizeInference(
|
|
313
|
+
private static _handleSizeInference(
|
|
308
314
|
name: string,
|
|
309
315
|
capacity: number,
|
|
310
316
|
isConst: boolean,
|
|
311
317
|
): string {
|
|
312
|
-
const fillValue =
|
|
318
|
+
const fillValue = CodeGenState.lastArrayFillValue;
|
|
313
319
|
if (fillValue !== undefined) {
|
|
314
320
|
throw new Error(
|
|
315
321
|
`Error: Fill-all syntax [${fillValue}*] requires explicit array size`,
|
|
316
322
|
);
|
|
317
323
|
}
|
|
318
324
|
|
|
319
|
-
const arraySize =
|
|
325
|
+
const arraySize = CodeGenState.lastArrayInitCount;
|
|
320
326
|
|
|
321
327
|
// Update type registry with inferred size
|
|
322
|
-
|
|
328
|
+
CodeGenState.typeRegistry.set(name, {
|
|
323
329
|
baseType: "char",
|
|
324
330
|
bitWidth: 8,
|
|
325
331
|
isArray: true,
|
|
@@ -336,16 +342,16 @@ class StringDeclHelper {
|
|
|
336
342
|
* Handle explicit array size with validation.
|
|
337
343
|
* Returns the dimension string to append to declaration.
|
|
338
344
|
*/
|
|
339
|
-
private _handleExplicitSize(
|
|
345
|
+
private static _handleExplicitSize(
|
|
340
346
|
arrayDims: Parser.ArrayDimensionContext[],
|
|
347
|
+
callbacks: IStringDeclCallbacks,
|
|
341
348
|
): string {
|
|
342
|
-
const declaredSize =
|
|
349
|
+
const declaredSize = StringDeclHelper._getFirstDimNumericSize(arrayDims);
|
|
343
350
|
|
|
344
351
|
// Validate element count matches declared size (only for non-fill-all)
|
|
345
352
|
if (declaredSize !== null) {
|
|
346
|
-
const isFillAll =
|
|
347
|
-
|
|
348
|
-
const elementCount = this.deps.arrayInitState.lastArrayInitCount;
|
|
353
|
+
const isFillAll = CodeGenState.lastArrayFillValue !== undefined;
|
|
354
|
+
const elementCount = CodeGenState.lastArrayInitCount;
|
|
349
355
|
|
|
350
356
|
if (!isFillAll && elementCount !== declaredSize) {
|
|
351
357
|
throw new Error(
|
|
@@ -354,18 +360,18 @@ class StringDeclHelper {
|
|
|
354
360
|
}
|
|
355
361
|
}
|
|
356
362
|
|
|
357
|
-
return
|
|
363
|
+
return callbacks.generateArrayDimensions(arrayDims);
|
|
358
364
|
}
|
|
359
365
|
|
|
360
366
|
/**
|
|
361
367
|
* Expand fill-all syntax if needed.
|
|
362
368
|
* ["Hello"*] with size 3 -> {"Hello", "Hello", "Hello"}
|
|
363
369
|
*/
|
|
364
|
-
private _expandFillAllIfNeeded(
|
|
370
|
+
private static _expandFillAllIfNeeded(
|
|
365
371
|
initValue: string,
|
|
366
372
|
arrayDims: Parser.ArrayDimensionContext[],
|
|
367
373
|
): string {
|
|
368
|
-
const fillVal =
|
|
374
|
+
const fillVal = CodeGenState.lastArrayFillValue;
|
|
369
375
|
if (fillVal === undefined) {
|
|
370
376
|
return initValue;
|
|
371
377
|
}
|
|
@@ -375,7 +381,7 @@ class StringDeclHelper {
|
|
|
375
381
|
return initValue;
|
|
376
382
|
}
|
|
377
383
|
|
|
378
|
-
const declaredSize =
|
|
384
|
+
const declaredSize = StringDeclHelper._getFirstDimNumericSize(arrayDims);
|
|
379
385
|
if (declaredSize === null) {
|
|
380
386
|
return initValue;
|
|
381
387
|
}
|
|
@@ -387,7 +393,7 @@ class StringDeclHelper {
|
|
|
387
393
|
/**
|
|
388
394
|
* Get the numeric size from the first array dimension, or null if not numeric.
|
|
389
395
|
*/
|
|
390
|
-
private _getFirstDimNumericSize(
|
|
396
|
+
private static _getFirstDimNumericSize(
|
|
391
397
|
arrayDims: Parser.ArrayDimensionContext[],
|
|
392
398
|
): number | null {
|
|
393
399
|
const firstDimExpr = arrayDims[0]?.expression();
|
|
@@ -406,7 +412,7 @@ class StringDeclHelper {
|
|
|
406
412
|
/**
|
|
407
413
|
* Generate string concatenation declaration.
|
|
408
414
|
*/
|
|
409
|
-
private
|
|
415
|
+
private static _generateConcatDecl(
|
|
410
416
|
name: string,
|
|
411
417
|
capacity: number,
|
|
412
418
|
concatOps: IStringConcatOps,
|
|
@@ -414,7 +420,7 @@ class StringDeclHelper {
|
|
|
414
420
|
): IStringDeclResult {
|
|
415
421
|
// String concatenation requires runtime function calls (strncpy, strncat)
|
|
416
422
|
// which cannot exist at global scope in C
|
|
417
|
-
if (!
|
|
423
|
+
if (!CodeGenState.inFunctionBody) {
|
|
418
424
|
throw new Error(
|
|
419
425
|
`Error: String concatenation cannot be used at global scope. ` +
|
|
420
426
|
`Move the declaration inside a function.`,
|
|
@@ -430,7 +436,7 @@ class StringDeclHelper {
|
|
|
430
436
|
}
|
|
431
437
|
|
|
432
438
|
// Generate safe concatenation code
|
|
433
|
-
const indent = FormatUtils.indent(
|
|
439
|
+
const indent = FormatUtils.indent(CodeGenState.indentLevel);
|
|
434
440
|
const lines: string[] = [];
|
|
435
441
|
lines.push(
|
|
436
442
|
`${constMod}char ${name}[${capacity + 1}] = "";`,
|
|
@@ -444,7 +450,7 @@ class StringDeclHelper {
|
|
|
444
450
|
/**
|
|
445
451
|
* Generate substring extraction declaration.
|
|
446
452
|
*/
|
|
447
|
-
private
|
|
453
|
+
private static _generateSubstringDecl(
|
|
448
454
|
name: string,
|
|
449
455
|
capacity: number,
|
|
450
456
|
substringOps: ISubstringOps,
|
|
@@ -452,7 +458,7 @@ class StringDeclHelper {
|
|
|
452
458
|
): IStringDeclResult {
|
|
453
459
|
// Substring extraction requires runtime function calls (strncpy)
|
|
454
460
|
// which cannot exist at global scope in C
|
|
455
|
-
if (!
|
|
461
|
+
if (!CodeGenState.inFunctionBody) {
|
|
456
462
|
throw new Error(
|
|
457
463
|
`Error: Substring extraction cannot be used at global scope. ` +
|
|
458
464
|
`Move the declaration inside a function.`,
|
|
@@ -481,7 +487,7 @@ class StringDeclHelper {
|
|
|
481
487
|
}
|
|
482
488
|
|
|
483
489
|
// Generate safe substring extraction code
|
|
484
|
-
const indent = FormatUtils.indent(
|
|
490
|
+
const indent = FormatUtils.indent(CodeGenState.indentLevel);
|
|
485
491
|
const lines: string[] = [];
|
|
486
492
|
lines.push(
|
|
487
493
|
`${constMod}char ${name}[${capacity + 1}] = "";`,
|
|
@@ -494,11 +500,12 @@ class StringDeclHelper {
|
|
|
494
500
|
/**
|
|
495
501
|
* Generate unsized const string declaration.
|
|
496
502
|
*/
|
|
497
|
-
private
|
|
503
|
+
private static _generateUnsizedStringDecl(
|
|
498
504
|
name: string,
|
|
499
505
|
expression: Parser.ExpressionContext | null,
|
|
500
506
|
modifiers: IStringDeclModifiers,
|
|
501
507
|
isConst: boolean,
|
|
508
|
+
callbacks: IStringDeclCallbacks,
|
|
502
509
|
): IStringDeclResult {
|
|
503
510
|
if (!isConst) {
|
|
504
511
|
throw new Error(
|
|
@@ -520,11 +527,11 @@ class StringDeclHelper {
|
|
|
520
527
|
}
|
|
521
528
|
|
|
522
529
|
// Infer capacity from literal length
|
|
523
|
-
const inferredCapacity =
|
|
524
|
-
|
|
530
|
+
const inferredCapacity = StringUtils.literalLength(exprText);
|
|
531
|
+
callbacks.requireStringInclude();
|
|
525
532
|
|
|
526
533
|
// Register in type registry with inferred capacity
|
|
527
|
-
|
|
534
|
+
CodeGenState.typeRegistry.set(name, {
|
|
528
535
|
baseType: "char",
|
|
529
536
|
bitWidth: 8,
|
|
530
537
|
isArray: true,
|
|
@@ -242,6 +242,15 @@ class TypeGenerationHelper {
|
|
|
242
242
|
return "string";
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
+
// Bug fix: Handle arrayType syntax (u16[8] myArray) - check inner primitive type
|
|
246
|
+
if (ctx.arrayType()) {
|
|
247
|
+
const arrCtx = ctx.arrayType()!;
|
|
248
|
+
if (arrCtx.primitiveType()) {
|
|
249
|
+
const type = arrCtx.primitiveType()!.getText();
|
|
250
|
+
return TypeGenerationHelper.generatePrimitiveType(type).include;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
245
254
|
return null;
|
|
246
255
|
}
|
|
247
256
|
}
|