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.
- package/README.md +86 -63
- package/grammar/CNext.g4 +3 -17
- package/package.json +1 -1
- package/src/cli/serve/ServeCommand.ts +57 -45
- package/src/lib/__tests__/parseCHeader.mocked.test.ts +145 -0
- package/src/transpiler/Transpiler.ts +603 -613
- package/src/transpiler/__tests__/DualCodePaths.test.ts +5 -1
- package/src/transpiler/__tests__/Transpiler.coverage.test.ts +2 -99
- package/src/transpiler/__tests__/Transpiler.test.ts +3 -26
- package/src/transpiler/data/IncludeTreeWalker.ts +1 -1
- package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +23 -52
- package/src/transpiler/logic/parser/grammar/CNext.interp +1 -3
- package/src/transpiler/logic/parser/grammar/CNextListener.ts +0 -22
- package/src/transpiler/logic/parser/grammar/CNextParser.ts +665 -1084
- package/src/transpiler/logic/parser/grammar/CNextVisitor.ts +0 -14
- package/src/transpiler/logic/symbols/CppSymbolCollector.ts +67 -43
- package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
- package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
- package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
- package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
- package/src/transpiler/output/codegen/CodeGenerator.ts +1410 -2587
- package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
- package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
- package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +2082 -52
- package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
- package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
- package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +227 -66
- package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +55 -58
- package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +288 -275
- package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +195 -133
- package/src/transpiler/output/codegen/assignment/AssignmentContextBuilder.ts +24 -74
- package/src/transpiler/output/codegen/assignment/AssignmentKind.ts +3 -0
- package/src/transpiler/output/codegen/assignment/IAssignmentContext.ts +3 -0
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +290 -320
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +42 -0
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +76 -2
- package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
- package/src/transpiler/output/codegen/generators/IOrchestrator.ts +5 -1
- package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
- package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/RegisterGenerator.ts +11 -24
- package/src/transpiler/output/codegen/generators/declarationGenerators/RegisterMacroGenerator.ts +64 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +137 -61
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopedRegisterGenerator.ts +18 -27
- package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +5 -1
- package/src/transpiler/output/codegen/generators/statements/ControlFlowGenerator.ts +1 -17
- package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
- package/src/transpiler/output/codegen/helpers/ArrayAccessHelper.ts +129 -0
- package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +40 -44
- package/src/transpiler/output/codegen/helpers/AssignmentTargetExtractor.ts +17 -45
- package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +83 -78
- package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
- package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
- package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
- package/src/transpiler/output/codegen/helpers/MemberSeparatorResolver.ts +10 -3
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
- package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +44 -0
- package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayAccessHelper.test.ts +479 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
- package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
- package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
- package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
- package/src/transpiler/output/codegen/helpers/__tests__/MemberSeparatorResolver.test.ts +1 -0
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
- package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +201 -0
- package/src/transpiler/output/codegen/helpers/__tests__/TypeGenerationHelper.test.ts +50 -0
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
- package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
- package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
- package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
- package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
- package/src/transpiler/output/codegen/types/IArrayAccessDeps.ts +23 -0
- package/src/transpiler/output/codegen/types/IArrayAccessInfo.ts +26 -0
- package/src/transpiler/output/codegen/types/IMemberSeparatorDeps.ts +7 -0
- package/src/transpiler/output/codegen/utils/CodegenParserUtils.ts +98 -0
- package/src/transpiler/output/codegen/utils/ExpressionUnwrapper.ts +22 -22
- package/src/transpiler/output/codegen/utils/__tests__/CodegenParserUtils.test.ts +228 -0
- package/src/transpiler/types/IFileResult.ts +0 -4
- package/src/transpiler/types/IPipelineFile.ts +27 -0
- package/src/transpiler/types/IPipelineInput.ts +23 -0
- package/src/transpiler/types/TranspilerState.ts +1 -1
- package/src/utils/FormatUtils.ts +28 -2
- package/src/utils/MapUtils.ts +25 -0
- package/src/utils/PostfixAnalysisUtils.ts +48 -0
- package/src/utils/__tests__/FormatUtils.test.ts +42 -0
- package/src/utils/__tests__/MapUtils.test.ts +85 -0
- package/src/utils/constants/OperatorMappings.ts +19 -0
- package/src/transpiler/logic/StandaloneContextBuilder.ts +0 -150
- package/src/transpiler/logic/__tests__/StandaloneContextBuilder.test.ts +0 -647
- package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
- package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
- package/src/transpiler/types/ITranspileContext.ts +0 -49
- 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;
|