c-next 0.1.62 → 0.1.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +86 -63
  2. package/package.json +1 -1
  3. package/src/transpiler/Transpiler.ts +3 -2
  4. package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
  5. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +1 -1
  6. package/src/transpiler/__tests__/Transpiler.test.ts +0 -23
  7. package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
  8. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
  9. package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
  10. package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
  11. package/src/transpiler/output/codegen/CodeGenerator.ts +817 -1377
  12. package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
  13. package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
  14. package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
  15. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +326 -60
  16. package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
  17. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
  18. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
  19. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
  20. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +39 -43
  21. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +52 -55
  22. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +122 -62
  23. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
  24. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +143 -126
  25. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +287 -320
  26. package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
  27. package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
  28. package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
  29. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +121 -51
  30. package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
  31. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
  32. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
  33. package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
  34. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
  35. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +21 -30
  36. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +56 -53
  37. package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
  38. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
  39. package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
  40. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
  41. package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
  42. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
  43. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
  44. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
  45. package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
  46. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
  47. package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
  48. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
  49. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
  50. package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
  51. package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
  52. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
  53. package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
  54. package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
  55. package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
@@ -5,26 +5,18 @@
5
5
  import { describe, it, expect, beforeEach } from "vitest";
6
6
  import TypeResolver from "../TypeResolver";
7
7
  import SymbolTable from "../../../logic/symbols/SymbolTable";
8
- import ITypeResolverDeps from "../types/ITypeResolverDeps";
8
+ import CodeGenState from "../CodeGenState";
9
9
  import TTypeInfo from "../types/TTypeInfo";
10
10
 
11
11
  describe("TypeResolver", () => {
12
- let resolver: TypeResolver;
13
12
  let symbolTable: SymbolTable;
14
13
  let typeRegistry: Map<string, TTypeInfo>;
15
14
 
16
15
  beforeEach(() => {
16
+ CodeGenState.reset();
17
17
  symbolTable = new SymbolTable();
18
- typeRegistry = new Map();
19
-
20
- const deps: ITypeResolverDeps = {
21
- symbols: null,
22
- symbolTable,
23
- typeRegistry,
24
- resolveIdentifier: (name: string) => name,
25
- };
26
-
27
- resolver = new TypeResolver(deps);
18
+ typeRegistry = CodeGenState.typeRegistry;
19
+ CodeGenState.symbolTable = symbolTable;
28
20
  });
29
21
 
30
22
  // ========================================================================
@@ -33,80 +25,80 @@ describe("TypeResolver", () => {
33
25
 
34
26
  describe("isIntegerType", () => {
35
27
  it("should return true for unsigned integer types", () => {
36
- expect(resolver.isIntegerType("u8")).toBe(true);
37
- expect(resolver.isIntegerType("u16")).toBe(true);
38
- expect(resolver.isIntegerType("u32")).toBe(true);
39
- expect(resolver.isIntegerType("u64")).toBe(true);
28
+ expect(TypeResolver.isIntegerType("u8")).toBe(true);
29
+ expect(TypeResolver.isIntegerType("u16")).toBe(true);
30
+ expect(TypeResolver.isIntegerType("u32")).toBe(true);
31
+ expect(TypeResolver.isIntegerType("u64")).toBe(true);
40
32
  });
41
33
 
42
34
  it("should return true for signed integer types", () => {
43
- expect(resolver.isIntegerType("i8")).toBe(true);
44
- expect(resolver.isIntegerType("i16")).toBe(true);
45
- expect(resolver.isIntegerType("i32")).toBe(true);
46
- expect(resolver.isIntegerType("i64")).toBe(true);
35
+ expect(TypeResolver.isIntegerType("i8")).toBe(true);
36
+ expect(TypeResolver.isIntegerType("i16")).toBe(true);
37
+ expect(TypeResolver.isIntegerType("i32")).toBe(true);
38
+ expect(TypeResolver.isIntegerType("i64")).toBe(true);
47
39
  });
48
40
 
49
41
  it("should return false for non-integer types", () => {
50
- expect(resolver.isIntegerType("f32")).toBe(false);
51
- expect(resolver.isIntegerType("f64")).toBe(false);
52
- expect(resolver.isIntegerType("bool")).toBe(false);
53
- expect(resolver.isIntegerType("void")).toBe(false);
54
- expect(resolver.isIntegerType("MyStruct")).toBe(false);
42
+ expect(TypeResolver.isIntegerType("f32")).toBe(false);
43
+ expect(TypeResolver.isIntegerType("f64")).toBe(false);
44
+ expect(TypeResolver.isIntegerType("bool")).toBe(false);
45
+ expect(TypeResolver.isIntegerType("void")).toBe(false);
46
+ expect(TypeResolver.isIntegerType("MyStruct")).toBe(false);
55
47
  });
56
48
  });
57
49
 
58
50
  describe("isFloatType", () => {
59
51
  it("should return true for float types", () => {
60
- expect(resolver.isFloatType("f32")).toBe(true);
61
- expect(resolver.isFloatType("f64")).toBe(true);
52
+ expect(TypeResolver.isFloatType("f32")).toBe(true);
53
+ expect(TypeResolver.isFloatType("f64")).toBe(true);
62
54
  });
63
55
 
64
56
  it("should return false for non-float types", () => {
65
- expect(resolver.isFloatType("u32")).toBe(false);
66
- expect(resolver.isFloatType("i32")).toBe(false);
67
- expect(resolver.isFloatType("bool")).toBe(false);
57
+ expect(TypeResolver.isFloatType("u32")).toBe(false);
58
+ expect(TypeResolver.isFloatType("i32")).toBe(false);
59
+ expect(TypeResolver.isFloatType("bool")).toBe(false);
68
60
  });
69
61
  });
70
62
 
71
63
  describe("isSignedType", () => {
72
64
  it("should return true for signed integer types", () => {
73
- expect(resolver.isSignedType("i8")).toBe(true);
74
- expect(resolver.isSignedType("i16")).toBe(true);
75
- expect(resolver.isSignedType("i32")).toBe(true);
76
- expect(resolver.isSignedType("i64")).toBe(true);
65
+ expect(TypeResolver.isSignedType("i8")).toBe(true);
66
+ expect(TypeResolver.isSignedType("i16")).toBe(true);
67
+ expect(TypeResolver.isSignedType("i32")).toBe(true);
68
+ expect(TypeResolver.isSignedType("i64")).toBe(true);
77
69
  });
78
70
 
79
71
  it("should return false for unsigned types", () => {
80
- expect(resolver.isSignedType("u8")).toBe(false);
81
- expect(resolver.isSignedType("u16")).toBe(false);
82
- expect(resolver.isSignedType("u32")).toBe(false);
83
- expect(resolver.isSignedType("u64")).toBe(false);
72
+ expect(TypeResolver.isSignedType("u8")).toBe(false);
73
+ expect(TypeResolver.isSignedType("u16")).toBe(false);
74
+ expect(TypeResolver.isSignedType("u32")).toBe(false);
75
+ expect(TypeResolver.isSignedType("u64")).toBe(false);
84
76
  });
85
77
 
86
78
  it("should return false for non-integer types", () => {
87
- expect(resolver.isSignedType("f32")).toBe(false);
88
- expect(resolver.isSignedType("bool")).toBe(false);
79
+ expect(TypeResolver.isSignedType("f32")).toBe(false);
80
+ expect(TypeResolver.isSignedType("bool")).toBe(false);
89
81
  });
90
82
  });
91
83
 
92
84
  describe("isUnsignedType", () => {
93
85
  it("should return true for unsigned integer types", () => {
94
- expect(resolver.isUnsignedType("u8")).toBe(true);
95
- expect(resolver.isUnsignedType("u16")).toBe(true);
96
- expect(resolver.isUnsignedType("u32")).toBe(true);
97
- expect(resolver.isUnsignedType("u64")).toBe(true);
86
+ expect(TypeResolver.isUnsignedType("u8")).toBe(true);
87
+ expect(TypeResolver.isUnsignedType("u16")).toBe(true);
88
+ expect(TypeResolver.isUnsignedType("u32")).toBe(true);
89
+ expect(TypeResolver.isUnsignedType("u64")).toBe(true);
98
90
  });
99
91
 
100
92
  it("should return false for signed types", () => {
101
- expect(resolver.isUnsignedType("i8")).toBe(false);
102
- expect(resolver.isUnsignedType("i16")).toBe(false);
103
- expect(resolver.isUnsignedType("i32")).toBe(false);
104
- expect(resolver.isUnsignedType("i64")).toBe(false);
93
+ expect(TypeResolver.isUnsignedType("i8")).toBe(false);
94
+ expect(TypeResolver.isUnsignedType("i16")).toBe(false);
95
+ expect(TypeResolver.isUnsignedType("i32")).toBe(false);
96
+ expect(TypeResolver.isUnsignedType("i64")).toBe(false);
105
97
  });
106
98
 
107
99
  it("should return false for non-integer types", () => {
108
- expect(resolver.isUnsignedType("f32")).toBe(false);
109
- expect(resolver.isUnsignedType("bool")).toBe(false);
100
+ expect(TypeResolver.isUnsignedType("f32")).toBe(false);
101
+ expect(TypeResolver.isUnsignedType("bool")).toBe(false);
110
102
  });
111
103
  });
112
104
 
@@ -119,16 +111,16 @@ describe("TypeResolver", () => {
119
111
  symbolTable.addStructField("Point", "x", "i32");
120
112
  symbolTable.addStructField("Point", "y", "i32");
121
113
 
122
- expect(resolver.isStructType("Point")).toBe(true);
114
+ expect(TypeResolver.isStructType("Point")).toBe(true);
123
115
  });
124
116
 
125
117
  it("should return false for unknown type", () => {
126
- expect(resolver.isStructType("UnknownStruct")).toBe(false);
118
+ expect(TypeResolver.isStructType("UnknownStruct")).toBe(false);
127
119
  });
128
120
 
129
121
  it("should return false for primitive types", () => {
130
- expect(resolver.isStructType("u32")).toBe(false);
131
- expect(resolver.isStructType("f64")).toBe(false);
122
+ expect(TypeResolver.isStructType("u32")).toBe(false);
123
+ expect(TypeResolver.isStructType("f64")).toBe(false);
132
124
  });
133
125
  });
134
126
 
@@ -138,83 +130,99 @@ describe("TypeResolver", () => {
138
130
 
139
131
  describe("isNarrowingConversion", () => {
140
132
  it("should return true when target is smaller than source", () => {
141
- expect(resolver.isNarrowingConversion("u32", "u16")).toBe(true);
142
- expect(resolver.isNarrowingConversion("u32", "u8")).toBe(true);
143
- expect(resolver.isNarrowingConversion("u64", "u32")).toBe(true);
144
- expect(resolver.isNarrowingConversion("i64", "i8")).toBe(true);
133
+ expect(TypeResolver.isNarrowingConversion("u32", "u16")).toBe(true);
134
+ expect(TypeResolver.isNarrowingConversion("u32", "u8")).toBe(true);
135
+ expect(TypeResolver.isNarrowingConversion("u64", "u32")).toBe(true);
136
+ expect(TypeResolver.isNarrowingConversion("i64", "i8")).toBe(true);
145
137
  });
146
138
 
147
139
  it("should return false when target is same size or larger", () => {
148
- expect(resolver.isNarrowingConversion("u16", "u32")).toBe(false);
149
- expect(resolver.isNarrowingConversion("u32", "u32")).toBe(false);
150
- expect(resolver.isNarrowingConversion("u8", "u64")).toBe(false);
140
+ expect(TypeResolver.isNarrowingConversion("u16", "u32")).toBe(false);
141
+ expect(TypeResolver.isNarrowingConversion("u32", "u32")).toBe(false);
142
+ expect(TypeResolver.isNarrowingConversion("u8", "u64")).toBe(false);
151
143
  });
152
144
 
153
145
  it("should return false for unknown types", () => {
154
- expect(resolver.isNarrowingConversion("unknown", "u32")).toBe(false);
155
- expect(resolver.isNarrowingConversion("u32", "unknown")).toBe(false);
146
+ expect(TypeResolver.isNarrowingConversion("unknown", "u32")).toBe(false);
147
+ expect(TypeResolver.isNarrowingConversion("u32", "unknown")).toBe(false);
156
148
  });
157
149
  });
158
150
 
159
151
  describe("isSignConversion", () => {
160
152
  it("should return true for signed to unsigned conversion", () => {
161
- expect(resolver.isSignConversion("i32", "u32")).toBe(true);
162
- expect(resolver.isSignConversion("i8", "u64")).toBe(true);
153
+ expect(TypeResolver.isSignConversion("i32", "u32")).toBe(true);
154
+ expect(TypeResolver.isSignConversion("i8", "u64")).toBe(true);
163
155
  });
164
156
 
165
157
  it("should return true for unsigned to signed conversion", () => {
166
- expect(resolver.isSignConversion("u32", "i32")).toBe(true);
167
- expect(resolver.isSignConversion("u8", "i64")).toBe(true);
158
+ expect(TypeResolver.isSignConversion("u32", "i32")).toBe(true);
159
+ expect(TypeResolver.isSignConversion("u8", "i64")).toBe(true);
168
160
  });
169
161
 
170
162
  it("should return false for same-sign conversion", () => {
171
- expect(resolver.isSignConversion("i32", "i64")).toBe(false);
172
- expect(resolver.isSignConversion("u32", "u64")).toBe(false);
163
+ expect(TypeResolver.isSignConversion("i32", "i64")).toBe(false);
164
+ expect(TypeResolver.isSignConversion("u32", "u64")).toBe(false);
173
165
  });
174
166
 
175
167
  it("should return false for non-integer types", () => {
176
- expect(resolver.isSignConversion("f32", "f64")).toBe(false);
177
- expect(resolver.isSignConversion("bool", "u8")).toBe(false);
168
+ expect(TypeResolver.isSignConversion("f32", "f64")).toBe(false);
169
+ expect(TypeResolver.isSignConversion("bool", "u8")).toBe(false);
178
170
  });
179
171
  });
180
172
 
181
173
  describe("validateTypeConversion", () => {
182
174
  it("should not throw for same type", () => {
183
- expect(() => resolver.validateTypeConversion("u32", "u32")).not.toThrow();
184
- expect(() => resolver.validateTypeConversion("i64", "i64")).not.toThrow();
175
+ expect(() =>
176
+ TypeResolver.validateTypeConversion("u32", "u32"),
177
+ ).not.toThrow();
178
+ expect(() =>
179
+ TypeResolver.validateTypeConversion("i64", "i64"),
180
+ ).not.toThrow();
185
181
  });
186
182
 
187
183
  it("should not throw for widening conversion", () => {
188
- expect(() => resolver.validateTypeConversion("u32", "u16")).not.toThrow();
189
- expect(() => resolver.validateTypeConversion("u64", "u8")).not.toThrow();
190
- expect(() => resolver.validateTypeConversion("i64", "i32")).not.toThrow();
184
+ expect(() =>
185
+ TypeResolver.validateTypeConversion("u32", "u16"),
186
+ ).not.toThrow();
187
+ expect(() =>
188
+ TypeResolver.validateTypeConversion("u64", "u8"),
189
+ ).not.toThrow();
190
+ expect(() =>
191
+ TypeResolver.validateTypeConversion("i64", "i32"),
192
+ ).not.toThrow();
191
193
  });
192
194
 
193
195
  it("should throw for narrowing conversion", () => {
194
- expect(() => resolver.validateTypeConversion("u8", "u32")).toThrow(
196
+ expect(() => TypeResolver.validateTypeConversion("u8", "u32")).toThrow(
195
197
  /narrowing/,
196
198
  );
197
- expect(() => resolver.validateTypeConversion("u16", "u64")).toThrow(
199
+ expect(() => TypeResolver.validateTypeConversion("u16", "u64")).toThrow(
198
200
  /narrowing/,
199
201
  );
200
202
  });
201
203
 
202
204
  it("should throw for sign conversion", () => {
203
- expect(() => resolver.validateTypeConversion("u32", "i32")).toThrow(
205
+ expect(() => TypeResolver.validateTypeConversion("u32", "i32")).toThrow(
204
206
  /sign change/,
205
207
  );
206
- expect(() => resolver.validateTypeConversion("i32", "u32")).toThrow(
208
+ expect(() => TypeResolver.validateTypeConversion("i32", "u32")).toThrow(
207
209
  /sign change/,
208
210
  );
209
211
  });
210
212
 
211
213
  it("should not throw when source type is null", () => {
212
- expect(() => resolver.validateTypeConversion("u32", null)).not.toThrow();
214
+ expect(() =>
215
+ TypeResolver.validateTypeConversion("u32", null),
216
+ ).not.toThrow();
213
217
  });
214
218
 
215
219
  it("should not throw for non-integer types", () => {
216
- expect(() => resolver.validateTypeConversion("f32", "f64")).not.toThrow();
217
- expect(() => resolver.validateTypeConversion("bool", "u8")).not.toThrow();
220
+ expect(() =>
221
+ TypeResolver.validateTypeConversion("f32", "f64"),
222
+ ).not.toThrow();
223
+ expect(() =>
224
+ TypeResolver.validateTypeConversion("bool", "u8"),
225
+ ).not.toThrow();
218
226
  });
219
227
  });
220
228
 
@@ -225,60 +233,62 @@ describe("TypeResolver", () => {
225
233
  describe("validateLiteralFitsType", () => {
226
234
  describe("unsigned types", () => {
227
235
  it("should accept valid u8 values", () => {
228
- expect(() => resolver.validateLiteralFitsType("0", "u8")).not.toThrow();
229
236
  expect(() =>
230
- resolver.validateLiteralFitsType("255", "u8"),
237
+ TypeResolver.validateLiteralFitsType("0", "u8"),
238
+ ).not.toThrow();
239
+ expect(() =>
240
+ TypeResolver.validateLiteralFitsType("255", "u8"),
231
241
  ).not.toThrow();
232
242
  expect(() =>
233
- resolver.validateLiteralFitsType("0xFF", "u8"),
243
+ TypeResolver.validateLiteralFitsType("0xFF", "u8"),
234
244
  ).not.toThrow();
235
245
  });
236
246
 
237
247
  it("should reject out-of-range u8 values", () => {
238
- expect(() => resolver.validateLiteralFitsType("256", "u8")).toThrow(
239
- /exceeds u8 range/,
240
- );
241
- expect(() => resolver.validateLiteralFitsType("1000", "u8")).toThrow(
248
+ expect(() => TypeResolver.validateLiteralFitsType("256", "u8")).toThrow(
242
249
  /exceeds u8 range/,
243
250
  );
251
+ expect(() =>
252
+ TypeResolver.validateLiteralFitsType("1000", "u8"),
253
+ ).toThrow(/exceeds u8 range/);
244
254
  });
245
255
 
246
256
  it("should reject negative values for unsigned types", () => {
247
- expect(() => resolver.validateLiteralFitsType("-1", "u8")).toThrow(
248
- /Negative value/,
249
- );
250
- expect(() => resolver.validateLiteralFitsType("-100", "u32")).toThrow(
257
+ expect(() => TypeResolver.validateLiteralFitsType("-1", "u8")).toThrow(
251
258
  /Negative value/,
252
259
  );
260
+ expect(() =>
261
+ TypeResolver.validateLiteralFitsType("-100", "u32"),
262
+ ).toThrow(/Negative value/);
253
263
  });
254
264
 
255
265
  it("should accept valid u16 values", () => {
256
266
  expect(() =>
257
- resolver.validateLiteralFitsType("65535", "u16"),
267
+ TypeResolver.validateLiteralFitsType("65535", "u16"),
258
268
  ).not.toThrow();
259
269
  expect(() =>
260
- resolver.validateLiteralFitsType("0xFFFF", "u16"),
270
+ TypeResolver.validateLiteralFitsType("0xFFFF", "u16"),
261
271
  ).not.toThrow();
262
272
  });
263
273
 
264
274
  it("should reject out-of-range u16 values", () => {
265
- expect(() => resolver.validateLiteralFitsType("65536", "u16")).toThrow(
266
- /exceeds u16 range/,
267
- );
275
+ expect(() =>
276
+ TypeResolver.validateLiteralFitsType("65536", "u16"),
277
+ ).toThrow(/exceeds u16 range/);
268
278
  });
269
279
 
270
280
  it("should accept valid u32 values", () => {
271
281
  expect(() =>
272
- resolver.validateLiteralFitsType("4294967295", "u32"),
282
+ TypeResolver.validateLiteralFitsType("4294967295", "u32"),
273
283
  ).not.toThrow();
274
284
  expect(() =>
275
- resolver.validateLiteralFitsType("0xFFFFFFFF", "u32"),
285
+ TypeResolver.validateLiteralFitsType("0xFFFFFFFF", "u32"),
276
286
  ).not.toThrow();
277
287
  });
278
288
 
279
289
  it("should reject out-of-range u32 values", () => {
280
290
  expect(() =>
281
- resolver.validateLiteralFitsType("4294967296", "u32"),
291
+ TypeResolver.validateLiteralFitsType("4294967296", "u32"),
282
292
  ).toThrow(/exceeds u32 range/);
283
293
  });
284
294
  });
@@ -286,38 +296,40 @@ describe("TypeResolver", () => {
286
296
  describe("signed types", () => {
287
297
  it("should accept valid i8 values", () => {
288
298
  expect(() =>
289
- resolver.validateLiteralFitsType("-128", "i8"),
299
+ TypeResolver.validateLiteralFitsType("-128", "i8"),
300
+ ).not.toThrow();
301
+ expect(() =>
302
+ TypeResolver.validateLiteralFitsType("127", "i8"),
290
303
  ).not.toThrow();
291
304
  expect(() =>
292
- resolver.validateLiteralFitsType("127", "i8"),
305
+ TypeResolver.validateLiteralFitsType("0", "i8"),
293
306
  ).not.toThrow();
294
- expect(() => resolver.validateLiteralFitsType("0", "i8")).not.toThrow();
295
307
  });
296
308
 
297
309
  it("should reject out-of-range i8 values", () => {
298
- expect(() => resolver.validateLiteralFitsType("128", "i8")).toThrow(
299
- /exceeds i8 range/,
300
- );
301
- expect(() => resolver.validateLiteralFitsType("-129", "i8")).toThrow(
310
+ expect(() => TypeResolver.validateLiteralFitsType("128", "i8")).toThrow(
302
311
  /exceeds i8 range/,
303
312
  );
313
+ expect(() =>
314
+ TypeResolver.validateLiteralFitsType("-129", "i8"),
315
+ ).toThrow(/exceeds i8 range/);
304
316
  });
305
317
 
306
318
  it("should accept valid i32 values", () => {
307
319
  expect(() =>
308
- resolver.validateLiteralFitsType("-2147483648", "i32"),
320
+ TypeResolver.validateLiteralFitsType("-2147483648", "i32"),
309
321
  ).not.toThrow();
310
322
  expect(() =>
311
- resolver.validateLiteralFitsType("2147483647", "i32"),
323
+ TypeResolver.validateLiteralFitsType("2147483647", "i32"),
312
324
  ).not.toThrow();
313
325
  });
314
326
 
315
327
  it("should reject out-of-range i32 values", () => {
316
328
  expect(() =>
317
- resolver.validateLiteralFitsType("2147483648", "i32"),
329
+ TypeResolver.validateLiteralFitsType("2147483648", "i32"),
318
330
  ).toThrow(/exceeds i32 range/);
319
331
  expect(() =>
320
- resolver.validateLiteralFitsType("-2147483649", "i32"),
332
+ TypeResolver.validateLiteralFitsType("-2147483649", "i32"),
321
333
  ).toThrow(/exceeds i32 range/);
322
334
  });
323
335
  });
@@ -325,19 +337,19 @@ describe("TypeResolver", () => {
325
337
  describe("hex and binary literals", () => {
326
338
  it("should validate hex literals", () => {
327
339
  expect(() =>
328
- resolver.validateLiteralFitsType("0xFF", "u8"),
340
+ TypeResolver.validateLiteralFitsType("0xFF", "u8"),
329
341
  ).not.toThrow();
330
- expect(() => resolver.validateLiteralFitsType("0x100", "u8")).toThrow(
331
- /exceeds u8 range/,
332
- );
342
+ expect(() =>
343
+ TypeResolver.validateLiteralFitsType("0x100", "u8"),
344
+ ).toThrow(/exceeds u8 range/);
333
345
  });
334
346
 
335
347
  it("should validate binary literals", () => {
336
348
  expect(() =>
337
- resolver.validateLiteralFitsType("0b11111111", "u8"),
349
+ TypeResolver.validateLiteralFitsType("0b11111111", "u8"),
338
350
  ).not.toThrow();
339
351
  expect(() =>
340
- resolver.validateLiteralFitsType("0b100000000", "u8"),
352
+ TypeResolver.validateLiteralFitsType("0b100000000", "u8"),
341
353
  ).toThrow(/exceeds u8 range/);
342
354
  });
343
355
  });
@@ -345,19 +357,19 @@ describe("TypeResolver", () => {
345
357
  describe("edge cases", () => {
346
358
  it("should skip validation for unknown types", () => {
347
359
  expect(() =>
348
- resolver.validateLiteralFitsType("999999", "unknown"),
360
+ TypeResolver.validateLiteralFitsType("999999", "unknown"),
349
361
  ).not.toThrow();
350
362
  expect(() =>
351
- resolver.validateLiteralFitsType("999999", "f32"),
363
+ TypeResolver.validateLiteralFitsType("999999", "f32"),
352
364
  ).not.toThrow();
353
365
  });
354
366
 
355
367
  it("should skip validation for non-integer literals", () => {
356
368
  expect(() =>
357
- resolver.validateLiteralFitsType("3.14", "u8"),
369
+ TypeResolver.validateLiteralFitsType("3.14", "u8"),
358
370
  ).not.toThrow();
359
371
  expect(() =>
360
- resolver.validateLiteralFitsType("hello", "u8"),
372
+ TypeResolver.validateLiteralFitsType("hello", "u8"),
361
373
  ).not.toThrow();
362
374
  });
363
375
  });
@@ -368,7 +380,6 @@ describe("TypeResolver", () => {
368
380
  // ========================================================================
369
381
 
370
382
  describe("getPrimaryExpressionType", () => {
371
- // Helper to create mock primary expression context
372
383
  const mockPrimary = (opts: {
373
384
  identifier?: string;
374
385
  literal?: string;
@@ -377,13 +388,15 @@ describe("TypeResolver", () => {
377
388
  return {
378
389
  IDENTIFIER: () =>
379
390
  opts.identifier ? { getText: () => opts.identifier } : null,
391
+ GLOBAL: () => null,
392
+ THIS: () => null,
380
393
  literal: () => (opts.literal ? { getText: () => opts.literal } : null),
381
394
  expression: () => null,
382
395
  castExpression: () =>
383
396
  opts.castType
384
397
  ? { type: () => ({ getText: () => opts.castType }) }
385
398
  : null,
386
- } as Parameters<typeof resolver.getPrimaryExpressionType>[0];
399
+ } as Parameters<typeof TypeResolver.getPrimaryExpressionType>[0];
387
400
  };
388
401
 
389
402
  it("should return type for identifier in registry", () => {
@@ -394,32 +407,32 @@ describe("TypeResolver", () => {
394
407
  isConst: false,
395
408
  });
396
409
  const ctx = mockPrimary({ identifier: "myVar" });
397
- expect(resolver.getPrimaryExpressionType(ctx)).toBe("u32");
410
+ expect(TypeResolver.getPrimaryExpressionType(ctx)).toBe("u32");
398
411
  });
399
412
 
400
413
  it("should return null for identifier not in registry", () => {
401
414
  const ctx = mockPrimary({ identifier: "unknownVar" });
402
- expect(resolver.getPrimaryExpressionType(ctx)).toBeNull();
415
+ expect(TypeResolver.getPrimaryExpressionType(ctx)).toBeNull();
403
416
  });
404
417
 
405
418
  it("should return type from literal suffix", () => {
406
419
  const ctx = mockPrimary({ literal: "42u8" });
407
- expect(resolver.getPrimaryExpressionType(ctx)).toBe("u8");
420
+ expect(TypeResolver.getPrimaryExpressionType(ctx)).toBe("u8");
408
421
  });
409
422
 
410
423
  it("should return bool for boolean literal", () => {
411
424
  const ctx = mockPrimary({ literal: "true" });
412
- expect(resolver.getPrimaryExpressionType(ctx)).toBe("bool");
425
+ expect(TypeResolver.getPrimaryExpressionType(ctx)).toBe("bool");
413
426
  });
414
427
 
415
428
  it("should return type from cast expression", () => {
416
429
  const ctx = mockPrimary({ castType: "i16" });
417
- expect(resolver.getPrimaryExpressionType(ctx)).toBe("i16");
430
+ expect(TypeResolver.getPrimaryExpressionType(ctx)).toBe("i16");
418
431
  });
419
432
 
420
433
  it("should return null when no matching component", () => {
421
434
  const ctx = mockPrimary({});
422
- expect(resolver.getPrimaryExpressionType(ctx)).toBeNull();
435
+ expect(TypeResolver.getPrimaryExpressionType(ctx)).toBeNull();
423
436
  });
424
437
  });
425
438
 
@@ -428,7 +441,6 @@ describe("TypeResolver", () => {
428
441
  // ========================================================================
429
442
 
430
443
  describe("getExpressionType", () => {
431
- // Helper to create mock expression context with nested structure
432
444
  const mockExpressionWithOr = (orCount: number) => {
433
445
  const orExprs = Array(orCount)
434
446
  .fill(null)
@@ -450,7 +462,7 @@ describe("TypeResolver", () => {
450
462
  ternaryExpression: () => ({
451
463
  orExpression: () => orExprs,
452
464
  }),
453
- } as unknown as Parameters<typeof resolver.getExpressionType>[0];
465
+ } as unknown as Parameters<typeof TypeResolver.getExpressionType>[0];
454
466
  };
455
467
 
456
468
  const mockExpressionWithAnd = (andCount: number) => {
@@ -466,7 +478,7 @@ describe("TypeResolver", () => {
466
478
  ternaryExpression: () => ({
467
479
  orExpression: () => [{ andExpression: () => andExprs }],
468
480
  }),
469
- } as unknown as Parameters<typeof resolver.getExpressionType>[0];
481
+ } as unknown as Parameters<typeof TypeResolver.getExpressionType>[0];
470
482
  };
471
483
 
472
484
  const mockExpressionWithEquality = (eqCount: number) => {
@@ -482,7 +494,7 @@ describe("TypeResolver", () => {
482
494
  { andExpression: () => [{ equalityExpression: () => eqExprs }] },
483
495
  ],
484
496
  }),
485
- } as unknown as Parameters<typeof resolver.getExpressionType>[0];
497
+ } as unknown as Parameters<typeof TypeResolver.getExpressionType>[0];
486
498
  };
487
499
 
488
500
  const mockExpressionWithRelational = (relCount: number) => {
@@ -506,32 +518,30 @@ describe("TypeResolver", () => {
506
518
  },
507
519
  ],
508
520
  }),
509
- } as unknown as Parameters<typeof resolver.getExpressionType>[0];
521
+ } as unknown as Parameters<typeof TypeResolver.getExpressionType>[0];
510
522
  };
511
523
 
512
524
  it("should return null for ternary expression (multiple or expressions)", () => {
513
525
  const ctx = mockExpressionWithOr(3);
514
- expect(resolver.getExpressionType(ctx)).toBeNull();
526
+ expect(TypeResolver.getExpressionType(ctx)).toBeNull();
515
527
  });
516
528
 
517
529
  it("should return bool for logical OR expression", () => {
518
530
  const ctx = mockExpressionWithAnd(2);
519
- expect(resolver.getExpressionType(ctx)).toBe("bool");
531
+ expect(TypeResolver.getExpressionType(ctx)).toBe("bool");
520
532
  });
521
533
 
522
534
  it("should return bool for logical AND expression", () => {
523
535
  const ctx = mockExpressionWithEquality(2);
524
- expect(resolver.getExpressionType(ctx)).toBe("bool");
536
+ expect(TypeResolver.getExpressionType(ctx)).toBe("bool");
525
537
  });
526
538
 
527
539
  it("should return bool for equality expression", () => {
528
540
  const ctx = mockExpressionWithRelational(2);
529
- expect(resolver.getExpressionType(ctx)).toBe("bool");
541
+ expect(TypeResolver.getExpressionType(ctx)).toBe("bool");
530
542
  });
531
543
 
532
544
  it("should return null for simple arithmetic expression", () => {
533
- // Expression with 1 of each - falls through to null (can't determine arithmetic type)
534
- // Need to mock the full depth of the expression tree
535
545
  const ctx = {
536
546
  ternaryExpression: () => ({
537
547
  orExpression: () => [
@@ -554,7 +564,6 @@ describe("TypeResolver", () => {
554
564
  {
555
565
  multiplicativeExpression: () => [
556
566
  {
557
- // 2 unary expressions = binary operation, can't determine type
558
567
  unaryExpression: () => [
559
568
  {},
560
569
  {},
@@ -580,9 +589,9 @@ describe("TypeResolver", () => {
580
589
  },
581
590
  ],
582
591
  }),
583
- } as unknown as Parameters<typeof resolver.getExpressionType>[0];
592
+ } as unknown as Parameters<typeof TypeResolver.getExpressionType>[0];
584
593
 
585
- expect(resolver.getExpressionType(ctx)).toBeNull();
594
+ expect(TypeResolver.getExpressionType(ctx)).toBeNull();
586
595
  });
587
596
  });
588
597
 
@@ -595,9 +604,11 @@ describe("TypeResolver", () => {
595
604
  const ctx = {
596
605
  primaryExpression: () => null,
597
606
  children: [],
598
- } as unknown as Parameters<typeof resolver.getPostfixExpressionType>[0];
607
+ } as unknown as Parameters<
608
+ typeof TypeResolver.getPostfixExpressionType
609
+ >[0];
599
610
 
600
- expect(resolver.getPostfixExpressionType(ctx)).toBeNull();
611
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBeNull();
601
612
  });
602
613
 
603
614
  it("should return type from simple identifier", () => {
@@ -616,9 +627,11 @@ describe("TypeResolver", () => {
616
627
  castExpression: () => null,
617
628
  }),
618
629
  children: [{ getText: () => "counter" }],
619
- } as unknown as Parameters<typeof resolver.getPostfixExpressionType>[0];
630
+ } as unknown as Parameters<
631
+ typeof TypeResolver.getPostfixExpressionType
632
+ >[0];
620
633
 
621
- expect(resolver.getPostfixExpressionType(ctx)).toBe("u32");
634
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBe("u32");
622
635
  });
623
636
 
624
637
  it("should return null when primary type cannot be determined", () => {
@@ -630,9 +643,11 @@ describe("TypeResolver", () => {
630
643
  castExpression: () => null,
631
644
  }),
632
645
  children: [{ getText: () => "unknownVar" }],
633
- } as unknown as Parameters<typeof resolver.getPostfixExpressionType>[0];
646
+ } as unknown as Parameters<
647
+ typeof TypeResolver.getPostfixExpressionType
648
+ >[0];
634
649
 
635
- expect(resolver.getPostfixExpressionType(ctx)).toBeNull();
650
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBeNull();
636
651
  });
637
652
 
638
653
  it("should return member type for struct member access", () => {
@@ -652,9 +667,11 @@ describe("TypeResolver", () => {
652
667
  castExpression: () => null,
653
668
  }),
654
669
  children: [{ getText: () => "point" }, { getText: () => ".x" }],
655
- } as unknown as Parameters<typeof resolver.getPostfixExpressionType>[0];
670
+ } as unknown as Parameters<
671
+ typeof TypeResolver.getPostfixExpressionType
672
+ >[0];
656
673
 
657
- expect(resolver.getPostfixExpressionType(ctx)).toBe("i32");
674
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBe("i32");
658
675
  });
659
676
 
660
677
  it("should return null for unknown member", () => {
@@ -674,9 +691,11 @@ describe("TypeResolver", () => {
674
691
  castExpression: () => null,
675
692
  }),
676
693
  children: [{ getText: () => "point" }, { getText: () => ".unknown" }],
677
- } as unknown as Parameters<typeof resolver.getPostfixExpressionType>[0];
694
+ } as unknown as Parameters<
695
+ typeof TypeResolver.getPostfixExpressionType
696
+ >[0];
678
697
 
679
- expect(resolver.getPostfixExpressionType(ctx)).toBeNull();
698
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBeNull();
680
699
  });
681
700
 
682
701
  it("should return null for range bit indexing", () => {
@@ -695,9 +714,11 @@ describe("TypeResolver", () => {
695
714
  castExpression: () => null,
696
715
  }),
697
716
  children: [{ getText: () => "flags" }, { getText: () => "[0, 8]" }],
698
- } as unknown as Parameters<typeof resolver.getPostfixExpressionType>[0];
717
+ } as unknown as Parameters<
718
+ typeof TypeResolver.getPostfixExpressionType
719
+ >[0];
699
720
 
700
- expect(resolver.getPostfixExpressionType(ctx)).toBeNull();
721
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBeNull();
701
722
  });
702
723
 
703
724
  it("should return bool for single bit indexing on integer", () => {
@@ -716,12 +737,14 @@ describe("TypeResolver", () => {
716
737
  castExpression: () => null,
717
738
  }),
718
739
  children: [{ getText: () => "flags" }, { getText: () => "[7]" }],
719
- } as unknown as Parameters<typeof resolver.getPostfixExpressionType>[0];
740
+ } as unknown as Parameters<
741
+ typeof TypeResolver.getPostfixExpressionType
742
+ >[0];
720
743
 
721
- expect(resolver.getPostfixExpressionType(ctx)).toBe("bool");
744
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBe("bool");
722
745
  });
723
746
 
724
- it("should return element type for array indexing on non-integer", () => {
747
+ it("should return element type for struct array member indexing", () => {
725
748
  typeRegistry.set("data", {
726
749
  baseType: "Data",
727
750
  bitWidth: 0,
@@ -742,11 +765,219 @@ describe("TypeResolver", () => {
742
765
  { getText: () => ".values" },
743
766
  { getText: () => "[0]" },
744
767
  ],
745
- } as unknown as Parameters<typeof resolver.getPostfixExpressionType>[0];
768
+ } as unknown as Parameters<
769
+ typeof TypeResolver.getPostfixExpressionType
770
+ >[0];
771
+
772
+ // Bug fix: After .values (u8 array), [0] should be array element access -> "u8"
773
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBe("u8");
774
+ });
775
+
776
+ it("should return element type for direct array variable indexing", () => {
777
+ typeRegistry.set("arr", {
778
+ baseType: "u8",
779
+ bitWidth: 8,
780
+ isArray: true,
781
+ isConst: false,
782
+ });
783
+
784
+ const ctx = {
785
+ primaryExpression: () => ({
786
+ IDENTIFIER: () => ({ getText: () => "arr" }),
787
+ literal: () => null,
788
+ expression: () => null,
789
+ castExpression: () => null,
790
+ }),
791
+ children: [{ getText: () => "arr" }, { getText: () => "[0]" }],
792
+ } as unknown as Parameters<
793
+ typeof TypeResolver.getPostfixExpressionType
794
+ >[0];
795
+
796
+ // u8 array with [0] should be array element access -> "u8" (not "bool")
797
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBe("u8");
798
+ });
799
+
800
+ it("should return bool for bit indexing on plain integer variable", () => {
801
+ typeRegistry.set("val", {
802
+ baseType: "u8",
803
+ bitWidth: 8,
804
+ isArray: false,
805
+ isConst: false,
806
+ });
807
+
808
+ const ctx = {
809
+ primaryExpression: () => ({
810
+ IDENTIFIER: () => ({ getText: () => "val" }),
811
+ literal: () => null,
812
+ expression: () => null,
813
+ castExpression: () => null,
814
+ }),
815
+ children: [{ getText: () => "val" }, { getText: () => "[0]" }],
816
+ } as unknown as Parameters<
817
+ typeof TypeResolver.getPostfixExpressionType
818
+ >[0];
819
+
820
+ // Plain u8 (not array) with [0] should be bit indexing -> "bool"
821
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBe("bool");
822
+ });
823
+ });
824
+
825
+ // ========================================================================
826
+ // global/this Primary Expression Handling
827
+ // ========================================================================
828
+
829
+ describe("getPostfixExpressionType with global/this", () => {
830
+ it("should resolve global.structVar.field type", () => {
831
+ typeRegistry.set("config", {
832
+ baseType: "TConfig",
833
+ bitWidth: 0,
834
+ isArray: false,
835
+ isConst: false,
836
+ });
837
+ symbolTable.addStructField("TConfig", "value", "u32");
838
+
839
+ const ctx = {
840
+ primaryExpression: () => ({
841
+ IDENTIFIER: () => null,
842
+ GLOBAL: () => ({ getText: () => "global" }),
843
+ THIS: () => null,
844
+ literal: () => null,
845
+ expression: () => null,
846
+ castExpression: () => null,
847
+ }),
848
+ children: [
849
+ { getText: () => "global" },
850
+ { getText: () => ".config" },
851
+ { getText: () => ".value" },
852
+ ],
853
+ } as unknown as Parameters<
854
+ typeof TypeResolver.getPostfixExpressionType
855
+ >[0];
856
+
857
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBe("u32");
858
+ });
859
+
860
+ it("should resolve global.arrayVar[0] element type", () => {
861
+ typeRegistry.set("inputs", {
862
+ baseType: "TInput",
863
+ bitWidth: 0,
864
+ isArray: true,
865
+ isConst: false,
866
+ });
867
+
868
+ const ctx = {
869
+ primaryExpression: () => ({
870
+ IDENTIFIER: () => null,
871
+ GLOBAL: () => ({ getText: () => "global" }),
872
+ THIS: () => null,
873
+ literal: () => null,
874
+ expression: () => null,
875
+ castExpression: () => null,
876
+ }),
877
+ children: [
878
+ { getText: () => "global" },
879
+ { getText: () => ".inputs" },
880
+ { getText: () => "[0]" },
881
+ ],
882
+ } as unknown as Parameters<
883
+ typeof TypeResolver.getPostfixExpressionType
884
+ >[0];
746
885
 
747
- // After .values, type is "u8" (array element type)
748
- // Then [0] on "u8" - u8 is an integer, so it returns "bool" for bit access
749
- expect(resolver.getPostfixExpressionType(ctx)).toBe("bool");
886
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBe("TInput");
887
+ });
888
+
889
+ it("should resolve this.scopeVar type", () => {
890
+ CodeGenState.currentScope = "Motor";
891
+ typeRegistry.set("Motor_speed", {
892
+ baseType: "u32",
893
+ bitWidth: 32,
894
+ isArray: false,
895
+ isConst: false,
896
+ });
897
+
898
+ const ctx = {
899
+ primaryExpression: () => ({
900
+ IDENTIFIER: () => null,
901
+ GLOBAL: () => null,
902
+ THIS: () => ({ getText: () => "this" }),
903
+ literal: () => null,
904
+ expression: () => null,
905
+ castExpression: () => null,
906
+ }),
907
+ children: [{ getText: () => "this" }, { getText: () => ".speed" }],
908
+ } as unknown as Parameters<
909
+ typeof TypeResolver.getPostfixExpressionType
910
+ >[0];
911
+
912
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBe("u32");
913
+ });
914
+
915
+ it("should return null for global.unknownVar", () => {
916
+ const ctx = {
917
+ primaryExpression: () => ({
918
+ IDENTIFIER: () => null,
919
+ GLOBAL: () => ({ getText: () => "global" }),
920
+ THIS: () => null,
921
+ literal: () => null,
922
+ expression: () => null,
923
+ castExpression: () => null,
924
+ }),
925
+ children: [{ getText: () => "global" }, { getText: () => ".unknown" }],
926
+ } as unknown as Parameters<
927
+ typeof TypeResolver.getPostfixExpressionType
928
+ >[0];
929
+
930
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBeNull();
931
+ });
932
+
933
+ it("should return null for this.X without current scope", () => {
934
+ CodeGenState.currentScope = null;
935
+
936
+ const ctx = {
937
+ primaryExpression: () => ({
938
+ IDENTIFIER: () => null,
939
+ GLOBAL: () => null,
940
+ THIS: () => ({ getText: () => "this" }),
941
+ literal: () => null,
942
+ expression: () => null,
943
+ castExpression: () => null,
944
+ }),
945
+ children: [{ getText: () => "this" }, { getText: () => ".speed" }],
946
+ } as unknown as Parameters<
947
+ typeof TypeResolver.getPostfixExpressionType
948
+ >[0];
949
+
950
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBeNull();
951
+ });
952
+
953
+ it("should resolve global.struct.enumField for enum type", () => {
954
+ typeRegistry.set("input", {
955
+ baseType: "TInput",
956
+ bitWidth: 0,
957
+ isArray: false,
958
+ isConst: false,
959
+ });
960
+ symbolTable.addStructField("TInput", "assignedValue", "EValueId");
961
+
962
+ const ctx = {
963
+ primaryExpression: () => ({
964
+ IDENTIFIER: () => null,
965
+ GLOBAL: () => ({ getText: () => "global" }),
966
+ THIS: () => null,
967
+ literal: () => null,
968
+ expression: () => null,
969
+ castExpression: () => null,
970
+ }),
971
+ children: [
972
+ { getText: () => "global" },
973
+ { getText: () => ".input" },
974
+ { getText: () => ".assignedValue" },
975
+ ],
976
+ } as unknown as Parameters<
977
+ typeof TypeResolver.getPostfixExpressionType
978
+ >[0];
979
+
980
+ expect(TypeResolver.getPostfixExpressionType(ctx)).toBe("EValueId");
750
981
  });
751
982
  });
752
983
 
@@ -774,18 +1005,18 @@ describe("TypeResolver", () => {
774
1005
  children: [{ getText: () => "value" }],
775
1006
  }),
776
1007
  unaryExpression: () => null,
777
- } as unknown as Parameters<typeof resolver.getUnaryExpressionType>[0];
1008
+ } as unknown as Parameters<typeof TypeResolver.getUnaryExpressionType>[0];
778
1009
 
779
- expect(resolver.getUnaryExpressionType(ctx)).toBe("i32");
1010
+ expect(TypeResolver.getUnaryExpressionType(ctx)).toBe("i32");
780
1011
  });
781
1012
 
782
1013
  it("should return null when no postfix or unary", () => {
783
1014
  const ctx = {
784
1015
  postfixExpression: () => null,
785
1016
  unaryExpression: () => null,
786
- } as unknown as Parameters<typeof resolver.getUnaryExpressionType>[0];
1017
+ } as unknown as Parameters<typeof TypeResolver.getUnaryExpressionType>[0];
787
1018
 
788
- expect(resolver.getUnaryExpressionType(ctx)).toBeNull();
1019
+ expect(TypeResolver.getUnaryExpressionType(ctx)).toBeNull();
789
1020
  });
790
1021
 
791
1022
  it("should recurse through unary expression chain", () => {
@@ -796,7 +1027,6 @@ describe("TypeResolver", () => {
796
1027
  isConst: false,
797
1028
  });
798
1029
 
799
- // Represents: -x (unary minus with nested expression)
800
1030
  const ctx = {
801
1031
  postfixExpression: () => null,
802
1032
  unaryExpression: () => ({
@@ -811,9 +1041,9 @@ describe("TypeResolver", () => {
811
1041
  }),
812
1042
  unaryExpression: () => null,
813
1043
  }),
814
- } as unknown as Parameters<typeof resolver.getUnaryExpressionType>[0];
1044
+ } as unknown as Parameters<typeof TypeResolver.getUnaryExpressionType>[0];
815
1045
 
816
- expect(resolver.getUnaryExpressionType(ctx)).toBe("i32");
1046
+ expect(TypeResolver.getUnaryExpressionType(ctx)).toBe("i32");
817
1047
  });
818
1048
  });
819
1049
 
@@ -822,57 +1052,60 @@ describe("TypeResolver", () => {
822
1052
  // ========================================================================
823
1053
 
824
1054
  describe("getLiteralType", () => {
825
- // Helper to create mock literal context
826
1055
  const mockLiteral = (text: string) =>
827
1056
  ({ getText: () => text }) as Parameters<
828
- typeof resolver.getLiteralType
1057
+ typeof TypeResolver.getLiteralType
829
1058
  >[0];
830
1059
 
831
1060
  describe("boolean literals", () => {
832
1061
  it("should return bool for true", () => {
833
- expect(resolver.getLiteralType(mockLiteral("true"))).toBe("bool");
1062
+ expect(TypeResolver.getLiteralType(mockLiteral("true"))).toBe("bool");
834
1063
  });
835
1064
 
836
1065
  it("should return bool for false", () => {
837
- expect(resolver.getLiteralType(mockLiteral("false"))).toBe("bool");
1066
+ expect(TypeResolver.getLiteralType(mockLiteral("false"))).toBe("bool");
838
1067
  });
839
1068
  });
840
1069
 
841
1070
  describe("integer suffixes", () => {
842
1071
  it("should detect u8 suffix", () => {
843
- expect(resolver.getLiteralType(mockLiteral("255u8"))).toBe("u8");
844
- expect(resolver.getLiteralType(mockLiteral("0U8"))).toBe("u8");
1072
+ expect(TypeResolver.getLiteralType(mockLiteral("255u8"))).toBe("u8");
1073
+ expect(TypeResolver.getLiteralType(mockLiteral("0U8"))).toBe("u8");
845
1074
  });
846
1075
 
847
1076
  it("should detect u16 suffix", () => {
848
- expect(resolver.getLiteralType(mockLiteral("1000u16"))).toBe("u16");
1077
+ expect(TypeResolver.getLiteralType(mockLiteral("1000u16"))).toBe("u16");
849
1078
  });
850
1079
 
851
1080
  it("should detect u32 suffix", () => {
852
- expect(resolver.getLiteralType(mockLiteral("1000000u32"))).toBe("u32");
1081
+ expect(TypeResolver.getLiteralType(mockLiteral("1000000u32"))).toBe(
1082
+ "u32",
1083
+ );
853
1084
  });
854
1085
 
855
1086
  it("should detect u64 suffix", () => {
856
- expect(resolver.getLiteralType(mockLiteral("1000000000u64"))).toBe(
1087
+ expect(TypeResolver.getLiteralType(mockLiteral("1000000000u64"))).toBe(
857
1088
  "u64",
858
1089
  );
859
1090
  });
860
1091
 
861
1092
  it("should detect i8 suffix", () => {
862
- expect(resolver.getLiteralType(mockLiteral("-50i8"))).toBe("i8");
863
- expect(resolver.getLiteralType(mockLiteral("50I8"))).toBe("i8");
1093
+ expect(TypeResolver.getLiteralType(mockLiteral("-50i8"))).toBe("i8");
1094
+ expect(TypeResolver.getLiteralType(mockLiteral("50I8"))).toBe("i8");
864
1095
  });
865
1096
 
866
1097
  it("should detect i16 suffix", () => {
867
- expect(resolver.getLiteralType(mockLiteral("1000i16"))).toBe("i16");
1098
+ expect(TypeResolver.getLiteralType(mockLiteral("1000i16"))).toBe("i16");
868
1099
  });
869
1100
 
870
1101
  it("should detect i32 suffix", () => {
871
- expect(resolver.getLiteralType(mockLiteral("1000000i32"))).toBe("i32");
1102
+ expect(TypeResolver.getLiteralType(mockLiteral("1000000i32"))).toBe(
1103
+ "i32",
1104
+ );
872
1105
  });
873
1106
 
874
1107
  it("should detect i64 suffix", () => {
875
- expect(resolver.getLiteralType(mockLiteral("1000000000i64"))).toBe(
1108
+ expect(TypeResolver.getLiteralType(mockLiteral("1000000000i64"))).toBe(
876
1109
  "i64",
877
1110
  );
878
1111
  });
@@ -880,27 +1113,31 @@ describe("TypeResolver", () => {
880
1113
 
881
1114
  describe("float suffixes", () => {
882
1115
  it("should detect f32 suffix", () => {
883
- expect(resolver.getLiteralType(mockLiteral("3.14f32"))).toBe("f32");
884
- expect(resolver.getLiteralType(mockLiteral("3.14F32"))).toBe("f32");
1116
+ expect(TypeResolver.getLiteralType(mockLiteral("3.14f32"))).toBe("f32");
1117
+ expect(TypeResolver.getLiteralType(mockLiteral("3.14F32"))).toBe("f32");
885
1118
  });
886
1119
 
887
1120
  it("should detect f64 suffix", () => {
888
- expect(resolver.getLiteralType(mockLiteral("3.14159f64"))).toBe("f64");
889
- expect(resolver.getLiteralType(mockLiteral("3.14159F64"))).toBe("f64");
1121
+ expect(TypeResolver.getLiteralType(mockLiteral("3.14159f64"))).toBe(
1122
+ "f64",
1123
+ );
1124
+ expect(TypeResolver.getLiteralType(mockLiteral("3.14159F64"))).toBe(
1125
+ "f64",
1126
+ );
890
1127
  });
891
1128
  });
892
1129
 
893
1130
  describe("unsuffixed literals", () => {
894
1131
  it("should return null for unsuffixed integer", () => {
895
- expect(resolver.getLiteralType(mockLiteral("42"))).toBeNull();
1132
+ expect(TypeResolver.getLiteralType(mockLiteral("42"))).toBeNull();
896
1133
  });
897
1134
 
898
1135
  it("should return null for unsuffixed hex", () => {
899
- expect(resolver.getLiteralType(mockLiteral("0xFF"))).toBeNull();
1136
+ expect(TypeResolver.getLiteralType(mockLiteral("0xFF"))).toBeNull();
900
1137
  });
901
1138
 
902
1139
  it("should return null for unsuffixed float", () => {
903
- expect(resolver.getLiteralType(mockLiteral("3.14"))).toBeNull();
1140
+ expect(TypeResolver.getLiteralType(mockLiteral("3.14"))).toBeNull();
904
1141
  });
905
1142
  });
906
1143
  });
@@ -914,7 +1151,7 @@ describe("TypeResolver", () => {
914
1151
  symbolTable.addStructField("Point", "x", "i32");
915
1152
  symbolTable.addStructField("Point", "y", "i32");
916
1153
 
917
- const xInfo = resolver.getMemberTypeInfo("Point", "x");
1154
+ const xInfo = TypeResolver.getMemberTypeInfo("Point", "x");
918
1155
  expect(xInfo).toBeDefined();
919
1156
  expect(xInfo?.baseType).toBe("i32");
920
1157
  expect(xInfo?.isArray).toBe(false);
@@ -923,19 +1160,21 @@ describe("TypeResolver", () => {
923
1160
  it("should return array info for array fields", () => {
924
1161
  symbolTable.addStructField("Buffer", "data", "u8", [256]);
925
1162
 
926
- const dataInfo = resolver.getMemberTypeInfo("Buffer", "data");
1163
+ const dataInfo = TypeResolver.getMemberTypeInfo("Buffer", "data");
927
1164
  expect(dataInfo).toBeDefined();
928
1165
  expect(dataInfo?.baseType).toBe("u8");
929
1166
  expect(dataInfo?.isArray).toBe(true);
930
1167
  });
931
1168
 
932
1169
  it("should return undefined for unknown struct", () => {
933
- expect(resolver.getMemberTypeInfo("Unknown", "field")).toBeUndefined();
1170
+ expect(
1171
+ TypeResolver.getMemberTypeInfo("Unknown", "field"),
1172
+ ).toBeUndefined();
934
1173
  });
935
1174
 
936
1175
  it("should return undefined for unknown field", () => {
937
1176
  symbolTable.addStructField("Point", "x", "i32");
938
- expect(resolver.getMemberTypeInfo("Point", "z")).toBeUndefined();
1177
+ expect(TypeResolver.getMemberTypeInfo("Point", "z")).toBeUndefined();
939
1178
  });
940
1179
  });
941
1180
  });