@ugo-studio/jspp 0.3.0 → 0.3.2
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/LICENSE +25 -25
- package/README.md +20 -12
- package/dist/cli/args.js +22 -0
- package/dist/cli/compiler.js +53 -0
- package/dist/cli/index.js +43 -107
- package/dist/cli/pch.js +71 -0
- package/dist/cli/runner.js +23 -0
- package/dist/cli/spinner.js +27 -11
- package/dist/cli/transpiler.js +20 -0
- package/dist/cli/utils.js +59 -0
- package/dist/cli/wasm.js +70 -0
- package/dist/index.js +17 -6
- package/dist/{analysis → interpreter/analysis}/scope.js +38 -3
- package/dist/{analysis → interpreter/analysis}/typeAnalyzer.js +563 -28
- package/dist/{core → interpreter/core}/codegen/class-handlers.js +1 -1
- package/dist/{core → interpreter/core}/codegen/control-flow-handlers.js +12 -11
- package/dist/{core → interpreter/core}/codegen/declaration-handlers.js +28 -9
- package/dist/{core → interpreter/core}/codegen/destructuring-handlers.js +9 -4
- package/dist/{core → interpreter/core}/codegen/expression-handlers.js +82 -88
- package/dist/{core → interpreter/core}/codegen/function-handlers.js +159 -46
- package/dist/{core → interpreter/core}/codegen/helpers.js +170 -25
- package/dist/interpreter/core/codegen/index.js +156 -0
- package/dist/{core → interpreter/core}/codegen/literal-handlers.js +9 -0
- package/dist/{core → interpreter/core}/codegen/statement-handlers.js +47 -7
- package/package.json +6 -4
- package/scripts/precompile-headers.ts +293 -50
- package/scripts/setup-compiler.ts +63 -63
- package/scripts/setup-emsdk.ts +114 -0
- package/src/prelude/any_value.cpp +888 -0
- package/src/prelude/any_value.hpp +29 -24
- package/src/prelude/{exception_helpers.hpp → exception.cpp} +53 -53
- package/src/prelude/exception.hpp +27 -27
- package/src/prelude/iterator_instantiations.hpp +10 -0
- package/src/prelude/{index.hpp → jspp.hpp} +13 -17
- package/src/prelude/library/array.cpp +191 -0
- package/src/prelude/library/array.hpp +5 -178
- package/src/prelude/library/boolean.cpp +30 -0
- package/src/prelude/library/boolean.hpp +14 -0
- package/src/prelude/library/console.cpp +125 -0
- package/src/prelude/library/console.hpp +9 -97
- package/src/prelude/library/error.cpp +100 -0
- package/src/prelude/library/error.hpp +8 -108
- package/src/prelude/library/function.cpp +69 -0
- package/src/prelude/library/function.hpp +6 -5
- package/src/prelude/library/global.cpp +98 -0
- package/src/prelude/library/global.hpp +12 -28
- package/src/prelude/library/global_usings.hpp +15 -0
- package/src/prelude/library/math.cpp +261 -0
- package/src/prelude/library/math.hpp +8 -288
- package/src/prelude/library/object.cpp +379 -0
- package/src/prelude/library/object.hpp +5 -267
- package/src/prelude/library/performance.cpp +21 -0
- package/src/prelude/library/performance.hpp +5 -20
- package/src/prelude/library/process.cpp +38 -0
- package/src/prelude/library/process.hpp +3 -31
- package/src/prelude/library/promise.cpp +131 -0
- package/src/prelude/library/promise.hpp +5 -116
- package/src/prelude/library/symbol.cpp +56 -0
- package/src/prelude/library/symbol.hpp +5 -46
- package/src/prelude/library/timer.cpp +88 -0
- package/src/prelude/library/timer.hpp +11 -87
- package/src/prelude/runtime.cpp +19 -0
- package/src/prelude/types.hpp +26 -20
- package/src/prelude/utils/access.hpp +123 -32
- package/src/prelude/utils/assignment_operators.hpp +119 -99
- package/src/prelude/utils/log_any_value/array.hpp +61 -40
- package/src/prelude/utils/log_any_value/function.hpp +39 -39
- package/src/prelude/utils/log_any_value/log_any_value.hpp +1 -1
- package/src/prelude/utils/log_any_value/object.hpp +60 -3
- package/src/prelude/utils/log_any_value/primitives.hpp +1 -1
- package/src/prelude/utils/operators.hpp +109 -94
- package/src/prelude/utils/operators_native.hpp +349 -0
- package/src/prelude/utils/well_known_symbols.hpp +24 -24
- package/src/prelude/values/array.cpp +1399 -0
- package/src/prelude/values/array.hpp +4 -0
- package/src/prelude/values/async_iterator.cpp +251 -0
- package/src/prelude/values/async_iterator.hpp +60 -32
- package/src/prelude/values/boolean.cpp +64 -0
- package/src/prelude/values/function.cpp +262 -0
- package/src/prelude/values/function.hpp +10 -30
- package/src/prelude/values/iterator.cpp +309 -0
- package/src/prelude/values/iterator.hpp +33 -64
- package/src/prelude/values/number.cpp +221 -0
- package/src/prelude/values/object.cpp +200 -0
- package/src/prelude/values/object.hpp +4 -0
- package/src/prelude/values/promise.cpp +479 -0
- package/src/prelude/values/promise.hpp +9 -2
- package/src/prelude/values/prototypes/array.hpp +46 -1348
- package/src/prelude/values/prototypes/async_iterator.hpp +19 -61
- package/src/prelude/values/prototypes/boolean.hpp +24 -0
- package/src/prelude/values/prototypes/function.hpp +7 -46
- package/src/prelude/values/prototypes/iterator.hpp +15 -191
- package/src/prelude/values/prototypes/number.hpp +30 -210
- package/src/prelude/values/prototypes/object.hpp +7 -23
- package/src/prelude/values/prototypes/promise.hpp +8 -186
- package/src/prelude/values/prototypes/string.hpp +28 -553
- package/src/prelude/values/prototypes/symbol.hpp +9 -70
- package/src/prelude/values/shape.hpp +52 -52
- package/src/prelude/values/string.cpp +485 -0
- package/src/prelude/values/symbol.cpp +89 -0
- package/src/prelude/values/symbol.hpp +101 -101
- package/dist/cli/file-utils.js +0 -20
- package/dist/cli-utils/args.js +0 -59
- package/dist/cli-utils/colors.js +0 -9
- package/dist/cli-utils/file-utils.js +0 -20
- package/dist/cli-utils/spinner.js +0 -55
- package/dist/cli.js +0 -153
- package/dist/core/codegen/index.js +0 -86
- package/src/prelude/any_value_access.hpp +0 -170
- package/src/prelude/any_value_defines.hpp +0 -190
- package/src/prelude/any_value_helpers.hpp +0 -374
- package/src/prelude/utils/operators_primitive.hpp +0 -337
- package/src/prelude/values/helpers/array.hpp +0 -199
- package/src/prelude/values/helpers/async_iterator.hpp +0 -275
- package/src/prelude/values/helpers/function.hpp +0 -109
- package/src/prelude/values/helpers/iterator.hpp +0 -145
- package/src/prelude/values/helpers/object.hpp +0 -104
- package/src/prelude/values/helpers/promise.hpp +0 -254
- package/src/prelude/values/helpers/string.hpp +0 -37
- package/src/prelude/values/helpers/symbol.hpp +0 -21
- /package/dist/{ast → interpreter/ast}/symbols.js +0 -0
- /package/dist/{ast → interpreter/ast}/types.js +0 -0
- /package/dist/{core → interpreter/core}/codegen/visitor.js +0 -0
- /package/dist/{core → interpreter/core}/constants.js +0 -0
- /package/dist/{core → interpreter/core}/error.js +0 -0
- /package/dist/{core → interpreter/core}/parser.js +0 -0
- /package/dist/{core → interpreter/core}/traverser.js +0 -0
|
@@ -1,7 +1,82 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
2
|
import fs from "fs/promises";
|
|
3
3
|
import path from "path";
|
|
4
4
|
|
|
5
|
+
const COLORS = {
|
|
6
|
+
reset: "\x1b[0m",
|
|
7
|
+
cyan: "\x1b[36m",
|
|
8
|
+
green: "\x1b[32m",
|
|
9
|
+
yellow: "\x1b[33m",
|
|
10
|
+
red: "\x1b[31m",
|
|
11
|
+
dim: "\x1b[2m",
|
|
12
|
+
bold: "\x1b[1m",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export class Spinner {
|
|
16
|
+
private frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
17
|
+
private interval: any = null;
|
|
18
|
+
private frameIndex = 0;
|
|
19
|
+
public text: string;
|
|
20
|
+
|
|
21
|
+
constructor(text: string) {
|
|
22
|
+
this.text = text;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
start() {
|
|
26
|
+
process.stdout.write("\x1b[?25l"); // Hide cursor
|
|
27
|
+
this.frameIndex = 0;
|
|
28
|
+
this.render();
|
|
29
|
+
this.interval = setInterval(() => {
|
|
30
|
+
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
31
|
+
this.render();
|
|
32
|
+
}, 80);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
update(text: string) {
|
|
36
|
+
this.text = text;
|
|
37
|
+
this.render();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
stop(symbol: string = "", color: string = COLORS.reset) {
|
|
41
|
+
if (this.interval) {
|
|
42
|
+
clearInterval(this.interval);
|
|
43
|
+
this.interval = null;
|
|
44
|
+
}
|
|
45
|
+
this.clearLine();
|
|
46
|
+
process.stdout.write(
|
|
47
|
+
`${color}${symbol} ${COLORS.reset} ${this.text}\n`,
|
|
48
|
+
);
|
|
49
|
+
process.stdout.write("\x1b[?25h"); // Show cursor
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
succeed(text?: string) {
|
|
53
|
+
if (text) this.text = text;
|
|
54
|
+
this.stop("✔", COLORS.green);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
fail(text?: string) {
|
|
58
|
+
if (text) this.text = text;
|
|
59
|
+
this.stop("✖", COLORS.red);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
info(text?: string) {
|
|
63
|
+
if (text) this.text = text;
|
|
64
|
+
this.stop("ℹ", COLORS.cyan);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private render() {
|
|
68
|
+
this.clearLine();
|
|
69
|
+
const frame = this.frames[this.frameIndex];
|
|
70
|
+
process.stdout.write(
|
|
71
|
+
`${COLORS.cyan}${frame} ${COLORS.reset} ${this.text}`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private clearLine() {
|
|
76
|
+
process.stdout.write("\r\x1b[K");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
5
80
|
const PRELUDE_DIR = path.resolve(process.cwd(), "src", "prelude");
|
|
6
81
|
const PRECOMPILED_HEADER_BASE_DIR = path.resolve(
|
|
7
82
|
process.cwd(),
|
|
@@ -11,11 +86,24 @@ const PRECOMPILED_HEADER_BASE_DIR = path.resolve(
|
|
|
11
86
|
const MODES = [
|
|
12
87
|
{
|
|
13
88
|
name: "debug",
|
|
14
|
-
flags: ["-
|
|
89
|
+
flags: ["-Og"],
|
|
90
|
+
linkerFlags: [],
|
|
91
|
+
compiler: "g++",
|
|
92
|
+
archiver: "ar",
|
|
15
93
|
},
|
|
16
94
|
{
|
|
17
95
|
name: "release",
|
|
18
96
|
flags: ["-O3", "-DNDEBUG"],
|
|
97
|
+
linkerFlags: [],
|
|
98
|
+
compiler: "g++",
|
|
99
|
+
archiver: "ar",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: "wasm",
|
|
103
|
+
flags: ["-O3", "-DNDEBUG"],
|
|
104
|
+
linkerFlags: ["-sASYNCIFY", "-sALLOW_MEMORY_GROWTH=1"],
|
|
105
|
+
compiler: "em++",
|
|
106
|
+
archiver: "emar",
|
|
19
107
|
},
|
|
20
108
|
];
|
|
21
109
|
|
|
@@ -24,15 +112,19 @@ if (process.platform === "win32") {
|
|
|
24
112
|
MODES[1].flags.push("-Wa,-mbig-obj");
|
|
25
113
|
}
|
|
26
114
|
|
|
27
|
-
async function getLatestMtime(
|
|
115
|
+
async function getLatestMtime(
|
|
116
|
+
dirPath: string,
|
|
117
|
+
filter?: (name: string) => boolean,
|
|
118
|
+
): Promise<number> {
|
|
28
119
|
let maxMtime = 0;
|
|
29
120
|
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
30
121
|
for (const entry of entries) {
|
|
31
122
|
const fullPath = path.join(dirPath, entry.name);
|
|
32
123
|
if (entry.isDirectory()) {
|
|
33
|
-
const nestedMtime = await getLatestMtime(fullPath);
|
|
124
|
+
const nestedMtime = await getLatestMtime(fullPath, filter);
|
|
34
125
|
if (nestedMtime > maxMtime) maxMtime = nestedMtime;
|
|
35
126
|
} else {
|
|
127
|
+
if (filter && !filter(entry.name)) continue;
|
|
36
128
|
const stats = await fs.stat(fullPath);
|
|
37
129
|
if (stats.mtimeMs > maxMtime) maxMtime = stats.mtimeMs;
|
|
38
130
|
}
|
|
@@ -40,53 +132,91 @@ async function getLatestMtime(dirPath: string): Promise<number> {
|
|
|
40
132
|
return maxMtime;
|
|
41
133
|
}
|
|
42
134
|
|
|
135
|
+
async function findCppFiles(dir: string): Promise<string[]> {
|
|
136
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
137
|
+
const files = await Promise.all(entries.map((entry) => {
|
|
138
|
+
const res = path.resolve(dir, entry.name);
|
|
139
|
+
if (entry.isDirectory()) {
|
|
140
|
+
return findCppFiles(res);
|
|
141
|
+
} else {
|
|
142
|
+
return res.endsWith(".cpp") ? [res] : [];
|
|
143
|
+
}
|
|
144
|
+
}));
|
|
145
|
+
return Array.prototype.concat(...files);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function runCommand(cmd: string, args: string[]): Promise<boolean> {
|
|
149
|
+
// console.log(`${COLORS.dim}> ${cmd} ${args.join(" ")}${COLORS.reset}`);
|
|
150
|
+
return new Promise((resolve) => {
|
|
151
|
+
const proc = spawn(cmd, args, {
|
|
152
|
+
stdio: "inherit",
|
|
153
|
+
shell: process.platform === "win32",
|
|
154
|
+
});
|
|
155
|
+
proc.on("close", (code) => resolve(code === 0));
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
43
159
|
async function precompileHeaders() {
|
|
44
160
|
const force = process.argv.includes("--force");
|
|
161
|
+
const jsppCliIsParent = process.argv.includes("--jspp-cli-is-parent");
|
|
162
|
+
const silent = process.argv.includes("--silent");
|
|
163
|
+
|
|
164
|
+
const modeArgIdx = process.argv.indexOf("--mode");
|
|
165
|
+
const targetMode = modeArgIdx !== -1
|
|
166
|
+
? process.argv[modeArgIdx + 1]
|
|
167
|
+
: undefined;
|
|
168
|
+
|
|
169
|
+
if (!jsppCliIsParent && !silent) {
|
|
170
|
+
console.log(
|
|
171
|
+
`${COLORS.bold}${COLORS.cyan}JSPP: Precompiling headers and runtime...${COLORS.reset}\n`,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
45
175
|
try {
|
|
46
176
|
await fs.mkdir(PRECOMPILED_HEADER_BASE_DIR, { recursive: true });
|
|
47
|
-
|
|
177
|
+
|
|
178
|
+
const latestHeaderMtime = await getLatestMtime(
|
|
179
|
+
PRELUDE_DIR,
|
|
180
|
+
(name) => name.endsWith(".hpp") || name.endsWith(".h"),
|
|
181
|
+
);
|
|
48
182
|
|
|
49
183
|
for (const mode of MODES) {
|
|
184
|
+
if (targetMode && mode.name !== targetMode) continue;
|
|
185
|
+
|
|
50
186
|
const modeDir = path.join(PRECOMPILED_HEADER_BASE_DIR, mode.name);
|
|
51
|
-
const headerPath = path.join(modeDir, "
|
|
52
|
-
const gchPath = path.join(modeDir, "
|
|
187
|
+
const headerPath = path.join(modeDir, "jspp.hpp");
|
|
188
|
+
const gchPath = path.join(modeDir, "jspp.hpp.gch");
|
|
189
|
+
|
|
190
|
+
const modeLabel = `[${mode.name.toUpperCase()}]`;
|
|
191
|
+
const spinner = new Spinner(`${modeLabel} Checking headers...`);
|
|
192
|
+
if (!silent) spinner.start();
|
|
53
193
|
|
|
54
|
-
|
|
194
|
+
await fs.mkdir(modeDir, { recursive: true });
|
|
195
|
+
|
|
196
|
+
let gchRebuilt = false;
|
|
197
|
+
let shouldBuildGch = force;
|
|
198
|
+
|
|
199
|
+
if (!shouldBuildGch) {
|
|
55
200
|
try {
|
|
56
201
|
const gchStats = await fs.stat(gchPath);
|
|
57
|
-
if (gchStats.mtimeMs
|
|
58
|
-
|
|
59
|
-
`[${mode.name.toUpperCase()}] Headers are up-to-date. Skipping.`,
|
|
60
|
-
);
|
|
61
|
-
continue;
|
|
202
|
+
if (latestHeaderMtime > gchStats.mtimeMs) {
|
|
203
|
+
shouldBuildGch = true;
|
|
62
204
|
}
|
|
63
205
|
} catch (e) {
|
|
64
|
-
|
|
206
|
+
shouldBuildGch = true;
|
|
65
207
|
}
|
|
66
208
|
}
|
|
67
209
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (
|
|
76
|
-
await fs.stat(gchPath).then(
|
|
77
|
-
() => true,
|
|
78
|
-
() => false,
|
|
79
|
-
)
|
|
80
|
-
) {
|
|
81
|
-
await fs.unlink(gchPath);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
console.log(`[${mode.name.toUpperCase()}] Compiling header...`);
|
|
85
|
-
const tempGchPath = `${gchPath}.tmp`;
|
|
210
|
+
if (shouldBuildGch) {
|
|
211
|
+
if (silent) spinner.start();
|
|
212
|
+
spinner.update(`${modeLabel} Compiling header...`);
|
|
213
|
+
await fs.copyFile(
|
|
214
|
+
path.join(PRELUDE_DIR, "jspp.hpp"),
|
|
215
|
+
headerPath,
|
|
216
|
+
);
|
|
86
217
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
[
|
|
218
|
+
const tempGchPath = `${gchPath}.tmp`;
|
|
219
|
+
const success = await runCommand(mode.compiler, [
|
|
90
220
|
"-x",
|
|
91
221
|
"c++-header",
|
|
92
222
|
"-std=c++23",
|
|
@@ -95,31 +225,144 @@ async function precompileHeaders() {
|
|
|
95
225
|
"-o",
|
|
96
226
|
tempGchPath,
|
|
97
227
|
"-I",
|
|
228
|
+
modeDir,
|
|
229
|
+
"-I",
|
|
98
230
|
PRELUDE_DIR,
|
|
99
|
-
]
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
231
|
+
]);
|
|
232
|
+
|
|
233
|
+
if (!success) {
|
|
234
|
+
spinner.fail(`${modeLabel} Failed to precompile headers.`);
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
await fs.rename(tempGchPath, gchPath);
|
|
239
|
+
gchRebuilt = true;
|
|
240
|
+
spinner.succeed(`${modeLabel} PCH Success.`);
|
|
241
|
+
} else {
|
|
242
|
+
if (!silent) {
|
|
243
|
+
spinner.succeed(`${modeLabel} Headers are up-to-date.`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// --- Incremental Compilation of .cpp files ---
|
|
248
|
+
const cppFiles = await findCppFiles(PRELUDE_DIR);
|
|
249
|
+
const objFiles: string[] = [];
|
|
250
|
+
let anyObjRebuilt = false;
|
|
251
|
+
|
|
252
|
+
// We need gchPath to exist for next check, if it doesn't we probably have a problem or it's a first run
|
|
253
|
+
let gchMtime = 0;
|
|
254
|
+
try {
|
|
255
|
+
gchMtime = (await fs.stat(gchPath)).mtimeMs;
|
|
256
|
+
} catch (e) {}
|
|
257
|
+
|
|
258
|
+
const libSpinner = new Spinner(
|
|
259
|
+
`${modeLabel} Checking runtime library...`,
|
|
103
260
|
);
|
|
261
|
+
if (!silent) libSpinner.start();
|
|
104
262
|
|
|
105
|
-
|
|
263
|
+
for (let idx = 0; idx < cppFiles.length; idx++) {
|
|
264
|
+
const cppFile = cppFiles[idx];
|
|
265
|
+
const relativePath = path.relative(PRELUDE_DIR, cppFile);
|
|
266
|
+
const objFile = path.join(
|
|
267
|
+
modeDir,
|
|
268
|
+
relativePath.replace(/\.cpp$/, ".o"),
|
|
269
|
+
);
|
|
270
|
+
await fs.mkdir(path.dirname(objFile), { recursive: true });
|
|
271
|
+
objFiles.push(objFile);
|
|
272
|
+
|
|
273
|
+
let shouldCompile = force || gchRebuilt;
|
|
274
|
+
if (!shouldCompile) {
|
|
275
|
+
try {
|
|
276
|
+
const objStats = await fs.stat(objFile);
|
|
277
|
+
const cppStats = await fs.stat(cppFile);
|
|
278
|
+
if (
|
|
279
|
+
cppStats.mtimeMs > objStats.mtimeMs ||
|
|
280
|
+
gchMtime > objStats.mtimeMs
|
|
281
|
+
) {
|
|
282
|
+
shouldCompile = true;
|
|
283
|
+
}
|
|
284
|
+
} catch (e) {
|
|
285
|
+
shouldCompile = true;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (shouldCompile) {
|
|
290
|
+
if (silent && !libSpinner["interval"]) libSpinner.start();
|
|
291
|
+
libSpinner.update(
|
|
292
|
+
`${modeLabel} Compiling ${relativePath} ${COLORS.dim}[${
|
|
293
|
+
idx + 1
|
|
294
|
+
}/${cppFiles.length}]${COLORS.reset}`,
|
|
295
|
+
);
|
|
296
|
+
const success = await runCommand(mode.compiler, [
|
|
297
|
+
"-c",
|
|
298
|
+
"-std=c++23",
|
|
299
|
+
...mode.flags,
|
|
300
|
+
cppFile,
|
|
301
|
+
"-o",
|
|
302
|
+
objFile,
|
|
303
|
+
"-I",
|
|
304
|
+
modeDir,
|
|
305
|
+
"-I",
|
|
306
|
+
PRELUDE_DIR,
|
|
307
|
+
]);
|
|
308
|
+
|
|
309
|
+
if (!success) {
|
|
310
|
+
libSpinner.fail(
|
|
311
|
+
`${modeLabel} Failed to compile ${relativePath}`,
|
|
312
|
+
);
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
anyObjRebuilt = true;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const libPath = path.join(modeDir, "libjspp.a");
|
|
320
|
+
let shouldArchive = anyObjRebuilt;
|
|
321
|
+
if (!shouldArchive) {
|
|
106
322
|
try {
|
|
107
|
-
await fs.
|
|
323
|
+
await fs.access(libPath);
|
|
108
324
|
} catch (e) {
|
|
109
|
-
|
|
325
|
+
shouldArchive = true;
|
|
110
326
|
}
|
|
111
|
-
console.error(
|
|
112
|
-
`[${mode.name.toUpperCase()}] Failed to precompile headers.`,
|
|
113
|
-
);
|
|
114
|
-
process.exit(1);
|
|
115
327
|
}
|
|
116
328
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
329
|
+
if (shouldArchive) {
|
|
330
|
+
if (silent && !libSpinner["interval"]) libSpinner.start();
|
|
331
|
+
libSpinner.update(`${modeLabel} Updating runtime library...`);
|
|
332
|
+
const tempLibPath = `${libPath}.tmp`;
|
|
333
|
+
|
|
334
|
+
const success = await runCommand(mode.archiver, [
|
|
335
|
+
"rcs",
|
|
336
|
+
tempLibPath,
|
|
337
|
+
...objFiles,
|
|
338
|
+
]);
|
|
339
|
+
|
|
340
|
+
if (!success) {
|
|
341
|
+
libSpinner.fail(
|
|
342
|
+
`${modeLabel} Failed to create static library.`,
|
|
343
|
+
);
|
|
344
|
+
process.exit(1);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
await fs.rename(tempLibPath, libPath);
|
|
348
|
+
libSpinner.succeed(`${modeLabel} Runtime Library Success.`);
|
|
349
|
+
} else {
|
|
350
|
+
if (!silent) {
|
|
351
|
+
libSpinner.succeed(
|
|
352
|
+
`${modeLabel} Runtime library is up-to-date.`,
|
|
353
|
+
);
|
|
354
|
+
} else {
|
|
355
|
+
libSpinner.stop();
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (!jsppCliIsParent && !silent) {
|
|
360
|
+
console.log(
|
|
361
|
+
`\n${COLORS.bold}${COLORS.green}JSPP: Environment ready.${COLORS.reset}\n`,
|
|
362
|
+
);
|
|
120
363
|
}
|
|
121
364
|
} catch (error: any) {
|
|
122
|
-
console.error(
|
|
365
|
+
console.error(`${COLORS.red}Error: ${error.message}${COLORS.reset}`);
|
|
123
366
|
process.exit(1);
|
|
124
367
|
}
|
|
125
368
|
}
|
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
import { spawnSync } from "child_process";
|
|
2
|
-
import { platform } from "os";
|
|
3
|
-
|
|
4
|
-
const COLORS = {
|
|
5
|
-
reset: "\x1b[0m",
|
|
6
|
-
green: "\x1b[32m",
|
|
7
|
-
yellow: "\x1b[33m",
|
|
8
|
-
red: "\x1b[31m",
|
|
9
|
-
cyan: "\x1b[36m",
|
|
10
|
-
bold: "\x1b[1m",
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
function checkGpp(): boolean {
|
|
14
|
-
try {
|
|
15
|
-
const result = spawnSync("g++", ["--version"], { encoding: "utf8" });
|
|
16
|
-
return result.status === 0;
|
|
17
|
-
} catch (e) {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function setup() {
|
|
23
|
-
console.log(`${COLORS.bold}${COLORS.cyan}JSPP: Checking for C++ compiler...${COLORS.reset}`);
|
|
24
|
-
|
|
25
|
-
if (checkGpp()) {
|
|
26
|
-
console.log(`${COLORS.green}✔ g++ found.${COLORS.reset}`);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
console.log(`${COLORS.yellow}⚠ g++ (GCC) not found in PATH. JSPP requires a C++23 compatible compiler.${COLORS.reset}`);
|
|
31
|
-
|
|
32
|
-
const os = platform();
|
|
33
|
-
|
|
34
|
-
if (os === "win32") {
|
|
35
|
-
console.log(`\n${COLORS.bold}To install GCC on Windows:${COLORS.reset}`);
|
|
36
|
-
console.log(`1. Install MinGW-w64 via MSYS2: ${COLORS.cyan}https://www.msys2.org/${COLORS.reset}`);
|
|
37
|
-
console.log(`2. Or use winget: ${COLORS.cyan}winget install MSYS2.MSYS2${COLORS.reset}`);
|
|
38
|
-
console.log(` Then run: ${COLORS.bold}pacman -S mingw-w64-x86_64-gcc${COLORS.reset}`);
|
|
39
|
-
} else if (os === "linux") {
|
|
40
|
-
console.log(`\n${COLORS.bold}To install GCC on Linux (Ubuntu/Debian):${COLORS.reset}`);
|
|
41
|
-
console.log(`${COLORS.cyan}sudo apt update && sudo apt install g++-14 -y${COLORS.reset}`);
|
|
42
|
-
console.log(`\nAttempting to install now (may require password)...`);
|
|
43
|
-
|
|
44
|
-
// Try to install automatically on Linux if apt is found
|
|
45
|
-
try {
|
|
46
|
-
const install = spawnSync("sudo", ["apt-get", "install", "-y", "g++-14"], { stdio: "inherit" });
|
|
47
|
-
if (install.status === 0) {
|
|
48
|
-
console.log(`${COLORS.green}✔ g++-14 installed successfully.${COLORS.reset}`);
|
|
49
|
-
// Try to set up symlink if needed or just inform user
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
} catch (e) {
|
|
53
|
-
console.error(`${COLORS.red}Automatic installation failed. Please install manually.${COLORS.reset}`);
|
|
54
|
-
}
|
|
55
|
-
} else if (os === "darwin") {
|
|
56
|
-
console.log(`\n${COLORS.bold}To install GCC on macOS:${COLORS.reset}`);
|
|
57
|
-
console.log(`${COLORS.cyan}brew install gcc${COLORS.reset}`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
console.log(`\n${COLORS.bold}After installation, please ensure 'g++' is in your PATH and restart your terminal.${COLORS.reset}\n`);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
setup();
|
|
1
|
+
import { spawnSync } from "child_process";
|
|
2
|
+
import { platform } from "os";
|
|
3
|
+
|
|
4
|
+
const COLORS = {
|
|
5
|
+
reset: "\x1b[0m",
|
|
6
|
+
green: "\x1b[32m",
|
|
7
|
+
yellow: "\x1b[33m",
|
|
8
|
+
red: "\x1b[31m",
|
|
9
|
+
cyan: "\x1b[36m",
|
|
10
|
+
bold: "\x1b[1m",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
function checkGpp(): boolean {
|
|
14
|
+
try {
|
|
15
|
+
const result = spawnSync("g++", ["--version"], { encoding: "utf8" });
|
|
16
|
+
return result.status === 0;
|
|
17
|
+
} catch (e) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function setup() {
|
|
23
|
+
console.log(`${COLORS.bold}${COLORS.cyan}JSPP: Checking for C++ compiler...${COLORS.reset}`);
|
|
24
|
+
|
|
25
|
+
if (checkGpp()) {
|
|
26
|
+
console.log(`${COLORS.green}✔ g++ found.${COLORS.reset}`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.log(`${COLORS.yellow}⚠ g++ (GCC) not found in PATH. JSPP requires a C++23 compatible compiler.${COLORS.reset}`);
|
|
31
|
+
|
|
32
|
+
const os = platform();
|
|
33
|
+
|
|
34
|
+
if (os === "win32") {
|
|
35
|
+
console.log(`\n${COLORS.bold}To install GCC on Windows:${COLORS.reset}`);
|
|
36
|
+
console.log(`1. Install MinGW-w64 via MSYS2: ${COLORS.cyan}https://www.msys2.org/${COLORS.reset}`);
|
|
37
|
+
console.log(`2. Or use winget: ${COLORS.cyan}winget install MSYS2.MSYS2${COLORS.reset}`);
|
|
38
|
+
console.log(` Then run: ${COLORS.bold}pacman -S mingw-w64-x86_64-gcc${COLORS.reset}`);
|
|
39
|
+
} else if (os === "linux") {
|
|
40
|
+
console.log(`\n${COLORS.bold}To install GCC on Linux (Ubuntu/Debian):${COLORS.reset}`);
|
|
41
|
+
console.log(`${COLORS.cyan}sudo apt update && sudo apt install g++-14 -y${COLORS.reset}`);
|
|
42
|
+
console.log(`\nAttempting to install now (may require password)...`);
|
|
43
|
+
|
|
44
|
+
// Try to install automatically on Linux if apt is found
|
|
45
|
+
try {
|
|
46
|
+
const install = spawnSync("sudo", ["apt-get", "install", "-y", "g++-14"], { stdio: "inherit" });
|
|
47
|
+
if (install.status === 0) {
|
|
48
|
+
console.log(`${COLORS.green}✔ g++-14 installed successfully.${COLORS.reset}`);
|
|
49
|
+
// Try to set up symlink if needed or just inform user
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
} catch (e) {
|
|
53
|
+
console.error(`${COLORS.red}Automatic installation failed. Please install manually.${COLORS.reset}`);
|
|
54
|
+
}
|
|
55
|
+
} else if (os === "darwin") {
|
|
56
|
+
console.log(`\n${COLORS.bold}To install GCC on macOS:${COLORS.reset}`);
|
|
57
|
+
console.log(`${COLORS.cyan}brew install gcc${COLORS.reset}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log(`\n${COLORS.bold}After installation, please ensure 'g++' is in your PATH and restart your terminal.${COLORS.reset}\n`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
setup();
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { spawnSync } from "child_process";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { platform } from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
|
|
6
|
+
const COLORS = {
|
|
7
|
+
reset: "\x1b[0m",
|
|
8
|
+
green: "\x1b[32m",
|
|
9
|
+
yellow: "\x1b[33m",
|
|
10
|
+
red: "\x1b[31m",
|
|
11
|
+
cyan: "\x1b[36m",
|
|
12
|
+
bold: "\x1b[1m",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const EMSDK_DIR = path.resolve(process.cwd(), ".emsdk");
|
|
16
|
+
const isWin = platform() === "win32";
|
|
17
|
+
const emsdkCmd = isWin ? "emsdk.bat" : "./emsdk";
|
|
18
|
+
|
|
19
|
+
function checkEmcc(): boolean {
|
|
20
|
+
try {
|
|
21
|
+
const result = spawnSync("emcc", ["--version"], { encoding: "utf8" });
|
|
22
|
+
return result.status === 0;
|
|
23
|
+
} catch (e) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function runCommand(
|
|
29
|
+
cmd: string,
|
|
30
|
+
args: string[],
|
|
31
|
+
cwd: string = process.cwd(),
|
|
32
|
+
): boolean {
|
|
33
|
+
console.log(`${COLORS.cyan}> ${cmd} ${args.join(" ")}${COLORS.reset}`);
|
|
34
|
+
const result = spawnSync(cmd, args, {
|
|
35
|
+
cwd,
|
|
36
|
+
stdio: "inherit",
|
|
37
|
+
shell: isWin,
|
|
38
|
+
});
|
|
39
|
+
return result.status === 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function setup() {
|
|
43
|
+
console.log(
|
|
44
|
+
`${COLORS.bold}${COLORS.cyan}JSPP: Setting up Emscripten SDK for Wasm support...${COLORS.reset}`,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
if (checkEmcc()) {
|
|
48
|
+
console.log(
|
|
49
|
+
`${COLORS.green}✔ Emscripten (emcc) found in PATH.${COLORS.reset}`,
|
|
50
|
+
);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (fs.existsSync(path.join(EMSDK_DIR, emsdkCmd))) {
|
|
55
|
+
console.log(
|
|
56
|
+
`${COLORS.yellow}ℹ Local EMSDK found in .emsdk directory.${COLORS.reset}`,
|
|
57
|
+
);
|
|
58
|
+
} else {
|
|
59
|
+
console.log(
|
|
60
|
+
`${COLORS.yellow}ℹ EMSDK not found. Cloning from GitHub...${COLORS.reset}`,
|
|
61
|
+
);
|
|
62
|
+
if (
|
|
63
|
+
!runCommand("git", [
|
|
64
|
+
"clone",
|
|
65
|
+
"https://github.com/emscripten-core/emsdk.git",
|
|
66
|
+
".emsdk",
|
|
67
|
+
])
|
|
68
|
+
) {
|
|
69
|
+
console.error(
|
|
70
|
+
`${COLORS.red}Error: Failed to clone EMSDK repository. Make sure 'git' is installed.${COLORS.reset}`,
|
|
71
|
+
);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log(
|
|
77
|
+
`${COLORS.cyan}Installing latest Emscripten SDK...${COLORS.reset}`,
|
|
78
|
+
);
|
|
79
|
+
if (!runCommand(emsdkCmd, ["install", "latest"], EMSDK_DIR)) {
|
|
80
|
+
console.error(
|
|
81
|
+
`${COLORS.red}Error: Failed to install Emscripten SDK.${COLORS.reset}`,
|
|
82
|
+
);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log(
|
|
87
|
+
`${COLORS.cyan}Activating latest Emscripten SDK...${COLORS.reset}`,
|
|
88
|
+
);
|
|
89
|
+
if (
|
|
90
|
+
!runCommand(emsdkCmd, ["activate", "latest", "--permanent"], EMSDK_DIR)
|
|
91
|
+
) {
|
|
92
|
+
console.error(
|
|
93
|
+
`${COLORS.red}Error: Failed to activate Emscripten SDK.${COLORS.reset}`,
|
|
94
|
+
);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
console.log(
|
|
99
|
+
`\n${COLORS.green}✔ Emscripten SDK setup complete.${COLORS.reset}`,
|
|
100
|
+
);
|
|
101
|
+
console.log(
|
|
102
|
+
`${COLORS.yellow}Note: To use emcc in your current terminal, you may need to run:${COLORS.reset}`,
|
|
103
|
+
);
|
|
104
|
+
if (isWin) {
|
|
105
|
+
console.log(`${COLORS.bold} .emsdk\\emsdk_env.bat${COLORS.reset}`);
|
|
106
|
+
} else {
|
|
107
|
+
console.log(
|
|
108
|
+
`${COLORS.bold} source .emsdk/emsdk_env.sh${COLORS.reset}`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
console.log("");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
setup();
|