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
@@ -1,647 +0,0 @@
1
- /**
2
- * Unit tests for StandaloneContextBuilder
3
- * Issue #591: Tests for standalone context building logic
4
- *
5
- * Targets 100% coverage by testing all branches:
6
- * - processHeaders with/without debug mode
7
- * - processHeaders with/without header include directives
8
- * - processHeaders with/without errors
9
- * - processCNextIncludes with/without errors
10
- */
11
- import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
12
-
13
- import StandaloneContextBuilder from "../StandaloneContextBuilder";
14
- import IncludeResolver from "../../data/IncludeResolver";
15
- import IncludeTreeWalker from "../../data/IncludeTreeWalker";
16
- import IDiscoveredFile from "../../data/types/IDiscoveredFile";
17
- import EFileType from "../../data/types/EFileType";
18
-
19
- // Mock the dependencies
20
- vi.mock("../../data/IncludeResolver", () => ({
21
- default: {
22
- resolveHeadersTransitively: vi.fn(),
23
- },
24
- }));
25
-
26
- vi.mock("../../data/IncludeTreeWalker", () => ({
27
- default: {
28
- walk: vi.fn(),
29
- },
30
- }));
31
-
32
- /**
33
- * Creates a mock transpiler for testing
34
- */
35
- function createMockTranspiler(options?: {
36
- debugMode?: boolean;
37
- includeDirs?: string[];
38
- processedHeaders?: Set<string>;
39
- }) {
40
- return {
41
- collectHeaderSymbols: vi.fn(),
42
- collectCNextSymbols: vi.fn(),
43
- getIncludeDirs: vi.fn().mockReturnValue(options?.includeDirs ?? ["/inc"]),
44
- setHeaderIncludeDirective: vi.fn(),
45
- addWarning: vi.fn(),
46
- getProcessedHeaders: vi
47
- .fn()
48
- .mockReturnValue(options?.processedHeaders ?? new Set()),
49
- isDebugMode: vi.fn().mockReturnValue(options?.debugMode ?? false),
50
- };
51
- }
52
-
53
- /**
54
- * Creates a mock IDiscoveredFile
55
- */
56
- function createMockFile(
57
- path: string,
58
- type: EFileType = EFileType.CHeader,
59
- ): IDiscoveredFile {
60
- const extensions: Record<EFileType, string> = {
61
- [EFileType.CHeader]: ".h",
62
- [EFileType.CppHeader]: ".hpp",
63
- [EFileType.CNext]: ".cnx",
64
- [EFileType.CSource]: ".c",
65
- [EFileType.CppSource]: ".cpp",
66
- [EFileType.Unknown]: "",
67
- };
68
- return {
69
- path,
70
- type,
71
- extension: extensions[type],
72
- };
73
- }
74
-
75
- describe("StandaloneContextBuilder", () => {
76
- beforeEach(() => {
77
- vi.clearAllMocks();
78
- });
79
-
80
- afterEach(() => {
81
- vi.restoreAllMocks();
82
- });
83
-
84
- // ==========================================================================
85
- // build() - Main entry point
86
- // ==========================================================================
87
-
88
- describe("build()", () => {
89
- it("should call processHeaders and processCNextIncludes", () => {
90
- const transpiler = createMockTranspiler();
91
- const resolved = {
92
- headers: [createMockFile("/path/types.h")],
93
- cnextIncludes: [createMockFile("/path/shared.cnx", EFileType.CNext)],
94
- warnings: [],
95
- headerIncludeDirectives: new Map<string, string>(),
96
- };
97
-
98
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
99
- headers: resolved.headers,
100
- warnings: [],
101
- });
102
-
103
- // Capture the walk callback for later testing
104
- vi.mocked(IncludeTreeWalker.walk).mockImplementation(() => {});
105
-
106
- StandaloneContextBuilder.build(transpiler, resolved);
107
-
108
- // Verify resolveHeadersTransitively was called
109
- expect(IncludeResolver.resolveHeadersTransitively).toHaveBeenCalledWith(
110
- resolved.headers,
111
- ["/inc"],
112
- expect.objectContaining({
113
- processedPaths: transpiler.getProcessedHeaders(),
114
- }),
115
- );
116
-
117
- // Verify walk was called with cnextIncludes
118
- expect(IncludeTreeWalker.walk).toHaveBeenCalledWith(
119
- resolved.cnextIncludes,
120
- ["/inc"],
121
- expect.any(Function),
122
- );
123
- });
124
- });
125
-
126
- // ==========================================================================
127
- // processHeaders - Header processing logic
128
- // ==========================================================================
129
-
130
- describe("processHeaders()", () => {
131
- it("should process headers from resolveHeadersTransitively", () => {
132
- const transpiler = createMockTranspiler();
133
- const header = createMockFile("/path/types.h");
134
- const resolved = {
135
- headers: [header],
136
- cnextIncludes: [],
137
- warnings: [],
138
- headerIncludeDirectives: new Map<string, string>(),
139
- };
140
-
141
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
142
- headers: [header],
143
- warnings: [],
144
- });
145
-
146
- StandaloneContextBuilder.build(transpiler, resolved);
147
-
148
- expect(transpiler.collectHeaderSymbols).toHaveBeenCalledWith(header);
149
- });
150
-
151
- it("should set header include directive when present", () => {
152
- const transpiler = createMockTranspiler();
153
- const header = createMockFile("/path/types.h");
154
- const directive = '#include "types.h"';
155
- const resolved = {
156
- headers: [header],
157
- cnextIncludes: [],
158
- warnings: [],
159
- headerIncludeDirectives: new Map([[header.path, directive]]),
160
- };
161
-
162
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
163
- headers: [header],
164
- warnings: [],
165
- });
166
-
167
- StandaloneContextBuilder.build(transpiler, resolved);
168
-
169
- expect(transpiler.setHeaderIncludeDirective).toHaveBeenCalledWith(
170
- header.path,
171
- directive,
172
- );
173
- });
174
-
175
- it("should NOT set header include directive when not present", () => {
176
- const transpiler = createMockTranspiler();
177
- const header = createMockFile("/path/types.h");
178
- const resolved = {
179
- headers: [header],
180
- cnextIncludes: [],
181
- warnings: [],
182
- headerIncludeDirectives: new Map<string, string>(), // Empty map
183
- };
184
-
185
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
186
- headers: [header],
187
- warnings: [],
188
- });
189
-
190
- StandaloneContextBuilder.build(transpiler, resolved);
191
-
192
- expect(transpiler.setHeaderIncludeDirective).not.toHaveBeenCalled();
193
- });
194
-
195
- it("should add warnings from header resolution", () => {
196
- const transpiler = createMockTranspiler();
197
- const resolved = {
198
- headers: [],
199
- cnextIncludes: [],
200
- warnings: [],
201
- headerIncludeDirectives: new Map<string, string>(),
202
- };
203
-
204
- const headerWarnings = [
205
- 'Warning: #include "missing.h" not found',
206
- "Warning: Could not read header /bad/path.h",
207
- ];
208
-
209
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
210
- headers: [],
211
- warnings: headerWarnings,
212
- });
213
-
214
- StandaloneContextBuilder.build(transpiler, resolved);
215
-
216
- expect(transpiler.addWarning).toHaveBeenCalledTimes(2);
217
- expect(transpiler.addWarning).toHaveBeenCalledWith(headerWarnings[0]);
218
- expect(transpiler.addWarning).toHaveBeenCalledWith(headerWarnings[1]);
219
- });
220
-
221
- it("should catch and report errors from collectHeaderSymbols", () => {
222
- const transpiler = createMockTranspiler();
223
- const header = createMockFile("/path/bad.h");
224
- const resolved = {
225
- headers: [header],
226
- cnextIncludes: [],
227
- warnings: [],
228
- headerIncludeDirectives: new Map<string, string>(),
229
- };
230
-
231
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
232
- headers: [header],
233
- warnings: [],
234
- });
235
-
236
- const testError = new Error("Parse failed");
237
- transpiler.collectHeaderSymbols.mockImplementation(() => {
238
- throw testError;
239
- });
240
-
241
- // Should not throw
242
- expect(() =>
243
- StandaloneContextBuilder.build(transpiler, resolved),
244
- ).not.toThrow();
245
-
246
- // Should add warning with error message
247
- expect(transpiler.addWarning).toHaveBeenCalledWith(
248
- `Failed to process header ${header.path}: ${testError}`,
249
- );
250
- });
251
-
252
- it("should process multiple headers in order", () => {
253
- const transpiler = createMockTranspiler();
254
- const header1 = createMockFile("/path/base.h");
255
- const header2 = createMockFile("/path/derived.h");
256
- const resolved = {
257
- headers: [header1, header2],
258
- cnextIncludes: [],
259
- warnings: [],
260
- headerIncludeDirectives: new Map([
261
- [header1.path, '#include "base.h"'],
262
- [header2.path, '#include "derived.h"'],
263
- ]),
264
- };
265
-
266
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
267
- headers: [header1, header2],
268
- warnings: [],
269
- });
270
-
271
- const callOrder: string[] = [];
272
- transpiler.collectHeaderSymbols.mockImplementation(
273
- (h: IDiscoveredFile) => {
274
- callOrder.push(h.path);
275
- },
276
- );
277
-
278
- StandaloneContextBuilder.build(transpiler, resolved);
279
-
280
- expect(callOrder).toEqual([header1.path, header2.path]);
281
- });
282
-
283
- it("should pass debug callback when debug mode is enabled", () => {
284
- const transpiler = createMockTranspiler({ debugMode: true });
285
- const resolved = {
286
- headers: [],
287
- cnextIncludes: [],
288
- warnings: [],
289
- headerIncludeDirectives: new Map<string, string>(),
290
- };
291
-
292
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
293
- headers: [],
294
- warnings: [],
295
- });
296
-
297
- // Spy on console.log to verify debug callback works
298
- const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => {});
299
-
300
- StandaloneContextBuilder.build(transpiler, resolved);
301
-
302
- // Get the options passed to resolveHeadersTransitively
303
- const call = vi.mocked(IncludeResolver.resolveHeadersTransitively).mock
304
- .calls[0];
305
- const options = call[2];
306
-
307
- // onDebug should be defined when debug mode is on
308
- expect(options?.onDebug).toBeDefined();
309
-
310
- // Call the debug callback to verify it logs
311
- options?.onDebug?.("test message");
312
- expect(consoleSpy).toHaveBeenCalledWith("[DEBUG] test message");
313
-
314
- consoleSpy.mockRestore();
315
- });
316
-
317
- it("should NOT pass debug callback when debug mode is disabled", () => {
318
- const transpiler = createMockTranspiler({ debugMode: false });
319
- const resolved = {
320
- headers: [],
321
- cnextIncludes: [],
322
- warnings: [],
323
- headerIncludeDirectives: new Map<string, string>(),
324
- };
325
-
326
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
327
- headers: [],
328
- warnings: [],
329
- });
330
-
331
- StandaloneContextBuilder.build(transpiler, resolved);
332
-
333
- // Get the options passed to resolveHeadersTransitively
334
- const call = vi.mocked(IncludeResolver.resolveHeadersTransitively).mock
335
- .calls[0];
336
- const options = call[2];
337
-
338
- // onDebug should be undefined when debug mode is off
339
- expect(options?.onDebug).toBeUndefined();
340
- });
341
-
342
- it("should pass processedHeaders to resolveHeadersTransitively", () => {
343
- const processedHeaders = new Set(["/already/processed.h"]);
344
- const transpiler = createMockTranspiler({ processedHeaders });
345
- const resolved = {
346
- headers: [],
347
- cnextIncludes: [],
348
- warnings: [],
349
- headerIncludeDirectives: new Map<string, string>(),
350
- };
351
-
352
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
353
- headers: [],
354
- warnings: [],
355
- });
356
-
357
- StandaloneContextBuilder.build(transpiler, resolved);
358
-
359
- const call = vi.mocked(IncludeResolver.resolveHeadersTransitively).mock
360
- .calls[0];
361
- expect(call[2]?.processedPaths).toBe(processedHeaders);
362
- });
363
-
364
- it("should spread includeDirs into array for resolveHeadersTransitively", () => {
365
- const includeDirs = ["/dir1", "/dir2"];
366
- const transpiler = createMockTranspiler({ includeDirs });
367
- const resolved = {
368
- headers: [],
369
- cnextIncludes: [],
370
- warnings: [],
371
- headerIncludeDirectives: new Map<string, string>(),
372
- };
373
-
374
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
375
- headers: [],
376
- warnings: [],
377
- });
378
-
379
- StandaloneContextBuilder.build(transpiler, resolved);
380
-
381
- const call = vi.mocked(IncludeResolver.resolveHeadersTransitively).mock
382
- .calls[0];
383
- expect(call[1]).toEqual(["/dir1", "/dir2"]);
384
- });
385
- });
386
-
387
- // ==========================================================================
388
- // processCNextIncludes - C-Next include processing logic
389
- // ==========================================================================
390
-
391
- describe("processCNextIncludes()", () => {
392
- it("should call walk with cnextIncludes and includeDirs", () => {
393
- const transpiler = createMockTranspiler({ includeDirs: ["/inc"] });
394
- const cnxFile = createMockFile("/path/shared.cnx", EFileType.CNext);
395
- const resolved = {
396
- headers: [],
397
- cnextIncludes: [cnxFile],
398
- warnings: [],
399
- headerIncludeDirectives: new Map<string, string>(),
400
- };
401
-
402
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
403
- headers: [],
404
- warnings: [],
405
- });
406
-
407
- StandaloneContextBuilder.build(transpiler, resolved);
408
-
409
- expect(IncludeTreeWalker.walk).toHaveBeenCalledWith(
410
- [cnxFile],
411
- ["/inc"],
412
- expect.any(Function),
413
- );
414
- });
415
-
416
- it("should call collectCNextSymbols for each file in walk callback", () => {
417
- const transpiler = createMockTranspiler();
418
- const cnxFile = createMockFile("/path/shared.cnx", EFileType.CNext);
419
- const resolved = {
420
- headers: [],
421
- cnextIncludes: [cnxFile],
422
- warnings: [],
423
- headerIncludeDirectives: new Map<string, string>(),
424
- };
425
-
426
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
427
- headers: [],
428
- warnings: [],
429
- });
430
-
431
- // Capture and invoke the walk callback
432
- vi.mocked(IncludeTreeWalker.walk).mockImplementation(
433
- (includes, _dirs, callback) => {
434
- for (const include of includes) {
435
- callback(include as IDiscoveredFile);
436
- }
437
- },
438
- );
439
-
440
- StandaloneContextBuilder.build(transpiler, resolved);
441
-
442
- expect(transpiler.collectCNextSymbols).toHaveBeenCalledWith(cnxFile);
443
- });
444
-
445
- it("should catch errors and add warning in walk callback", () => {
446
- const transpiler = createMockTranspiler();
447
- const cnxFile = createMockFile("/path/broken.cnx", EFileType.CNext);
448
- const resolved = {
449
- headers: [],
450
- cnextIncludes: [cnxFile],
451
- warnings: [],
452
- headerIncludeDirectives: new Map<string, string>(),
453
- };
454
-
455
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
456
- headers: [],
457
- warnings: [],
458
- });
459
-
460
- const testError = new Error("Syntax error");
461
- transpiler.collectCNextSymbols.mockImplementation(() => {
462
- throw testError;
463
- });
464
-
465
- // Capture and invoke the walk callback
466
- vi.mocked(IncludeTreeWalker.walk).mockImplementation(
467
- (includes, _dirs, callback) => {
468
- for (const include of includes) {
469
- callback(include as IDiscoveredFile);
470
- }
471
- },
472
- );
473
-
474
- // Should not throw
475
- expect(() =>
476
- StandaloneContextBuilder.build(transpiler, resolved),
477
- ).not.toThrow();
478
-
479
- expect(transpiler.addWarning).toHaveBeenCalledWith(
480
- `Failed to process C-Next include ${cnxFile.path}: ${testError}`,
481
- );
482
- });
483
-
484
- it("should return false from walk callback on error to stop branch traversal", () => {
485
- const transpiler = createMockTranspiler();
486
- const cnxFile = createMockFile("/path/broken.cnx", EFileType.CNext);
487
- const resolved = {
488
- headers: [],
489
- cnextIncludes: [cnxFile],
490
- warnings: [],
491
- headerIncludeDirectives: new Map<string, string>(),
492
- };
493
-
494
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
495
- headers: [],
496
- warnings: [],
497
- });
498
-
499
- const testError = new Error("Syntax error");
500
- transpiler.collectCNextSymbols.mockImplementation(() => {
501
- throw testError;
502
- });
503
-
504
- let callbackResult: boolean | void = undefined;
505
- vi.mocked(IncludeTreeWalker.walk).mockImplementation(
506
- (includes, _dirs, callback) => {
507
- for (const include of includes) {
508
- callbackResult = callback(include as IDiscoveredFile);
509
- }
510
- },
511
- );
512
-
513
- StandaloneContextBuilder.build(transpiler, resolved);
514
-
515
- expect(callbackResult).toBe(false);
516
- });
517
-
518
- it("should process multiple C-Next includes", () => {
519
- const transpiler = createMockTranspiler();
520
- const cnxFile1 = createMockFile("/path/shared1.cnx", EFileType.CNext);
521
- const cnxFile2 = createMockFile("/path/shared2.cnx", EFileType.CNext);
522
- const resolved = {
523
- headers: [],
524
- cnextIncludes: [cnxFile1, cnxFile2],
525
- warnings: [],
526
- headerIncludeDirectives: new Map<string, string>(),
527
- };
528
-
529
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
530
- headers: [],
531
- warnings: [],
532
- });
533
-
534
- const processedFiles: string[] = [];
535
- vi.mocked(IncludeTreeWalker.walk).mockImplementation(
536
- (includes, _dirs, callback) => {
537
- for (const include of includes) {
538
- callback(include as IDiscoveredFile);
539
- processedFiles.push((include as IDiscoveredFile).path);
540
- }
541
- },
542
- );
543
-
544
- StandaloneContextBuilder.build(transpiler, resolved);
545
-
546
- expect(processedFiles).toEqual([cnxFile1.path, cnxFile2.path]);
547
- expect(transpiler.collectCNextSymbols).toHaveBeenCalledTimes(2);
548
- });
549
- });
550
-
551
- // ==========================================================================
552
- // Integration scenarios
553
- // ==========================================================================
554
-
555
- describe("integration scenarios", () => {
556
- it("should handle mixed headers and C-Next includes", () => {
557
- const transpiler = createMockTranspiler();
558
- const header = createMockFile("/path/types.h");
559
- const cnxFile = createMockFile("/path/shared.cnx", EFileType.CNext);
560
- const resolved = {
561
- headers: [header],
562
- cnextIncludes: [cnxFile],
563
- warnings: [],
564
- headerIncludeDirectives: new Map([[header.path, '#include "types.h"']]),
565
- };
566
-
567
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
568
- headers: [header],
569
- warnings: [],
570
- });
571
-
572
- vi.mocked(IncludeTreeWalker.walk).mockImplementation(
573
- (includes, _dirs, callback) => {
574
- for (const include of includes) {
575
- callback(include as IDiscoveredFile);
576
- }
577
- },
578
- );
579
-
580
- StandaloneContextBuilder.build(transpiler, resolved);
581
-
582
- expect(transpiler.collectHeaderSymbols).toHaveBeenCalledWith(header);
583
- expect(transpiler.setHeaderIncludeDirective).toHaveBeenCalledWith(
584
- header.path,
585
- '#include "types.h"',
586
- );
587
- expect(transpiler.collectCNextSymbols).toHaveBeenCalledWith(cnxFile);
588
- });
589
-
590
- it("should handle empty inputs", () => {
591
- const transpiler = createMockTranspiler();
592
- const resolved = {
593
- headers: [],
594
- cnextIncludes: [],
595
- warnings: [],
596
- headerIncludeDirectives: new Map<string, string>(),
597
- };
598
-
599
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
600
- headers: [],
601
- warnings: [],
602
- });
603
-
604
- // Should not throw
605
- expect(() =>
606
- StandaloneContextBuilder.build(transpiler, resolved),
607
- ).not.toThrow();
608
-
609
- expect(transpiler.collectHeaderSymbols).not.toHaveBeenCalled();
610
- expect(transpiler.collectCNextSymbols).not.toHaveBeenCalled();
611
- });
612
-
613
- it("should continue processing after header error", () => {
614
- const transpiler = createMockTranspiler();
615
- const header1 = createMockFile("/path/bad.h");
616
- const header2 = createMockFile("/path/good.h");
617
- const resolved = {
618
- headers: [header1, header2],
619
- cnextIncludes: [],
620
- warnings: [],
621
- headerIncludeDirectives: new Map<string, string>(),
622
- };
623
-
624
- vi.mocked(IncludeResolver.resolveHeadersTransitively).mockReturnValue({
625
- headers: [header1, header2],
626
- warnings: [],
627
- });
628
-
629
- let callCount = 0;
630
- transpiler.collectHeaderSymbols.mockImplementation(() => {
631
- callCount++;
632
- if (callCount === 1) {
633
- throw new Error("First header failed");
634
- }
635
- });
636
-
637
- StandaloneContextBuilder.build(transpiler, resolved);
638
-
639
- // Should have tried to process both headers
640
- expect(transpiler.collectHeaderSymbols).toHaveBeenCalledTimes(2);
641
- // Should have added warning for the first one
642
- expect(transpiler.addWarning).toHaveBeenCalledWith(
643
- expect.stringContaining("bad.h"),
644
- );
645
- });
646
- });
647
- });
@@ -1,23 +0,0 @@
1
- /**
2
- * Dependencies for TypeResolver - allows TypeResolver to be independent of CodeGenerator
3
- * Issue #61: Extracted dependencies for better separation of concerns
4
- */
5
- import ICodeGenSymbols from "../../../types/ICodeGenSymbols";
6
- import SymbolTable from "../../../logic/symbols/SymbolTable";
7
- import TTypeInfo from "./TTypeInfo";
8
-
9
- interface ITypeResolverDeps {
10
- /** Symbol information from C-Next source (ADR-055: ICodeGenSymbols) */
11
- symbols: ICodeGenSymbols | null;
12
-
13
- /** Symbol table for C header struct lookups */
14
- symbolTable: SymbolTable | null;
15
-
16
- /** Type registry for variable type information */
17
- typeRegistry: Map<string, TTypeInfo>;
18
-
19
- /** Callback to resolve identifiers to scoped names */
20
- resolveIdentifier: (name: string) => string;
21
- }
22
-
23
- export default ITypeResolverDeps;