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
|
@@ -4,37 +4,16 @@
|
|
|
4
4
|
* Analyzes an assignment context and determines which AssignmentKind it is.
|
|
5
5
|
* The classification order matches the original generateAssignment() method's
|
|
6
6
|
* if-else chain to ensure identical behavior.
|
|
7
|
+
*
|
|
8
|
+
* Migrated to use CodeGenState instead of constructor DI.
|
|
7
9
|
*/
|
|
8
10
|
import AssignmentKind from "./AssignmentKind";
|
|
9
11
|
import IAssignmentContext from "./IAssignmentContext";
|
|
10
|
-
import
|
|
12
|
+
import CodeGenState from "../CodeGenState";
|
|
11
13
|
import SubscriptClassifier from "../subscript/SubscriptClassifier";
|
|
12
14
|
import TTypeInfo from "../types/TTypeInfo";
|
|
13
15
|
import TypeCheckUtils from "../../../../utils/TypeCheckUtils";
|
|
14
16
|
|
|
15
|
-
/**
|
|
16
|
-
* Dependencies for classification.
|
|
17
|
-
*/
|
|
18
|
-
interface IClassifierDeps {
|
|
19
|
-
/** Symbol information (registers, bitmaps, structs, etc.) */
|
|
20
|
-
readonly symbols: ICodeGenSymbols;
|
|
21
|
-
|
|
22
|
-
/** Type registry: variable name -> type info */
|
|
23
|
-
readonly typeRegistry: ReadonlyMap<string, TTypeInfo>;
|
|
24
|
-
|
|
25
|
-
/** Current scope name, null if not in scope */
|
|
26
|
-
readonly currentScope: string | null;
|
|
27
|
-
|
|
28
|
-
/** Check if a type name is a known struct */
|
|
29
|
-
isKnownStruct(typeName: string): boolean;
|
|
30
|
-
|
|
31
|
-
/** Check if a name is a known scope */
|
|
32
|
-
isKnownScope(name: string): boolean;
|
|
33
|
-
|
|
34
|
-
/** Get member type info for a struct field */
|
|
35
|
-
getMemberTypeInfo(structType: string, memberName: string): TTypeInfo | null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
17
|
/**
|
|
39
18
|
* Classifies assignment statements by analyzing their structure.
|
|
40
19
|
*
|
|
@@ -48,12 +27,10 @@ interface IClassifierDeps {
|
|
|
48
27
|
* 7. Simple fallback
|
|
49
28
|
*/
|
|
50
29
|
class AssignmentClassifier {
|
|
51
|
-
constructor(private readonly deps: IClassifierDeps) {}
|
|
52
|
-
|
|
53
30
|
/**
|
|
54
31
|
* Check if typeInfo represents a simple string type (not a 2D+ string array).
|
|
55
32
|
*/
|
|
56
|
-
private isSimpleStringType(typeInfo: TTypeInfo | undefined): boolean {
|
|
33
|
+
private static isSimpleStringType(typeInfo: TTypeInfo | undefined): boolean {
|
|
57
34
|
return (
|
|
58
35
|
typeInfo?.isString === true &&
|
|
59
36
|
typeInfo.stringCapacity !== undefined &&
|
|
@@ -64,7 +41,7 @@ class AssignmentClassifier {
|
|
|
64
41
|
/**
|
|
65
42
|
* Extract struct name and field name from a 2-identifier context.
|
|
66
43
|
*/
|
|
67
|
-
private getStructFieldNames(
|
|
44
|
+
private static getStructFieldNames(
|
|
68
45
|
ctx: IAssignmentContext,
|
|
69
46
|
): { structName: string; fieldName: string } | null {
|
|
70
47
|
if (ctx.identifiers.length !== 2) {
|
|
@@ -76,39 +53,40 @@ class AssignmentClassifier {
|
|
|
76
53
|
/**
|
|
77
54
|
* Classify an assignment context into an AssignmentKind.
|
|
78
55
|
*/
|
|
79
|
-
classify(ctx: IAssignmentContext): AssignmentKind {
|
|
56
|
+
static classify(ctx: IAssignmentContext): AssignmentKind {
|
|
80
57
|
// === Priority 1: Bitmap field assignments ===
|
|
81
|
-
const bitmapKind =
|
|
58
|
+
const bitmapKind = AssignmentClassifier.classifyBitmapField(ctx);
|
|
82
59
|
if (bitmapKind !== null) {
|
|
83
60
|
return bitmapKind;
|
|
84
61
|
}
|
|
85
62
|
|
|
86
63
|
// === Priority 2: Member access with subscripts (arrays, register bits) ===
|
|
87
|
-
const memberSubscriptKind =
|
|
64
|
+
const memberSubscriptKind =
|
|
65
|
+
AssignmentClassifier.classifyMemberWithSubscript(ctx);
|
|
88
66
|
if (memberSubscriptKind !== null) {
|
|
89
67
|
return memberSubscriptKind;
|
|
90
68
|
}
|
|
91
69
|
|
|
92
70
|
// === Priority 3: Global/this prefix patterns ===
|
|
93
|
-
const prefixKind =
|
|
71
|
+
const prefixKind = AssignmentClassifier.classifyPrefixPattern(ctx);
|
|
94
72
|
if (prefixKind !== null) {
|
|
95
73
|
return prefixKind;
|
|
96
74
|
}
|
|
97
75
|
|
|
98
76
|
// === Priority 4: Simple array/bit access ===
|
|
99
|
-
const arrayBitKind =
|
|
77
|
+
const arrayBitKind = AssignmentClassifier.classifyArrayOrBitAccess(ctx);
|
|
100
78
|
if (arrayBitKind !== null) {
|
|
101
79
|
return arrayBitKind;
|
|
102
80
|
}
|
|
103
81
|
|
|
104
82
|
// === Priority 5: Atomic/overflow compound assignments ===
|
|
105
|
-
const specialKind =
|
|
83
|
+
const specialKind = AssignmentClassifier.classifySpecialCompound(ctx);
|
|
106
84
|
if (specialKind !== null) {
|
|
107
85
|
return specialKind;
|
|
108
86
|
}
|
|
109
87
|
|
|
110
88
|
// === Priority 6: String assignments ===
|
|
111
|
-
const stringKind =
|
|
89
|
+
const stringKind = AssignmentClassifier.classifyStringAssignment(ctx);
|
|
112
90
|
if (stringKind !== null) {
|
|
113
91
|
return stringKind;
|
|
114
92
|
}
|
|
@@ -127,7 +105,9 @@ class AssignmentClassifier {
|
|
|
127
105
|
* Classify bitmap field assignments.
|
|
128
106
|
* Patterns: var.field, struct.bitmapMember.field, REG.MEMBER.field, Scope.REG.MEMBER.field
|
|
129
107
|
*/
|
|
130
|
-
private classifyBitmapField(
|
|
108
|
+
private static classifyBitmapField(
|
|
109
|
+
ctx: IAssignmentContext,
|
|
110
|
+
): AssignmentKind | null {
|
|
131
111
|
// Must have member access without subscripts
|
|
132
112
|
if (!ctx.hasMemberAccess || ctx.hasArrayAccess) {
|
|
133
113
|
return null;
|
|
@@ -139,15 +119,19 @@ class AssignmentClassifier {
|
|
|
139
119
|
}
|
|
140
120
|
|
|
141
121
|
if (ids.length === 2) {
|
|
142
|
-
return
|
|
122
|
+
return AssignmentClassifier.classifySimpleBitmapField(ids[0], ids[1]);
|
|
143
123
|
}
|
|
144
124
|
|
|
145
125
|
if (ids.length === 3) {
|
|
146
|
-
return
|
|
126
|
+
return AssignmentClassifier.classifyThreeIdBitmapField(
|
|
127
|
+
ids[0],
|
|
128
|
+
ids[1],
|
|
129
|
+
ids[2],
|
|
130
|
+
);
|
|
147
131
|
}
|
|
148
132
|
|
|
149
133
|
if (ids.length === 4) {
|
|
150
|
-
return
|
|
134
|
+
return AssignmentClassifier.classifyScopedRegisterBitmapField(ids);
|
|
151
135
|
}
|
|
152
136
|
|
|
153
137
|
return null;
|
|
@@ -156,16 +140,16 @@ class AssignmentClassifier {
|
|
|
156
140
|
/**
|
|
157
141
|
* Classify 2-id bitmap field: var.field
|
|
158
142
|
*/
|
|
159
|
-
private classifySimpleBitmapField(
|
|
143
|
+
private static classifySimpleBitmapField(
|
|
160
144
|
varName: string,
|
|
161
145
|
fieldName: string,
|
|
162
146
|
): AssignmentKind | null {
|
|
163
|
-
const typeInfo =
|
|
147
|
+
const typeInfo = CodeGenState.typeRegistry.get(varName);
|
|
164
148
|
if (!typeInfo?.isBitmap || !typeInfo.bitmapTypeName) {
|
|
165
149
|
return null;
|
|
166
150
|
}
|
|
167
151
|
|
|
168
|
-
const width =
|
|
152
|
+
const width = AssignmentClassifier.lookupBitmapFieldWidth(
|
|
169
153
|
typeInfo.bitmapTypeName,
|
|
170
154
|
fieldName,
|
|
171
155
|
);
|
|
@@ -181,19 +165,22 @@ class AssignmentClassifier {
|
|
|
181
165
|
/**
|
|
182
166
|
* Classify 3-id bitmap field: REG.MEMBER.field or struct.bitmapMember.field
|
|
183
167
|
*/
|
|
184
|
-
private classifyThreeIdBitmapField(
|
|
168
|
+
private static classifyThreeIdBitmapField(
|
|
185
169
|
firstName: string,
|
|
186
170
|
secondName: string,
|
|
187
171
|
fieldName: string,
|
|
188
172
|
): AssignmentKind | null {
|
|
189
173
|
// Check if register member bitmap field: REG.MEMBER.field
|
|
190
|
-
if (
|
|
191
|
-
const bitmapType =
|
|
174
|
+
if (CodeGenState.symbols!.knownRegisters.has(firstName)) {
|
|
175
|
+
const bitmapType = AssignmentClassifier.lookupRegisterMemberBitmapType(
|
|
192
176
|
firstName,
|
|
193
177
|
secondName,
|
|
194
178
|
);
|
|
195
179
|
if (bitmapType) {
|
|
196
|
-
const width =
|
|
180
|
+
const width = AssignmentClassifier.lookupBitmapFieldWidth(
|
|
181
|
+
bitmapType,
|
|
182
|
+
fieldName,
|
|
183
|
+
);
|
|
197
184
|
if (width !== null) {
|
|
198
185
|
return AssignmentKind.REGISTER_MEMBER_BITMAP_FIELD;
|
|
199
186
|
}
|
|
@@ -202,12 +189,15 @@ class AssignmentClassifier {
|
|
|
202
189
|
}
|
|
203
190
|
|
|
204
191
|
// Check if struct member bitmap field: struct.bitmapMember.field
|
|
205
|
-
const structTypeInfo =
|
|
206
|
-
if (
|
|
192
|
+
const structTypeInfo = CodeGenState.typeRegistry.get(firstName);
|
|
193
|
+
if (
|
|
194
|
+
!structTypeInfo ||
|
|
195
|
+
!CodeGenState.isKnownStruct(structTypeInfo.baseType)
|
|
196
|
+
) {
|
|
207
197
|
return null;
|
|
208
198
|
}
|
|
209
199
|
|
|
210
|
-
const memberInfo =
|
|
200
|
+
const memberInfo = CodeGenState.getMemberTypeInfo(
|
|
211
201
|
structTypeInfo.baseType,
|
|
212
202
|
secondName,
|
|
213
203
|
);
|
|
@@ -215,7 +205,10 @@ class AssignmentClassifier {
|
|
|
215
205
|
return null;
|
|
216
206
|
}
|
|
217
207
|
|
|
218
|
-
const width =
|
|
208
|
+
const width = AssignmentClassifier.lookupBitmapFieldWidth(
|
|
209
|
+
memberInfo.baseType,
|
|
210
|
+
fieldName,
|
|
211
|
+
);
|
|
219
212
|
if (width !== null) {
|
|
220
213
|
return AssignmentKind.STRUCT_MEMBER_BITMAP_FIELD;
|
|
221
214
|
}
|
|
@@ -226,25 +219,31 @@ class AssignmentClassifier {
|
|
|
226
219
|
/**
|
|
227
220
|
* Classify 4-id scoped register bitmap field: Scope.REG.MEMBER.field
|
|
228
221
|
*/
|
|
229
|
-
private classifyScopedRegisterBitmapField(
|
|
222
|
+
private static classifyScopedRegisterBitmapField(
|
|
230
223
|
ids: readonly string[],
|
|
231
224
|
): AssignmentKind | null {
|
|
232
225
|
const scopeName = ids[0];
|
|
233
|
-
if (!
|
|
226
|
+
if (!CodeGenState.isKnownScope(scopeName)) {
|
|
234
227
|
return null;
|
|
235
228
|
}
|
|
236
229
|
|
|
237
230
|
const fullRegName = `${scopeName}_${ids[1]}`;
|
|
238
|
-
if (!
|
|
231
|
+
if (!CodeGenState.symbols!.knownRegisters.has(fullRegName)) {
|
|
239
232
|
return null;
|
|
240
233
|
}
|
|
241
234
|
|
|
242
|
-
const bitmapType =
|
|
235
|
+
const bitmapType = AssignmentClassifier.lookupRegisterMemberBitmapType(
|
|
236
|
+
fullRegName,
|
|
237
|
+
ids[2],
|
|
238
|
+
);
|
|
243
239
|
if (!bitmapType) {
|
|
244
240
|
return null;
|
|
245
241
|
}
|
|
246
242
|
|
|
247
|
-
const width =
|
|
243
|
+
const width = AssignmentClassifier.lookupBitmapFieldWidth(
|
|
244
|
+
bitmapType,
|
|
245
|
+
ids[3],
|
|
246
|
+
);
|
|
248
247
|
if (width !== null) {
|
|
249
248
|
return AssignmentKind.SCOPED_REGISTER_MEMBER_BITMAP_FIELD;
|
|
250
249
|
}
|
|
@@ -256,7 +255,7 @@ class AssignmentClassifier {
|
|
|
256
255
|
* Classify member access with subscripts.
|
|
257
256
|
* Patterns: arr[i][j], struct.arr[i], REG.MEMBER[bit], matrix[i][j][bit]
|
|
258
257
|
*/
|
|
259
|
-
private classifyMemberWithSubscript(
|
|
258
|
+
private static classifyMemberWithSubscript(
|
|
260
259
|
ctx: IAssignmentContext,
|
|
261
260
|
): AssignmentKind | null {
|
|
262
261
|
// Need subscripts through memberAccess pattern
|
|
@@ -271,7 +270,7 @@ class AssignmentClassifier {
|
|
|
271
270
|
|
|
272
271
|
const ids = ctx.identifiers;
|
|
273
272
|
const firstId = ids[0];
|
|
274
|
-
const typeInfo =
|
|
273
|
+
const typeInfo = CodeGenState.typeRegistry.get(firstId);
|
|
275
274
|
|
|
276
275
|
// Check for bit range through struct chain: devices[0].control[0, 4]
|
|
277
276
|
// Detected by last subscript having 2 expressions (start, width)
|
|
@@ -281,12 +280,15 @@ class AssignmentClassifier {
|
|
|
281
280
|
|
|
282
281
|
// Multi-dimensional array element: arr[i][j] (1 identifier, multiple subscripts)
|
|
283
282
|
if (ids.length === 1) {
|
|
284
|
-
return
|
|
283
|
+
return AssignmentClassifier.classifyMultiDimArrayAccess(
|
|
284
|
+
typeInfo,
|
|
285
|
+
ctx.subscripts.length,
|
|
286
|
+
);
|
|
285
287
|
}
|
|
286
288
|
|
|
287
289
|
// 2+ identifiers with subscripts: register bit or bitmap array
|
|
288
290
|
if (ids.length >= 2) {
|
|
289
|
-
const registerKind =
|
|
291
|
+
const registerKind = AssignmentClassifier.classifyRegisterBitAccess(
|
|
290
292
|
ids,
|
|
291
293
|
ctx.subscripts.length,
|
|
292
294
|
);
|
|
@@ -294,7 +296,7 @@ class AssignmentClassifier {
|
|
|
294
296
|
return registerKind;
|
|
295
297
|
}
|
|
296
298
|
|
|
297
|
-
return
|
|
299
|
+
return AssignmentClassifier.classifyBitmapArrayField(
|
|
298
300
|
ids[1],
|
|
299
301
|
typeInfo,
|
|
300
302
|
ctx.subscripts.length,
|
|
@@ -307,7 +309,7 @@ class AssignmentClassifier {
|
|
|
307
309
|
/**
|
|
308
310
|
* Classify multi-dimensional array access: arr[i][j] or arr[i][j][bit]
|
|
309
311
|
*/
|
|
310
|
-
private classifyMultiDimArrayAccess(
|
|
312
|
+
private static classifyMultiDimArrayAccess(
|
|
311
313
|
typeInfo: TTypeInfo | undefined,
|
|
312
314
|
subscriptCount: number,
|
|
313
315
|
): AssignmentKind | null {
|
|
@@ -331,16 +333,16 @@ class AssignmentClassifier {
|
|
|
331
333
|
/**
|
|
332
334
|
* Classify register bit access: REG.MEMBER[bit] or Scope.REG.MEMBER[bit]
|
|
333
335
|
*/
|
|
334
|
-
private classifyRegisterBitAccess(
|
|
336
|
+
private static classifyRegisterBitAccess(
|
|
335
337
|
ids: readonly string[],
|
|
336
338
|
subscriptCount: number,
|
|
337
339
|
): AssignmentKind | null {
|
|
338
340
|
const firstId = ids[0];
|
|
339
341
|
|
|
340
342
|
// Check for scoped register: Scope.REG.MEMBER[bit]
|
|
341
|
-
if (
|
|
343
|
+
if (CodeGenState.isKnownScope(firstId) && ids.length >= 3) {
|
|
342
344
|
const scopedRegName = `${firstId}_${ids[1]}`;
|
|
343
|
-
if (
|
|
345
|
+
if (CodeGenState.symbols!.knownRegisters.has(scopedRegName)) {
|
|
344
346
|
return subscriptCount === 2
|
|
345
347
|
? AssignmentKind.REGISTER_BIT_RANGE
|
|
346
348
|
: AssignmentKind.REGISTER_BIT;
|
|
@@ -348,7 +350,7 @@ class AssignmentClassifier {
|
|
|
348
350
|
}
|
|
349
351
|
|
|
350
352
|
// Check for non-scoped register: REG.MEMBER[bit]
|
|
351
|
-
if (
|
|
353
|
+
if (CodeGenState.symbols!.knownRegisters.has(firstId)) {
|
|
352
354
|
return subscriptCount === 2
|
|
353
355
|
? AssignmentKind.REGISTER_BIT_RANGE
|
|
354
356
|
: AssignmentKind.REGISTER_BIT;
|
|
@@ -360,7 +362,7 @@ class AssignmentClassifier {
|
|
|
360
362
|
/**
|
|
361
363
|
* Classify bitmap array element field: bitmapArr[i].field
|
|
362
364
|
*/
|
|
363
|
-
private classifyBitmapArrayField(
|
|
365
|
+
private static classifyBitmapArrayField(
|
|
364
366
|
secondId: string,
|
|
365
367
|
typeInfo: TTypeInfo | undefined,
|
|
366
368
|
subscriptCount: number,
|
|
@@ -373,7 +375,7 @@ class AssignmentClassifier {
|
|
|
373
375
|
return null;
|
|
374
376
|
}
|
|
375
377
|
|
|
376
|
-
const width =
|
|
378
|
+
const width = AssignmentClassifier.lookupBitmapFieldWidth(
|
|
377
379
|
typeInfo.bitmapTypeName,
|
|
378
380
|
secondId,
|
|
379
381
|
);
|
|
@@ -387,7 +389,7 @@ class AssignmentClassifier {
|
|
|
387
389
|
/**
|
|
388
390
|
* Classify global.* and this.* prefix patterns.
|
|
389
391
|
*/
|
|
390
|
-
private classifyPrefixPattern(
|
|
392
|
+
private static classifyPrefixPattern(
|
|
391
393
|
ctx: IAssignmentContext,
|
|
392
394
|
): AssignmentKind | null {
|
|
393
395
|
if (!ctx.hasGlobal && !ctx.hasThis) {
|
|
@@ -395,11 +397,11 @@ class AssignmentClassifier {
|
|
|
395
397
|
}
|
|
396
398
|
|
|
397
399
|
if (ctx.hasGlobal && ctx.postfixOpsCount > 0) {
|
|
398
|
-
return
|
|
400
|
+
return AssignmentClassifier.classifyGlobalPrefix(ctx);
|
|
399
401
|
}
|
|
400
402
|
|
|
401
403
|
if (ctx.hasThis && ctx.postfixOpsCount > 0) {
|
|
402
|
-
return
|
|
404
|
+
return AssignmentClassifier.classifyThisPrefix(ctx);
|
|
403
405
|
}
|
|
404
406
|
|
|
405
407
|
return null;
|
|
@@ -408,11 +410,11 @@ class AssignmentClassifier {
|
|
|
408
410
|
/**
|
|
409
411
|
* Classify global.* patterns: global.reg[bit], global.arr[i], global.member
|
|
410
412
|
*/
|
|
411
|
-
private classifyGlobalPrefix(ctx: IAssignmentContext): AssignmentKind {
|
|
413
|
+
private static classifyGlobalPrefix(ctx: IAssignmentContext): AssignmentKind {
|
|
412
414
|
const firstId = ctx.identifiers[0];
|
|
413
415
|
|
|
414
416
|
if (ctx.hasArrayAccess) {
|
|
415
|
-
if (
|
|
417
|
+
if (CodeGenState.symbols!.knownRegisters.has(firstId)) {
|
|
416
418
|
return AssignmentKind.GLOBAL_REGISTER_BIT;
|
|
417
419
|
}
|
|
418
420
|
return AssignmentKind.GLOBAL_ARRAY;
|
|
@@ -424,24 +426,27 @@ class AssignmentClassifier {
|
|
|
424
426
|
/**
|
|
425
427
|
* Classify this.* patterns: this.reg[bit], this.member, this.REG.MEMBER.field
|
|
426
428
|
*/
|
|
427
|
-
private classifyThisPrefix(ctx: IAssignmentContext): AssignmentKind {
|
|
428
|
-
if (!
|
|
429
|
+
private static classifyThisPrefix(ctx: IAssignmentContext): AssignmentKind {
|
|
430
|
+
if (!CodeGenState.currentScope) {
|
|
429
431
|
return AssignmentKind.THIS_MEMBER;
|
|
430
432
|
}
|
|
431
433
|
|
|
432
434
|
const firstId = ctx.identifiers[0];
|
|
433
|
-
const scopedRegName = `${
|
|
435
|
+
const scopedRegName = `${CodeGenState.currentScope}_${firstId}`;
|
|
434
436
|
|
|
435
437
|
if (ctx.hasArrayAccess) {
|
|
436
|
-
return
|
|
438
|
+
return AssignmentClassifier.classifyThisWithArrayAccess(
|
|
439
|
+
ctx,
|
|
440
|
+
scopedRegName,
|
|
441
|
+
);
|
|
437
442
|
}
|
|
438
443
|
|
|
439
444
|
// this.REG.MEMBER.field (scoped register bitmap field)
|
|
440
445
|
if (
|
|
441
446
|
ctx.identifiers.length === 3 &&
|
|
442
|
-
|
|
447
|
+
CodeGenState.symbols!.knownRegisters.has(scopedRegName)
|
|
443
448
|
) {
|
|
444
|
-
const bitmapType =
|
|
449
|
+
const bitmapType = AssignmentClassifier.lookupRegisterMemberBitmapType(
|
|
445
450
|
scopedRegName,
|
|
446
451
|
ctx.identifiers[1],
|
|
447
452
|
);
|
|
@@ -456,11 +461,11 @@ class AssignmentClassifier {
|
|
|
456
461
|
/**
|
|
457
462
|
* Classify this.reg[bit] / this.arr[i] patterns with array access.
|
|
458
463
|
*/
|
|
459
|
-
private classifyThisWithArrayAccess(
|
|
464
|
+
private static classifyThisWithArrayAccess(
|
|
460
465
|
ctx: IAssignmentContext,
|
|
461
466
|
scopedRegName: string,
|
|
462
467
|
): AssignmentKind {
|
|
463
|
-
if (
|
|
468
|
+
if (CodeGenState.symbols!.knownRegisters.has(scopedRegName)) {
|
|
464
469
|
const hasBitRange = ctx.postfixOps.some((op) => op.COMMA() !== null);
|
|
465
470
|
return hasBitRange
|
|
466
471
|
? AssignmentKind.SCOPED_REGISTER_BIT_RANGE
|
|
@@ -476,7 +481,7 @@ class AssignmentClassifier {
|
|
|
476
481
|
* Issue #579: Uses shared SubscriptClassifier to ensure consistent behavior
|
|
477
482
|
* with the expression path in CodeGenerator._generatePostfixExpr.
|
|
478
483
|
*/
|
|
479
|
-
private classifyArrayOrBitAccess(
|
|
484
|
+
private static classifyArrayOrBitAccess(
|
|
480
485
|
ctx: IAssignmentContext,
|
|
481
486
|
): AssignmentKind | null {
|
|
482
487
|
// Must have arrayAccess without memberAccess or prefix
|
|
@@ -489,7 +494,7 @@ class AssignmentClassifier {
|
|
|
489
494
|
}
|
|
490
495
|
|
|
491
496
|
const name = ctx.identifiers[0];
|
|
492
|
-
const typeInfo =
|
|
497
|
+
const typeInfo = CodeGenState.typeRegistry.get(name) ?? null;
|
|
493
498
|
|
|
494
499
|
// Use shared classifier for array vs bit access decision
|
|
495
500
|
// Use lastSubscriptExprCount to distinguish [0][0] (two ops, each 1 expr)
|
|
@@ -542,7 +547,7 @@ class AssignmentClassifier {
|
|
|
542
547
|
* Classify atomic and overflow-clamped compound assignments.
|
|
543
548
|
* Handles simple identifiers, this.member, and global.member patterns.
|
|
544
549
|
*/
|
|
545
|
-
private classifySpecialCompound(
|
|
550
|
+
private static classifySpecialCompound(
|
|
546
551
|
ctx: IAssignmentContext,
|
|
547
552
|
): AssignmentKind | null {
|
|
548
553
|
if (!ctx.isCompound) {
|
|
@@ -553,16 +558,16 @@ class AssignmentClassifier {
|
|
|
553
558
|
let typeInfo;
|
|
554
559
|
if (ctx.isSimpleIdentifier) {
|
|
555
560
|
const id = ctx.identifiers[0];
|
|
556
|
-
typeInfo =
|
|
557
|
-
} else if (ctx.isSimpleThisAccess &&
|
|
561
|
+
typeInfo = CodeGenState.typeRegistry.get(id);
|
|
562
|
+
} else if (ctx.isSimpleThisAccess && CodeGenState.currentScope) {
|
|
558
563
|
// this.member pattern: lookup using scoped name
|
|
559
564
|
const memberName = ctx.identifiers[0];
|
|
560
|
-
const scopedName = `${
|
|
561
|
-
typeInfo =
|
|
565
|
+
const scopedName = `${CodeGenState.currentScope}_${memberName}`;
|
|
566
|
+
typeInfo = CodeGenState.typeRegistry.get(scopedName);
|
|
562
567
|
} else if (ctx.isSimpleGlobalAccess) {
|
|
563
568
|
// global.member pattern: lookup using direct name
|
|
564
569
|
const memberName = ctx.identifiers[0];
|
|
565
|
-
typeInfo =
|
|
570
|
+
typeInfo = CodeGenState.typeRegistry.get(memberName);
|
|
566
571
|
} else {
|
|
567
572
|
return null;
|
|
568
573
|
}
|
|
@@ -594,13 +599,13 @@ class AssignmentClassifier {
|
|
|
594
599
|
/**
|
|
595
600
|
* Check if a simple identifier is a string variable.
|
|
596
601
|
*/
|
|
597
|
-
private _classifySimpleStringVar(
|
|
602
|
+
private static _classifySimpleStringVar(
|
|
598
603
|
ctx: IAssignmentContext,
|
|
599
604
|
): AssignmentKind | null {
|
|
600
605
|
if (!ctx.isSimpleIdentifier) return null;
|
|
601
606
|
const id = ctx.identifiers[0];
|
|
602
|
-
const typeInfo =
|
|
603
|
-
return
|
|
607
|
+
const typeInfo = CodeGenState.typeRegistry.get(id);
|
|
608
|
+
return AssignmentClassifier.isSimpleStringType(typeInfo)
|
|
604
609
|
? AssignmentKind.STRING_SIMPLE
|
|
605
610
|
: null;
|
|
606
611
|
}
|
|
@@ -608,14 +613,14 @@ class AssignmentClassifier {
|
|
|
608
613
|
/**
|
|
609
614
|
* Check if this.member is a string.
|
|
610
615
|
*/
|
|
611
|
-
private _classifyThisMemberString(
|
|
616
|
+
private static _classifyThisMemberString(
|
|
612
617
|
ctx: IAssignmentContext,
|
|
613
618
|
): AssignmentKind | null {
|
|
614
|
-
if (!ctx.isSimpleThisAccess || !
|
|
619
|
+
if (!ctx.isSimpleThisAccess || !CodeGenState.currentScope) return null;
|
|
615
620
|
const memberName = ctx.identifiers[0];
|
|
616
|
-
const scopedName = `${
|
|
617
|
-
const typeInfo =
|
|
618
|
-
return
|
|
621
|
+
const scopedName = `${CodeGenState.currentScope}_${memberName}`;
|
|
622
|
+
const typeInfo = CodeGenState.typeRegistry.get(scopedName);
|
|
623
|
+
return AssignmentClassifier.isSimpleStringType(typeInfo)
|
|
619
624
|
? AssignmentKind.STRING_THIS_MEMBER
|
|
620
625
|
: null;
|
|
621
626
|
}
|
|
@@ -623,13 +628,13 @@ class AssignmentClassifier {
|
|
|
623
628
|
/**
|
|
624
629
|
* Check if global.member is a string.
|
|
625
630
|
*/
|
|
626
|
-
private _classifyGlobalString(
|
|
631
|
+
private static _classifyGlobalString(
|
|
627
632
|
ctx: IAssignmentContext,
|
|
628
633
|
): AssignmentKind | null {
|
|
629
634
|
if (!ctx.isSimpleGlobalAccess) return null;
|
|
630
635
|
const id = ctx.identifiers[0];
|
|
631
|
-
const typeInfo =
|
|
632
|
-
return
|
|
636
|
+
const typeInfo = CodeGenState.typeRegistry.get(id);
|
|
637
|
+
return AssignmentClassifier.isSimpleStringType(typeInfo)
|
|
633
638
|
? AssignmentKind.STRING_GLOBAL
|
|
634
639
|
: null;
|
|
635
640
|
}
|
|
@@ -638,9 +643,12 @@ class AssignmentClassifier {
|
|
|
638
643
|
* Resolve struct type from variable name.
|
|
639
644
|
* Returns the base struct type if valid, null if not a known struct.
|
|
640
645
|
*/
|
|
641
|
-
private _resolveStructType(structName: string): string | null {
|
|
642
|
-
const structTypeInfo =
|
|
643
|
-
if (
|
|
646
|
+
private static _resolveStructType(structName: string): string | null {
|
|
647
|
+
const structTypeInfo = CodeGenState.typeRegistry.get(structName);
|
|
648
|
+
if (
|
|
649
|
+
!structTypeInfo ||
|
|
650
|
+
!CodeGenState.isKnownStruct(structTypeInfo.baseType)
|
|
651
|
+
) {
|
|
644
652
|
return null;
|
|
645
653
|
}
|
|
646
654
|
return structTypeInfo.baseType;
|
|
@@ -650,15 +658,17 @@ class AssignmentClassifier {
|
|
|
650
658
|
* Resolve struct field type from struct variable name and field name.
|
|
651
659
|
* Returns null if struct type can't be resolved or field doesn't exist.
|
|
652
660
|
*/
|
|
653
|
-
private _resolveStructFieldType(structFieldNames: {
|
|
661
|
+
private static _resolveStructFieldType(structFieldNames: {
|
|
654
662
|
structName: string;
|
|
655
663
|
fieldName: string;
|
|
656
664
|
}): { structType: string; fieldType: string | undefined } | null {
|
|
657
|
-
const structType =
|
|
665
|
+
const structType = AssignmentClassifier._resolveStructType(
|
|
666
|
+
structFieldNames.structName,
|
|
667
|
+
);
|
|
658
668
|
if (!structType) {
|
|
659
669
|
return null;
|
|
660
670
|
}
|
|
661
|
-
const structFields =
|
|
671
|
+
const structFields = CodeGenState.symbols!.structFields.get(structType);
|
|
662
672
|
const fieldType = structFields?.get(structFieldNames.fieldName);
|
|
663
673
|
return { structType, fieldType };
|
|
664
674
|
}
|
|
@@ -666,14 +676,15 @@ class AssignmentClassifier {
|
|
|
666
676
|
/**
|
|
667
677
|
* Check if struct.field is a string field.
|
|
668
678
|
*/
|
|
669
|
-
private _classifyStructFieldString(
|
|
679
|
+
private static _classifyStructFieldString(
|
|
670
680
|
ctx: IAssignmentContext,
|
|
671
681
|
structFieldNames: { structName: string; fieldName: string } | null,
|
|
672
682
|
): AssignmentKind | null {
|
|
673
683
|
if (!ctx.hasMemberAccess || ctx.hasArrayAccess || !structFieldNames) {
|
|
674
684
|
return null;
|
|
675
685
|
}
|
|
676
|
-
const resolved =
|
|
686
|
+
const resolved =
|
|
687
|
+
AssignmentClassifier._resolveStructFieldType(structFieldNames);
|
|
677
688
|
if (!resolved) {
|
|
678
689
|
return null;
|
|
679
690
|
}
|
|
@@ -685,7 +696,7 @@ class AssignmentClassifier {
|
|
|
685
696
|
/**
|
|
686
697
|
* Check if struct.arr[i] is a string array element.
|
|
687
698
|
*/
|
|
688
|
-
private _classifyStructArrayElementString(
|
|
699
|
+
private static _classifyStructArrayElementString(
|
|
689
700
|
ctx: IAssignmentContext,
|
|
690
701
|
structFieldNames: { structName: string; fieldName: string } | null,
|
|
691
702
|
): AssignmentKind | null {
|
|
@@ -697,17 +708,19 @@ class AssignmentClassifier {
|
|
|
697
708
|
) {
|
|
698
709
|
return null;
|
|
699
710
|
}
|
|
700
|
-
const resolved =
|
|
711
|
+
const resolved =
|
|
712
|
+
AssignmentClassifier._resolveStructFieldType(structFieldNames);
|
|
701
713
|
if (!resolved) {
|
|
702
714
|
return null;
|
|
703
715
|
}
|
|
704
716
|
|
|
705
717
|
const { structType, fieldType } = resolved;
|
|
706
718
|
const { fieldName } = structFieldNames;
|
|
707
|
-
const fieldArrays =
|
|
708
|
-
const dimensions =
|
|
709
|
-
.get(structType)
|
|
710
|
-
|
|
719
|
+
const fieldArrays = CodeGenState.symbols!.structFieldArrays.get(structType);
|
|
720
|
+
const dimensions =
|
|
721
|
+
CodeGenState.symbols!.structFieldDimensions.get(structType)?.get(
|
|
722
|
+
fieldName,
|
|
723
|
+
);
|
|
711
724
|
|
|
712
725
|
const isStringArrayField =
|
|
713
726
|
fieldType &&
|
|
@@ -724,30 +737,34 @@ class AssignmentClassifier {
|
|
|
724
737
|
/**
|
|
725
738
|
* Classify string assignments.
|
|
726
739
|
*/
|
|
727
|
-
private classifyStringAssignment(
|
|
740
|
+
private static classifyStringAssignment(
|
|
728
741
|
ctx: IAssignmentContext,
|
|
729
742
|
): AssignmentKind | null {
|
|
730
743
|
// Simple string variable
|
|
731
|
-
const simpleVar =
|
|
744
|
+
const simpleVar = AssignmentClassifier._classifySimpleStringVar(ctx);
|
|
732
745
|
if (simpleVar) return simpleVar;
|
|
733
746
|
|
|
734
747
|
// this.member string
|
|
735
|
-
const thisMember =
|
|
748
|
+
const thisMember = AssignmentClassifier._classifyThisMemberString(ctx);
|
|
736
749
|
if (thisMember) return thisMember;
|
|
737
750
|
|
|
738
751
|
// global.member string
|
|
739
|
-
const globalMember =
|
|
752
|
+
const globalMember = AssignmentClassifier._classifyGlobalString(ctx);
|
|
740
753
|
if (globalMember) return globalMember;
|
|
741
754
|
|
|
742
755
|
// struct.field or struct.arr[i] string
|
|
743
|
-
const structFieldNames =
|
|
744
|
-
const structField =
|
|
745
|
-
if (structField) return structField;
|
|
746
|
-
|
|
747
|
-
const structArrayElement = this._classifyStructArrayElementString(
|
|
756
|
+
const structFieldNames = AssignmentClassifier.getStructFieldNames(ctx);
|
|
757
|
+
const structField = AssignmentClassifier._classifyStructFieldString(
|
|
748
758
|
ctx,
|
|
749
759
|
structFieldNames,
|
|
750
760
|
);
|
|
761
|
+
if (structField) return structField;
|
|
762
|
+
|
|
763
|
+
const structArrayElement =
|
|
764
|
+
AssignmentClassifier._classifyStructArrayElementString(
|
|
765
|
+
ctx,
|
|
766
|
+
structFieldNames,
|
|
767
|
+
);
|
|
751
768
|
if (structArrayElement) return structArrayElement;
|
|
752
769
|
|
|
753
770
|
return null;
|
|
@@ -757,11 +774,11 @@ class AssignmentClassifier {
|
|
|
757
774
|
* Look up a bitmap field's width by bitmap type name and field name.
|
|
758
775
|
* Returns the field width if found, or null if the bitmap/field doesn't exist.
|
|
759
776
|
*/
|
|
760
|
-
private lookupBitmapFieldWidth(
|
|
777
|
+
private static lookupBitmapFieldWidth(
|
|
761
778
|
bitmapTypeName: string,
|
|
762
779
|
fieldName: string,
|
|
763
780
|
): number | null {
|
|
764
|
-
const fields =
|
|
781
|
+
const fields = CodeGenState.symbols!.bitmapFields.get(bitmapTypeName);
|
|
765
782
|
if (fields?.has(fieldName)) {
|
|
766
783
|
return fields.get(fieldName)!.width;
|
|
767
784
|
}
|
|
@@ -772,12 +789,12 @@ class AssignmentClassifier {
|
|
|
772
789
|
* Look up the bitmap type for a register member (e.g., "REG_MEMBER" -> "BitmapType").
|
|
773
790
|
* Returns the bitmap type name if found, or null.
|
|
774
791
|
*/
|
|
775
|
-
private lookupRegisterMemberBitmapType(
|
|
792
|
+
private static lookupRegisterMemberBitmapType(
|
|
776
793
|
registerName: string,
|
|
777
794
|
memberName: string,
|
|
778
795
|
): string | null {
|
|
779
796
|
const key = `${registerName}_${memberName}`;
|
|
780
|
-
return
|
|
797
|
+
return CodeGenState.symbols!.registerMemberTypes.get(key) ?? null;
|
|
781
798
|
}
|
|
782
799
|
}
|
|
783
800
|
|