c-next 0.1.65 → 0.1.67
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/package.json +5 -1
- package/src/transpiler/Transpiler.ts +49 -42
- package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +129 -0
- package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +27 -3
- package/src/transpiler/output/codegen/CodeGenerator.ts +131 -186
- package/src/transpiler/output/codegen/TypeResolver.ts +2 -2
- package/src/transpiler/output/codegen/TypeValidator.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +1087 -0
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +665 -1315
- package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +1 -1
- package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +1 -1
- package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +1 -1
- package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +1 -1
- package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +1 -1
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +1 -1
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +1 -1
- package/src/transpiler/output/codegen/assignment/handlers/AccessPatternHandlers.ts +24 -27
- package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +25 -18
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +27 -33
- package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +39 -42
- package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +39 -97
- package/src/transpiler/output/codegen/assignment/handlers/RegisterUtils.ts +75 -0
- package/src/transpiler/output/codegen/assignment/handlers/SimpleHandler.ts +9 -6
- package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +30 -22
- package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +42 -50
- package/src/transpiler/output/codegen/assignment/handlers/TAssignmentHandler.ts +6 -5
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +81 -134
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +85 -124
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +82 -124
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +135 -297
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +105 -227
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterUtils.test.ts +214 -1
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +66 -127
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/StringHandlers.test.ts +37 -83
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +162 -0
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +618 -12
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +819 -0
- package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +1 -1
- package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +1 -1
- package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
- package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +337 -0
- package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +135 -0
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/VariableDeclarationFormatter.ts +118 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +426 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +315 -0
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclarationFormatter.test.ts +333 -0
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/types/ICodeGenApi.ts +57 -0
- package/src/transpiler/output/codegen/types/IParameterInput.ts +58 -0
- package/src/transpiler/output/codegen/types/IVariableFormatInput.ts +51 -0
- package/src/transpiler/output/headers/BaseHeaderGenerator.ts +20 -35
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +21 -48
- package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +0 -64
- package/src/transpiler/{output/codegen → state}/CodeGenState.ts +46 -26
- package/src/transpiler/{output/codegen → state}/__tests__/CodeGenState.test.ts +12 -2
- package/src/transpiler/output/codegen/assignment/handlers/IHandlerDeps.ts +0 -161
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
* Tests shared utilities for register assignment handlers.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { describe, expect, it } from "vitest";
|
|
6
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
7
7
|
import RegisterUtils from "../RegisterUtils";
|
|
8
|
+
import CodeGenState from "../../../../../state/CodeGenState";
|
|
9
|
+
import HandlerTestUtils from "./handlerTestUtils";
|
|
8
10
|
|
|
9
11
|
describe("RegisterUtils", () => {
|
|
10
12
|
describe("isWriteOnlyRegister", () => {
|
|
@@ -36,4 +38,215 @@ describe("RegisterUtils", () => {
|
|
|
36
38
|
expect(RegisterUtils.isWriteOnlyRegister("")).toBe(false);
|
|
37
39
|
});
|
|
38
40
|
});
|
|
41
|
+
|
|
42
|
+
describe("extractBitRangeParams", () => {
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
CodeGenState.reset();
|
|
45
|
+
HandlerTestUtils.setupMockGenerator({
|
|
46
|
+
generateExpression: vi
|
|
47
|
+
.fn()
|
|
48
|
+
.mockImplementation((ctx) => ctx?.mockExpr ?? "0"),
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("extracts start, width, and mask from subscripts", () => {
|
|
53
|
+
const subscripts = [{ mockExpr: "4" }, { mockExpr: "8" }];
|
|
54
|
+
const result = RegisterUtils.extractBitRangeParams(subscripts);
|
|
55
|
+
|
|
56
|
+
expect(result.start).toBe("4");
|
|
57
|
+
expect(result.width).toBe("8");
|
|
58
|
+
// BitUtils.generateMask returns optimized hex for common widths
|
|
59
|
+
expect(result.mask).toBe("0xFFU");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("handles dynamic expressions", () => {
|
|
63
|
+
const subscripts = [{ mockExpr: "offset" }, { mockExpr: "width_var" }];
|
|
64
|
+
const result = RegisterUtils.extractBitRangeParams(subscripts);
|
|
65
|
+
|
|
66
|
+
expect(result.start).toBe("offset");
|
|
67
|
+
expect(result.width).toBe("width_var");
|
|
68
|
+
expect(result.mask).toBe("((1U << width_var) - 1)");
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("tryGenerateMMIO", () => {
|
|
73
|
+
beforeEach(() => {
|
|
74
|
+
CodeGenState.reset();
|
|
75
|
+
HandlerTestUtils.setupMockSymbols({
|
|
76
|
+
registerBaseAddresses: new Map([["GPIO7", "0x401B8000"]]),
|
|
77
|
+
registerMemberOffsets: new Map([["GPIO7_DR", "0x00"]]),
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("returns success:false when start is not constant", () => {
|
|
82
|
+
HandlerTestUtils.setupMockGenerator({
|
|
83
|
+
tryEvaluateConstant: vi.fn().mockReturnValue(undefined),
|
|
84
|
+
});
|
|
85
|
+
const subscripts = [{}, {}];
|
|
86
|
+
|
|
87
|
+
const result = RegisterUtils.tryGenerateMMIO(
|
|
88
|
+
"GPIO7_DR",
|
|
89
|
+
"GPIO7",
|
|
90
|
+
subscripts,
|
|
91
|
+
"0xFF",
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
expect(result.success).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("returns success:false when start is not byte-aligned", () => {
|
|
98
|
+
HandlerTestUtils.setupMockGenerator({
|
|
99
|
+
tryEvaluateConstant: vi
|
|
100
|
+
.fn()
|
|
101
|
+
.mockReturnValueOnce(3) // start = 3 (not byte-aligned)
|
|
102
|
+
.mockReturnValueOnce(8), // width = 8
|
|
103
|
+
});
|
|
104
|
+
const subscripts = [{}, {}];
|
|
105
|
+
|
|
106
|
+
const result = RegisterUtils.tryGenerateMMIO(
|
|
107
|
+
"GPIO7_DR",
|
|
108
|
+
"GPIO7",
|
|
109
|
+
subscripts,
|
|
110
|
+
"0xFF",
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
expect(result.success).toBe(false);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("returns success:false when width is not standard (8, 16, 32)", () => {
|
|
117
|
+
HandlerTestUtils.setupMockGenerator({
|
|
118
|
+
tryEvaluateConstant: vi
|
|
119
|
+
.fn()
|
|
120
|
+
.mockReturnValueOnce(0) // start = 0
|
|
121
|
+
.mockReturnValueOnce(12), // width = 12 (non-standard)
|
|
122
|
+
});
|
|
123
|
+
const subscripts = [{}, {}];
|
|
124
|
+
|
|
125
|
+
const result = RegisterUtils.tryGenerateMMIO(
|
|
126
|
+
"GPIO7_DR",
|
|
127
|
+
"GPIO7",
|
|
128
|
+
subscripts,
|
|
129
|
+
"0xFF",
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
expect(result.success).toBe(false);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("returns success:false when base address not found", () => {
|
|
136
|
+
HandlerTestUtils.setupMockGenerator({
|
|
137
|
+
tryEvaluateConstant: vi
|
|
138
|
+
.fn()
|
|
139
|
+
.mockReturnValueOnce(0)
|
|
140
|
+
.mockReturnValueOnce(8),
|
|
141
|
+
});
|
|
142
|
+
HandlerTestUtils.setupMockSymbols({
|
|
143
|
+
registerBaseAddresses: new Map(), // No base address
|
|
144
|
+
registerMemberOffsets: new Map([["GPIO7_DR", "0x00"]]),
|
|
145
|
+
});
|
|
146
|
+
const subscripts = [{}, {}];
|
|
147
|
+
|
|
148
|
+
const result = RegisterUtils.tryGenerateMMIO(
|
|
149
|
+
"GPIO7_DR",
|
|
150
|
+
"GPIO7",
|
|
151
|
+
subscripts,
|
|
152
|
+
"0xFF",
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
expect(result.success).toBe(false);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("generates MMIO for byte-aligned 8-bit write at offset 0", () => {
|
|
159
|
+
HandlerTestUtils.setupMockGenerator({
|
|
160
|
+
tryEvaluateConstant: vi
|
|
161
|
+
.fn()
|
|
162
|
+
.mockReturnValueOnce(0) // start = 0
|
|
163
|
+
.mockReturnValueOnce(8), // width = 8
|
|
164
|
+
});
|
|
165
|
+
const subscripts = [{}, {}];
|
|
166
|
+
|
|
167
|
+
const result = RegisterUtils.tryGenerateMMIO(
|
|
168
|
+
"GPIO7_DR",
|
|
169
|
+
"GPIO7",
|
|
170
|
+
subscripts,
|
|
171
|
+
"0xFF",
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
expect(result.success).toBe(true);
|
|
175
|
+
expect(result.statement).toBe(
|
|
176
|
+
"*((volatile uint8_t*)(0x401B8000 + 0x00)) = (0xFF);",
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("generates MMIO for byte-aligned 16-bit write with byte offset", () => {
|
|
181
|
+
HandlerTestUtils.setupMockGenerator({
|
|
182
|
+
tryEvaluateConstant: vi
|
|
183
|
+
.fn()
|
|
184
|
+
.mockReturnValueOnce(8) // start = 8 (1 byte offset)
|
|
185
|
+
.mockReturnValueOnce(16), // width = 16
|
|
186
|
+
});
|
|
187
|
+
const subscripts = [{}, {}];
|
|
188
|
+
|
|
189
|
+
const result = RegisterUtils.tryGenerateMMIO(
|
|
190
|
+
"GPIO7_DR",
|
|
191
|
+
"GPIO7",
|
|
192
|
+
subscripts,
|
|
193
|
+
"0xABCD",
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
expect(result.success).toBe(true);
|
|
197
|
+
expect(result.statement).toBe(
|
|
198
|
+
"*((volatile uint16_t*)(0x401B8000 + 0x00 + 1)) = (0xABCD);",
|
|
199
|
+
);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("generates MMIO for 32-bit write", () => {
|
|
203
|
+
HandlerTestUtils.setupMockGenerator({
|
|
204
|
+
tryEvaluateConstant: vi
|
|
205
|
+
.fn()
|
|
206
|
+
.mockReturnValueOnce(0) // start = 0
|
|
207
|
+
.mockReturnValueOnce(32), // width = 32
|
|
208
|
+
});
|
|
209
|
+
const subscripts = [{}, {}];
|
|
210
|
+
|
|
211
|
+
const result = RegisterUtils.tryGenerateMMIO(
|
|
212
|
+
"GPIO7_DR",
|
|
213
|
+
"GPIO7",
|
|
214
|
+
subscripts,
|
|
215
|
+
"0xDEADBEEF",
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
expect(result.success).toBe(true);
|
|
219
|
+
expect(result.statement).toBe(
|
|
220
|
+
"*((volatile uint32_t*)(0x401B8000 + 0x00)) = (0xDEADBEEF);",
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
describe("generateWriteOnlyBitRange", () => {
|
|
226
|
+
it("generates write-only bit range assignment", () => {
|
|
227
|
+
const result = RegisterUtils.generateWriteOnlyBitRange(
|
|
228
|
+
"GPIO7_DR",
|
|
229
|
+
"value",
|
|
230
|
+
"((1U << 8) - 1)",
|
|
231
|
+
"4",
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
expect(result).toBe("GPIO7_DR = ((value & ((1U << 8) - 1)) << 4);");
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
describe("generateRmwBitRange", () => {
|
|
239
|
+
it("generates read-modify-write bit range assignment", () => {
|
|
240
|
+
const result = RegisterUtils.generateRmwBitRange(
|
|
241
|
+
"GPIO7_DR",
|
|
242
|
+
"value",
|
|
243
|
+
"((1U << 8) - 1)",
|
|
244
|
+
"4",
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
expect(result).toBe(
|
|
248
|
+
"GPIO7_DR = (GPIO7_DR & ~(((1U << 8) - 1) << 4)) | ((value & ((1U << 8) - 1)) << 4);",
|
|
249
|
+
);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
39
252
|
});
|
|
@@ -3,53 +3,12 @@
|
|
|
3
3
|
* Tests atomic RMW and overflow clamp handler functions.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { describe, expect, it, vi } from "vitest";
|
|
6
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
7
7
|
import specialHandlers from "../SpecialHandlers";
|
|
8
8
|
import AssignmentKind from "../../AssignmentKind";
|
|
9
9
|
import IAssignmentContext from "../../IAssignmentContext";
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Create mock dependencies for testing.
|
|
14
|
-
*/
|
|
15
|
-
function createMockDeps(overrides: Record<string, unknown> = {}): IHandlerDeps {
|
|
16
|
-
const base = {
|
|
17
|
-
typeRegistry: new Map(),
|
|
18
|
-
symbols: {
|
|
19
|
-
structFields: new Map(),
|
|
20
|
-
structFieldDimensions: new Map(),
|
|
21
|
-
bitmapFields: new Map(),
|
|
22
|
-
registerMemberAccess: new Map(),
|
|
23
|
-
registerBaseAddresses: new Map(),
|
|
24
|
-
registerMemberOffsets: new Map(),
|
|
25
|
-
registerMemberTypes: new Map(),
|
|
26
|
-
},
|
|
27
|
-
currentScope: null,
|
|
28
|
-
currentParameters: new Map(),
|
|
29
|
-
targetCapabilities: { hasLDREX: false },
|
|
30
|
-
generateAssignmentTarget: vi.fn().mockReturnValue("target"),
|
|
31
|
-
generateExpression: vi
|
|
32
|
-
.fn()
|
|
33
|
-
.mockImplementation((ctx) => ctx?.mockValue ?? "0"),
|
|
34
|
-
markNeedsString: vi.fn(),
|
|
35
|
-
markClampOpUsed: vi.fn(),
|
|
36
|
-
isKnownScope: vi.fn().mockReturnValue(false),
|
|
37
|
-
isKnownStruct: vi.fn().mockReturnValue(false),
|
|
38
|
-
validateCrossScopeVisibility: vi.fn(),
|
|
39
|
-
validateBitmapFieldLiteral: vi.fn(),
|
|
40
|
-
checkArrayBounds: vi.fn(),
|
|
41
|
-
analyzeMemberChainForBitAccess: vi
|
|
42
|
-
.fn()
|
|
43
|
-
.mockReturnValue({ isBitAccess: false }),
|
|
44
|
-
tryEvaluateConstant: vi.fn().mockReturnValue(undefined),
|
|
45
|
-
getMemberTypeInfo: vi.fn().mockReturnValue(null),
|
|
46
|
-
generateFloatBitWrite: vi.fn().mockReturnValue(null),
|
|
47
|
-
foldBooleanToInt: vi.fn().mockImplementation((expr) => expr),
|
|
48
|
-
generateAtomicRMW: vi.fn().mockReturnValue("atomic_rmw_result"),
|
|
49
|
-
...overrides,
|
|
50
|
-
};
|
|
51
|
-
return base as unknown as IHandlerDeps;
|
|
52
|
-
}
|
|
10
|
+
import CodeGenState from "../../../../../state/CodeGenState";
|
|
11
|
+
import HandlerTestUtils from "./handlerTestUtils";
|
|
53
12
|
|
|
54
13
|
/**
|
|
55
14
|
* Create mock context for testing.
|
|
@@ -80,6 +39,12 @@ function createMockContext(
|
|
|
80
39
|
}
|
|
81
40
|
|
|
82
41
|
describe("SpecialHandlers", () => {
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
CodeGenState.reset();
|
|
44
|
+
HandlerTestUtils.setupMockGenerator();
|
|
45
|
+
HandlerTestUtils.setupMockSymbols();
|
|
46
|
+
});
|
|
47
|
+
|
|
83
48
|
describe("handler registration", () => {
|
|
84
49
|
it("registers all expected special assignment kinds", () => {
|
|
85
50
|
const kinds = specialHandlers.map(([kind]) => kind);
|
|
@@ -98,19 +63,18 @@ describe("SpecialHandlers", () => {
|
|
|
98
63
|
specialHandlers.find(([kind]) => kind === AssignmentKind.ATOMIC_RMW)?.[1];
|
|
99
64
|
|
|
100
65
|
it("delegates to generateAtomicRMW for simple identifier", () => {
|
|
101
|
-
|
|
66
|
+
CodeGenState.typeRegistry = new Map([
|
|
102
67
|
["counter", { baseType: "u32", isAtomic: true }],
|
|
103
|
-
]);
|
|
68
|
+
]) as any;
|
|
104
69
|
const generateAtomicRMW = vi.fn().mockReturnValue("LDREX/STREX pattern");
|
|
105
70
|
const generateAssignmentTarget = vi.fn().mockReturnValue("counter");
|
|
106
|
-
|
|
107
|
-
typeRegistry,
|
|
71
|
+
HandlerTestUtils.setupMockGenerator({
|
|
108
72
|
generateAtomicRMW,
|
|
109
73
|
generateAssignmentTarget,
|
|
110
74
|
});
|
|
111
75
|
const ctx = createMockContext();
|
|
112
76
|
|
|
113
|
-
const result = getHandler()!(ctx
|
|
77
|
+
const result = getHandler()!(ctx);
|
|
114
78
|
|
|
115
79
|
expect(generateAtomicRMW).toHaveBeenCalledWith("counter", "+=", "1", {
|
|
116
80
|
baseType: "u32",
|
|
@@ -120,16 +84,15 @@ describe("SpecialHandlers", () => {
|
|
|
120
84
|
});
|
|
121
85
|
|
|
122
86
|
it("handles this.member atomic variable", () => {
|
|
123
|
-
|
|
87
|
+
CodeGenState.currentScope = "Motor";
|
|
88
|
+
CodeGenState.typeRegistry = new Map([
|
|
124
89
|
["Motor_count", { baseType: "u32", isAtomic: true }],
|
|
125
|
-
]);
|
|
90
|
+
]) as any;
|
|
126
91
|
const generateAtomicRMW = vi.fn().mockReturnValue("atomic result");
|
|
127
92
|
const generateAssignmentTarget = vi.fn().mockReturnValue("Motor_count");
|
|
128
|
-
|
|
129
|
-
typeRegistry,
|
|
93
|
+
HandlerTestUtils.setupMockGenerator({
|
|
130
94
|
generateAtomicRMW,
|
|
131
95
|
generateAssignmentTarget,
|
|
132
|
-
currentScope: "Motor",
|
|
133
96
|
});
|
|
134
97
|
const ctx = createMockContext({
|
|
135
98
|
identifiers: ["count"],
|
|
@@ -137,7 +100,7 @@ describe("SpecialHandlers", () => {
|
|
|
137
100
|
isSimpleThisAccess: true,
|
|
138
101
|
});
|
|
139
102
|
|
|
140
|
-
const result = getHandler()!(ctx
|
|
103
|
+
const result = getHandler()!(ctx);
|
|
141
104
|
|
|
142
105
|
expect(generateAtomicRMW).toHaveBeenCalledWith("Motor_count", "+=", "1", {
|
|
143
106
|
baseType: "u32",
|
|
@@ -147,13 +110,12 @@ describe("SpecialHandlers", () => {
|
|
|
147
110
|
});
|
|
148
111
|
|
|
149
112
|
it("handles global.member atomic variable", () => {
|
|
150
|
-
|
|
113
|
+
CodeGenState.typeRegistry = new Map([
|
|
151
114
|
["globalCounter", { baseType: "u32", isAtomic: true }],
|
|
152
|
-
]);
|
|
115
|
+
]) as any;
|
|
153
116
|
const generateAtomicRMW = vi.fn().mockReturnValue("global atomic result");
|
|
154
117
|
const generateAssignmentTarget = vi.fn().mockReturnValue("globalCounter");
|
|
155
|
-
|
|
156
|
-
typeRegistry,
|
|
118
|
+
HandlerTestUtils.setupMockGenerator({
|
|
157
119
|
generateAtomicRMW,
|
|
158
120
|
generateAssignmentTarget,
|
|
159
121
|
});
|
|
@@ -163,19 +125,18 @@ describe("SpecialHandlers", () => {
|
|
|
163
125
|
isSimpleGlobalAccess: true,
|
|
164
126
|
});
|
|
165
127
|
|
|
166
|
-
const result = getHandler()!(ctx
|
|
128
|
+
const result = getHandler()!(ctx);
|
|
167
129
|
|
|
168
130
|
expect(result).toBe("global atomic result");
|
|
169
131
|
});
|
|
170
132
|
|
|
171
133
|
it("handles subtract operation", () => {
|
|
172
|
-
|
|
134
|
+
CodeGenState.typeRegistry = new Map([
|
|
173
135
|
["counter", { baseType: "u32", isAtomic: true }],
|
|
174
|
-
]);
|
|
136
|
+
]) as any;
|
|
175
137
|
const generateAtomicRMW = vi.fn().mockReturnValue("atomic sub");
|
|
176
138
|
const generateAssignmentTarget = vi.fn().mockReturnValue("counter");
|
|
177
|
-
|
|
178
|
-
typeRegistry,
|
|
139
|
+
HandlerTestUtils.setupMockGenerator({
|
|
179
140
|
generateAtomicRMW,
|
|
180
141
|
generateAssignmentTarget,
|
|
181
142
|
});
|
|
@@ -184,7 +145,7 @@ describe("SpecialHandlers", () => {
|
|
|
184
145
|
cOp: "-=",
|
|
185
146
|
});
|
|
186
147
|
|
|
187
|
-
getHandler()!(ctx
|
|
148
|
+
getHandler()!(ctx);
|
|
188
149
|
|
|
189
150
|
expect(generateAtomicRMW).toHaveBeenCalledWith(
|
|
190
151
|
"counter",
|
|
@@ -202,14 +163,11 @@ describe("SpecialHandlers", () => {
|
|
|
202
163
|
)?.[1];
|
|
203
164
|
|
|
204
165
|
it("generates clamp add helper for u8", () => {
|
|
205
|
-
|
|
166
|
+
CodeGenState.typeRegistry = new Map([
|
|
206
167
|
["saturated", { baseType: "u8", overflowBehavior: "clamp" }],
|
|
207
|
-
]);
|
|
208
|
-
const markClampOpUsed = vi.fn();
|
|
168
|
+
]) as any;
|
|
209
169
|
const generateAssignmentTarget = vi.fn().mockReturnValue("saturated");
|
|
210
|
-
|
|
211
|
-
typeRegistry,
|
|
212
|
-
markClampOpUsed,
|
|
170
|
+
HandlerTestUtils.setupMockGenerator({
|
|
213
171
|
generateAssignmentTarget,
|
|
214
172
|
});
|
|
215
173
|
const ctx = createMockContext({
|
|
@@ -217,21 +175,18 @@ describe("SpecialHandlers", () => {
|
|
|
217
175
|
generatedValue: "200",
|
|
218
176
|
});
|
|
219
177
|
|
|
220
|
-
const result = getHandler()!(ctx
|
|
178
|
+
const result = getHandler()!(ctx);
|
|
221
179
|
|
|
222
|
-
expect(
|
|
180
|
+
expect(CodeGenState.usedClampOps.has("add_u8")).toBe(true);
|
|
223
181
|
expect(result).toBe("saturated = cnx_clamp_add_u8(saturated, 200);");
|
|
224
182
|
});
|
|
225
183
|
|
|
226
184
|
it("generates clamp sub helper for u16", () => {
|
|
227
|
-
|
|
185
|
+
CodeGenState.typeRegistry = new Map([
|
|
228
186
|
["value", { baseType: "u16", overflowBehavior: "clamp" }],
|
|
229
|
-
]);
|
|
230
|
-
const markClampOpUsed = vi.fn();
|
|
187
|
+
]) as any;
|
|
231
188
|
const generateAssignmentTarget = vi.fn().mockReturnValue("value");
|
|
232
|
-
|
|
233
|
-
typeRegistry,
|
|
234
|
-
markClampOpUsed,
|
|
189
|
+
HandlerTestUtils.setupMockGenerator({
|
|
235
190
|
generateAssignmentTarget,
|
|
236
191
|
});
|
|
237
192
|
const ctx = createMockContext({
|
|
@@ -241,21 +196,18 @@ describe("SpecialHandlers", () => {
|
|
|
241
196
|
generatedValue: "100",
|
|
242
197
|
});
|
|
243
198
|
|
|
244
|
-
const result = getHandler()!(ctx
|
|
199
|
+
const result = getHandler()!(ctx);
|
|
245
200
|
|
|
246
|
-
expect(
|
|
201
|
+
expect(CodeGenState.usedClampOps.has("sub_u16")).toBe(true);
|
|
247
202
|
expect(result).toBe("value = cnx_clamp_sub_u16(value, 100);");
|
|
248
203
|
});
|
|
249
204
|
|
|
250
205
|
it("generates clamp mul helper for u32", () => {
|
|
251
|
-
|
|
206
|
+
CodeGenState.typeRegistry = new Map([
|
|
252
207
|
["result", { baseType: "u32", overflowBehavior: "clamp" }],
|
|
253
|
-
]);
|
|
254
|
-
const markClampOpUsed = vi.fn();
|
|
208
|
+
]) as any;
|
|
255
209
|
const generateAssignmentTarget = vi.fn().mockReturnValue("result");
|
|
256
|
-
|
|
257
|
-
typeRegistry,
|
|
258
|
-
markClampOpUsed,
|
|
210
|
+
HandlerTestUtils.setupMockGenerator({
|
|
259
211
|
generateAssignmentTarget,
|
|
260
212
|
});
|
|
261
213
|
const ctx = createMockContext({
|
|
@@ -265,21 +217,18 @@ describe("SpecialHandlers", () => {
|
|
|
265
217
|
generatedValue: "2",
|
|
266
218
|
});
|
|
267
219
|
|
|
268
|
-
const result = getHandler()!(ctx
|
|
220
|
+
const result = getHandler()!(ctx);
|
|
269
221
|
|
|
270
|
-
expect(
|
|
222
|
+
expect(CodeGenState.usedClampOps.has("mul_u32")).toBe(true);
|
|
271
223
|
expect(result).toBe("result = cnx_clamp_mul_u32(result, 2);");
|
|
272
224
|
});
|
|
273
225
|
|
|
274
226
|
it("uses native arithmetic for float types", () => {
|
|
275
|
-
|
|
227
|
+
CodeGenState.typeRegistry = new Map([
|
|
276
228
|
["f", { baseType: "f32", overflowBehavior: "clamp" }],
|
|
277
|
-
]);
|
|
278
|
-
const markClampOpUsed = vi.fn();
|
|
229
|
+
]) as any;
|
|
279
230
|
const generateAssignmentTarget = vi.fn().mockReturnValue("f");
|
|
280
|
-
|
|
281
|
-
typeRegistry,
|
|
282
|
-
markClampOpUsed,
|
|
231
|
+
HandlerTestUtils.setupMockGenerator({
|
|
283
232
|
generateAssignmentTarget,
|
|
284
233
|
});
|
|
285
234
|
const ctx = createMockContext({
|
|
@@ -287,19 +236,18 @@ describe("SpecialHandlers", () => {
|
|
|
287
236
|
generatedValue: "1000.0",
|
|
288
237
|
});
|
|
289
238
|
|
|
290
|
-
const result = getHandler()!(ctx
|
|
239
|
+
const result = getHandler()!(ctx);
|
|
291
240
|
|
|
292
|
-
expect(
|
|
241
|
+
expect(CodeGenState.usedClampOps.size).toBe(0);
|
|
293
242
|
expect(result).toBe("f += 1000.0;");
|
|
294
243
|
});
|
|
295
244
|
|
|
296
245
|
it("uses native arithmetic for f64 type", () => {
|
|
297
|
-
|
|
246
|
+
CodeGenState.typeRegistry = new Map([
|
|
298
247
|
["d", { baseType: "f64", overflowBehavior: "clamp" }],
|
|
299
|
-
]);
|
|
248
|
+
]) as any;
|
|
300
249
|
const generateAssignmentTarget = vi.fn().mockReturnValue("d");
|
|
301
|
-
|
|
302
|
-
typeRegistry,
|
|
250
|
+
HandlerTestUtils.setupMockGenerator({
|
|
303
251
|
generateAssignmentTarget,
|
|
304
252
|
});
|
|
305
253
|
const ctx = createMockContext({
|
|
@@ -308,20 +256,17 @@ describe("SpecialHandlers", () => {
|
|
|
308
256
|
generatedValue: "0.5",
|
|
309
257
|
});
|
|
310
258
|
|
|
311
|
-
const result = getHandler()!(ctx
|
|
259
|
+
const result = getHandler()!(ctx);
|
|
312
260
|
|
|
313
261
|
expect(result).toBe("d -= 0.5;");
|
|
314
262
|
});
|
|
315
263
|
|
|
316
264
|
it("falls back to native for unsupported operators", () => {
|
|
317
|
-
|
|
265
|
+
CodeGenState.typeRegistry = new Map([
|
|
318
266
|
["value", { baseType: "u32", overflowBehavior: "clamp" }],
|
|
319
|
-
]);
|
|
320
|
-
const markClampOpUsed = vi.fn();
|
|
267
|
+
]) as any;
|
|
321
268
|
const generateAssignmentTarget = vi.fn().mockReturnValue("value");
|
|
322
|
-
|
|
323
|
-
typeRegistry,
|
|
324
|
-
markClampOpUsed,
|
|
269
|
+
HandlerTestUtils.setupMockGenerator({
|
|
325
270
|
generateAssignmentTarget,
|
|
326
271
|
});
|
|
327
272
|
const ctx = createMockContext({
|
|
@@ -331,23 +276,20 @@ describe("SpecialHandlers", () => {
|
|
|
331
276
|
generatedValue: "2",
|
|
332
277
|
});
|
|
333
278
|
|
|
334
|
-
const result = getHandler()!(ctx
|
|
279
|
+
const result = getHandler()!(ctx);
|
|
335
280
|
|
|
336
|
-
expect(
|
|
281
|
+
expect(CodeGenState.usedClampOps.size).toBe(0);
|
|
337
282
|
expect(result).toBe("value /= 2;");
|
|
338
283
|
});
|
|
339
284
|
|
|
340
285
|
it("handles this.member with clamp", () => {
|
|
341
|
-
|
|
286
|
+
CodeGenState.currentScope = "Motor";
|
|
287
|
+
CodeGenState.typeRegistry = new Map([
|
|
342
288
|
["Motor_speed", { baseType: "u8", overflowBehavior: "clamp" }],
|
|
343
|
-
]);
|
|
344
|
-
const markClampOpUsed = vi.fn();
|
|
289
|
+
]) as any;
|
|
345
290
|
const generateAssignmentTarget = vi.fn().mockReturnValue("Motor_speed");
|
|
346
|
-
|
|
347
|
-
typeRegistry,
|
|
348
|
-
markClampOpUsed,
|
|
291
|
+
HandlerTestUtils.setupMockGenerator({
|
|
349
292
|
generateAssignmentTarget,
|
|
350
|
-
currentScope: "Motor",
|
|
351
293
|
});
|
|
352
294
|
const ctx = createMockContext({
|
|
353
295
|
identifiers: ["speed"],
|
|
@@ -356,21 +298,18 @@ describe("SpecialHandlers", () => {
|
|
|
356
298
|
generatedValue: "10",
|
|
357
299
|
});
|
|
358
300
|
|
|
359
|
-
const result = getHandler()!(ctx
|
|
301
|
+
const result = getHandler()!(ctx);
|
|
360
302
|
|
|
361
|
-
expect(
|
|
303
|
+
expect(CodeGenState.usedClampOps.has("add_u8")).toBe(true);
|
|
362
304
|
expect(result).toBe("Motor_speed = cnx_clamp_add_u8(Motor_speed, 10);");
|
|
363
305
|
});
|
|
364
306
|
|
|
365
307
|
it("handles global.member with clamp", () => {
|
|
366
|
-
|
|
308
|
+
CodeGenState.typeRegistry = new Map([
|
|
367
309
|
["globalValue", { baseType: "i16", overflowBehavior: "clamp" }],
|
|
368
|
-
]);
|
|
369
|
-
const markClampOpUsed = vi.fn();
|
|
310
|
+
]) as any;
|
|
370
311
|
const generateAssignmentTarget = vi.fn().mockReturnValue("globalValue");
|
|
371
|
-
|
|
372
|
-
typeRegistry,
|
|
373
|
-
markClampOpUsed,
|
|
312
|
+
HandlerTestUtils.setupMockGenerator({
|
|
374
313
|
generateAssignmentTarget,
|
|
375
314
|
});
|
|
376
315
|
const ctx = createMockContext({
|
|
@@ -380,9 +319,9 @@ describe("SpecialHandlers", () => {
|
|
|
380
319
|
generatedValue: "50",
|
|
381
320
|
});
|
|
382
321
|
|
|
383
|
-
const result = getHandler()!(ctx
|
|
322
|
+
const result = getHandler()!(ctx);
|
|
384
323
|
|
|
385
|
-
expect(
|
|
324
|
+
expect(CodeGenState.usedClampOps.has("add_i16")).toBe(true);
|
|
386
325
|
expect(result).toBe("globalValue = cnx_clamp_add_i16(globalValue, 50);");
|
|
387
326
|
});
|
|
388
327
|
});
|