c-next 0.1.61 → 0.1.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +86 -63
  2. package/grammar/CNext.g4 +3 -17
  3. package/package.json +1 -1
  4. package/src/cli/serve/ServeCommand.ts +57 -45
  5. package/src/lib/__tests__/parseCHeader.mocked.test.ts +145 -0
  6. package/src/transpiler/Transpiler.ts +603 -613
  7. package/src/transpiler/__tests__/DualCodePaths.test.ts +5 -1
  8. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +2 -99
  9. package/src/transpiler/__tests__/Transpiler.test.ts +3 -26
  10. package/src/transpiler/data/IncludeTreeWalker.ts +1 -1
  11. package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +23 -52
  12. package/src/transpiler/logic/parser/grammar/CNext.interp +1 -3
  13. package/src/transpiler/logic/parser/grammar/CNextListener.ts +0 -22
  14. package/src/transpiler/logic/parser/grammar/CNextParser.ts +665 -1084
  15. package/src/transpiler/logic/parser/grammar/CNextVisitor.ts +0 -14
  16. package/src/transpiler/logic/symbols/CppSymbolCollector.ts +67 -43
  17. package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
  18. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
  19. package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
  20. package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
  21. package/src/transpiler/output/codegen/CodeGenerator.ts +1410 -2587
  22. package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
  23. package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
  24. package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
  25. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +2082 -52
  26. package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
  27. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
  28. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
  29. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
  30. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +227 -66
  31. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +55 -58
  32. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +288 -275
  33. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
  34. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +195 -133
  35. package/src/transpiler/output/codegen/assignment/AssignmentContextBuilder.ts +24 -74
  36. package/src/transpiler/output/codegen/assignment/AssignmentKind.ts +3 -0
  37. package/src/transpiler/output/codegen/assignment/IAssignmentContext.ts +3 -0
  38. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +290 -320
  39. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +42 -0
  40. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +76 -2
  41. package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
  42. package/src/transpiler/output/codegen/generators/IOrchestrator.ts +5 -1
  43. package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
  44. package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
  45. package/src/transpiler/output/codegen/generators/declarationGenerators/RegisterGenerator.ts +11 -24
  46. package/src/transpiler/output/codegen/generators/declarationGenerators/RegisterMacroGenerator.ts +64 -0
  47. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +137 -61
  48. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopedRegisterGenerator.ts +18 -27
  49. package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
  50. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
  51. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
  52. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +5 -1
  53. package/src/transpiler/output/codegen/generators/statements/ControlFlowGenerator.ts +1 -17
  54. package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
  55. package/src/transpiler/output/codegen/helpers/ArrayAccessHelper.ts +129 -0
  56. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
  57. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +40 -44
  58. package/src/transpiler/output/codegen/helpers/AssignmentTargetExtractor.ts +17 -45
  59. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +83 -78
  60. package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
  61. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
  62. package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
  63. package/src/transpiler/output/codegen/helpers/MemberSeparatorResolver.ts +10 -3
  64. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
  65. package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +44 -0
  66. package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
  67. package/src/transpiler/output/codegen/helpers/__tests__/ArrayAccessHelper.test.ts +479 -0
  68. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
  69. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
  70. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
  71. package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
  72. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
  73. package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
  74. package/src/transpiler/output/codegen/helpers/__tests__/MemberSeparatorResolver.test.ts +1 -0
  75. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
  76. package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +201 -0
  77. package/src/transpiler/output/codegen/helpers/__tests__/TypeGenerationHelper.test.ts +50 -0
  78. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
  79. package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
  80. package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
  81. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
  82. package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
  83. package/src/transpiler/output/codegen/types/IArrayAccessDeps.ts +23 -0
  84. package/src/transpiler/output/codegen/types/IArrayAccessInfo.ts +26 -0
  85. package/src/transpiler/output/codegen/types/IMemberSeparatorDeps.ts +7 -0
  86. package/src/transpiler/output/codegen/utils/CodegenParserUtils.ts +98 -0
  87. package/src/transpiler/output/codegen/utils/ExpressionUnwrapper.ts +22 -22
  88. package/src/transpiler/output/codegen/utils/__tests__/CodegenParserUtils.test.ts +228 -0
  89. package/src/transpiler/types/IFileResult.ts +0 -4
  90. package/src/transpiler/types/IPipelineFile.ts +27 -0
  91. package/src/transpiler/types/IPipelineInput.ts +23 -0
  92. package/src/transpiler/types/TranspilerState.ts +1 -1
  93. package/src/utils/FormatUtils.ts +28 -2
  94. package/src/utils/MapUtils.ts +25 -0
  95. package/src/utils/PostfixAnalysisUtils.ts +48 -0
  96. package/src/utils/__tests__/FormatUtils.test.ts +42 -0
  97. package/src/utils/__tests__/MapUtils.test.ts +85 -0
  98. package/src/utils/constants/OperatorMappings.ts +19 -0
  99. package/src/transpiler/logic/StandaloneContextBuilder.ts +0 -150
  100. package/src/transpiler/logic/__tests__/StandaloneContextBuilder.test.ts +0 -647
  101. package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
  102. package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
  103. package/src/transpiler/types/ITranspileContext.ts +0 -49
  104. package/src/transpiler/types/ITranspileContribution.ts +0 -32
@@ -2,50 +2,39 @@
2
2
  * Unit tests for StringDeclHelper
3
3
  *
4
4
  * Issue #644: Tests for the extracted string declaration helper.
5
+ * Migrated to use CodeGenState instead of constructor DI.
5
6
  */
6
7
 
7
8
  import { describe, it, expect, beforeEach, vi } from "vitest";
8
9
  import StringDeclHelper from "../StringDeclHelper.js";
9
- import type TTypeInfo from "../../types/TTypeInfo.js";
10
+ import CodeGenState from "../../CodeGenState.js";
10
11
 
11
- describe("StringDeclHelper", () => {
12
- let typeRegistry: Map<string, TTypeInfo>;
13
- let localArrays: Set<string>;
14
- let arrayInitState: {
15
- lastArrayInitCount: number;
16
- lastArrayFillValue: string | undefined;
17
- };
18
- let helper: StringDeclHelper;
12
+ /**
13
+ * Default callbacks for testing.
14
+ */
15
+ const defaultCallbacks = {
16
+ generateExpression: vi.fn((ctx: { getText: () => string }) => ctx.getText()),
17
+ generateArrayDimensions: vi.fn(
18
+ (dims: { expression: () => { getText: () => string } | null }[]) =>
19
+ dims
20
+ .map((d) => {
21
+ const expr = d.expression();
22
+ return expr ? `[${expr.getText()}]` : "[]";
23
+ })
24
+ .join(""),
25
+ ),
26
+ getStringConcatOperands: vi.fn(() => null),
27
+ getSubstringOperands: vi.fn(() => null),
28
+ getStringExprCapacity: vi.fn(() => null),
29
+ requireStringInclude: vi.fn(),
30
+ };
19
31
 
32
+ describe("StringDeclHelper", () => {
20
33
  beforeEach(() => {
21
- typeRegistry = new Map();
22
- localArrays = new Set();
23
- arrayInitState = {
24
- lastArrayInitCount: 0,
25
- lastArrayFillValue: undefined,
26
- };
27
-
28
- helper = new StringDeclHelper({
29
- typeRegistry,
30
- getInFunctionBody: () => true,
31
- getIndentLevel: () => 1,
32
- arrayInitState,
33
- localArrays,
34
- generateExpression: vi.fn((ctx) => ctx.getText()),
35
- generateArrayDimensions: vi.fn((dims) =>
36
- dims
37
- .map((d: { expression: () => { getText: () => string } | null }) => {
38
- const expr = d.expression();
39
- return expr ? `[${expr.getText()}]` : "[]";
40
- })
41
- .join(""),
42
- ),
43
- getStringConcatOperands: vi.fn(() => null),
44
- getSubstringOperands: vi.fn(() => null),
45
- getStringLiteralLength: vi.fn((literal) => literal.length - 2), // Remove quotes
46
- getStringExprCapacity: vi.fn(() => null),
47
- requireStringInclude: vi.fn(),
48
- });
34
+ CodeGenState.reset();
35
+ CodeGenState.inFunctionBody = true;
36
+ CodeGenState.indentLevel = 1;
37
+ vi.clearAllMocks();
49
38
  });
50
39
 
51
40
  describe("generateStringDecl", () => {
@@ -54,13 +43,14 @@ describe("StringDeclHelper", () => {
54
43
  stringType: () => null,
55
44
  } as never;
56
45
 
57
- const result = helper.generateStringDecl(
46
+ const result = StringDeclHelper.generateStringDecl(
58
47
  typeCtx,
59
48
  "myVar",
60
49
  null,
61
50
  [],
62
51
  { extern: "", const: "", atomic: "", volatile: "" },
63
52
  false,
53
+ defaultCallbacks,
64
54
  );
65
55
 
66
56
  expect(result.handled).toBe(false);
@@ -77,13 +67,14 @@ describe("StringDeclHelper", () => {
77
67
  getText: () => '"Hello"',
78
68
  } as never;
79
69
 
80
- const result = helper.generateStringDecl(
70
+ const result = StringDeclHelper.generateStringDecl(
81
71
  typeCtx,
82
72
  "greeting",
83
73
  expression,
84
74
  [],
85
75
  { extern: "", const: "", atomic: "", volatile: "" },
86
76
  false,
77
+ defaultCallbacks,
87
78
  );
88
79
 
89
80
  expect(result.handled).toBe(true);
@@ -98,13 +89,14 @@ describe("StringDeclHelper", () => {
98
89
  }),
99
90
  } as never;
100
91
 
101
- const result = helper.generateStringDecl(
92
+ const result = StringDeclHelper.generateStringDecl(
102
93
  typeCtx,
103
94
  "buffer",
104
95
  null,
105
96
  [],
106
97
  { extern: "", const: "", atomic: "", volatile: "" },
107
98
  false,
99
+ defaultCallbacks,
108
100
  );
109
101
 
110
102
  expect(result.handled).toBe(true);
@@ -122,13 +114,14 @@ describe("StringDeclHelper", () => {
122
114
  getText: () => '"Test"',
123
115
  } as never;
124
116
 
125
- const result = helper.generateStringDecl(
117
+ const result = StringDeclHelper.generateStringDecl(
126
118
  typeCtx,
127
119
  "label",
128
120
  expression,
129
121
  [],
130
122
  { extern: "", const: "const ", atomic: "", volatile: "" },
131
123
  true,
124
+ defaultCallbacks,
132
125
  );
133
126
 
134
127
  expect(result.handled).toBe(true);
@@ -147,13 +140,14 @@ describe("StringDeclHelper", () => {
147
140
  } as never;
148
141
 
149
142
  expect(() =>
150
- helper.generateStringDecl(
143
+ StringDeclHelper.generateStringDecl(
151
144
  typeCtx,
152
145
  "small",
153
146
  expression,
154
147
  [],
155
148
  { extern: "", const: "", atomic: "", volatile: "" },
156
149
  false,
150
+ defaultCallbacks,
157
151
  ),
158
152
  ).toThrow("exceeds string<5> capacity");
159
153
  });
@@ -166,13 +160,14 @@ describe("StringDeclHelper", () => {
166
160
  } as never;
167
161
 
168
162
  expect(() =>
169
- helper.generateStringDecl(
163
+ StringDeclHelper.generateStringDecl(
170
164
  typeCtx,
171
165
  "invalid",
172
166
  null,
173
167
  [],
174
168
  { extern: "", const: "", atomic: "", volatile: "" },
175
169
  false,
170
+ defaultCallbacks,
176
171
  ),
177
172
  ).toThrow("Non-const string requires explicit capacity");
178
173
  });
@@ -185,13 +180,14 @@ describe("StringDeclHelper", () => {
185
180
  } as never;
186
181
 
187
182
  expect(() =>
188
- helper.generateStringDecl(
183
+ StringDeclHelper.generateStringDecl(
189
184
  typeCtx,
190
185
  "invalid",
191
186
  null,
192
187
  [],
193
188
  { extern: "", const: "const ", atomic: "", volatile: "" },
194
189
  true,
190
+ defaultCallbacks,
195
191
  ),
196
192
  ).toThrow("const string requires initializer");
197
193
  });
@@ -208,33 +204,24 @@ describe("StringDeclHelper", () => {
208
204
  } as never;
209
205
 
210
206
  expect(() =>
211
- helper.generateStringDecl(
207
+ StringDeclHelper.generateStringDecl(
212
208
  typeCtx,
213
209
  "invalid",
214
210
  expression,
215
211
  [],
216
212
  { extern: "", const: "const ", atomic: "", volatile: "" },
217
213
  true,
214
+ defaultCallbacks,
218
215
  ),
219
216
  ).toThrow("const string requires string literal");
220
217
  });
221
218
 
222
219
  it("generates unsized const string with literal initializer", () => {
223
220
  const requireStringInclude = vi.fn();
224
- const helperWithMock = new StringDeclHelper({
225
- typeRegistry,
226
- getInFunctionBody: () => true,
227
- getIndentLevel: () => 1,
228
- arrayInitState,
229
- localArrays,
230
- generateExpression: vi.fn((ctx) => ctx.getText()),
231
- generateArrayDimensions: vi.fn(),
232
- getStringConcatOperands: vi.fn(() => null),
233
- getSubstringOperands: vi.fn(() => null),
234
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
235
- getStringExprCapacity: vi.fn(() => null),
221
+ const callbacks = {
222
+ ...defaultCallbacks,
236
223
  requireStringInclude,
237
- });
224
+ };
238
225
 
239
226
  const typeCtx = {
240
227
  stringType: () => ({
@@ -246,19 +233,20 @@ describe("StringDeclHelper", () => {
246
233
  getText: () => '"Hello"',
247
234
  } as never;
248
235
 
249
- const result = helperWithMock.generateStringDecl(
236
+ const result = StringDeclHelper.generateStringDecl(
250
237
  typeCtx,
251
238
  "greeting",
252
239
  expression,
253
240
  [],
254
241
  { extern: "", const: "const ", atomic: "", volatile: "" },
255
242
  true,
243
+ callbacks,
256
244
  );
257
245
 
258
246
  expect(result.handled).toBe(true);
259
247
  expect(result.code).toBe('const char greeting[6] = "Hello";');
260
248
  expect(requireStringInclude).toHaveBeenCalled();
261
- expect(typeRegistry.get("greeting")).toMatchObject({
249
+ expect(CodeGenState.typeRegistry.get("greeting")).toMatchObject({
262
250
  baseType: "char",
263
251
  isString: true,
264
252
  stringCapacity: 5,
@@ -276,13 +264,14 @@ describe("StringDeclHelper", () => {
276
264
  getText: () => '"External"',
277
265
  } as never;
278
266
 
279
- const result = helper.generateStringDecl(
267
+ const result = StringDeclHelper.generateStringDecl(
280
268
  typeCtx,
281
269
  "extStr",
282
270
  expression,
283
271
  [],
284
272
  { extern: "extern ", const: "", atomic: "", volatile: "" },
285
273
  false,
274
+ defaultCallbacks,
286
275
  );
287
276
 
288
277
  expect(result.handled).toBe(true);
@@ -292,21 +281,10 @@ describe("StringDeclHelper", () => {
292
281
 
293
282
  describe("string variable assignment validation", () => {
294
283
  it("throws error when source string capacity exceeds destination", () => {
295
- const getStringExprCapacity = vi.fn(() => 100);
296
- const helperWithCapacity = new StringDeclHelper({
297
- typeRegistry,
298
- getInFunctionBody: () => true,
299
- getIndentLevel: () => 1,
300
- arrayInitState,
301
- localArrays,
302
- generateExpression: vi.fn((ctx) => ctx.getText()),
303
- generateArrayDimensions: vi.fn(),
304
- getStringConcatOperands: vi.fn(() => null),
305
- getSubstringOperands: vi.fn(() => null),
306
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
307
- getStringExprCapacity,
308
- requireStringInclude: vi.fn(),
309
- });
284
+ const callbacks = {
285
+ ...defaultCallbacks,
286
+ getStringExprCapacity: vi.fn(() => 100),
287
+ };
310
288
 
311
289
  const typeCtx = {
312
290
  stringType: () => ({
@@ -319,33 +297,23 @@ describe("StringDeclHelper", () => {
319
297
  } as never;
320
298
 
321
299
  expect(() =>
322
- helperWithCapacity.generateStringDecl(
300
+ StringDeclHelper.generateStringDecl(
323
301
  typeCtx,
324
302
  "small",
325
303
  expression,
326
304
  [],
327
305
  { extern: "", const: "", atomic: "", volatile: "" },
328
306
  false,
307
+ callbacks,
329
308
  ),
330
309
  ).toThrow("Cannot assign string<100> to string<32>");
331
310
  });
332
311
 
333
312
  it("allows assignment when source capacity fits", () => {
334
- const getStringExprCapacity = vi.fn(() => 20);
335
- const helperWithCapacity = new StringDeclHelper({
336
- typeRegistry,
337
- getInFunctionBody: () => true,
338
- getIndentLevel: () => 1,
339
- arrayInitState,
340
- localArrays,
341
- generateExpression: vi.fn((ctx) => ctx.getText()),
342
- generateArrayDimensions: vi.fn(),
343
- getStringConcatOperands: vi.fn(() => null),
344
- getSubstringOperands: vi.fn(() => null),
345
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
346
- getStringExprCapacity,
347
- requireStringInclude: vi.fn(),
348
- });
313
+ const callbacks = {
314
+ ...defaultCallbacks,
315
+ getStringExprCapacity: vi.fn(() => 20),
316
+ };
349
317
 
350
318
  const typeCtx = {
351
319
  stringType: () => ({
@@ -357,13 +325,14 @@ describe("StringDeclHelper", () => {
357
325
  getText: () => "smallString",
358
326
  } as never;
359
327
 
360
- const result = helperWithCapacity.generateStringDecl(
328
+ const result = StringDeclHelper.generateStringDecl(
361
329
  typeCtx,
362
330
  "dest",
363
331
  expression,
364
332
  [],
365
333
  { extern: "", const: "", atomic: "", volatile: "" },
366
334
  false,
335
+ callbacks,
367
336
  );
368
337
 
369
338
  expect(result.handled).toBe(true);
@@ -379,22 +348,10 @@ describe("StringDeclHelper", () => {
379
348
  leftCapacity: 10,
380
349
  rightCapacity: 10,
381
350
  };
382
- const getStringConcatOperands = vi.fn(() => concatOps);
383
-
384
- const helperWithConcat = new StringDeclHelper({
385
- typeRegistry,
386
- getInFunctionBody: () => true,
387
- getIndentLevel: () => 1,
388
- arrayInitState,
389
- localArrays,
390
- generateExpression: vi.fn((ctx) => ctx.getText()),
391
- generateArrayDimensions: vi.fn(),
392
- getStringConcatOperands,
393
- getSubstringOperands: vi.fn(() => null),
394
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
395
- getStringExprCapacity: vi.fn(() => null),
396
- requireStringInclude: vi.fn(),
397
- });
351
+ const callbacks = {
352
+ ...defaultCallbacks,
353
+ getStringConcatOperands: vi.fn(() => concatOps),
354
+ };
398
355
 
399
356
  const typeCtx = {
400
357
  stringType: () => ({
@@ -406,13 +363,14 @@ describe("StringDeclHelper", () => {
406
363
  getText: () => "str1 + str2",
407
364
  } as never;
408
365
 
409
- const result = helperWithConcat.generateStringDecl(
366
+ const result = StringDeclHelper.generateStringDecl(
410
367
  typeCtx,
411
368
  "combined",
412
369
  expression,
413
370
  [],
414
371
  { extern: "", const: "", atomic: "", volatile: "" },
415
372
  false,
373
+ callbacks,
416
374
  );
417
375
 
418
376
  expect(result.handled).toBe(true);
@@ -425,27 +383,17 @@ describe("StringDeclHelper", () => {
425
383
  });
426
384
 
427
385
  it("throws error for concatenation at global scope", () => {
386
+ CodeGenState.inFunctionBody = false;
428
387
  const concatOps = {
429
388
  left: "str1",
430
389
  right: "str2",
431
390
  leftCapacity: 10,
432
391
  rightCapacity: 10,
433
392
  };
434
-
435
- const helperGlobalScope = new StringDeclHelper({
436
- typeRegistry,
437
- getInFunctionBody: () => false, // Global scope
438
- getIndentLevel: () => 0,
439
- arrayInitState,
440
- localArrays,
441
- generateExpression: vi.fn((ctx) => ctx.getText()),
442
- generateArrayDimensions: vi.fn(),
393
+ const callbacks = {
394
+ ...defaultCallbacks,
443
395
  getStringConcatOperands: vi.fn(() => concatOps),
444
- getSubstringOperands: vi.fn(() => null),
445
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
446
- getStringExprCapacity: vi.fn(() => null),
447
- requireStringInclude: vi.fn(),
448
- });
396
+ };
449
397
 
450
398
  const typeCtx = {
451
399
  stringType: () => ({
@@ -458,13 +406,14 @@ describe("StringDeclHelper", () => {
458
406
  } as never;
459
407
 
460
408
  expect(() =>
461
- helperGlobalScope.generateStringDecl(
409
+ StringDeclHelper.generateStringDecl(
462
410
  typeCtx,
463
411
  "combined",
464
412
  expression,
465
413
  [],
466
414
  { extern: "", const: "", atomic: "", volatile: "" },
467
415
  false,
416
+ callbacks,
468
417
  ),
469
418
  ).toThrow("String concatenation cannot be used at global scope");
470
419
  });
@@ -476,21 +425,10 @@ describe("StringDeclHelper", () => {
476
425
  leftCapacity: 20,
477
426
  rightCapacity: 20,
478
427
  };
479
-
480
- const helperWithConcat = new StringDeclHelper({
481
- typeRegistry,
482
- getInFunctionBody: () => true,
483
- getIndentLevel: () => 1,
484
- arrayInitState,
485
- localArrays,
486
- generateExpression: vi.fn((ctx) => ctx.getText()),
487
- generateArrayDimensions: vi.fn(),
428
+ const callbacks = {
429
+ ...defaultCallbacks,
488
430
  getStringConcatOperands: vi.fn(() => concatOps),
489
- getSubstringOperands: vi.fn(() => null),
490
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
491
- getStringExprCapacity: vi.fn(() => null),
492
- requireStringInclude: vi.fn(),
493
- });
431
+ };
494
432
 
495
433
  const typeCtx = {
496
434
  stringType: () => ({
@@ -503,13 +441,14 @@ describe("StringDeclHelper", () => {
503
441
  } as never;
504
442
 
505
443
  expect(() =>
506
- helperWithConcat.generateStringDecl(
444
+ StringDeclHelper.generateStringDecl(
507
445
  typeCtx,
508
446
  "combined",
509
447
  expression,
510
448
  [],
511
449
  { extern: "", const: "", atomic: "", volatile: "" },
512
450
  false,
451
+ callbacks,
513
452
  ),
514
453
  ).toThrow("String concatenation requires capacity 40, but string<30>");
515
454
  });
@@ -521,21 +460,10 @@ describe("StringDeclHelper", () => {
521
460
  leftCapacity: 5,
522
461
  rightCapacity: 5,
523
462
  };
524
-
525
- const helperWithConcat = new StringDeclHelper({
526
- typeRegistry,
527
- getInFunctionBody: () => true,
528
- getIndentLevel: () => 1,
529
- arrayInitState,
530
- localArrays,
531
- generateExpression: vi.fn((ctx) => ctx.getText()),
532
- generateArrayDimensions: vi.fn(),
463
+ const callbacks = {
464
+ ...defaultCallbacks,
533
465
  getStringConcatOperands: vi.fn(() => concatOps),
534
- getSubstringOperands: vi.fn(() => null),
535
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
536
- getStringExprCapacity: vi.fn(() => null),
537
- requireStringInclude: vi.fn(),
538
- });
466
+ };
539
467
 
540
468
  const typeCtx = {
541
469
  stringType: () => ({
@@ -547,13 +475,14 @@ describe("StringDeclHelper", () => {
547
475
  getText: () => "str1 + str2",
548
476
  } as never;
549
477
 
550
- const result = helperWithConcat.generateStringDecl(
478
+ const result = StringDeclHelper.generateStringDecl(
551
479
  typeCtx,
552
480
  "combined",
553
481
  expression,
554
482
  [],
555
483
  { extern: "", const: "const ", atomic: "", volatile: "" },
556
484
  true,
485
+ callbacks,
557
486
  );
558
487
 
559
488
  expect(result.code).toContain('const char combined[21] = "";');
@@ -568,21 +497,10 @@ describe("StringDeclHelper", () => {
568
497
  length: "5",
569
498
  sourceCapacity: 32,
570
499
  };
571
-
572
- const helperWithSubstr = new StringDeclHelper({
573
- typeRegistry,
574
- getInFunctionBody: () => true,
575
- getIndentLevel: () => 1,
576
- arrayInitState,
577
- localArrays,
578
- generateExpression: vi.fn((ctx) => ctx.getText()),
579
- generateArrayDimensions: vi.fn(),
580
- getStringConcatOperands: vi.fn(() => null),
500
+ const callbacks = {
501
+ ...defaultCallbacks,
581
502
  getSubstringOperands: vi.fn(() => substringOps),
582
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
583
- getStringExprCapacity: vi.fn(() => null),
584
- requireStringInclude: vi.fn(),
585
- });
503
+ };
586
504
 
587
505
  const typeCtx = {
588
506
  stringType: () => ({
@@ -594,13 +512,14 @@ describe("StringDeclHelper", () => {
594
512
  getText: () => "srcStr.substring(0, 5)",
595
513
  } as never;
596
514
 
597
- const result = helperWithSubstr.generateStringDecl(
515
+ const result = StringDeclHelper.generateStringDecl(
598
516
  typeCtx,
599
517
  "sub",
600
518
  expression,
601
519
  [],
602
520
  { extern: "", const: "", atomic: "", volatile: "" },
603
521
  false,
522
+ callbacks,
604
523
  );
605
524
 
606
525
  expect(result.handled).toBe(true);
@@ -610,27 +529,17 @@ describe("StringDeclHelper", () => {
610
529
  });
611
530
 
612
531
  it("throws error for substring at global scope", () => {
532
+ CodeGenState.inFunctionBody = false;
613
533
  const substringOps = {
614
534
  source: "srcStr",
615
535
  start: "0",
616
536
  length: "5",
617
537
  sourceCapacity: 32,
618
538
  };
619
-
620
- const helperGlobalScope = new StringDeclHelper({
621
- typeRegistry,
622
- getInFunctionBody: () => false,
623
- getIndentLevel: () => 0,
624
- arrayInitState,
625
- localArrays,
626
- generateExpression: vi.fn((ctx) => ctx.getText()),
627
- generateArrayDimensions: vi.fn(),
628
- getStringConcatOperands: vi.fn(() => null),
539
+ const callbacks = {
540
+ ...defaultCallbacks,
629
541
  getSubstringOperands: vi.fn(() => substringOps),
630
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
631
- getStringExprCapacity: vi.fn(() => null),
632
- requireStringInclude: vi.fn(),
633
- });
542
+ };
634
543
 
635
544
  const typeCtx = {
636
545
  stringType: () => ({
@@ -643,13 +552,14 @@ describe("StringDeclHelper", () => {
643
552
  } as never;
644
553
 
645
554
  expect(() =>
646
- helperGlobalScope.generateStringDecl(
555
+ StringDeclHelper.generateStringDecl(
647
556
  typeCtx,
648
557
  "sub",
649
558
  expression,
650
559
  [],
651
560
  { extern: "", const: "", atomic: "", volatile: "" },
652
561
  false,
562
+ callbacks,
653
563
  ),
654
564
  ).toThrow("Substring extraction cannot be used at global scope");
655
565
  });
@@ -661,21 +571,10 @@ describe("StringDeclHelper", () => {
661
571
  length: "10",
662
572
  sourceCapacity: 32, // start + length = 40 > 32
663
573
  };
664
-
665
- const helperWithSubstr = new StringDeclHelper({
666
- typeRegistry,
667
- getInFunctionBody: () => true,
668
- getIndentLevel: () => 1,
669
- arrayInitState,
670
- localArrays,
671
- generateExpression: vi.fn((ctx) => ctx.getText()),
672
- generateArrayDimensions: vi.fn(),
673
- getStringConcatOperands: vi.fn(() => null),
574
+ const callbacks = {
575
+ ...defaultCallbacks,
674
576
  getSubstringOperands: vi.fn(() => substringOps),
675
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
676
- getStringExprCapacity: vi.fn(() => null),
677
- requireStringInclude: vi.fn(),
678
- });
577
+ };
679
578
 
680
579
  const typeCtx = {
681
580
  stringType: () => ({
@@ -688,13 +587,14 @@ describe("StringDeclHelper", () => {
688
587
  } as never;
689
588
 
690
589
  expect(() =>
691
- helperWithSubstr.generateStringDecl(
590
+ StringDeclHelper.generateStringDecl(
692
591
  typeCtx,
693
592
  "sub",
694
593
  expression,
695
594
  [],
696
595
  { extern: "", const: "", atomic: "", volatile: "" },
697
596
  false,
597
+ callbacks,
698
598
  ),
699
599
  ).toThrow("Substring bounds [30, 10] exceed source string<32>");
700
600
  });
@@ -706,21 +606,10 @@ describe("StringDeclHelper", () => {
706
606
  length: "20",
707
607
  sourceCapacity: 32,
708
608
  };
709
-
710
- const helperWithSubstr = new StringDeclHelper({
711
- typeRegistry,
712
- getInFunctionBody: () => true,
713
- getIndentLevel: () => 1,
714
- arrayInitState,
715
- localArrays,
716
- generateExpression: vi.fn((ctx) => ctx.getText()),
717
- generateArrayDimensions: vi.fn(),
718
- getStringConcatOperands: vi.fn(() => null),
609
+ const callbacks = {
610
+ ...defaultCallbacks,
719
611
  getSubstringOperands: vi.fn(() => substringOps),
720
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
721
- getStringExprCapacity: vi.fn(() => null),
722
- requireStringInclude: vi.fn(),
723
- });
612
+ };
724
613
 
725
614
  const typeCtx = {
726
615
  stringType: () => ({
@@ -733,13 +622,14 @@ describe("StringDeclHelper", () => {
733
622
  } as never;
734
623
 
735
624
  expect(() =>
736
- helperWithSubstr.generateStringDecl(
625
+ StringDeclHelper.generateStringDecl(
737
626
  typeCtx,
738
627
  "sub",
739
628
  expression,
740
629
  [],
741
630
  { extern: "", const: "", atomic: "", volatile: "" },
742
631
  false,
632
+ callbacks,
743
633
  ),
744
634
  ).toThrow("Substring length 20 exceeds destination string<10>");
745
635
  });
@@ -751,21 +641,10 @@ describe("StringDeclHelper", () => {
751
641
  length: "5",
752
642
  sourceCapacity: 32,
753
643
  };
754
-
755
- const helperWithSubstr = new StringDeclHelper({
756
- typeRegistry,
757
- getInFunctionBody: () => true,
758
- getIndentLevel: () => 1,
759
- arrayInitState,
760
- localArrays,
761
- generateExpression: vi.fn((ctx) => ctx.getText()),
762
- generateArrayDimensions: vi.fn(),
763
- getStringConcatOperands: vi.fn(() => null),
644
+ const callbacks = {
645
+ ...defaultCallbacks,
764
646
  getSubstringOperands: vi.fn(() => substringOps),
765
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
766
- getStringExprCapacity: vi.fn(() => null),
767
- requireStringInclude: vi.fn(),
768
- });
647
+ };
769
648
 
770
649
  const typeCtx = {
771
650
  stringType: () => ({
@@ -777,16 +656,16 @@ describe("StringDeclHelper", () => {
777
656
  getText: () => "srcStr.substring(startVar, 5)",
778
657
  } as never;
779
658
 
780
- const result = helperWithSubstr.generateStringDecl(
659
+ const result = StringDeclHelper.generateStringDecl(
781
660
  typeCtx,
782
661
  "sub",
783
662
  expression,
784
663
  [],
785
664
  { extern: "", const: "", atomic: "", volatile: "" },
786
665
  false,
666
+ callbacks,
787
667
  );
788
668
 
789
- // Should succeed - no bounds check when start is not numeric
790
669
  expect(result.handled).toBe(true);
791
670
  expect(result.code).toContain("strncpy(sub, srcStr + startVar, 5)");
792
671
  });
@@ -798,21 +677,10 @@ describe("StringDeclHelper", () => {
798
677
  length: "lenVar", // Non-numeric
799
678
  sourceCapacity: 32,
800
679
  };
801
-
802
- const helperWithSubstr = new StringDeclHelper({
803
- typeRegistry,
804
- getInFunctionBody: () => true,
805
- getIndentLevel: () => 1,
806
- arrayInitState,
807
- localArrays,
808
- generateExpression: vi.fn((ctx) => ctx.getText()),
809
- generateArrayDimensions: vi.fn(),
810
- getStringConcatOperands: vi.fn(() => null),
680
+ const callbacks = {
681
+ ...defaultCallbacks,
811
682
  getSubstringOperands: vi.fn(() => substringOps),
812
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
813
- getStringExprCapacity: vi.fn(() => null),
814
- requireStringInclude: vi.fn(),
815
- });
683
+ };
816
684
 
817
685
  const typeCtx = {
818
686
  stringType: () => ({
@@ -824,13 +692,14 @@ describe("StringDeclHelper", () => {
824
692
  getText: () => "srcStr.substring(0, lenVar)",
825
693
  } as never;
826
694
 
827
- const result = helperWithSubstr.generateStringDecl(
695
+ const result = StringDeclHelper.generateStringDecl(
828
696
  typeCtx,
829
697
  "sub",
830
698
  expression,
831
699
  [],
832
700
  { extern: "", const: "", atomic: "", volatile: "" },
833
701
  false,
702
+ callbacks,
834
703
  );
835
704
 
836
705
  expect(result.handled).toBe(true);
@@ -844,21 +713,10 @@ describe("StringDeclHelper", () => {
844
713
  length: "3",
845
714
  sourceCapacity: 32,
846
715
  };
847
-
848
- const helperWithSubstr = new StringDeclHelper({
849
- typeRegistry,
850
- getInFunctionBody: () => true,
851
- getIndentLevel: () => 1,
852
- arrayInitState,
853
- localArrays,
854
- generateExpression: vi.fn((ctx) => ctx.getText()),
855
- generateArrayDimensions: vi.fn(),
856
- getStringConcatOperands: vi.fn(() => null),
716
+ const callbacks = {
717
+ ...defaultCallbacks,
857
718
  getSubstringOperands: vi.fn(() => substringOps),
858
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
859
- getStringExprCapacity: vi.fn(() => null),
860
- requireStringInclude: vi.fn(),
861
- });
719
+ };
862
720
 
863
721
  const typeCtx = {
864
722
  stringType: () => ({
@@ -870,13 +728,14 @@ describe("StringDeclHelper", () => {
870
728
  getText: () => "srcStr.substring(5, 3)",
871
729
  } as never;
872
730
 
873
- const result = helperWithSubstr.generateStringDecl(
731
+ const result = StringDeclHelper.generateStringDecl(
874
732
  typeCtx,
875
733
  "sub",
876
734
  expression,
877
735
  [],
878
736
  { extern: "", const: "const ", atomic: "", volatile: "" },
879
737
  true,
738
+ callbacks,
880
739
  );
881
740
 
882
741
  expect(result.code).toContain('const char sub[11] = "";');
@@ -885,31 +744,15 @@ describe("StringDeclHelper", () => {
885
744
 
886
745
  describe("string array declarations", () => {
887
746
  it("generates string array with explicit initializer list", () => {
888
- // The arrayInitState is shared and mutated by generateExpression
889
- const sharedArrayInitState = {
890
- lastArrayInitCount: 0,
891
- lastArrayFillValue: undefined as string | undefined,
892
- };
893
-
894
- const helperWithArray = new StringDeclHelper({
895
- typeRegistry,
896
- getInFunctionBody: () => true,
897
- getIndentLevel: () => 1,
898
- arrayInitState: sharedArrayInitState,
899
- localArrays,
900
- // generateExpression sets array init state as a side effect
747
+ const callbacks = {
748
+ ...defaultCallbacks,
901
749
  generateExpression: vi.fn(() => {
902
- sharedArrayInitState.lastArrayInitCount = 3;
903
- sharedArrayInitState.lastArrayFillValue = undefined;
750
+ CodeGenState.lastArrayInitCount = 3;
751
+ CodeGenState.lastArrayFillValue = undefined;
904
752
  return '{"Hello", "World", "Test"}';
905
753
  }),
906
754
  generateArrayDimensions: vi.fn(() => "[3]"),
907
- getStringConcatOperands: vi.fn(() => null),
908
- getSubstringOperands: vi.fn(() => null),
909
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
910
- getStringExprCapacity: vi.fn(() => null),
911
- requireStringInclude: vi.fn(),
912
- });
755
+ };
913
756
 
914
757
  const typeCtx = {
915
758
  stringType: () => ({
@@ -925,13 +768,14 @@ describe("StringDeclHelper", () => {
925
768
  { expression: () => ({ getText: () => "3" }) },
926
769
  ] as never[];
927
770
 
928
- const result = helperWithArray.generateStringDecl(
771
+ const result = StringDeclHelper.generateStringDecl(
929
772
  typeCtx,
930
773
  "labels",
931
774
  expression,
932
775
  arrayDims,
933
776
  { extern: "", const: "", atomic: "", volatile: "" },
934
777
  false,
778
+ callbacks,
935
779
  );
936
780
 
937
781
  expect(result.handled).toBe(true);
@@ -940,29 +784,15 @@ describe("StringDeclHelper", () => {
940
784
  });
941
785
 
942
786
  it("generates string array with size inference", () => {
943
- const sharedArrayInitState = {
944
- lastArrayInitCount: 0,
945
- lastArrayFillValue: undefined as string | undefined,
946
- };
947
-
948
- const helperWithArray = new StringDeclHelper({
949
- typeRegistry,
950
- getInFunctionBody: () => true,
951
- getIndentLevel: () => 1,
952
- arrayInitState: sharedArrayInitState,
953
- localArrays,
787
+ const callbacks = {
788
+ ...defaultCallbacks,
954
789
  generateExpression: vi.fn(() => {
955
- sharedArrayInitState.lastArrayInitCount = 2;
956
- sharedArrayInitState.lastArrayFillValue = undefined;
790
+ CodeGenState.lastArrayInitCount = 2;
791
+ CodeGenState.lastArrayFillValue = undefined;
957
792
  return '{"One", "Two"}';
958
793
  }),
959
794
  generateArrayDimensions: vi.fn(() => "[]"),
960
- getStringConcatOperands: vi.fn(() => null),
961
- getSubstringOperands: vi.fn(() => null),
962
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
963
- getStringExprCapacity: vi.fn(() => null),
964
- requireStringInclude: vi.fn(),
965
- });
795
+ };
966
796
 
967
797
  const typeCtx = {
968
798
  stringType: () => ({
@@ -978,19 +808,22 @@ describe("StringDeclHelper", () => {
978
808
  { expression: () => null }, // Empty dimension for inference
979
809
  ] as never[];
980
810
 
981
- const result = helperWithArray.generateStringDecl(
811
+ const result = StringDeclHelper.generateStringDecl(
982
812
  typeCtx,
983
813
  "labels",
984
814
  expression,
985
815
  arrayDims,
986
816
  { extern: "", const: "", atomic: "", volatile: "" },
987
817
  false,
818
+ callbacks,
988
819
  );
989
820
 
990
821
  expect(result.handled).toBe(true);
991
822
  expect(result.code).toContain("[2]"); // Inferred size
992
823
  expect(result.code).toContain("[11]"); // capacity + 1
993
- expect(typeRegistry.get("labels")?.arrayDimensions).toEqual([2, 11]);
824
+ expect(CodeGenState.typeRegistry.get("labels")?.arrayDimensions).toEqual([
825
+ 2, 11,
826
+ ]);
994
827
  });
995
828
 
996
829
  it("generates string array without initializer (zero-init)", () => {
@@ -1004,13 +837,14 @@ describe("StringDeclHelper", () => {
1004
837
  { expression: () => ({ getText: () => "5" }) },
1005
838
  ] as never[];
1006
839
 
1007
- const result = helper.generateStringDecl(
840
+ const result = StringDeclHelper.generateStringDecl(
1008
841
  typeCtx,
1009
842
  "messages",
1010
843
  null,
1011
844
  arrayDims,
1012
845
  { extern: "", const: "", atomic: "", volatile: "" },
1013
846
  false,
847
+ defaultCallbacks,
1014
848
  );
1015
849
 
1016
850
  expect(result.handled).toBe(true);
@@ -1018,29 +852,15 @@ describe("StringDeclHelper", () => {
1018
852
  });
1019
853
 
1020
854
  it("generates string array with fill-all syntax", () => {
1021
- const sharedArrayInitState = {
1022
- lastArrayInitCount: 0,
1023
- lastArrayFillValue: undefined as string | undefined,
1024
- };
1025
-
1026
- const helperWithFill = new StringDeclHelper({
1027
- typeRegistry,
1028
- getInFunctionBody: () => true,
1029
- getIndentLevel: () => 1,
1030
- arrayInitState: sharedArrayInitState,
1031
- localArrays,
855
+ const callbacks = {
856
+ ...defaultCallbacks,
1032
857
  generateExpression: vi.fn(() => {
1033
- sharedArrayInitState.lastArrayInitCount = 0;
1034
- sharedArrayInitState.lastArrayFillValue = '"Hello"';
858
+ CodeGenState.lastArrayInitCount = 0;
859
+ CodeGenState.lastArrayFillValue = '"Hello"';
1035
860
  return '{"Hello"*}';
1036
861
  }),
1037
862
  generateArrayDimensions: vi.fn(() => "[3]"),
1038
- getStringConcatOperands: vi.fn(() => null),
1039
- getSubstringOperands: vi.fn(() => null),
1040
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
1041
- getStringExprCapacity: vi.fn(() => null),
1042
- requireStringInclude: vi.fn(),
1043
- });
863
+ };
1044
864
 
1045
865
  const typeCtx = {
1046
866
  stringType: () => ({
@@ -1056,13 +876,14 @@ describe("StringDeclHelper", () => {
1056
876
  { expression: () => ({ getText: () => "3" }) },
1057
877
  ] as never[];
1058
878
 
1059
- const result = helperWithFill.generateStringDecl(
879
+ const result = StringDeclHelper.generateStringDecl(
1060
880
  typeCtx,
1061
881
  "greetings",
1062
882
  expression,
1063
883
  arrayDims,
1064
884
  { extern: "", const: "", atomic: "", volatile: "" },
1065
885
  false,
886
+ callbacks,
1066
887
  );
1067
888
 
1068
889
  expect(result.handled).toBe(true);
@@ -1070,29 +891,15 @@ describe("StringDeclHelper", () => {
1070
891
  });
1071
892
 
1072
893
  it("generates string array with empty fill value (no expansion)", () => {
1073
- const sharedArrayInitState = {
1074
- lastArrayInitCount: 0,
1075
- lastArrayFillValue: undefined as string | undefined,
1076
- };
1077
-
1078
- const helperWithFill = new StringDeclHelper({
1079
- typeRegistry,
1080
- getInFunctionBody: () => true,
1081
- getIndentLevel: () => 1,
1082
- arrayInitState: sharedArrayInitState,
1083
- localArrays,
894
+ const callbacks = {
895
+ ...defaultCallbacks,
1084
896
  generateExpression: vi.fn(() => {
1085
- sharedArrayInitState.lastArrayInitCount = 0;
1086
- sharedArrayInitState.lastArrayFillValue = '""';
897
+ CodeGenState.lastArrayInitCount = 0;
898
+ CodeGenState.lastArrayFillValue = '""';
1087
899
  return '{""*}';
1088
900
  }),
1089
901
  generateArrayDimensions: vi.fn(() => "[3]"),
1090
- getStringConcatOperands: vi.fn(() => null),
1091
- getSubstringOperands: vi.fn(() => null),
1092
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
1093
- getStringExprCapacity: vi.fn(() => null),
1094
- requireStringInclude: vi.fn(),
1095
- });
902
+ };
1096
903
 
1097
904
  const typeCtx = {
1098
905
  stringType: () => ({
@@ -1108,13 +915,14 @@ describe("StringDeclHelper", () => {
1108
915
  { expression: () => ({ getText: () => "3" }) },
1109
916
  ] as never[];
1110
917
 
1111
- const result = helperWithFill.generateStringDecl(
918
+ const result = StringDeclHelper.generateStringDecl(
1112
919
  typeCtx,
1113
920
  "empty",
1114
921
  expression,
1115
922
  arrayDims,
1116
923
  { extern: "", const: "", atomic: "", volatile: "" },
1117
924
  false,
925
+ callbacks,
1118
926
  );
1119
927
 
1120
928
  expect(result.handled).toBe(true);
@@ -1123,29 +931,15 @@ describe("StringDeclHelper", () => {
1123
931
  });
1124
932
 
1125
933
  it("throws error for fill-all without explicit size", () => {
1126
- const sharedArrayInitState = {
1127
- lastArrayInitCount: 0,
1128
- lastArrayFillValue: undefined as string | undefined,
1129
- };
1130
-
1131
- const helperWithFill = new StringDeclHelper({
1132
- typeRegistry,
1133
- getInFunctionBody: () => true,
1134
- getIndentLevel: () => 1,
1135
- arrayInitState: sharedArrayInitState,
1136
- localArrays,
934
+ const callbacks = {
935
+ ...defaultCallbacks,
1137
936
  generateExpression: vi.fn(() => {
1138
- sharedArrayInitState.lastArrayInitCount = 0;
1139
- sharedArrayInitState.lastArrayFillValue = '"Hello"';
937
+ CodeGenState.lastArrayInitCount = 0;
938
+ CodeGenState.lastArrayFillValue = '"Hello"';
1140
939
  return '{"Hello"*}';
1141
940
  }),
1142
941
  generateArrayDimensions: vi.fn(() => "[]"),
1143
- getStringConcatOperands: vi.fn(() => null),
1144
- getSubstringOperands: vi.fn(() => null),
1145
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
1146
- getStringExprCapacity: vi.fn(() => null),
1147
- requireStringInclude: vi.fn(),
1148
- });
942
+ };
1149
943
 
1150
944
  const typeCtx = {
1151
945
  stringType: () => ({
@@ -1162,41 +956,28 @@ describe("StringDeclHelper", () => {
1162
956
  ] as never[];
1163
957
 
1164
958
  expect(() =>
1165
- helperWithFill.generateStringDecl(
959
+ StringDeclHelper.generateStringDecl(
1166
960
  typeCtx,
1167
961
  "greetings",
1168
962
  expression,
1169
963
  arrayDims,
1170
964
  { extern: "", const: "", atomic: "", volatile: "" },
1171
965
  false,
966
+ callbacks,
1172
967
  ),
1173
968
  ).toThrow("Fill-all syntax");
1174
969
  });
1175
970
 
1176
971
  it("throws error for array size mismatch", () => {
1177
- const sharedArrayInitState = {
1178
- lastArrayInitCount: 0,
1179
- lastArrayFillValue: undefined as string | undefined,
1180
- };
1181
-
1182
- const helperWithArray = new StringDeclHelper({
1183
- typeRegistry,
1184
- getInFunctionBody: () => true,
1185
- getIndentLevel: () => 1,
1186
- arrayInitState: sharedArrayInitState,
1187
- localArrays,
972
+ const callbacks = {
973
+ ...defaultCallbacks,
1188
974
  generateExpression: vi.fn(() => {
1189
- sharedArrayInitState.lastArrayInitCount = 2; // Only 2 elements
1190
- sharedArrayInitState.lastArrayFillValue = undefined;
975
+ CodeGenState.lastArrayInitCount = 2; // Only 2 elements
976
+ CodeGenState.lastArrayFillValue = undefined;
1191
977
  return '{"One", "Two"}';
1192
978
  }),
1193
979
  generateArrayDimensions: vi.fn(() => "[3]"),
1194
- getStringConcatOperands: vi.fn(() => null),
1195
- getSubstringOperands: vi.fn(() => null),
1196
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
1197
- getStringExprCapacity: vi.fn(() => null),
1198
- requireStringInclude: vi.fn(),
1199
- });
980
+ };
1200
981
 
1201
982
  const typeCtx = {
1202
983
  stringType: () => ({
@@ -1213,22 +994,19 @@ describe("StringDeclHelper", () => {
1213
994
  ] as never[];
1214
995
 
1215
996
  expect(() =>
1216
- helperWithArray.generateStringDecl(
997
+ StringDeclHelper.generateStringDecl(
1217
998
  typeCtx,
1218
999
  "labels",
1219
1000
  expression,
1220
1001
  arrayDims,
1221
1002
  { extern: "", const: "", atomic: "", volatile: "" },
1222
1003
  false,
1004
+ callbacks,
1223
1005
  ),
1224
1006
  ).toThrow("Array size mismatch - declared [3] but got 2 elements");
1225
1007
  });
1226
1008
 
1227
1009
  it("throws error for string array initialization from variable", () => {
1228
- // Reset array init state to simulate non-array-initializer
1229
- arrayInitState.lastArrayInitCount = 0;
1230
- arrayInitState.lastArrayFillValue = undefined;
1231
-
1232
1010
  const typeCtx = {
1233
1011
  stringType: () => ({
1234
1012
  INTEGER_LITERAL: () => ({ getText: () => "10" }),
@@ -1244,41 +1022,28 @@ describe("StringDeclHelper", () => {
1244
1022
  ] as never[];
1245
1023
 
1246
1024
  expect(() =>
1247
- helper.generateStringDecl(
1025
+ StringDeclHelper.generateStringDecl(
1248
1026
  typeCtx,
1249
1027
  "labels",
1250
1028
  expression,
1251
1029
  arrayDims,
1252
1030
  { extern: "", const: "", atomic: "", volatile: "" },
1253
1031
  false,
1032
+ defaultCallbacks,
1254
1033
  ),
1255
1034
  ).toThrow("String array initialization from variables not supported");
1256
1035
  });
1257
1036
 
1258
1037
  it("generates string array with modifiers", () => {
1259
- const sharedArrayInitState = {
1260
- lastArrayInitCount: 0,
1261
- lastArrayFillValue: undefined as string | undefined,
1262
- };
1263
-
1264
- const helperWithArray = new StringDeclHelper({
1265
- typeRegistry,
1266
- getInFunctionBody: () => true,
1267
- getIndentLevel: () => 1,
1268
- arrayInitState: sharedArrayInitState,
1269
- localArrays,
1038
+ const callbacks = {
1039
+ ...defaultCallbacks,
1270
1040
  generateExpression: vi.fn(() => {
1271
- sharedArrayInitState.lastArrayInitCount = 2;
1272
- sharedArrayInitState.lastArrayFillValue = undefined;
1041
+ CodeGenState.lastArrayInitCount = 2;
1042
+ CodeGenState.lastArrayFillValue = undefined;
1273
1043
  return '{"A", "B"}';
1274
1044
  }),
1275
1045
  generateArrayDimensions: vi.fn(() => "[2]"),
1276
- getStringConcatOperands: vi.fn(() => null),
1277
- getSubstringOperands: vi.fn(() => null),
1278
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
1279
- getStringExprCapacity: vi.fn(() => null),
1280
- requireStringInclude: vi.fn(),
1281
- });
1046
+ };
1282
1047
 
1283
1048
  const typeCtx = {
1284
1049
  stringType: () => ({
@@ -1294,7 +1059,7 @@ describe("StringDeclHelper", () => {
1294
1059
  { expression: () => ({ getText: () => "2" }) },
1295
1060
  ] as never[];
1296
1061
 
1297
- const result = helperWithArray.generateStringDecl(
1062
+ const result = StringDeclHelper.generateStringDecl(
1298
1063
  typeCtx,
1299
1064
  "data",
1300
1065
  expression,
@@ -1306,35 +1071,22 @@ describe("StringDeclHelper", () => {
1306
1071
  volatile: "volatile ",
1307
1072
  },
1308
1073
  true,
1074
+ callbacks,
1309
1075
  );
1310
1076
 
1311
1077
  expect(result.code).toContain("extern const volatile char data");
1312
1078
  });
1313
1079
 
1314
1080
  it("handles non-numeric array dimension (macro)", () => {
1315
- const sharedArrayInitState = {
1316
- lastArrayInitCount: 0,
1317
- lastArrayFillValue: undefined as string | undefined,
1318
- };
1319
-
1320
- const helperWithArray = new StringDeclHelper({
1321
- typeRegistry,
1322
- getInFunctionBody: () => true,
1323
- getIndentLevel: () => 1,
1324
- arrayInitState: sharedArrayInitState,
1325
- localArrays,
1081
+ const callbacks = {
1082
+ ...defaultCallbacks,
1326
1083
  generateExpression: vi.fn(() => {
1327
- sharedArrayInitState.lastArrayInitCount = 2;
1328
- sharedArrayInitState.lastArrayFillValue = undefined;
1084
+ CodeGenState.lastArrayInitCount = 2;
1085
+ CodeGenState.lastArrayFillValue = undefined;
1329
1086
  return '{"A", "B"}';
1330
1087
  }),
1331
1088
  generateArrayDimensions: vi.fn(() => "[ARRAY_SIZE]"),
1332
- getStringConcatOperands: vi.fn(() => null),
1333
- getSubstringOperands: vi.fn(() => null),
1334
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
1335
- getStringExprCapacity: vi.fn(() => null),
1336
- requireStringInclude: vi.fn(),
1337
- });
1089
+ };
1338
1090
 
1339
1091
  const typeCtx = {
1340
1092
  stringType: () => ({
@@ -1351,44 +1103,29 @@ describe("StringDeclHelper", () => {
1351
1103
  ] as never[];
1352
1104
 
1353
1105
  // Should not throw - macros skip size validation
1354
- const result = helperWithArray.generateStringDecl(
1106
+ const result = StringDeclHelper.generateStringDecl(
1355
1107
  typeCtx,
1356
1108
  "data",
1357
1109
  expression,
1358
1110
  arrayDims,
1359
1111
  { extern: "", const: "", atomic: "", volatile: "" },
1360
1112
  false,
1113
+ callbacks,
1361
1114
  );
1362
1115
 
1363
1116
  expect(result.handled).toBe(true);
1364
1117
  });
1365
1118
 
1366
1119
  it("tracks local arrays in localArrays set", () => {
1367
- const sharedArrayInitState = {
1368
- lastArrayInitCount: 0,
1369
- lastArrayFillValue: undefined as string | undefined,
1370
- };
1371
-
1372
- const localArraysSet = new Set<string>();
1373
-
1374
- const helperWithTracking = new StringDeclHelper({
1375
- typeRegistry,
1376
- getInFunctionBody: () => true,
1377
- getIndentLevel: () => 1,
1378
- arrayInitState: sharedArrayInitState,
1379
- localArrays: localArraysSet,
1120
+ const callbacks = {
1121
+ ...defaultCallbacks,
1380
1122
  generateExpression: vi.fn(() => {
1381
- sharedArrayInitState.lastArrayInitCount = 2;
1382
- sharedArrayInitState.lastArrayFillValue = undefined;
1123
+ CodeGenState.lastArrayInitCount = 2;
1124
+ CodeGenState.lastArrayFillValue = undefined;
1383
1125
  return '{"X", "Y"}';
1384
1126
  }),
1385
1127
  generateArrayDimensions: vi.fn(() => "[2]"),
1386
- getStringConcatOperands: vi.fn(() => null),
1387
- getSubstringOperands: vi.fn(() => null),
1388
- getStringLiteralLength: vi.fn((literal) => literal.length - 2),
1389
- getStringExprCapacity: vi.fn(() => null),
1390
- requireStringInclude: vi.fn(),
1391
- });
1128
+ };
1392
1129
 
1393
1130
  const typeCtx = {
1394
1131
  stringType: () => ({
@@ -1404,16 +1141,17 @@ describe("StringDeclHelper", () => {
1404
1141
  { expression: () => ({ getText: () => "2" }) },
1405
1142
  ] as never[];
1406
1143
 
1407
- helperWithTracking.generateStringDecl(
1144
+ StringDeclHelper.generateStringDecl(
1408
1145
  typeCtx,
1409
1146
  "tracked",
1410
1147
  expression,
1411
1148
  arrayDims,
1412
1149
  { extern: "", const: "", atomic: "", volatile: "" },
1413
1150
  false,
1151
+ callbacks,
1414
1152
  );
1415
1153
 
1416
- expect(localArraysSet.has("tracked")).toBe(true);
1154
+ expect(CodeGenState.localArrays.has("tracked")).toBe(true);
1417
1155
  });
1418
1156
  });
1419
1157
  });