c-next 0.1.62 → 0.1.64
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 +848 -1382
- 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 +462 -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
|
@@ -3,22 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Issue #644: Tests for the extracted member chain analyzer.
|
|
5
5
|
* Updated to use unified postfixTargetOp grammar after consolidation.
|
|
6
|
+
* Migrated to use CodeGenState instead of constructor DI.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
|
-
import { describe, it, expect, beforeEach
|
|
9
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
9
10
|
import MemberChainAnalyzer from "../MemberChainAnalyzer.js";
|
|
10
|
-
import
|
|
11
|
+
import CodeGenState from "../../CodeGenState.js";
|
|
11
12
|
import type * as Parser from "../../../../logic/parser/grammar/CNextParser.js";
|
|
12
13
|
|
|
13
|
-
/** Test-local copy of IMemberChainAnalyzerDeps interface */
|
|
14
|
-
interface IMemberChainAnalyzerDeps {
|
|
15
|
-
typeRegistry: ReadonlyMap<string, TTypeInfo>;
|
|
16
|
-
structFields: ReadonlyMap<string, ReadonlyMap<string, string>>;
|
|
17
|
-
structFieldArrays: ReadonlyMap<string, ReadonlySet<string>>;
|
|
18
|
-
isKnownStruct: (name: string) => boolean;
|
|
19
|
-
generateExpression: (ctx: Parser.ExpressionContext) => string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
14
|
/** Mock type for PostfixTargetOpContext */
|
|
23
15
|
interface IMockPostfixOp {
|
|
24
16
|
IDENTIFIER: () => { getText: () => string } | null;
|
|
@@ -65,47 +57,89 @@ function createTargetCtx(baseId: string | null, postfixOps: IMockPostfixOp[]) {
|
|
|
65
57
|
} as unknown as Parser.AssignmentTargetContext;
|
|
66
58
|
}
|
|
67
59
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Mock generateExpression callback - just returns getText() of the context
|
|
62
|
+
*/
|
|
63
|
+
function mockGenerateExpression(ctx: Parser.ExpressionContext): string {
|
|
64
|
+
return (ctx as unknown as { getText(): string }).getText();
|
|
65
|
+
}
|
|
74
66
|
|
|
67
|
+
describe("MemberChainAnalyzer", () => {
|
|
75
68
|
beforeEach(() => {
|
|
76
|
-
|
|
77
|
-
structFields = new Map();
|
|
78
|
-
structFieldArrays = new Map();
|
|
79
|
-
|
|
80
|
-
deps = {
|
|
81
|
-
typeRegistry,
|
|
82
|
-
structFields,
|
|
83
|
-
structFieldArrays,
|
|
84
|
-
isKnownStruct: vi.fn((name) => structFields.has(name)),
|
|
85
|
-
generateExpression: vi.fn((ctx) =>
|
|
86
|
-
(ctx as { getText(): string }).getText(),
|
|
87
|
-
),
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
analyzer = new MemberChainAnalyzer(deps);
|
|
69
|
+
CodeGenState.reset();
|
|
91
70
|
});
|
|
92
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Helper to set up struct fields in CodeGenState.symbols
|
|
74
|
+
*/
|
|
75
|
+
function setupStructFields(
|
|
76
|
+
structName: string,
|
|
77
|
+
fields: Map<string, string>,
|
|
78
|
+
arrayFields: Set<string> = new Set(),
|
|
79
|
+
): void {
|
|
80
|
+
// Initialize symbols if not set
|
|
81
|
+
if (!CodeGenState.symbols) {
|
|
82
|
+
CodeGenState.symbols = {
|
|
83
|
+
knownStructs: new Set(),
|
|
84
|
+
knownScopes: new Set(),
|
|
85
|
+
knownEnums: new Set(),
|
|
86
|
+
knownBitmaps: new Set(),
|
|
87
|
+
knownRegisters: new Set(),
|
|
88
|
+
structFields: new Map(),
|
|
89
|
+
structFieldArrays: new Map(),
|
|
90
|
+
structFieldDimensions: new Map(),
|
|
91
|
+
enumMembers: new Map(),
|
|
92
|
+
bitmapFields: new Map(),
|
|
93
|
+
bitmapBackingType: new Map(),
|
|
94
|
+
bitmapBitWidth: new Map(),
|
|
95
|
+
scopeMembers: new Map(),
|
|
96
|
+
scopeMemberVisibility: new Map(),
|
|
97
|
+
scopedRegisters: new Map(),
|
|
98
|
+
registerMemberAccess: new Map(),
|
|
99
|
+
registerMemberTypes: new Map(),
|
|
100
|
+
registerBaseAddresses: new Map(),
|
|
101
|
+
registerMemberOffsets: new Map(),
|
|
102
|
+
registerMemberCTypes: new Map(),
|
|
103
|
+
scopeVariableUsage: new Map(),
|
|
104
|
+
scopePrivateConstValues: new Map(),
|
|
105
|
+
functionReturnTypes: new Map(),
|
|
106
|
+
getSingleFunctionForVariable: () => null,
|
|
107
|
+
hasPublicSymbols: () => false,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
(CodeGenState.symbols.knownStructs as Set<string>).add(structName);
|
|
111
|
+
(CodeGenState.symbols.structFields as Map<string, Map<string, string>>).set(
|
|
112
|
+
structName,
|
|
113
|
+
fields,
|
|
114
|
+
);
|
|
115
|
+
(CodeGenState.symbols.structFieldArrays as Map<string, Set<string>>).set(
|
|
116
|
+
structName,
|
|
117
|
+
arrayFields,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
93
121
|
describe("analyze", () => {
|
|
94
122
|
it("returns isBitAccess false when no base identifier", () => {
|
|
95
123
|
const targetCtx = createTargetCtx(null, []);
|
|
96
|
-
const result =
|
|
124
|
+
const result = MemberChainAnalyzer.analyze(
|
|
125
|
+
targetCtx,
|
|
126
|
+
mockGenerateExpression,
|
|
127
|
+
);
|
|
97
128
|
expect(result.isBitAccess).toBe(false);
|
|
98
129
|
});
|
|
99
130
|
|
|
100
131
|
it("returns isBitAccess false when no postfix operations", () => {
|
|
101
132
|
const targetCtx = createTargetCtx("x", []);
|
|
102
|
-
const result =
|
|
133
|
+
const result = MemberChainAnalyzer.analyze(
|
|
134
|
+
targetCtx,
|
|
135
|
+
mockGenerateExpression,
|
|
136
|
+
);
|
|
103
137
|
expect(result.isBitAccess).toBe(false);
|
|
104
138
|
});
|
|
105
139
|
|
|
106
140
|
it("returns isBitAccess false when last op is member access", () => {
|
|
107
141
|
// point.flags (no subscript at end)
|
|
108
|
-
typeRegistry.set("point", {
|
|
142
|
+
CodeGenState.typeRegistry.set("point", {
|
|
109
143
|
baseType: "Point",
|
|
110
144
|
bitWidth: 0,
|
|
111
145
|
isArray: false,
|
|
@@ -113,16 +147,19 @@ describe("MemberChainAnalyzer", () => {
|
|
|
113
147
|
});
|
|
114
148
|
const pointFields = new Map<string, string>();
|
|
115
149
|
pointFields.set("flags", "u8");
|
|
116
|
-
|
|
150
|
+
setupStructFields("Point", pointFields);
|
|
117
151
|
|
|
118
152
|
const targetCtx = createTargetCtx("point", [createMemberOp("flags")]);
|
|
119
|
-
const result =
|
|
153
|
+
const result = MemberChainAnalyzer.analyze(
|
|
154
|
+
targetCtx,
|
|
155
|
+
mockGenerateExpression,
|
|
156
|
+
);
|
|
120
157
|
expect(result.isBitAccess).toBe(false);
|
|
121
158
|
});
|
|
122
159
|
|
|
123
160
|
it("returns isBitAccess false when last subscript has 2 expressions (bit range)", () => {
|
|
124
161
|
// flags[0, 8] - bit range, not single bit access
|
|
125
|
-
typeRegistry.set("flags", {
|
|
162
|
+
CodeGenState.typeRegistry.set("flags", {
|
|
126
163
|
baseType: "u32",
|
|
127
164
|
bitWidth: 32,
|
|
128
165
|
isArray: false,
|
|
@@ -130,7 +167,10 @@ describe("MemberChainAnalyzer", () => {
|
|
|
130
167
|
});
|
|
131
168
|
|
|
132
169
|
const targetCtx = createTargetCtx("flags", [createBitRangeOp("0", "8")]);
|
|
133
|
-
const result =
|
|
170
|
+
const result = MemberChainAnalyzer.analyze(
|
|
171
|
+
targetCtx,
|
|
172
|
+
mockGenerateExpression,
|
|
173
|
+
);
|
|
134
174
|
expect(result.isBitAccess).toBe(false);
|
|
135
175
|
});
|
|
136
176
|
|
|
@@ -138,10 +178,9 @@ describe("MemberChainAnalyzer", () => {
|
|
|
138
178
|
// Setup: struct Point { u8 flags; }
|
|
139
179
|
const pointFields = new Map<string, string>();
|
|
140
180
|
pointFields.set("flags", "u8");
|
|
141
|
-
|
|
142
|
-
structFieldArrays.set("Point", new Set());
|
|
181
|
+
setupStructFields("Point", pointFields);
|
|
143
182
|
|
|
144
|
-
typeRegistry.set("point", {
|
|
183
|
+
CodeGenState.typeRegistry.set("point", {
|
|
145
184
|
baseType: "Point",
|
|
146
185
|
bitWidth: 0,
|
|
147
186
|
isArray: false,
|
|
@@ -153,7 +192,10 @@ describe("MemberChainAnalyzer", () => {
|
|
|
153
192
|
createSubscriptOp("3"),
|
|
154
193
|
]);
|
|
155
194
|
|
|
156
|
-
const result =
|
|
195
|
+
const result = MemberChainAnalyzer.analyze(
|
|
196
|
+
targetCtx,
|
|
197
|
+
mockGenerateExpression,
|
|
198
|
+
);
|
|
157
199
|
|
|
158
200
|
expect(result.isBitAccess).toBe(true);
|
|
159
201
|
expect(result.baseTarget).toBe("point.flags");
|
|
@@ -165,10 +207,9 @@ describe("MemberChainAnalyzer", () => {
|
|
|
165
207
|
// Setup: struct Grid { u8 items[10]; }
|
|
166
208
|
const gridFields = new Map<string, string>();
|
|
167
209
|
gridFields.set("items", "u8");
|
|
168
|
-
|
|
169
|
-
structFieldArrays.set("Grid", new Set(["items"]));
|
|
210
|
+
setupStructFields("Grid", gridFields, new Set(["items"]));
|
|
170
211
|
|
|
171
|
-
typeRegistry.set("grid", {
|
|
212
|
+
CodeGenState.typeRegistry.set("grid", {
|
|
172
213
|
baseType: "Grid",
|
|
173
214
|
bitWidth: 0,
|
|
174
215
|
isArray: false,
|
|
@@ -180,7 +221,10 @@ describe("MemberChainAnalyzer", () => {
|
|
|
180
221
|
createSubscriptOp("0"),
|
|
181
222
|
]);
|
|
182
223
|
|
|
183
|
-
const result =
|
|
224
|
+
const result = MemberChainAnalyzer.analyze(
|
|
225
|
+
targetCtx,
|
|
226
|
+
mockGenerateExpression,
|
|
227
|
+
);
|
|
184
228
|
|
|
185
229
|
// items is an array, so [0] is array access, not bit access
|
|
186
230
|
expect(result.isBitAccess).toBe(false);
|
|
@@ -190,10 +234,9 @@ describe("MemberChainAnalyzer", () => {
|
|
|
190
234
|
// Setup: struct Point { string name; }
|
|
191
235
|
const pointFields = new Map<string, string>();
|
|
192
236
|
pointFields.set("name", "string");
|
|
193
|
-
|
|
194
|
-
structFieldArrays.set("Point", new Set());
|
|
237
|
+
setupStructFields("Point", pointFields);
|
|
195
238
|
|
|
196
|
-
typeRegistry.set("point", {
|
|
239
|
+
CodeGenState.typeRegistry.set("point", {
|
|
197
240
|
baseType: "Point",
|
|
198
241
|
bitWidth: 0,
|
|
199
242
|
isArray: false,
|
|
@@ -205,7 +248,10 @@ describe("MemberChainAnalyzer", () => {
|
|
|
205
248
|
createSubscriptOp("0"),
|
|
206
249
|
]);
|
|
207
250
|
|
|
208
|
-
const result =
|
|
251
|
+
const result = MemberChainAnalyzer.analyze(
|
|
252
|
+
targetCtx,
|
|
253
|
+
mockGenerateExpression,
|
|
254
|
+
);
|
|
209
255
|
|
|
210
256
|
// name is a string, not an integer, so no bit access
|
|
211
257
|
expect(result.isBitAccess).toBe(false);
|
|
@@ -215,10 +261,9 @@ describe("MemberChainAnalyzer", () => {
|
|
|
215
261
|
// Setup: struct Device { u8 flags; }, Device devices[4];
|
|
216
262
|
const deviceFields = new Map<string, string>();
|
|
217
263
|
deviceFields.set("flags", "u8");
|
|
218
|
-
|
|
219
|
-
structFieldArrays.set("Device", new Set());
|
|
264
|
+
setupStructFields("Device", deviceFields);
|
|
220
265
|
|
|
221
|
-
typeRegistry.set("devices", {
|
|
266
|
+
CodeGenState.typeRegistry.set("devices", {
|
|
222
267
|
baseType: "Device",
|
|
223
268
|
bitWidth: 0,
|
|
224
269
|
isArray: true,
|
|
@@ -232,7 +277,10 @@ describe("MemberChainAnalyzer", () => {
|
|
|
232
277
|
createSubscriptOp("7"),
|
|
233
278
|
]);
|
|
234
279
|
|
|
235
|
-
const result =
|
|
280
|
+
const result = MemberChainAnalyzer.analyze(
|
|
281
|
+
targetCtx,
|
|
282
|
+
mockGenerateExpression,
|
|
283
|
+
);
|
|
236
284
|
|
|
237
285
|
expect(result.isBitAccess).toBe(true);
|
|
238
286
|
expect(result.baseTarget).toBe("devices[0].flags");
|
|
@@ -242,7 +290,7 @@ describe("MemberChainAnalyzer", () => {
|
|
|
242
290
|
|
|
243
291
|
it("returns false for 2D array element: matrix[0][1]", () => {
|
|
244
292
|
// matrix[0][1] is array access, not bit access
|
|
245
|
-
typeRegistry.set("matrix", {
|
|
293
|
+
CodeGenState.typeRegistry.set("matrix", {
|
|
246
294
|
baseType: "u8",
|
|
247
295
|
bitWidth: 8,
|
|
248
296
|
isArray: true,
|
|
@@ -255,7 +303,10 @@ describe("MemberChainAnalyzer", () => {
|
|
|
255
303
|
createSubscriptOp("1"),
|
|
256
304
|
]);
|
|
257
305
|
|
|
258
|
-
const result =
|
|
306
|
+
const result = MemberChainAnalyzer.analyze(
|
|
307
|
+
targetCtx,
|
|
308
|
+
mockGenerateExpression,
|
|
309
|
+
);
|
|
259
310
|
|
|
260
311
|
// This is 2D array access, not bit access
|
|
261
312
|
expect(result.isBitAccess).toBe(false);
|
|
@@ -264,7 +315,7 @@ describe("MemberChainAnalyzer", () => {
|
|
|
264
315
|
it("detects bit access on 2D array element: matrix[0][1][3]", () => {
|
|
265
316
|
// matrix[0][1][3] where matrix is u8[4][4]
|
|
266
317
|
// The third subscript [3] is bit access on the u8 element
|
|
267
|
-
typeRegistry.set("matrix", {
|
|
318
|
+
CodeGenState.typeRegistry.set("matrix", {
|
|
268
319
|
baseType: "u8",
|
|
269
320
|
bitWidth: 8,
|
|
270
321
|
isArray: true,
|
|
@@ -278,7 +329,10 @@ describe("MemberChainAnalyzer", () => {
|
|
|
278
329
|
createSubscriptOp("3"),
|
|
279
330
|
]);
|
|
280
331
|
|
|
281
|
-
const result =
|
|
332
|
+
const result = MemberChainAnalyzer.analyze(
|
|
333
|
+
targetCtx,
|
|
334
|
+
mockGenerateExpression,
|
|
335
|
+
);
|
|
282
336
|
|
|
283
337
|
expect(result.isBitAccess).toBe(true);
|
|
284
338
|
expect(result.baseTarget).toBe("matrix[0][1]");
|
|
@@ -293,14 +347,17 @@ describe("MemberChainAnalyzer", () => {
|
|
|
293
347
|
createSubscriptOp("0"),
|
|
294
348
|
]);
|
|
295
349
|
|
|
296
|
-
const result =
|
|
350
|
+
const result = MemberChainAnalyzer.analyze(
|
|
351
|
+
targetCtx,
|
|
352
|
+
mockGenerateExpression,
|
|
353
|
+
);
|
|
297
354
|
|
|
298
355
|
expect(result.isBitAccess).toBe(false);
|
|
299
356
|
});
|
|
300
357
|
|
|
301
358
|
it("returns false for member access on non-struct", () => {
|
|
302
359
|
// x.field[0] where x is a primitive
|
|
303
|
-
typeRegistry.set("x", {
|
|
360
|
+
CodeGenState.typeRegistry.set("x", {
|
|
304
361
|
baseType: "u32",
|
|
305
362
|
bitWidth: 32,
|
|
306
363
|
isArray: false,
|
|
@@ -312,7 +369,10 @@ describe("MemberChainAnalyzer", () => {
|
|
|
312
369
|
createSubscriptOp("0"),
|
|
313
370
|
]);
|
|
314
371
|
|
|
315
|
-
const result =
|
|
372
|
+
const result = MemberChainAnalyzer.analyze(
|
|
373
|
+
targetCtx,
|
|
374
|
+
mockGenerateExpression,
|
|
375
|
+
);
|
|
316
376
|
|
|
317
377
|
expect(result.isBitAccess).toBe(false);
|
|
318
378
|
});
|