c-next 0.2.11 → 0.2.13
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 +80 -649
- package/dist/index.js +8273 -6357
- package/dist/index.js.map +4 -4
- package/grammar/C.g4 +17 -4
- package/package.json +3 -3
- package/src/__tests__/index.test.ts +1 -1
- package/src/cli/CleanCommand.ts +8 -12
- package/src/cli/Cli.ts +29 -6
- package/src/cli/Runner.ts +42 -62
- package/src/cli/__tests__/CleanCommand.test.ts +10 -10
- package/src/cli/__tests__/Cli.test.ts +59 -7
- package/src/cli/__tests__/ConfigPrinter.test.ts +12 -12
- package/src/cli/__tests__/PathNormalizer.test.ts +5 -5
- package/src/cli/__tests__/Runner.test.ts +108 -82
- package/src/cli/serve/ServeCommand.ts +1 -1
- package/src/cli/types/ICliConfig.ts +2 -2
- package/src/lib/parseWithSymbols.ts +21 -21
- package/src/transpiler/Transpiler.ts +99 -46
- package/src/transpiler/__tests__/DualCodePaths.test.ts +29 -29
- package/src/transpiler/__tests__/Transpiler.coverage.test.ts +244 -72
- package/src/transpiler/__tests__/Transpiler.test.ts +32 -72
- package/src/transpiler/__tests__/determineProjectRoot.test.ts +30 -28
- package/src/transpiler/__tests__/needsConditionalPreprocessing.test.ts +1 -1
- package/src/transpiler/data/CNextMarkerDetector.ts +34 -0
- package/src/transpiler/data/CppEntryPointScanner.ts +174 -0
- package/src/transpiler/data/FileDiscovery.ts +2 -105
- package/src/transpiler/data/InputExpansion.ts +37 -81
- package/src/transpiler/data/__tests__/CNextMarkerDetector.test.ts +62 -0
- package/src/transpiler/data/__tests__/CppEntryPointScanner.test.ts +239 -0
- package/src/transpiler/data/__tests__/FileDiscovery.test.ts +45 -191
- package/src/transpiler/data/__tests__/InputExpansion.test.ts +36 -204
- package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +2 -2
- package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +4 -5
- package/src/transpiler/logic/parser/c/grammar/C.interp +33 -3
- package/src/transpiler/logic/parser/c/grammar/C.tokens +237 -207
- package/src/transpiler/logic/parser/c/grammar/CLexer.interp +48 -3
- package/src/transpiler/logic/parser/c/grammar/CLexer.tokens +237 -207
- package/src/transpiler/logic/parser/c/grammar/CLexer.ts +702 -611
- package/src/transpiler/logic/parser/c/grammar/CParser.ts +1221 -1107
- package/src/transpiler/logic/symbols/SymbolTable.ts +147 -73
- package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +157 -14
- package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +3 -3
- package/src/transpiler/logic/symbols/c/collectors/StructCollector.ts +7 -37
- package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolInfoAdapter.test.ts +6 -6
- package/src/transpiler/logic/symbols/cnext/adapters/TSymbolInfoAdapter.ts +28 -27
- package/src/transpiler/logic/symbols/cnext/index.ts +4 -4
- package/src/transpiler/logic/symbols/cnext/utils/SymbolNameUtils.ts +5 -5
- package/src/transpiler/output/codegen/CodeGenerator.ts +16 -1
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +15 -0
- package/src/transpiler/output/codegen/__tests__/ExpressionWalker.test.ts +3 -3
- package/src/transpiler/output/codegen/__tests__/RequireInclude.test.ts +14 -14
- package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +2 -2
- package/src/transpiler/output/codegen/helpers/FunctionContextManager.ts +15 -3
- package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +14 -6
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +1 -0
- package/src/transpiler/output/codegen/types/IFunctionContextCallbacks.ts +2 -0
- package/src/transpiler/output/codegen/utils/QualifiedNameGenerator.ts +7 -7
- package/src/transpiler/output/codegen/utils/__tests__/QualifiedNameGenerator.test.ts +3 -3
- package/src/transpiler/output/headers/BaseHeaderGenerator.ts +10 -1
- package/src/transpiler/output/headers/HeaderGenerator.ts +3 -0
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +6 -2
- package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +16 -0
- package/src/transpiler/output/headers/adapters/HeaderSymbolAdapter.ts +19 -19
- package/src/transpiler/output/headers/adapters/__tests__/HeaderSymbolAdapter.test.ts +5 -5
- package/src/transpiler/state/SymbolRegistry.ts +10 -12
- package/src/transpiler/state/__tests__/SymbolRegistry.test.ts +11 -13
- package/src/transpiler/types/ICachedFileEntry.ts +4 -0
- package/src/transpiler/types/IPipelineFile.ts +3 -0
- package/src/transpiler/types/ITranspilerConfig.ts +2 -2
- package/src/transpiler/types/symbols/IScopeSymbol.ts +1 -1
- package/src/utils/FunctionUtils.ts +3 -3
- package/src/utils/__tests__/FunctionUtils.test.ts +6 -4
- package/src/utils/cache/CacheManager.ts +28 -15
- package/src/utils/cache/__tests__/CacheManager.test.ts +6 -4
- package/src/transpiler/data/types/IDiscoveryOptions.ts +0 -15
|
@@ -41,7 +41,7 @@ describe("ConfigPrinter", () => {
|
|
|
41
41
|
|
|
42
42
|
it("displays config file path when provided", () => {
|
|
43
43
|
const config: ICliConfig = {
|
|
44
|
-
|
|
44
|
+
input: "",
|
|
45
45
|
outputPath: "",
|
|
46
46
|
includeDirs: [],
|
|
47
47
|
defines: {},
|
|
@@ -63,7 +63,7 @@ describe("ConfigPrinter", () => {
|
|
|
63
63
|
|
|
64
64
|
it("displays (none) when no config file is loaded", () => {
|
|
65
65
|
const config: ICliConfig = {
|
|
66
|
-
|
|
66
|
+
input: "",
|
|
67
67
|
outputPath: "",
|
|
68
68
|
includeDirs: [],
|
|
69
69
|
defines: {},
|
|
@@ -83,7 +83,7 @@ describe("ConfigPrinter", () => {
|
|
|
83
83
|
|
|
84
84
|
it("displays cppRequired value", () => {
|
|
85
85
|
const config: ICliConfig = {
|
|
86
|
-
|
|
86
|
+
input: "",
|
|
87
87
|
outputPath: "",
|
|
88
88
|
includeDirs: [],
|
|
89
89
|
defines: {},
|
|
@@ -102,7 +102,7 @@ describe("ConfigPrinter", () => {
|
|
|
102
102
|
|
|
103
103
|
it("displays debugMode value", () => {
|
|
104
104
|
const config: ICliConfig = {
|
|
105
|
-
|
|
105
|
+
input: "",
|
|
106
106
|
outputPath: "",
|
|
107
107
|
includeDirs: [],
|
|
108
108
|
defines: {},
|
|
@@ -122,7 +122,7 @@ describe("ConfigPrinter", () => {
|
|
|
122
122
|
|
|
123
123
|
it("displays target value when set", () => {
|
|
124
124
|
const config: ICliConfig = {
|
|
125
|
-
|
|
125
|
+
input: "",
|
|
126
126
|
outputPath: "",
|
|
127
127
|
includeDirs: [],
|
|
128
128
|
defines: {},
|
|
@@ -142,7 +142,7 @@ describe("ConfigPrinter", () => {
|
|
|
142
142
|
|
|
143
143
|
it("displays (none) for target when not set", () => {
|
|
144
144
|
const config: ICliConfig = {
|
|
145
|
-
|
|
145
|
+
input: "",
|
|
146
146
|
outputPath: "",
|
|
147
147
|
includeDirs: [],
|
|
148
148
|
defines: {},
|
|
@@ -161,7 +161,7 @@ describe("ConfigPrinter", () => {
|
|
|
161
161
|
|
|
162
162
|
it("displays output path when set", () => {
|
|
163
163
|
const config: ICliConfig = {
|
|
164
|
-
|
|
164
|
+
input: "",
|
|
165
165
|
outputPath: "build/",
|
|
166
166
|
includeDirs: [],
|
|
167
167
|
defines: {},
|
|
@@ -180,7 +180,7 @@ describe("ConfigPrinter", () => {
|
|
|
180
180
|
|
|
181
181
|
it("displays (same dir as input) when output not set", () => {
|
|
182
182
|
const config: ICliConfig = {
|
|
183
|
-
|
|
183
|
+
input: "",
|
|
184
184
|
outputPath: "",
|
|
185
185
|
includeDirs: [],
|
|
186
186
|
defines: {},
|
|
@@ -199,7 +199,7 @@ describe("ConfigPrinter", () => {
|
|
|
199
199
|
|
|
200
200
|
it("displays include directories", () => {
|
|
201
201
|
const config: ICliConfig = {
|
|
202
|
-
|
|
202
|
+
input: "",
|
|
203
203
|
outputPath: "",
|
|
204
204
|
includeDirs: ["lib/", "vendor/include/"],
|
|
205
205
|
defines: {},
|
|
@@ -219,7 +219,7 @@ describe("ConfigPrinter", () => {
|
|
|
219
219
|
|
|
220
220
|
it("displays (none) when no include directories", () => {
|
|
221
221
|
const config: ICliConfig = {
|
|
222
|
-
|
|
222
|
+
input: "",
|
|
223
223
|
outputPath: "",
|
|
224
224
|
includeDirs: [],
|
|
225
225
|
defines: {},
|
|
@@ -238,7 +238,7 @@ describe("ConfigPrinter", () => {
|
|
|
238
238
|
|
|
239
239
|
it("displays defines with values", () => {
|
|
240
240
|
const config: ICliConfig = {
|
|
241
|
-
|
|
241
|
+
input: "",
|
|
242
242
|
outputPath: "",
|
|
243
243
|
includeDirs: [],
|
|
244
244
|
defines: { DEBUG: true, VERSION: "1.0" },
|
|
@@ -258,7 +258,7 @@ describe("ConfigPrinter", () => {
|
|
|
258
258
|
|
|
259
259
|
it("displays header text", () => {
|
|
260
260
|
const config: ICliConfig = {
|
|
261
|
-
|
|
261
|
+
input: "",
|
|
262
262
|
outputPath: "",
|
|
263
263
|
includeDirs: [],
|
|
264
264
|
defines: {},
|
|
@@ -321,7 +321,7 @@ describe("PathNormalizer", () => {
|
|
|
321
321
|
};
|
|
322
322
|
|
|
323
323
|
const config: ICliConfig = {
|
|
324
|
-
|
|
324
|
+
input: "file.cnx",
|
|
325
325
|
outputPath: "~/build",
|
|
326
326
|
includeDirs: ["~/sdk/include"],
|
|
327
327
|
defines: {},
|
|
@@ -344,7 +344,7 @@ describe("PathNormalizer", () => {
|
|
|
344
344
|
|
|
345
345
|
it("handles undefined optional fields", () => {
|
|
346
346
|
const config: ICliConfig = {
|
|
347
|
-
|
|
347
|
+
input: "file.cnx",
|
|
348
348
|
outputPath: "",
|
|
349
349
|
includeDirs: [],
|
|
350
350
|
defines: {},
|
|
@@ -363,7 +363,7 @@ describe("PathNormalizer", () => {
|
|
|
363
363
|
|
|
364
364
|
it("expands ** in include paths", () => {
|
|
365
365
|
const config: ICliConfig = {
|
|
366
|
-
|
|
366
|
+
input: "",
|
|
367
367
|
outputPath: "",
|
|
368
368
|
includeDirs: [`${tempDir}/include/**`],
|
|
369
369
|
defines: {},
|
|
@@ -382,7 +382,7 @@ describe("PathNormalizer", () => {
|
|
|
382
382
|
|
|
383
383
|
it("preserves non-path fields unchanged", () => {
|
|
384
384
|
const config: ICliConfig = {
|
|
385
|
-
|
|
385
|
+
input: "a.cnx",
|
|
386
386
|
outputPath: "",
|
|
387
387
|
includeDirs: [],
|
|
388
388
|
defines: { DEBUG: true },
|
|
@@ -397,7 +397,7 @@ describe("PathNormalizer", () => {
|
|
|
397
397
|
|
|
398
398
|
const result = PathNormalizer.normalizeConfig(config);
|
|
399
399
|
|
|
400
|
-
expect(result.
|
|
400
|
+
expect(result.input).toBe("a.cnx");
|
|
401
401
|
expect(result.defines).toEqual({ DEBUG: true });
|
|
402
402
|
expect(result.preprocess).toBe(true);
|
|
403
403
|
expect(result.verbose).toBe(true);
|
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
6
6
|
import Runner from "../Runner";
|
|
7
|
-
import InputExpansion from "../../transpiler/data/InputExpansion";
|
|
8
7
|
import Transpiler from "../../transpiler/Transpiler";
|
|
9
8
|
import ResultPrinter from "../ResultPrinter";
|
|
10
9
|
import ICliConfig from "../types/ICliConfig";
|
|
10
|
+
import InputExpansion from "../../transpiler/data/InputExpansion";
|
|
11
11
|
import * as fs from "node:fs";
|
|
12
12
|
|
|
13
13
|
// Mock dependencies
|
|
14
|
-
vi.mock("../../transpiler/data/InputExpansion");
|
|
15
14
|
vi.mock("../../transpiler/Transpiler");
|
|
16
15
|
vi.mock("../ResultPrinter");
|
|
16
|
+
vi.mock("../../transpiler/data/InputExpansion");
|
|
17
17
|
vi.mock("node:fs", async () => {
|
|
18
18
|
const actual = await vi.importActual("node:fs");
|
|
19
19
|
return {
|
|
@@ -42,7 +42,7 @@ describe("Runner", () => {
|
|
|
42
42
|
|
|
43
43
|
// Default config
|
|
44
44
|
mockConfig = {
|
|
45
|
-
|
|
45
|
+
input: "src/main.cnx",
|
|
46
46
|
outputPath: "",
|
|
47
47
|
includeDirs: [],
|
|
48
48
|
defines: {},
|
|
@@ -59,11 +59,6 @@ describe("Runner", () => {
|
|
|
59
59
|
isDirectory: () => false,
|
|
60
60
|
} as fs.Stats);
|
|
61
61
|
|
|
62
|
-
// Mock InputExpansion
|
|
63
|
-
vi.mocked(InputExpansion.expandInputs).mockReturnValue([
|
|
64
|
-
"/project/src/main.cnx",
|
|
65
|
-
]);
|
|
66
|
-
|
|
67
62
|
// Mock Transpiler
|
|
68
63
|
mockTranspilerInstance = {
|
|
69
64
|
transpile: vi.fn().mockResolvedValue({
|
|
@@ -76,6 +71,9 @@ describe("Runner", () => {
|
|
|
76
71
|
vi.mocked(Transpiler).mockImplementation(function () {
|
|
77
72
|
return mockTranspilerInstance as unknown as Transpiler;
|
|
78
73
|
});
|
|
74
|
+
|
|
75
|
+
// Default: not a C++ entry point
|
|
76
|
+
vi.mocked(InputExpansion.isCppEntryPoint).mockReturnValue(false);
|
|
79
77
|
});
|
|
80
78
|
|
|
81
79
|
afterEach(() => {
|
|
@@ -85,48 +83,17 @@ describe("Runner", () => {
|
|
|
85
83
|
});
|
|
86
84
|
|
|
87
85
|
describe("execute", () => {
|
|
88
|
-
it("
|
|
86
|
+
it("resolves input and runs transpiler", async () => {
|
|
89
87
|
await expect(Runner.execute(mockConfig)).rejects.toThrow(
|
|
90
88
|
"process.exit(0)",
|
|
91
89
|
);
|
|
92
90
|
|
|
93
|
-
expect(InputExpansion.expandInputs).toHaveBeenCalledWith([
|
|
94
|
-
"src/main.cnx",
|
|
95
|
-
]);
|
|
96
91
|
expect(Transpiler).toHaveBeenCalled();
|
|
97
92
|
expect(mockTranspilerInstance.transpile).toHaveBeenCalled();
|
|
98
93
|
expect(ResultPrinter.print).toHaveBeenCalled();
|
|
99
94
|
});
|
|
100
95
|
|
|
101
|
-
it("exits with error when InputExpansion throws", async () => {
|
|
102
|
-
vi.mocked(InputExpansion.expandInputs).mockImplementation(() => {
|
|
103
|
-
throw new Error("Path not found");
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
await expect(Runner.execute(mockConfig)).rejects.toThrow(
|
|
107
|
-
"process.exit(1)",
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
111
|
-
"Error: Error: Path not found",
|
|
112
|
-
);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it("exits with error when no .cnx files found", async () => {
|
|
116
|
-
vi.mocked(InputExpansion.expandInputs).mockReturnValue([]);
|
|
117
|
-
|
|
118
|
-
await expect(Runner.execute(mockConfig)).rejects.toThrow(
|
|
119
|
-
"process.exit(1)",
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
123
|
-
"Error: No .cnx files found",
|
|
124
|
-
);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
96
|
it("passes include paths to Transpiler", async () => {
|
|
128
|
-
// Include discovery now happens inside Transpiler.discoverIncludes()
|
|
129
|
-
// Runner just passes config.includeDirs directly
|
|
130
97
|
mockConfig.includeDirs = ["/extra/include"];
|
|
131
98
|
|
|
132
99
|
await expect(Runner.execute(mockConfig)).rejects.toThrow(
|
|
@@ -162,10 +129,11 @@ describe("Runner", () => {
|
|
|
162
129
|
);
|
|
163
130
|
|
|
164
131
|
const transpilerCall = vi.mocked(Transpiler).mock.calls[0][0];
|
|
165
|
-
|
|
132
|
+
// outDir should be dirname of resolved input
|
|
133
|
+
expect(transpilerCall.outDir).toBeDefined();
|
|
166
134
|
});
|
|
167
135
|
|
|
168
|
-
it("handles explicit output filename
|
|
136
|
+
it("handles explicit output filename", async () => {
|
|
169
137
|
mockConfig.outputPath = "output/result.c";
|
|
170
138
|
|
|
171
139
|
mockTranspilerInstance.transpile.mockResolvedValue({
|
|
@@ -181,25 +149,9 @@ describe("Runner", () => {
|
|
|
181
149
|
expect(fs.renameSync).toHaveBeenCalled();
|
|
182
150
|
});
|
|
183
151
|
|
|
184
|
-
it("errors on explicit filename with multiple files", async () => {
|
|
185
|
-
mockConfig.outputPath = "output/result.c";
|
|
186
|
-
vi.mocked(InputExpansion.expandInputs).mockReturnValue([
|
|
187
|
-
"/project/src/a.cnx",
|
|
188
|
-
"/project/src/b.cnx",
|
|
189
|
-
]);
|
|
190
|
-
|
|
191
|
-
await expect(Runner.execute(mockConfig)).rejects.toThrow(
|
|
192
|
-
"process.exit(1)",
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
196
|
-
"Error: Cannot use explicit output filename with multiple input files",
|
|
197
|
-
);
|
|
198
|
-
});
|
|
199
|
-
|
|
200
152
|
it("passes all config options to Transpiler", async () => {
|
|
201
153
|
mockConfig = {
|
|
202
|
-
|
|
154
|
+
input: "src/main.cnx",
|
|
203
155
|
outputPath: "build/",
|
|
204
156
|
includeDirs: ["/inc"],
|
|
205
157
|
defines: { DEBUG: true },
|
|
@@ -259,29 +211,6 @@ describe("Runner", () => {
|
|
|
259
211
|
);
|
|
260
212
|
});
|
|
261
213
|
|
|
262
|
-
it("separates directory and file inputs", async () => {
|
|
263
|
-
mockConfig.inputs = ["src/", "extra/main.cnx"];
|
|
264
|
-
|
|
265
|
-
vi.mocked(fs.existsSync).mockImplementation((path) => {
|
|
266
|
-
return (
|
|
267
|
-
(path as string).endsWith("src/") ||
|
|
268
|
-
(path as string).includes("main.cnx")
|
|
269
|
-
);
|
|
270
|
-
});
|
|
271
|
-
vi.mocked(fs.statSync).mockImplementation((path) => {
|
|
272
|
-
return {
|
|
273
|
-
isDirectory: () => (path as string).endsWith("src/"),
|
|
274
|
-
} as fs.Stats;
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
await expect(Runner.execute(mockConfig)).rejects.toThrow(
|
|
278
|
-
"process.exit(0)",
|
|
279
|
-
);
|
|
280
|
-
|
|
281
|
-
const transpilerCall = vi.mocked(Transpiler).mock.calls[0][0];
|
|
282
|
-
expect(transpilerCall.inputs).toHaveLength(2);
|
|
283
|
-
});
|
|
284
|
-
|
|
285
214
|
it("doesn't rename when generated file matches explicit path", async () => {
|
|
286
215
|
mockConfig.outputPath = "/project/output/main.c";
|
|
287
216
|
|
|
@@ -297,5 +226,102 @@ describe("Runner", () => {
|
|
|
297
226
|
|
|
298
227
|
expect(fs.renameSync).not.toHaveBeenCalled();
|
|
299
228
|
});
|
|
229
|
+
|
|
230
|
+
describe("C++ entry point", () => {
|
|
231
|
+
beforeEach(() => {
|
|
232
|
+
vi.mocked(InputExpansion.isCppEntryPoint).mockReturnValue(true);
|
|
233
|
+
mockConfig.input = "src/main.cpp";
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it("prints scanning message for C++ entry point", async () => {
|
|
237
|
+
mockTranspilerInstance.transpile.mockResolvedValue({
|
|
238
|
+
success: true,
|
|
239
|
+
outputFiles: [],
|
|
240
|
+
errors: [],
|
|
241
|
+
filesProcessed: 1,
|
|
242
|
+
files: [{ sourcePath: "/project/src/led.cnx" }],
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
await expect(Runner.execute(mockConfig)).rejects.toThrow(
|
|
246
|
+
"process.exit(0)",
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
250
|
+
expect.stringContaining("Scanning main.cpp for C-Next includes..."),
|
|
251
|
+
);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it("prints found files when C-Next sources discovered", async () => {
|
|
255
|
+
mockTranspilerInstance.transpile.mockResolvedValue({
|
|
256
|
+
success: true,
|
|
257
|
+
outputFiles: ["/project/src/led.c"],
|
|
258
|
+
errors: [],
|
|
259
|
+
filesProcessed: 2,
|
|
260
|
+
files: [
|
|
261
|
+
{ sourcePath: "/project/src/led.cnx" },
|
|
262
|
+
{ sourcePath: "/project/src/motor.cnx" },
|
|
263
|
+
],
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
await expect(Runner.execute(mockConfig)).rejects.toThrow(
|
|
267
|
+
"process.exit(0)",
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
271
|
+
expect.stringContaining("Found 2 C-Next source file(s)"),
|
|
272
|
+
);
|
|
273
|
+
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
274
|
+
expect.stringContaining("led.cnx"),
|
|
275
|
+
);
|
|
276
|
+
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
277
|
+
expect.stringContaining("motor.cnx"),
|
|
278
|
+
);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it("prints getting started guide when no C-Next files found", async () => {
|
|
282
|
+
mockTranspilerInstance.transpile.mockResolvedValue({
|
|
283
|
+
success: true,
|
|
284
|
+
outputFiles: [],
|
|
285
|
+
errors: [],
|
|
286
|
+
filesProcessed: 0,
|
|
287
|
+
files: [],
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
await expect(Runner.execute(mockConfig)).rejects.toThrow(
|
|
291
|
+
"process.exit(0)",
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
295
|
+
expect.stringContaining("No C-Next files found"),
|
|
296
|
+
);
|
|
297
|
+
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
298
|
+
expect.stringContaining("Create a .cnx file"),
|
|
299
|
+
);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("does not print C++ entry point messages for .cnx files", async () => {
|
|
303
|
+
vi.mocked(InputExpansion.isCppEntryPoint).mockReturnValue(false);
|
|
304
|
+
mockConfig.input = "src/main.cnx";
|
|
305
|
+
|
|
306
|
+
mockTranspilerInstance.transpile.mockResolvedValue({
|
|
307
|
+
success: true,
|
|
308
|
+
outputFiles: ["/project/src/main.c"],
|
|
309
|
+
errors: [],
|
|
310
|
+
filesProcessed: 1,
|
|
311
|
+
files: [{ sourcePath: "/project/src/main.cnx" }],
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
await expect(Runner.execute(mockConfig)).rejects.toThrow(
|
|
315
|
+
"process.exit(0)",
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
expect(consoleLogSpy).not.toHaveBeenCalledWith(
|
|
319
|
+
expect.stringContaining("Scanning"),
|
|
320
|
+
);
|
|
321
|
+
expect(consoleLogSpy).not.toHaveBeenCalledWith(
|
|
322
|
+
expect.stringContaining("Found"),
|
|
323
|
+
);
|
|
324
|
+
});
|
|
325
|
+
});
|
|
300
326
|
});
|
|
301
327
|
});
|
|
@@ -247,7 +247,7 @@ class ServeCommand {
|
|
|
247
247
|
const config = ConfigLoader.load(workspacePath);
|
|
248
248
|
|
|
249
249
|
ServeCommand.transpiler = new Transpiler({
|
|
250
|
-
|
|
250
|
+
input: "",
|
|
251
251
|
includeDirs: config.include ?? [],
|
|
252
252
|
cppRequired: config.cppRequired ?? false,
|
|
253
253
|
target: config.target ?? "",
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* CLI flags with config file settings. CLI flags take precedence.
|
|
6
6
|
*/
|
|
7
7
|
interface ICliConfig {
|
|
8
|
-
/**
|
|
9
|
-
|
|
8
|
+
/** Entry point .cnx file to transpile */
|
|
9
|
+
input: string;
|
|
10
10
|
/** Output path (file or directory) */
|
|
11
11
|
outputPath: string;
|
|
12
12
|
/** Additional include directories */
|
|
@@ -57,14 +57,14 @@ function convertBitmap(
|
|
|
57
57
|
bitmap: import("../transpiler/types/symbols/IBitmapSymbol").default,
|
|
58
58
|
): ISymbolInfo[] {
|
|
59
59
|
const result: ISymbolInfo[] = [];
|
|
60
|
-
const
|
|
60
|
+
const cName = SymbolNameUtils.getTranspiledCName(bitmap);
|
|
61
61
|
const parent = bitmap.scope.name || undefined;
|
|
62
62
|
const bitmapId = getDotPathId(bitmap);
|
|
63
63
|
const bitmapParentId = getParentId(bitmap.scope);
|
|
64
64
|
|
|
65
65
|
result.push({
|
|
66
66
|
name: bitmap.name,
|
|
67
|
-
fullName:
|
|
67
|
+
fullName: cName,
|
|
68
68
|
kind: "bitmap",
|
|
69
69
|
type: bitmap.backingType,
|
|
70
70
|
parent,
|
|
@@ -77,9 +77,9 @@ function convertBitmap(
|
|
|
77
77
|
for (const [fieldName, fieldInfo] of bitmap.fields) {
|
|
78
78
|
result.push({
|
|
79
79
|
name: fieldName,
|
|
80
|
-
fullName: `${
|
|
80
|
+
fullName: `${cName}.${fieldName}`,
|
|
81
81
|
kind: "bitmapField",
|
|
82
|
-
parent:
|
|
82
|
+
parent: cName,
|
|
83
83
|
id: `${bitmapId}.${fieldName}`,
|
|
84
84
|
parentId: bitmapId,
|
|
85
85
|
line: bitmap.sourceLine,
|
|
@@ -94,14 +94,14 @@ function convertEnum(
|
|
|
94
94
|
enumSym: import("../transpiler/types/symbols/IEnumSymbol").default,
|
|
95
95
|
): ISymbolInfo[] {
|
|
96
96
|
const result: ISymbolInfo[] = [];
|
|
97
|
-
const
|
|
97
|
+
const cName = SymbolNameUtils.getTranspiledCName(enumSym);
|
|
98
98
|
const parent = enumSym.scope.name || undefined;
|
|
99
99
|
const enumId = getDotPathId(enumSym);
|
|
100
100
|
const enumParentId = getParentId(enumSym.scope);
|
|
101
101
|
|
|
102
102
|
result.push({
|
|
103
103
|
name: enumSym.name,
|
|
104
|
-
fullName:
|
|
104
|
+
fullName: cName,
|
|
105
105
|
kind: "enum",
|
|
106
106
|
parent,
|
|
107
107
|
id: enumId,
|
|
@@ -113,9 +113,9 @@ function convertEnum(
|
|
|
113
113
|
for (const [memberName] of enumSym.members) {
|
|
114
114
|
result.push({
|
|
115
115
|
name: memberName,
|
|
116
|
-
fullName: `${
|
|
116
|
+
fullName: `${cName}_${memberName}`,
|
|
117
117
|
kind: "enumMember",
|
|
118
|
-
parent:
|
|
118
|
+
parent: cName,
|
|
119
119
|
id: `${enumId}.${memberName}`,
|
|
120
120
|
parentId: enumId,
|
|
121
121
|
line: enumSym.sourceLine,
|
|
@@ -129,14 +129,14 @@ function convertStruct(
|
|
|
129
129
|
struct: import("../transpiler/types/symbols/IStructSymbol").default,
|
|
130
130
|
): ISymbolInfo[] {
|
|
131
131
|
const result: ISymbolInfo[] = [];
|
|
132
|
-
const
|
|
132
|
+
const cName = SymbolNameUtils.getTranspiledCName(struct);
|
|
133
133
|
const parent = struct.scope.name || undefined;
|
|
134
134
|
const structId = getDotPathId(struct);
|
|
135
135
|
const structParentId = getParentId(struct.scope);
|
|
136
136
|
|
|
137
137
|
result.push({
|
|
138
138
|
name: struct.name,
|
|
139
|
-
fullName:
|
|
139
|
+
fullName: cName,
|
|
140
140
|
kind: "struct",
|
|
141
141
|
parent,
|
|
142
142
|
id: structId,
|
|
@@ -148,10 +148,10 @@ function convertStruct(
|
|
|
148
148
|
for (const [fieldName, fieldInfo] of struct.fields) {
|
|
149
149
|
result.push({
|
|
150
150
|
name: fieldName,
|
|
151
|
-
fullName: `${
|
|
151
|
+
fullName: `${cName}.${fieldName}`,
|
|
152
152
|
kind: "field",
|
|
153
153
|
type: TypeResolver.getTypeName(fieldInfo.type),
|
|
154
|
-
parent:
|
|
154
|
+
parent: cName,
|
|
155
155
|
id: `${structId}.${fieldName}`,
|
|
156
156
|
parentId: structId,
|
|
157
157
|
line: struct.sourceLine,
|
|
@@ -165,7 +165,7 @@ function convertFunction(
|
|
|
165
165
|
func: import("../transpiler/types/symbols/IFunctionSymbol").default,
|
|
166
166
|
): ISymbolInfo[] {
|
|
167
167
|
const result: ISymbolInfo[] = [];
|
|
168
|
-
const
|
|
168
|
+
const cName = SymbolNameUtils.getTranspiledCName(func);
|
|
169
169
|
const parent = func.scope.name || undefined;
|
|
170
170
|
const returnType = TypeResolver.getTypeName(func.returnType);
|
|
171
171
|
|
|
@@ -173,11 +173,11 @@ function convertFunction(
|
|
|
173
173
|
const paramTypes = func.parameters.map((p) =>
|
|
174
174
|
TypeResolver.getTypeName(p.type),
|
|
175
175
|
);
|
|
176
|
-
const signature = `${returnType} ${
|
|
176
|
+
const signature = `${returnType} ${cName}(${paramTypes.join(", ")})`;
|
|
177
177
|
|
|
178
178
|
result.push({
|
|
179
179
|
name: func.name,
|
|
180
|
-
fullName:
|
|
180
|
+
fullName: cName,
|
|
181
181
|
kind: "function",
|
|
182
182
|
type: returnType,
|
|
183
183
|
parent,
|
|
@@ -194,13 +194,13 @@ function convertFunction(
|
|
|
194
194
|
function convertVariable(
|
|
195
195
|
variable: import("../transpiler/types/symbols/IVariableSymbol").default,
|
|
196
196
|
): ISymbolInfo {
|
|
197
|
-
const
|
|
197
|
+
const cName = SymbolNameUtils.getTranspiledCName(variable);
|
|
198
198
|
const parent = variable.scope.name || undefined;
|
|
199
199
|
const typeStr = TypeResolver.getTypeName(variable.type);
|
|
200
200
|
|
|
201
201
|
return {
|
|
202
202
|
name: variable.name,
|
|
203
|
-
fullName:
|
|
203
|
+
fullName: cName,
|
|
204
204
|
kind: "variable",
|
|
205
205
|
type: typeStr,
|
|
206
206
|
parent,
|
|
@@ -214,14 +214,14 @@ function convertRegister(
|
|
|
214
214
|
register: import("../transpiler/types/symbols/IRegisterSymbol").default,
|
|
215
215
|
): ISymbolInfo[] {
|
|
216
216
|
const result: ISymbolInfo[] = [];
|
|
217
|
-
const
|
|
217
|
+
const cName = SymbolNameUtils.getTranspiledCName(register);
|
|
218
218
|
const parent = register.scope.name || undefined;
|
|
219
219
|
const registerId = getDotPathId(register);
|
|
220
220
|
const registerParentId = getParentId(register.scope);
|
|
221
221
|
|
|
222
222
|
result.push({
|
|
223
223
|
name: register.name,
|
|
224
|
-
fullName:
|
|
224
|
+
fullName: cName,
|
|
225
225
|
kind: "register",
|
|
226
226
|
parent,
|
|
227
227
|
id: registerId,
|
|
@@ -233,9 +233,9 @@ function convertRegister(
|
|
|
233
233
|
for (const [memberName, memberInfo] of register.members) {
|
|
234
234
|
result.push({
|
|
235
235
|
name: memberName,
|
|
236
|
-
fullName: `${
|
|
236
|
+
fullName: `${cName}.${memberName}`,
|
|
237
237
|
kind: "registerMember",
|
|
238
|
-
parent:
|
|
238
|
+
parent: cName,
|
|
239
239
|
id: `${registerId}.${memberName}`,
|
|
240
240
|
parentId: registerId,
|
|
241
241
|
accessModifier: memberInfo.access,
|