c-next 0.1.61 → 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/grammar/CNext.g4 +3 -17
- package/package.json +1 -1
- package/src/cli/serve/ServeCommand.ts +57 -45
- package/src/lib/__tests__/parseCHeader.mocked.test.ts +145 -0
- package/src/transpiler/Transpiler.ts +603 -613
- package/src/transpiler/__tests__/DualCodePaths.test.ts +5 -1
- package/src/transpiler/__tests__/Transpiler.coverage.test.ts +2 -99
- package/src/transpiler/__tests__/Transpiler.test.ts +3 -26
- package/src/transpiler/data/IncludeTreeWalker.ts +1 -1
- package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +23 -52
- package/src/transpiler/logic/parser/grammar/CNext.interp +1 -3
- package/src/transpiler/logic/parser/grammar/CNextListener.ts +0 -22
- package/src/transpiler/logic/parser/grammar/CNextParser.ts +665 -1084
- package/src/transpiler/logic/parser/grammar/CNextVisitor.ts +0 -14
- package/src/transpiler/logic/symbols/CppSymbolCollector.ts +67 -43
- 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 +1410 -2587
- 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 +2082 -52
- 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 +227 -66
- package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +55 -58
- package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +288 -275
- package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +195 -133
- package/src/transpiler/output/codegen/assignment/AssignmentContextBuilder.ts +24 -74
- package/src/transpiler/output/codegen/assignment/AssignmentKind.ts +3 -0
- package/src/transpiler/output/codegen/assignment/IAssignmentContext.ts +3 -0
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +290 -320
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +42 -0
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +76 -2
- package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
- package/src/transpiler/output/codegen/generators/IOrchestrator.ts +5 -1
- 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/RegisterGenerator.ts +11 -24
- package/src/transpiler/output/codegen/generators/declarationGenerators/RegisterMacroGenerator.ts +64 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +137 -61
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopedRegisterGenerator.ts +18 -27
- 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/expressions/PostfixExpressionGenerator.ts +5 -1
- package/src/transpiler/output/codegen/generators/statements/ControlFlowGenerator.ts +1 -17
- package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
- package/src/transpiler/output/codegen/helpers/ArrayAccessHelper.ts +129 -0
- package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +40 -44
- package/src/transpiler/output/codegen/helpers/AssignmentTargetExtractor.ts +17 -45
- package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +83 -78
- 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/MemberSeparatorResolver.ts +10 -3
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
- package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +44 -0
- package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayAccessHelper.test.ts +479 -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__/MemberSeparatorResolver.test.ts +1 -0
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
- package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +201 -0
- package/src/transpiler/output/codegen/helpers/__tests__/TypeGenerationHelper.test.ts +50 -0
- 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/IArrayAccessDeps.ts +23 -0
- package/src/transpiler/output/codegen/types/IArrayAccessInfo.ts +26 -0
- package/src/transpiler/output/codegen/types/IMemberSeparatorDeps.ts +7 -0
- package/src/transpiler/output/codegen/utils/CodegenParserUtils.ts +98 -0
- package/src/transpiler/output/codegen/utils/ExpressionUnwrapper.ts +22 -22
- package/src/transpiler/output/codegen/utils/__tests__/CodegenParserUtils.test.ts +228 -0
- package/src/transpiler/types/IFileResult.ts +0 -4
- package/src/transpiler/types/IPipelineFile.ts +27 -0
- package/src/transpiler/types/IPipelineInput.ts +23 -0
- package/src/transpiler/types/TranspilerState.ts +1 -1
- package/src/utils/FormatUtils.ts +28 -2
- package/src/utils/MapUtils.ts +25 -0
- package/src/utils/PostfixAnalysisUtils.ts +48 -0
- package/src/utils/__tests__/FormatUtils.test.ts +42 -0
- package/src/utils/__tests__/MapUtils.test.ts +85 -0
- package/src/utils/constants/OperatorMappings.ts +19 -0
- package/src/transpiler/logic/StandaloneContextBuilder.ts +0 -150
- package/src/transpiler/logic/__tests__/StandaloneContextBuilder.test.ts +0 -647
- package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
- package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
- package/src/transpiler/types/ITranspileContext.ts +0 -49
- package/src/transpiler/types/ITranspileContribution.ts +0 -32
|
@@ -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,16 +270,25 @@ 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);
|
|
274
|
+
|
|
275
|
+
// Check for bit range through struct chain: devices[0].control[0, 4]
|
|
276
|
+
// Detected by last subscript having 2 expressions (start, width)
|
|
277
|
+
if (ctx.lastSubscriptExprCount === 2) {
|
|
278
|
+
return AssignmentKind.STRUCT_CHAIN_BIT_RANGE;
|
|
279
|
+
}
|
|
275
280
|
|
|
276
281
|
// Multi-dimensional array element: arr[i][j] (1 identifier, multiple subscripts)
|
|
277
282
|
if (ids.length === 1) {
|
|
278
|
-
return
|
|
283
|
+
return AssignmentClassifier.classifyMultiDimArrayAccess(
|
|
284
|
+
typeInfo,
|
|
285
|
+
ctx.subscripts.length,
|
|
286
|
+
);
|
|
279
287
|
}
|
|
280
288
|
|
|
281
289
|
// 2+ identifiers with subscripts: register bit or bitmap array
|
|
282
290
|
if (ids.length >= 2) {
|
|
283
|
-
const registerKind =
|
|
291
|
+
const registerKind = AssignmentClassifier.classifyRegisterBitAccess(
|
|
284
292
|
ids,
|
|
285
293
|
ctx.subscripts.length,
|
|
286
294
|
);
|
|
@@ -288,7 +296,7 @@ class AssignmentClassifier {
|
|
|
288
296
|
return registerKind;
|
|
289
297
|
}
|
|
290
298
|
|
|
291
|
-
return
|
|
299
|
+
return AssignmentClassifier.classifyBitmapArrayField(
|
|
292
300
|
ids[1],
|
|
293
301
|
typeInfo,
|
|
294
302
|
ctx.subscripts.length,
|
|
@@ -301,7 +309,7 @@ class AssignmentClassifier {
|
|
|
301
309
|
/**
|
|
302
310
|
* Classify multi-dimensional array access: arr[i][j] or arr[i][j][bit]
|
|
303
311
|
*/
|
|
304
|
-
private classifyMultiDimArrayAccess(
|
|
312
|
+
private static classifyMultiDimArrayAccess(
|
|
305
313
|
typeInfo: TTypeInfo | undefined,
|
|
306
314
|
subscriptCount: number,
|
|
307
315
|
): AssignmentKind | null {
|
|
@@ -325,16 +333,16 @@ class AssignmentClassifier {
|
|
|
325
333
|
/**
|
|
326
334
|
* Classify register bit access: REG.MEMBER[bit] or Scope.REG.MEMBER[bit]
|
|
327
335
|
*/
|
|
328
|
-
private classifyRegisterBitAccess(
|
|
336
|
+
private static classifyRegisterBitAccess(
|
|
329
337
|
ids: readonly string[],
|
|
330
338
|
subscriptCount: number,
|
|
331
339
|
): AssignmentKind | null {
|
|
332
340
|
const firstId = ids[0];
|
|
333
341
|
|
|
334
342
|
// Check for scoped register: Scope.REG.MEMBER[bit]
|
|
335
|
-
if (
|
|
343
|
+
if (CodeGenState.isKnownScope(firstId) && ids.length >= 3) {
|
|
336
344
|
const scopedRegName = `${firstId}_${ids[1]}`;
|
|
337
|
-
if (
|
|
345
|
+
if (CodeGenState.symbols!.knownRegisters.has(scopedRegName)) {
|
|
338
346
|
return subscriptCount === 2
|
|
339
347
|
? AssignmentKind.REGISTER_BIT_RANGE
|
|
340
348
|
: AssignmentKind.REGISTER_BIT;
|
|
@@ -342,7 +350,7 @@ class AssignmentClassifier {
|
|
|
342
350
|
}
|
|
343
351
|
|
|
344
352
|
// Check for non-scoped register: REG.MEMBER[bit]
|
|
345
|
-
if (
|
|
353
|
+
if (CodeGenState.symbols!.knownRegisters.has(firstId)) {
|
|
346
354
|
return subscriptCount === 2
|
|
347
355
|
? AssignmentKind.REGISTER_BIT_RANGE
|
|
348
356
|
: AssignmentKind.REGISTER_BIT;
|
|
@@ -354,7 +362,7 @@ class AssignmentClassifier {
|
|
|
354
362
|
/**
|
|
355
363
|
* Classify bitmap array element field: bitmapArr[i].field
|
|
356
364
|
*/
|
|
357
|
-
private classifyBitmapArrayField(
|
|
365
|
+
private static classifyBitmapArrayField(
|
|
358
366
|
secondId: string,
|
|
359
367
|
typeInfo: TTypeInfo | undefined,
|
|
360
368
|
subscriptCount: number,
|
|
@@ -367,7 +375,7 @@ class AssignmentClassifier {
|
|
|
367
375
|
return null;
|
|
368
376
|
}
|
|
369
377
|
|
|
370
|
-
const width =
|
|
378
|
+
const width = AssignmentClassifier.lookupBitmapFieldWidth(
|
|
371
379
|
typeInfo.bitmapTypeName,
|
|
372
380
|
secondId,
|
|
373
381
|
);
|
|
@@ -381,7 +389,7 @@ class AssignmentClassifier {
|
|
|
381
389
|
/**
|
|
382
390
|
* Classify global.* and this.* prefix patterns.
|
|
383
391
|
*/
|
|
384
|
-
private classifyPrefixPattern(
|
|
392
|
+
private static classifyPrefixPattern(
|
|
385
393
|
ctx: IAssignmentContext,
|
|
386
394
|
): AssignmentKind | null {
|
|
387
395
|
if (!ctx.hasGlobal && !ctx.hasThis) {
|
|
@@ -389,11 +397,11 @@ class AssignmentClassifier {
|
|
|
389
397
|
}
|
|
390
398
|
|
|
391
399
|
if (ctx.hasGlobal && ctx.postfixOpsCount > 0) {
|
|
392
|
-
return
|
|
400
|
+
return AssignmentClassifier.classifyGlobalPrefix(ctx);
|
|
393
401
|
}
|
|
394
402
|
|
|
395
403
|
if (ctx.hasThis && ctx.postfixOpsCount > 0) {
|
|
396
|
-
return
|
|
404
|
+
return AssignmentClassifier.classifyThisPrefix(ctx);
|
|
397
405
|
}
|
|
398
406
|
|
|
399
407
|
return null;
|
|
@@ -402,11 +410,11 @@ class AssignmentClassifier {
|
|
|
402
410
|
/**
|
|
403
411
|
* Classify global.* patterns: global.reg[bit], global.arr[i], global.member
|
|
404
412
|
*/
|
|
405
|
-
private classifyGlobalPrefix(ctx: IAssignmentContext): AssignmentKind {
|
|
413
|
+
private static classifyGlobalPrefix(ctx: IAssignmentContext): AssignmentKind {
|
|
406
414
|
const firstId = ctx.identifiers[0];
|
|
407
415
|
|
|
408
416
|
if (ctx.hasArrayAccess) {
|
|
409
|
-
if (
|
|
417
|
+
if (CodeGenState.symbols!.knownRegisters.has(firstId)) {
|
|
410
418
|
return AssignmentKind.GLOBAL_REGISTER_BIT;
|
|
411
419
|
}
|
|
412
420
|
return AssignmentKind.GLOBAL_ARRAY;
|
|
@@ -418,24 +426,27 @@ class AssignmentClassifier {
|
|
|
418
426
|
/**
|
|
419
427
|
* Classify this.* patterns: this.reg[bit], this.member, this.REG.MEMBER.field
|
|
420
428
|
*/
|
|
421
|
-
private classifyThisPrefix(ctx: IAssignmentContext): AssignmentKind {
|
|
422
|
-
if (!
|
|
429
|
+
private static classifyThisPrefix(ctx: IAssignmentContext): AssignmentKind {
|
|
430
|
+
if (!CodeGenState.currentScope) {
|
|
423
431
|
return AssignmentKind.THIS_MEMBER;
|
|
424
432
|
}
|
|
425
433
|
|
|
426
434
|
const firstId = ctx.identifiers[0];
|
|
427
|
-
const scopedRegName = `${
|
|
435
|
+
const scopedRegName = `${CodeGenState.currentScope}_${firstId}`;
|
|
428
436
|
|
|
429
437
|
if (ctx.hasArrayAccess) {
|
|
430
|
-
return
|
|
438
|
+
return AssignmentClassifier.classifyThisWithArrayAccess(
|
|
439
|
+
ctx,
|
|
440
|
+
scopedRegName,
|
|
441
|
+
);
|
|
431
442
|
}
|
|
432
443
|
|
|
433
444
|
// this.REG.MEMBER.field (scoped register bitmap field)
|
|
434
445
|
if (
|
|
435
446
|
ctx.identifiers.length === 3 &&
|
|
436
|
-
|
|
447
|
+
CodeGenState.symbols!.knownRegisters.has(scopedRegName)
|
|
437
448
|
) {
|
|
438
|
-
const bitmapType =
|
|
449
|
+
const bitmapType = AssignmentClassifier.lookupRegisterMemberBitmapType(
|
|
439
450
|
scopedRegName,
|
|
440
451
|
ctx.identifiers[1],
|
|
441
452
|
);
|
|
@@ -450,11 +461,11 @@ class AssignmentClassifier {
|
|
|
450
461
|
/**
|
|
451
462
|
* Classify this.reg[bit] / this.arr[i] patterns with array access.
|
|
452
463
|
*/
|
|
453
|
-
private classifyThisWithArrayAccess(
|
|
464
|
+
private static classifyThisWithArrayAccess(
|
|
454
465
|
ctx: IAssignmentContext,
|
|
455
466
|
scopedRegName: string,
|
|
456
467
|
): AssignmentKind {
|
|
457
|
-
if (
|
|
468
|
+
if (CodeGenState.symbols!.knownRegisters.has(scopedRegName)) {
|
|
458
469
|
const hasBitRange = ctx.postfixOps.some((op) => op.COMMA() !== null);
|
|
459
470
|
return hasBitRange
|
|
460
471
|
? AssignmentKind.SCOPED_REGISTER_BIT_RANGE
|
|
@@ -470,7 +481,7 @@ class AssignmentClassifier {
|
|
|
470
481
|
* Issue #579: Uses shared SubscriptClassifier to ensure consistent behavior
|
|
471
482
|
* with the expression path in CodeGenerator._generatePostfixExpr.
|
|
472
483
|
*/
|
|
473
|
-
private classifyArrayOrBitAccess(
|
|
484
|
+
private static classifyArrayOrBitAccess(
|
|
474
485
|
ctx: IAssignmentContext,
|
|
475
486
|
): AssignmentKind | null {
|
|
476
487
|
// Must have arrayAccess without memberAccess or prefix
|
|
@@ -483,17 +494,34 @@ class AssignmentClassifier {
|
|
|
483
494
|
}
|
|
484
495
|
|
|
485
496
|
const name = ctx.identifiers[0];
|
|
486
|
-
const typeInfo =
|
|
497
|
+
const typeInfo = CodeGenState.typeRegistry.get(name) ?? null;
|
|
487
498
|
|
|
488
499
|
// Use shared classifier for array vs bit access decision
|
|
500
|
+
// Use lastSubscriptExprCount to distinguish [0][0] (two ops, each 1 expr)
|
|
501
|
+
// from [0, 5] (one op, 2 exprs)
|
|
489
502
|
const subscriptKind = SubscriptClassifier.classify({
|
|
490
503
|
typeInfo,
|
|
491
|
-
subscriptCount: ctx.
|
|
504
|
+
subscriptCount: ctx.lastSubscriptExprCount,
|
|
492
505
|
isRegisterAccess: false,
|
|
493
506
|
});
|
|
494
507
|
|
|
495
508
|
switch (subscriptKind) {
|
|
496
509
|
case "array_element":
|
|
510
|
+
// Multi-dimensional array: matrix[i][j] has multiple subscript operations
|
|
511
|
+
// but each with 1 expression (vs slice [0, 5] with 2 expressions in 1 op)
|
|
512
|
+
if (ctx.subscripts.length > 1) {
|
|
513
|
+
// Check if last subscript is bit access on an integer array element
|
|
514
|
+
// e.g., matrix[i][j][bit] where matrix is 2D integer array
|
|
515
|
+
const numDims = typeInfo?.arrayDimensions?.length ?? 0;
|
|
516
|
+
if (
|
|
517
|
+
ctx.subscripts.length === numDims + 1 &&
|
|
518
|
+
typeInfo &&
|
|
519
|
+
TypeCheckUtils.isInteger(typeInfo.baseType)
|
|
520
|
+
) {
|
|
521
|
+
return AssignmentKind.ARRAY_ELEMENT_BIT;
|
|
522
|
+
}
|
|
523
|
+
return AssignmentKind.MULTI_DIM_ARRAY_ELEMENT;
|
|
524
|
+
}
|
|
497
525
|
// String array element (special case for 2D string arrays)
|
|
498
526
|
if (
|
|
499
527
|
typeInfo?.isString &&
|
|
@@ -519,7 +547,7 @@ class AssignmentClassifier {
|
|
|
519
547
|
* Classify atomic and overflow-clamped compound assignments.
|
|
520
548
|
* Handles simple identifiers, this.member, and global.member patterns.
|
|
521
549
|
*/
|
|
522
|
-
private classifySpecialCompound(
|
|
550
|
+
private static classifySpecialCompound(
|
|
523
551
|
ctx: IAssignmentContext,
|
|
524
552
|
): AssignmentKind | null {
|
|
525
553
|
if (!ctx.isCompound) {
|
|
@@ -530,16 +558,16 @@ class AssignmentClassifier {
|
|
|
530
558
|
let typeInfo;
|
|
531
559
|
if (ctx.isSimpleIdentifier) {
|
|
532
560
|
const id = ctx.identifiers[0];
|
|
533
|
-
typeInfo =
|
|
534
|
-
} else if (ctx.isSimpleThisAccess &&
|
|
561
|
+
typeInfo = CodeGenState.typeRegistry.get(id);
|
|
562
|
+
} else if (ctx.isSimpleThisAccess && CodeGenState.currentScope) {
|
|
535
563
|
// this.member pattern: lookup using scoped name
|
|
536
564
|
const memberName = ctx.identifiers[0];
|
|
537
|
-
const scopedName = `${
|
|
538
|
-
typeInfo =
|
|
565
|
+
const scopedName = `${CodeGenState.currentScope}_${memberName}`;
|
|
566
|
+
typeInfo = CodeGenState.typeRegistry.get(scopedName);
|
|
539
567
|
} else if (ctx.isSimpleGlobalAccess) {
|
|
540
568
|
// global.member pattern: lookup using direct name
|
|
541
569
|
const memberName = ctx.identifiers[0];
|
|
542
|
-
typeInfo =
|
|
570
|
+
typeInfo = CodeGenState.typeRegistry.get(memberName);
|
|
543
571
|
} else {
|
|
544
572
|
return null;
|
|
545
573
|
}
|
|
@@ -571,13 +599,13 @@ class AssignmentClassifier {
|
|
|
571
599
|
/**
|
|
572
600
|
* Check if a simple identifier is a string variable.
|
|
573
601
|
*/
|
|
574
|
-
private _classifySimpleStringVar(
|
|
602
|
+
private static _classifySimpleStringVar(
|
|
575
603
|
ctx: IAssignmentContext,
|
|
576
604
|
): AssignmentKind | null {
|
|
577
605
|
if (!ctx.isSimpleIdentifier) return null;
|
|
578
606
|
const id = ctx.identifiers[0];
|
|
579
|
-
const typeInfo =
|
|
580
|
-
return
|
|
607
|
+
const typeInfo = CodeGenState.typeRegistry.get(id);
|
|
608
|
+
return AssignmentClassifier.isSimpleStringType(typeInfo)
|
|
581
609
|
? AssignmentKind.STRING_SIMPLE
|
|
582
610
|
: null;
|
|
583
611
|
}
|
|
@@ -585,14 +613,14 @@ class AssignmentClassifier {
|
|
|
585
613
|
/**
|
|
586
614
|
* Check if this.member is a string.
|
|
587
615
|
*/
|
|
588
|
-
private _classifyThisMemberString(
|
|
616
|
+
private static _classifyThisMemberString(
|
|
589
617
|
ctx: IAssignmentContext,
|
|
590
618
|
): AssignmentKind | null {
|
|
591
|
-
if (!ctx.isSimpleThisAccess || !
|
|
619
|
+
if (!ctx.isSimpleThisAccess || !CodeGenState.currentScope) return null;
|
|
592
620
|
const memberName = ctx.identifiers[0];
|
|
593
|
-
const scopedName = `${
|
|
594
|
-
const typeInfo =
|
|
595
|
-
return
|
|
621
|
+
const scopedName = `${CodeGenState.currentScope}_${memberName}`;
|
|
622
|
+
const typeInfo = CodeGenState.typeRegistry.get(scopedName);
|
|
623
|
+
return AssignmentClassifier.isSimpleStringType(typeInfo)
|
|
596
624
|
? AssignmentKind.STRING_THIS_MEMBER
|
|
597
625
|
: null;
|
|
598
626
|
}
|
|
@@ -600,37 +628,67 @@ class AssignmentClassifier {
|
|
|
600
628
|
/**
|
|
601
629
|
* Check if global.member is a string.
|
|
602
630
|
*/
|
|
603
|
-
private _classifyGlobalString(
|
|
631
|
+
private static _classifyGlobalString(
|
|
604
632
|
ctx: IAssignmentContext,
|
|
605
633
|
): AssignmentKind | null {
|
|
606
634
|
if (!ctx.isSimpleGlobalAccess) return null;
|
|
607
635
|
const id = ctx.identifiers[0];
|
|
608
|
-
const typeInfo =
|
|
609
|
-
return
|
|
636
|
+
const typeInfo = CodeGenState.typeRegistry.get(id);
|
|
637
|
+
return AssignmentClassifier.isSimpleStringType(typeInfo)
|
|
610
638
|
? AssignmentKind.STRING_GLOBAL
|
|
611
639
|
: null;
|
|
612
640
|
}
|
|
613
641
|
|
|
642
|
+
/**
|
|
643
|
+
* Resolve struct type from variable name.
|
|
644
|
+
* Returns the base struct type if valid, null if not a known struct.
|
|
645
|
+
*/
|
|
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
|
+
) {
|
|
652
|
+
return null;
|
|
653
|
+
}
|
|
654
|
+
return structTypeInfo.baseType;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Resolve struct field type from struct variable name and field name.
|
|
659
|
+
* Returns null if struct type can't be resolved or field doesn't exist.
|
|
660
|
+
*/
|
|
661
|
+
private static _resolveStructFieldType(structFieldNames: {
|
|
662
|
+
structName: string;
|
|
663
|
+
fieldName: string;
|
|
664
|
+
}): { structType: string; fieldType: string | undefined } | null {
|
|
665
|
+
const structType = AssignmentClassifier._resolveStructType(
|
|
666
|
+
structFieldNames.structName,
|
|
667
|
+
);
|
|
668
|
+
if (!structType) {
|
|
669
|
+
return null;
|
|
670
|
+
}
|
|
671
|
+
const structFields = CodeGenState.symbols!.structFields.get(structType);
|
|
672
|
+
const fieldType = structFields?.get(structFieldNames.fieldName);
|
|
673
|
+
return { structType, fieldType };
|
|
674
|
+
}
|
|
675
|
+
|
|
614
676
|
/**
|
|
615
677
|
* Check if struct.field is a string field.
|
|
616
678
|
*/
|
|
617
|
-
private _classifyStructFieldString(
|
|
679
|
+
private static _classifyStructFieldString(
|
|
618
680
|
ctx: IAssignmentContext,
|
|
619
681
|
structFieldNames: { structName: string; fieldName: string } | null,
|
|
620
682
|
): AssignmentKind | null {
|
|
621
683
|
if (!ctx.hasMemberAccess || ctx.hasArrayAccess || !structFieldNames) {
|
|
622
684
|
return null;
|
|
623
685
|
}
|
|
624
|
-
const
|
|
625
|
-
|
|
626
|
-
if (!
|
|
686
|
+
const resolved =
|
|
687
|
+
AssignmentClassifier._resolveStructFieldType(structFieldNames);
|
|
688
|
+
if (!resolved) {
|
|
627
689
|
return null;
|
|
628
690
|
}
|
|
629
|
-
|
|
630
|
-
structTypeInfo.baseType,
|
|
631
|
-
);
|
|
632
|
-
const fieldType = structFields?.get(fieldName);
|
|
633
|
-
return fieldType && TypeCheckUtils.isString(fieldType)
|
|
691
|
+
return resolved.fieldType && TypeCheckUtils.isString(resolved.fieldType)
|
|
634
692
|
? AssignmentKind.STRING_STRUCT_FIELD
|
|
635
693
|
: null;
|
|
636
694
|
}
|
|
@@ -638,7 +696,7 @@ class AssignmentClassifier {
|
|
|
638
696
|
/**
|
|
639
697
|
* Check if struct.arr[i] is a string array element.
|
|
640
698
|
*/
|
|
641
|
-
private _classifyStructArrayElementString(
|
|
699
|
+
private static _classifyStructArrayElementString(
|
|
642
700
|
ctx: IAssignmentContext,
|
|
643
701
|
structFieldNames: { structName: string; fieldName: string } | null,
|
|
644
702
|
): AssignmentKind | null {
|
|
@@ -650,19 +708,19 @@ class AssignmentClassifier {
|
|
|
650
708
|
) {
|
|
651
709
|
return null;
|
|
652
710
|
}
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
if (!
|
|
711
|
+
const resolved =
|
|
712
|
+
AssignmentClassifier._resolveStructFieldType(structFieldNames);
|
|
713
|
+
if (!resolved) {
|
|
656
714
|
return null;
|
|
657
715
|
}
|
|
658
716
|
|
|
659
|
-
const structType =
|
|
660
|
-
const
|
|
661
|
-
const
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
717
|
+
const { structType, fieldType } = resolved;
|
|
718
|
+
const { fieldName } = structFieldNames;
|
|
719
|
+
const fieldArrays = CodeGenState.symbols!.structFieldArrays.get(structType);
|
|
720
|
+
const dimensions =
|
|
721
|
+
CodeGenState.symbols!.structFieldDimensions.get(structType)?.get(
|
|
722
|
+
fieldName,
|
|
723
|
+
);
|
|
666
724
|
|
|
667
725
|
const isStringArrayField =
|
|
668
726
|
fieldType &&
|
|
@@ -679,30 +737,34 @@ class AssignmentClassifier {
|
|
|
679
737
|
/**
|
|
680
738
|
* Classify string assignments.
|
|
681
739
|
*/
|
|
682
|
-
private classifyStringAssignment(
|
|
740
|
+
private static classifyStringAssignment(
|
|
683
741
|
ctx: IAssignmentContext,
|
|
684
742
|
): AssignmentKind | null {
|
|
685
743
|
// Simple string variable
|
|
686
|
-
const simpleVar =
|
|
744
|
+
const simpleVar = AssignmentClassifier._classifySimpleStringVar(ctx);
|
|
687
745
|
if (simpleVar) return simpleVar;
|
|
688
746
|
|
|
689
747
|
// this.member string
|
|
690
|
-
const thisMember =
|
|
748
|
+
const thisMember = AssignmentClassifier._classifyThisMemberString(ctx);
|
|
691
749
|
if (thisMember) return thisMember;
|
|
692
750
|
|
|
693
751
|
// global.member string
|
|
694
|
-
const globalMember =
|
|
752
|
+
const globalMember = AssignmentClassifier._classifyGlobalString(ctx);
|
|
695
753
|
if (globalMember) return globalMember;
|
|
696
754
|
|
|
697
755
|
// struct.field or struct.arr[i] string
|
|
698
|
-
const structFieldNames =
|
|
699
|
-
const structField =
|
|
700
|
-
if (structField) return structField;
|
|
701
|
-
|
|
702
|
-
const structArrayElement = this._classifyStructArrayElementString(
|
|
756
|
+
const structFieldNames = AssignmentClassifier.getStructFieldNames(ctx);
|
|
757
|
+
const structField = AssignmentClassifier._classifyStructFieldString(
|
|
703
758
|
ctx,
|
|
704
759
|
structFieldNames,
|
|
705
760
|
);
|
|
761
|
+
if (structField) return structField;
|
|
762
|
+
|
|
763
|
+
const structArrayElement =
|
|
764
|
+
AssignmentClassifier._classifyStructArrayElementString(
|
|
765
|
+
ctx,
|
|
766
|
+
structFieldNames,
|
|
767
|
+
);
|
|
706
768
|
if (structArrayElement) return structArrayElement;
|
|
707
769
|
|
|
708
770
|
return null;
|
|
@@ -712,11 +774,11 @@ class AssignmentClassifier {
|
|
|
712
774
|
* Look up a bitmap field's width by bitmap type name and field name.
|
|
713
775
|
* Returns the field width if found, or null if the bitmap/field doesn't exist.
|
|
714
776
|
*/
|
|
715
|
-
private lookupBitmapFieldWidth(
|
|
777
|
+
private static lookupBitmapFieldWidth(
|
|
716
778
|
bitmapTypeName: string,
|
|
717
779
|
fieldName: string,
|
|
718
780
|
): number | null {
|
|
719
|
-
const fields =
|
|
781
|
+
const fields = CodeGenState.symbols!.bitmapFields.get(bitmapTypeName);
|
|
720
782
|
if (fields?.has(fieldName)) {
|
|
721
783
|
return fields.get(fieldName)!.width;
|
|
722
784
|
}
|
|
@@ -727,12 +789,12 @@ class AssignmentClassifier {
|
|
|
727
789
|
* Look up the bitmap type for a register member (e.g., "REG_MEMBER" -> "BitmapType").
|
|
728
790
|
* Returns the bitmap type name if found, or null.
|
|
729
791
|
*/
|
|
730
|
-
private lookupRegisterMemberBitmapType(
|
|
792
|
+
private static lookupRegisterMemberBitmapType(
|
|
731
793
|
registerName: string,
|
|
732
794
|
memberName: string,
|
|
733
795
|
): string | null {
|
|
734
796
|
const key = `${registerName}_${memberName}`;
|
|
735
|
-
return
|
|
797
|
+
return CodeGenState.symbols!.registerMemberTypes.get(key) ?? null;
|
|
736
798
|
}
|
|
737
799
|
}
|
|
738
800
|
|