@ugo-studio/jspp 0.1.4 → 0.1.6
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/dist/analysis/scope.js +17 -0
- package/dist/analysis/typeAnalyzer.js +7 -1
- package/dist/ast/symbols.js +32 -0
- package/dist/ast/types.js +0 -6
- package/dist/cli-utils/args.js +57 -0
- package/dist/cli-utils/colors.js +9 -0
- package/dist/cli-utils/file-utils.js +20 -0
- package/dist/cli-utils/spinner.js +55 -0
- package/dist/cli.js +105 -30
- package/dist/core/codegen/class-handlers.js +10 -6
- package/dist/core/codegen/control-flow-handlers.js +57 -28
- package/dist/core/codegen/declaration-handlers.js +10 -6
- package/dist/core/codegen/expression-handlers.js +206 -61
- package/dist/core/codegen/function-handlers.js +203 -76
- package/dist/core/codegen/helpers.js +125 -28
- package/dist/core/codegen/index.js +23 -15
- package/dist/core/codegen/literal-handlers.js +15 -6
- package/dist/core/codegen/statement-handlers.js +282 -84
- package/dist/core/codegen/visitor.js +3 -1
- package/package.json +1 -1
- package/src/prelude/any_value.hpp +221 -342
- package/src/prelude/any_value_access.hpp +168 -81
- package/src/prelude/any_value_defines.hpp +74 -35
- package/src/prelude/any_value_helpers.hpp +75 -180
- package/src/prelude/exception.hpp +1 -0
- package/src/prelude/exception_helpers.hpp +4 -4
- package/src/prelude/index.hpp +12 -2
- package/src/prelude/library/array.hpp +190 -0
- package/src/prelude/library/console.hpp +6 -5
- package/src/prelude/library/error.hpp +10 -8
- package/src/prelude/library/function.hpp +10 -0
- package/src/prelude/library/global.hpp +20 -0
- package/src/prelude/library/math.hpp +308 -0
- package/src/prelude/library/object.hpp +288 -0
- package/src/prelude/library/performance.hpp +1 -1
- package/src/prelude/library/process.hpp +39 -0
- package/src/prelude/library/promise.hpp +57 -55
- package/src/prelude/library/symbol.hpp +45 -57
- package/src/prelude/library/timer.hpp +6 -6
- package/src/prelude/types.hpp +54 -0
- package/src/prelude/utils/access.hpp +215 -11
- package/src/prelude/utils/assignment_operators.hpp +99 -0
- package/src/prelude/utils/log_any_value/array.hpp +8 -8
- package/src/prelude/utils/log_any_value/function.hpp +6 -4
- package/src/prelude/utils/log_any_value/object.hpp +41 -24
- package/src/prelude/utils/log_any_value/primitives.hpp +3 -1
- package/src/prelude/utils/operators.hpp +750 -274
- package/src/prelude/utils/well_known_symbols.hpp +12 -0
- package/src/prelude/values/array.hpp +8 -6
- package/src/prelude/values/async_iterator.hpp +79 -0
- package/src/prelude/values/descriptors.hpp +2 -2
- package/src/prelude/values/function.hpp +72 -62
- package/src/prelude/values/helpers/array.hpp +64 -28
- package/src/prelude/values/helpers/async_iterator.hpp +275 -0
- package/src/prelude/values/helpers/function.hpp +81 -92
- package/src/prelude/values/helpers/iterator.hpp +3 -3
- package/src/prelude/values/helpers/object.hpp +54 -9
- package/src/prelude/values/helpers/promise.hpp +13 -6
- package/src/prelude/values/iterator.hpp +1 -1
- package/src/prelude/values/object.hpp +10 -3
- package/src/prelude/values/promise.hpp +7 -11
- package/src/prelude/values/prototypes/array.hpp +851 -12
- package/src/prelude/values/prototypes/async_iterator.hpp +50 -0
- package/src/prelude/values/prototypes/function.hpp +2 -2
- package/src/prelude/values/prototypes/iterator.hpp +5 -5
- package/src/prelude/values/prototypes/number.hpp +153 -0
- package/src/prelude/values/prototypes/object.hpp +2 -2
- package/src/prelude/values/prototypes/promise.hpp +40 -30
- package/src/prelude/values/prototypes/string.hpp +28 -28
- package/src/prelude/values/prototypes/symbol.hpp +20 -3
- package/src/prelude/values/shape.hpp +52 -0
package/dist/analysis/scope.js
CHANGED
|
@@ -14,12 +14,17 @@ export const BUILTIN_OBJECTS = new Set([
|
|
|
14
14
|
{ name: "performance", isConst: false },
|
|
15
15
|
{ name: "global", isConst: false },
|
|
16
16
|
{ name: "globalThis", isConst: false },
|
|
17
|
+
{ name: "process", isConst: false },
|
|
17
18
|
{ name: "Error", isConst: false },
|
|
18
19
|
{ name: "Promise", isConst: false },
|
|
20
|
+
{ name: "Function", isConst: false },
|
|
19
21
|
{ name: "setTimeout", isConst: false },
|
|
20
22
|
{ name: "clearTimeout", isConst: false },
|
|
21
23
|
{ name: "setInterval", isConst: false },
|
|
22
24
|
{ name: "clearInterval", isConst: false },
|
|
25
|
+
{ name: "Array", isConst: false },
|
|
26
|
+
{ name: "Object", isConst: false },
|
|
27
|
+
{ name: "Math", isConst: false },
|
|
23
28
|
]);
|
|
24
29
|
// Represents a single scope (e.g., a function body or a block statement)
|
|
25
30
|
export class Scope {
|
|
@@ -79,11 +84,23 @@ export class ScopeManager {
|
|
|
79
84
|
}
|
|
80
85
|
// Defines a variable in the current scope.
|
|
81
86
|
define(name, type) {
|
|
87
|
+
// if (name === "named" || name === "letVal") console.log("Defining", name, "in scope. isBuiltin:", type.isBuiltin, " type:", type.type);
|
|
82
88
|
if (this.reservedKeywords.has(name) && !type.isBuiltin) {
|
|
83
89
|
throw new Error(`SyntaxError: Unexpected reserved word "${name}"`);
|
|
84
90
|
}
|
|
85
91
|
this.currentScope.define(name, type);
|
|
86
92
|
}
|
|
93
|
+
// Defines a `var` variable (hoisted to function or global scope).
|
|
94
|
+
defineVar(name, type) {
|
|
95
|
+
if (this.reservedKeywords.has(name) && !type.isBuiltin) {
|
|
96
|
+
throw new Error(`SyntaxError: Unexpected reserved word "${name}"`);
|
|
97
|
+
}
|
|
98
|
+
let scope = this.currentScope;
|
|
99
|
+
while (scope.parent && scope.ownerFunction === scope.parent.ownerFunction) {
|
|
100
|
+
scope = scope.parent;
|
|
101
|
+
}
|
|
102
|
+
scope.define(name, type);
|
|
103
|
+
}
|
|
87
104
|
// Looks up a variable's type information from the current scope upwards.
|
|
88
105
|
lookup(name) {
|
|
89
106
|
const scope = this.currentScope.findScopeFor(name);
|
|
@@ -362,6 +362,7 @@ export class TypeAnalyzer {
|
|
|
362
362
|
enter: (node) => {
|
|
363
363
|
if (ts.isVariableDeclaration(node)) {
|
|
364
364
|
const name = node.name.getText();
|
|
365
|
+
const isBlockScoped = (node.parent.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
|
|
365
366
|
const isConst = (node.parent.flags & ts.NodeFlags.Const) !== 0;
|
|
366
367
|
let type = "auto";
|
|
367
368
|
let needsHeap = false;
|
|
@@ -381,7 +382,12 @@ export class TypeAnalyzer {
|
|
|
381
382
|
isConst,
|
|
382
383
|
needsHeapAllocation: needsHeap,
|
|
383
384
|
};
|
|
384
|
-
|
|
385
|
+
if (isBlockScoped) {
|
|
386
|
+
this.scopeManager.define(name, typeInfo);
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
this.scopeManager.defineVar(name, typeInfo);
|
|
390
|
+
}
|
|
385
391
|
}
|
|
386
392
|
},
|
|
387
393
|
},
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export var DeclaredSymbolType;
|
|
2
|
+
(function (DeclaredSymbolType) {
|
|
3
|
+
DeclaredSymbolType["letOrConst"] = "letOrConst";
|
|
4
|
+
DeclaredSymbolType["function"] = "function";
|
|
5
|
+
DeclaredSymbolType["var"] = "var";
|
|
6
|
+
})(DeclaredSymbolType || (DeclaredSymbolType = {}));
|
|
7
|
+
export class DeclaredSymbols {
|
|
8
|
+
symbols;
|
|
9
|
+
constructor(...m) {
|
|
10
|
+
this.symbols = new Map();
|
|
11
|
+
m.forEach((ds) => ds.symbols.forEach((v, k) => this.symbols.set(k, v)));
|
|
12
|
+
}
|
|
13
|
+
has(name) {
|
|
14
|
+
return this.symbols.has(name);
|
|
15
|
+
}
|
|
16
|
+
get(name) {
|
|
17
|
+
return this.symbols.get(name);
|
|
18
|
+
}
|
|
19
|
+
set(name, value) {
|
|
20
|
+
return this.symbols.set(name, value);
|
|
21
|
+
}
|
|
22
|
+
update(name, update) {
|
|
23
|
+
const oldValue = this.get(name);
|
|
24
|
+
if (oldValue) {
|
|
25
|
+
const newValue = { ...oldValue, ...update };
|
|
26
|
+
return this.symbols.set(name, newValue);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
toSet() {
|
|
30
|
+
return new Set(this.symbols.keys());
|
|
31
|
+
}
|
|
32
|
+
}
|
package/dist/ast/types.js
CHANGED
|
@@ -1,7 +1 @@
|
|
|
1
1
|
import * as ts from "typescript";
|
|
2
|
-
export var DeclaredSymbolType;
|
|
3
|
-
(function (DeclaredSymbolType) {
|
|
4
|
-
DeclaredSymbolType["letOrConst"] = "letOrConst";
|
|
5
|
-
DeclaredSymbolType["function"] = "function";
|
|
6
|
-
DeclaredSymbolType["var"] = "var";
|
|
7
|
-
})(DeclaredSymbolType || (DeclaredSymbolType = {}));
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { COLORS } from "./colors";
|
|
3
|
+
export function parseArgs(rawArgs) {
|
|
4
|
+
let jsFilePathArg = null;
|
|
5
|
+
let isRelease = false;
|
|
6
|
+
let keepCpp = false;
|
|
7
|
+
let outputExePath = null;
|
|
8
|
+
let scriptArgs = [];
|
|
9
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
10
|
+
const arg = rawArgs[i];
|
|
11
|
+
if (!arg)
|
|
12
|
+
continue;
|
|
13
|
+
if (arg === "--") {
|
|
14
|
+
scriptArgs = rawArgs.slice(i + 1);
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
if (arg === "--release") {
|
|
18
|
+
isRelease = true;
|
|
19
|
+
}
|
|
20
|
+
else if (arg === "--keep-cpp") {
|
|
21
|
+
keepCpp = true;
|
|
22
|
+
}
|
|
23
|
+
else if (arg === "-o" || arg === "--output") {
|
|
24
|
+
if (i + 1 < rawArgs.length) {
|
|
25
|
+
outputExePath = rawArgs[i + 1] ?? null;
|
|
26
|
+
i++;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
console.error(`${COLORS.red}Error: --output requires a file path argument.${COLORS.reset}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else if (arg.startsWith("-")) {
|
|
34
|
+
console.warn(`${COLORS.yellow}Warning: Unknown argument '${arg}'${COLORS.reset}`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
if (jsFilePathArg) {
|
|
38
|
+
console.error(`${COLORS.red}Error: Multiple input files specified.${COLORS.reset}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
jsFilePathArg = arg;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (!jsFilePathArg) {
|
|
45
|
+
console.log(`${COLORS.bold}Usage:${COLORS.reset} jspp <path-to-js-file> [--release] [--keep-cpp] [-o <output-path>] [-- <args...>]`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
jsFilePath: path.resolve(process.cwd(), jsFilePathArg),
|
|
50
|
+
isRelease,
|
|
51
|
+
keepCpp,
|
|
52
|
+
outputExePath: outputExePath
|
|
53
|
+
? path.resolve(process.cwd(), outputExePath)
|
|
54
|
+
: null,
|
|
55
|
+
scriptArgs,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
export async function getLatestMtime(dirPath) {
|
|
4
|
+
let maxMtime = 0;
|
|
5
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
6
|
+
for (const entry of entries) {
|
|
7
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
8
|
+
if (entry.isDirectory()) {
|
|
9
|
+
const nestedMtime = await getLatestMtime(fullPath);
|
|
10
|
+
if (nestedMtime > maxMtime)
|
|
11
|
+
maxMtime = nestedMtime;
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
const stats = await fs.stat(fullPath);
|
|
15
|
+
if (stats.mtimeMs > maxMtime)
|
|
16
|
+
maxMtime = stats.mtimeMs;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return maxMtime;
|
|
20
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { COLORS } from "./colors";
|
|
2
|
+
export class Spinner {
|
|
3
|
+
frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
4
|
+
interval = null;
|
|
5
|
+
frameIndex = 0;
|
|
6
|
+
text;
|
|
7
|
+
constructor(text) {
|
|
8
|
+
this.text = text;
|
|
9
|
+
}
|
|
10
|
+
start() {
|
|
11
|
+
process.stdout.write("\x1b[?25l"); // Hide cursor
|
|
12
|
+
this.frameIndex = 0;
|
|
13
|
+
this.render();
|
|
14
|
+
this.interval = setInterval(() => {
|
|
15
|
+
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
16
|
+
this.render();
|
|
17
|
+
}, 80);
|
|
18
|
+
}
|
|
19
|
+
update(text) {
|
|
20
|
+
this.text = text;
|
|
21
|
+
this.render();
|
|
22
|
+
}
|
|
23
|
+
stop(symbol = "", color = COLORS.reset) {
|
|
24
|
+
if (this.interval) {
|
|
25
|
+
clearInterval(this.interval);
|
|
26
|
+
this.interval = null;
|
|
27
|
+
}
|
|
28
|
+
this.clearLine();
|
|
29
|
+
process.stdout.write(`${color}${symbol} ${COLORS.reset} ${this.text}\n`);
|
|
30
|
+
process.stdout.write("\x1b[?25h"); // Show cursor
|
|
31
|
+
}
|
|
32
|
+
succeed(text) {
|
|
33
|
+
if (text)
|
|
34
|
+
this.text = text;
|
|
35
|
+
this.stop("✔", COLORS.green);
|
|
36
|
+
}
|
|
37
|
+
fail(text) {
|
|
38
|
+
if (text)
|
|
39
|
+
this.text = text;
|
|
40
|
+
this.stop("✖", COLORS.red);
|
|
41
|
+
}
|
|
42
|
+
info(text) {
|
|
43
|
+
if (text)
|
|
44
|
+
this.text = text;
|
|
45
|
+
this.stop("ℹ", COLORS.cyan);
|
|
46
|
+
}
|
|
47
|
+
render() {
|
|
48
|
+
this.clearLine();
|
|
49
|
+
const frame = this.frames[this.frameIndex];
|
|
50
|
+
process.stdout.write(`${COLORS.cyan}${frame} ${COLORS.reset} ${this.text}`);
|
|
51
|
+
}
|
|
52
|
+
clearLine() {
|
|
53
|
+
process.stdout.write("\r\x1b[K");
|
|
54
|
+
}
|
|
55
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -1,63 +1,138 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import fs from "fs/promises";
|
|
3
3
|
import path from "path";
|
|
4
|
+
import pkg from "../package.json";
|
|
5
|
+
import { parseArgs } from "./cli-utils/args";
|
|
6
|
+
import { COLORS } from "./cli-utils/colors";
|
|
7
|
+
import { getLatestMtime } from "./cli-utils/file-utils";
|
|
8
|
+
import { Spinner } from "./cli-utils/spinner";
|
|
4
9
|
import { Interpreter } from "./index";
|
|
5
10
|
async function main() {
|
|
6
|
-
const
|
|
7
|
-
if (args.length === 0) {
|
|
8
|
-
console.log("Usage: jspp <path-to-js-file>");
|
|
9
|
-
process.exit(1);
|
|
10
|
-
}
|
|
11
|
-
const jsFilePath = path.resolve(process.cwd(), args[0]);
|
|
11
|
+
const { jsFilePath, isRelease, keepCpp, outputExePath, scriptArgs } = parseArgs(process.argv.slice(2));
|
|
12
12
|
const jsFileName = path.basename(jsFilePath, ".js");
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
const
|
|
13
|
+
const sourceDir = path.dirname(jsFilePath);
|
|
14
|
+
// Intermediate C++ file goes alongside the source JS file
|
|
15
|
+
const cppFilePath = path.join(sourceDir, `${jsFileName}.cpp`);
|
|
16
|
+
// Determine output executable path
|
|
17
|
+
let exeFilePath;
|
|
18
|
+
if (outputExePath) {
|
|
19
|
+
exeFilePath = outputExePath;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
23
|
+
exeFilePath = path.join(sourceDir, `${jsFileName}${ext}`);
|
|
24
|
+
}
|
|
25
|
+
// Mode Configuration
|
|
26
|
+
const mode = isRelease ? "release" : "debug";
|
|
27
|
+
console.log(`${COLORS.bold}JSPP Compiler${COLORS.reset} ${COLORS.dim}v${pkg.version}${COLORS.reset}`);
|
|
28
|
+
console.log(`Mode: ${isRelease ? COLORS.green : COLORS.yellow}${mode.toUpperCase()}${COLORS.reset}\n`);
|
|
29
|
+
const flags = isRelease
|
|
30
|
+
? ["-O3", "-DNDEBUG", "-Wa,-mbig-obj"]
|
|
31
|
+
: ["-O0", "-Wa,-mbig-obj"];
|
|
32
|
+
const pchDir = path.resolve(process.cwd(), "prelude-build", mode);
|
|
33
|
+
const spinner = new Spinner("Initializing...");
|
|
16
34
|
try {
|
|
35
|
+
spinner.start();
|
|
36
|
+
// 1. Interpreter Phase
|
|
37
|
+
spinner.update(`Reading ${path.basename(jsFilePath)}...`);
|
|
17
38
|
const jsCode = await fs.readFile(jsFilePath, "utf-8");
|
|
39
|
+
spinner.update("Transpiling to C++...");
|
|
18
40
|
const interpreter = new Interpreter();
|
|
19
41
|
const { cppCode, preludePath } = interpreter.interpret(jsCode);
|
|
20
|
-
|
|
21
|
-
await fs.mkdir(
|
|
42
|
+
// Ensure directory for cpp file exists (should exist as it's source dir, but for safety if we change logic)
|
|
43
|
+
await fs.mkdir(path.dirname(cppFilePath), { recursive: true });
|
|
22
44
|
await fs.writeFile(cppFilePath, cppCode);
|
|
23
|
-
|
|
24
|
-
|
|
45
|
+
spinner.succeed(`Generated cpp`);
|
|
46
|
+
// 2. Precompiled Header Check
|
|
47
|
+
spinner.text = "Checking precompiled headers...";
|
|
48
|
+
spinner.start();
|
|
49
|
+
const pchFile = path.join(pchDir, "index.hpp.gch");
|
|
50
|
+
let shouldRebuild = false;
|
|
51
|
+
try {
|
|
52
|
+
const pchStats = await fs.stat(pchFile);
|
|
53
|
+
const sourceMtime = await getLatestMtime(preludePath);
|
|
54
|
+
if (sourceMtime > pchStats.mtimeMs) {
|
|
55
|
+
shouldRebuild = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
shouldRebuild = true;
|
|
60
|
+
}
|
|
61
|
+
if (shouldRebuild) {
|
|
62
|
+
spinner.update("Rebuilding precompiled headers (this may take a while)...");
|
|
63
|
+
// Use spawn (async) instead of spawnSync to keep spinner alive
|
|
64
|
+
const rebuild = Bun.spawn({
|
|
65
|
+
cmd: ["bun", "run", "scripts/precompile-headers.ts"],
|
|
66
|
+
stdout: "pipe", // pipe to hide output unless error, or handle differently
|
|
67
|
+
stderr: "pipe",
|
|
68
|
+
});
|
|
69
|
+
const exitCode = await rebuild.exited;
|
|
70
|
+
if (exitCode !== 0) {
|
|
71
|
+
const stderr = await new Response(rebuild.stderr).text();
|
|
72
|
+
spinner.fail("Failed to rebuild precompiled headers");
|
|
73
|
+
console.error(stderr);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
spinner.succeed("Precompiled headers updated");
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
spinner.succeed("Precompiled headers");
|
|
80
|
+
}
|
|
81
|
+
// 3. Compilation Phase
|
|
82
|
+
spinner.text = `Compiling binary...`;
|
|
83
|
+
spinner.start();
|
|
84
|
+
// Ensure output directory exists
|
|
85
|
+
await fs.mkdir(path.dirname(exeFilePath), { recursive: true });
|
|
86
|
+
const compile = Bun.spawn({
|
|
25
87
|
cmd: [
|
|
26
88
|
"g++",
|
|
27
89
|
"-std=c++23",
|
|
90
|
+
...flags,
|
|
28
91
|
cppFilePath,
|
|
29
92
|
"-o",
|
|
30
93
|
exeFilePath,
|
|
31
94
|
"-I",
|
|
95
|
+
pchDir,
|
|
96
|
+
"-I",
|
|
32
97
|
preludePath,
|
|
33
|
-
"-O3",
|
|
34
|
-
"-DNDEBUG",
|
|
35
|
-
// "-include",
|
|
36
|
-
// path.join(process.cwd(), "prelude-build", "index.hpp"),
|
|
37
98
|
],
|
|
38
|
-
stdout: "
|
|
39
|
-
stderr: "
|
|
99
|
+
stdout: "pipe",
|
|
100
|
+
stderr: "pipe",
|
|
40
101
|
});
|
|
41
|
-
|
|
42
|
-
|
|
102
|
+
const compileExitCode = await compile.exited;
|
|
103
|
+
if (compileExitCode !== 0) {
|
|
104
|
+
const stderr = await new Response(compile.stderr).text();
|
|
105
|
+
spinner.fail(`Compilation failed`);
|
|
106
|
+
console.error(stderr);
|
|
43
107
|
process.exit(1);
|
|
44
108
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
109
|
+
spinner.succeed(`Compiled to ${COLORS.green}${COLORS.bold}${path.basename(exeFilePath)}${COLORS.reset}`);
|
|
110
|
+
// Clean up C++ file if not requested to keep
|
|
111
|
+
if (!keepCpp) {
|
|
112
|
+
try {
|
|
113
|
+
await fs.unlink(cppFilePath);
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
// Ignore error if file cannot be deleted
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// 4. Execution Phase
|
|
120
|
+
console.log(`\n${COLORS.cyan}--- Running Output ---${COLORS.reset}`);
|
|
121
|
+
const run = Bun.spawn({
|
|
122
|
+
cmd: [exeFilePath, ...scriptArgs],
|
|
49
123
|
stdout: "inherit",
|
|
50
124
|
stderr: "inherit",
|
|
51
125
|
});
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
126
|
+
const runExitCode = await run.exited;
|
|
127
|
+
console.log(`${COLORS.cyan}----------------------${COLORS.reset}\n`);
|
|
128
|
+
if (runExitCode !== 0) {
|
|
129
|
+
console.error(`${COLORS.red}Execution failed with exit code ${runExitCode}${COLORS.reset}`);
|
|
55
130
|
process.exit(1);
|
|
56
131
|
}
|
|
57
|
-
console.log(`Successfully ran ${exeFilePath}`);
|
|
58
132
|
}
|
|
59
133
|
catch (error) {
|
|
60
|
-
|
|
134
|
+
spinner.fail("An unexpected error occurred");
|
|
135
|
+
console.error(error);
|
|
61
136
|
process.exit(1);
|
|
62
137
|
}
|
|
63
138
|
}
|
|
@@ -20,7 +20,7 @@ export function visitClassDeclaration(node, context) {
|
|
|
20
20
|
const scope = this.getScopeForNode(extendsExpr);
|
|
21
21
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(extendsExpr.getText(), scope);
|
|
22
22
|
if (typeInfo) {
|
|
23
|
-
parentName = this.getDerefCode(parentName, this.getJsVarName(extendsExpr), typeInfo);
|
|
23
|
+
parentName = this.getDerefCode(parentName, this.getJsVarName(extendsExpr), context, typeInfo);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -42,16 +42,16 @@ export function visitClassDeclaration(node, context) {
|
|
|
42
42
|
// Default constructor
|
|
43
43
|
if (parentName) {
|
|
44
44
|
constructorLambda =
|
|
45
|
-
`jspp::AnyValue::make_class([=](const jspp::AnyValue& ${this.globalThisVar},
|
|
45
|
+
`jspp::AnyValue::make_class([=](const jspp::AnyValue& ${this.globalThisVar}, std::span<const jspp::AnyValue> args) mutable -> jspp::AnyValue {
|
|
46
46
|
auto __parent = ${parentName};
|
|
47
|
-
__parent.
|
|
48
|
-
return jspp::
|
|
47
|
+
__parent.call(${this.globalThisVar}, args, "super");
|
|
48
|
+
return jspp::Constants::UNDEFINED;
|
|
49
49
|
}, "${className}")`;
|
|
50
50
|
}
|
|
51
51
|
else {
|
|
52
52
|
constructorLambda =
|
|
53
|
-
`jspp::AnyValue::make_class([=](const jspp::AnyValue& ${this.globalThisVar},
|
|
54
|
-
return jspp::
|
|
53
|
+
`jspp::AnyValue::make_class([=](const jspp::AnyValue& ${this.globalThisVar}, std::span<const jspp::AnyValue> args) mutable -> jspp::AnyValue {
|
|
54
|
+
return jspp::Constants::UNDEFINED;
|
|
55
55
|
}, "${className}")`;
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -63,6 +63,10 @@ export function visitClassDeclaration(node, context) {
|
|
|
63
63
|
code +=
|
|
64
64
|
`${this.indent()}(*${className}).get_own_property("prototype").set_prototype(${parentName}.get_own_property("prototype"));\n`;
|
|
65
65
|
}
|
|
66
|
+
else {
|
|
67
|
+
code +=
|
|
68
|
+
`${this.indent()}(*${className}).get_own_property("prototype").set_prototype(::Object.get_own_property("prototype"));\n`;
|
|
69
|
+
}
|
|
66
70
|
// Members
|
|
67
71
|
for (const member of node.members) {
|
|
68
72
|
if (ts.isMethodDeclaration(member)) {
|