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.
Files changed (73) hide show
  1. package/package.json +5 -1
  2. package/src/transpiler/Transpiler.ts +49 -42
  3. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +129 -0
  4. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +27 -3
  5. package/src/transpiler/output/codegen/CodeGenerator.ts +131 -186
  6. package/src/transpiler/output/codegen/TypeResolver.ts +2 -2
  7. package/src/transpiler/output/codegen/TypeValidator.ts +1 -1
  8. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +1087 -0
  9. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +665 -1315
  10. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +1 -1
  11. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +1 -1
  12. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +1 -1
  13. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +1 -1
  14. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +1 -1
  15. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +1 -1
  16. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +1 -1
  17. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +1 -1
  18. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +1 -1
  19. package/src/transpiler/output/codegen/assignment/handlers/AccessPatternHandlers.ts +24 -27
  20. package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +25 -18
  21. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +27 -33
  22. package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +39 -42
  23. package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +39 -97
  24. package/src/transpiler/output/codegen/assignment/handlers/RegisterUtils.ts +75 -0
  25. package/src/transpiler/output/codegen/assignment/handlers/SimpleHandler.ts +9 -6
  26. package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +30 -22
  27. package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +42 -50
  28. package/src/transpiler/output/codegen/assignment/handlers/TAssignmentHandler.ts +6 -5
  29. package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +81 -134
  30. package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +85 -124
  31. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +82 -124
  32. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +135 -297
  33. package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +105 -227
  34. package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterUtils.test.ts +214 -1
  35. package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +66 -127
  36. package/src/transpiler/output/codegen/assignment/handlers/__tests__/StringHandlers.test.ts +37 -83
  37. package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +162 -0
  38. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +618 -12
  39. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +819 -0
  40. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +1 -1
  41. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +1 -1
  42. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +1 -1
  43. package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +1 -1
  44. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
  45. package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +1 -1
  46. package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +337 -0
  47. package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +135 -0
  48. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +1 -1
  49. package/src/transpiler/output/codegen/helpers/VariableDeclarationFormatter.ts +118 -0
  50. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +1 -1
  51. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +1 -1
  52. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +1 -1
  53. package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +1 -1
  54. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +1 -1
  55. package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +1 -1
  56. package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +426 -0
  57. package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +315 -0
  58. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +1 -1
  59. package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclarationFormatter.test.ts +333 -0
  60. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +1 -1
  61. package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +1 -1
  62. package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +1 -1
  63. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +1 -1
  64. package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +1 -1
  65. package/src/transpiler/output/codegen/types/ICodeGenApi.ts +57 -0
  66. package/src/transpiler/output/codegen/types/IParameterInput.ts +58 -0
  67. package/src/transpiler/output/codegen/types/IVariableFormatInput.ts +51 -0
  68. package/src/transpiler/output/headers/BaseHeaderGenerator.ts +20 -35
  69. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +21 -48
  70. package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +0 -64
  71. package/src/transpiler/{output/codegen → state}/CodeGenState.ts +46 -26
  72. package/src/transpiler/{output/codegen → state}/__tests__/CodeGenState.test.ts +12 -2
  73. 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 IHandlerDeps from "../IHandlerDeps";
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
- const typeRegistry = new Map([
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
- const deps = createMockDeps({
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, deps);
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
- const typeRegistry = new Map([
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
- const deps = createMockDeps({
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, deps);
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
- const typeRegistry = new Map([
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
- const deps = createMockDeps({
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, deps);
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
- const typeRegistry = new Map([
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
- const deps = createMockDeps({
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, deps);
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
- const typeRegistry = new Map([
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
- const deps = createMockDeps({
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, deps);
178
+ const result = getHandler()!(ctx);
221
179
 
222
- expect(markClampOpUsed).toHaveBeenCalledWith("add", "u8");
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
- const typeRegistry = new Map([
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
- const deps = createMockDeps({
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, deps);
199
+ const result = getHandler()!(ctx);
245
200
 
246
- expect(markClampOpUsed).toHaveBeenCalledWith("sub", "u16");
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
- const typeRegistry = new Map([
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
- const deps = createMockDeps({
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, deps);
220
+ const result = getHandler()!(ctx);
269
221
 
270
- expect(markClampOpUsed).toHaveBeenCalledWith("mul", "u32");
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
- const typeRegistry = new Map([
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
- const deps = createMockDeps({
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, deps);
239
+ const result = getHandler()!(ctx);
291
240
 
292
- expect(markClampOpUsed).not.toHaveBeenCalled();
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
- const typeRegistry = new Map([
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
- const deps = createMockDeps({
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, deps);
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
- const typeRegistry = new Map([
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
- const deps = createMockDeps({
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, deps);
279
+ const result = getHandler()!(ctx);
335
280
 
336
- expect(markClampOpUsed).not.toHaveBeenCalled();
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
- const typeRegistry = new Map([
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
- const deps = createMockDeps({
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, deps);
301
+ const result = getHandler()!(ctx);
360
302
 
361
- expect(markClampOpUsed).toHaveBeenCalledWith("add", "u8");
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
- const typeRegistry = new Map([
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
- const deps = createMockDeps({
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, deps);
322
+ const result = getHandler()!(ctx);
384
323
 
385
- expect(markClampOpUsed).toHaveBeenCalledWith("add", "i16");
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
  });