@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,101 +1,101 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "types.hpp"
|
|
4
|
-
#include <atomic>
|
|
5
|
-
#include <string>
|
|
6
|
-
#include <unordered_map>
|
|
7
|
-
#include <unordered_set>
|
|
8
|
-
#include <optional>
|
|
9
|
-
|
|
10
|
-
namespace jspp
|
|
11
|
-
{
|
|
12
|
-
// Forward declaration of AnyValue
|
|
13
|
-
class AnyValue;
|
|
14
|
-
|
|
15
|
-
struct JsSymbol : HeapObject
|
|
16
|
-
{
|
|
17
|
-
std::string description;
|
|
18
|
-
std::string key; // Internal unique key used for AnyValue property maps
|
|
19
|
-
|
|
20
|
-
JsType get_heap_type() const override { return JsType::Symbol; }
|
|
21
|
-
|
|
22
|
-
// --- Registries ---
|
|
23
|
-
|
|
24
|
-
// 1. Global Symbol Registry (for Symbol.for/keyFor)
|
|
25
|
-
static std::unordered_map<std::string, JsSymbol*> ®istry()
|
|
26
|
-
{
|
|
27
|
-
static std::unordered_map<std::string, JsSymbol*> reg;
|
|
28
|
-
return reg;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// 2. All Internal Keys Registry (for robust Object.keys filtering)
|
|
32
|
-
static std::unordered_set<std::string> &internal_keys_registry()
|
|
33
|
-
{
|
|
34
|
-
static std::unordered_set<std::string> keys;
|
|
35
|
-
return keys;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
static bool is_internal_key(const std::string &k)
|
|
39
|
-
{
|
|
40
|
-
return internal_keys_registry().count(k) > 0;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// --- Constructors ---
|
|
44
|
-
|
|
45
|
-
// Standard Constructor (creates unique symbol)
|
|
46
|
-
JsSymbol(const std::string &desc) : description(desc)
|
|
47
|
-
{
|
|
48
|
-
static std::atomic<uint64_t> id_counter{0};
|
|
49
|
-
// Ensure unique internal key for property storage
|
|
50
|
-
key = "__Sym" + std::to_string(id_counter++) + "_" + desc;
|
|
51
|
-
|
|
52
|
-
// Register this key as a valid symbol key
|
|
53
|
-
internal_keys_registry().insert(key);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Constructor for Well-Known Symbols (fixed keys)
|
|
57
|
-
JsSymbol(const std::string &desc, const std::string &fixed_key)
|
|
58
|
-
: description(desc), key(fixed_key)
|
|
59
|
-
{
|
|
60
|
-
// Register this key as a valid symbol key
|
|
61
|
-
internal_keys_registry().insert(key);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// --- Global Registry API ---
|
|
65
|
-
|
|
66
|
-
// Implements Symbol.for(key)
|
|
67
|
-
static JsSymbol* for_global(const std::string ®istryKey)
|
|
68
|
-
{
|
|
69
|
-
auto ® = registry();
|
|
70
|
-
auto it = reg.find(registryKey);
|
|
71
|
-
if (it != reg.end())
|
|
72
|
-
{
|
|
73
|
-
return it->second;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Create new symbol with description = registryKey
|
|
77
|
-
auto newSym = new JsSymbol(registryKey);
|
|
78
|
-
newSym->ref(); // Keep it alive in registry
|
|
79
|
-
reg[registryKey] = newSym;
|
|
80
|
-
return newSym;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Implements Symbol.keyFor(sym)
|
|
84
|
-
static std::optional<std::string> key_for(const JsSymbol *sym)
|
|
85
|
-
{
|
|
86
|
-
auto ® = registry();
|
|
87
|
-
for (const auto &pair : reg)
|
|
88
|
-
{
|
|
89
|
-
if (pair.second == sym)
|
|
90
|
-
{
|
|
91
|
-
return pair.first;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return std::nullopt;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// --- Methods ---
|
|
98
|
-
std::string to_std_string() const;
|
|
99
|
-
AnyValue get_property(const std::string &key, const AnyValue &thisVal);
|
|
100
|
-
};
|
|
101
|
-
}
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include <atomic>
|
|
5
|
+
#include <string>
|
|
6
|
+
#include <unordered_map>
|
|
7
|
+
#include <unordered_set>
|
|
8
|
+
#include <optional>
|
|
9
|
+
|
|
10
|
+
namespace jspp
|
|
11
|
+
{
|
|
12
|
+
// Forward declaration of AnyValue
|
|
13
|
+
class AnyValue;
|
|
14
|
+
|
|
15
|
+
struct JsSymbol : HeapObject
|
|
16
|
+
{
|
|
17
|
+
std::string description;
|
|
18
|
+
std::string key; // Internal unique key used for AnyValue property maps
|
|
19
|
+
|
|
20
|
+
JsType get_heap_type() const override { return JsType::Symbol; }
|
|
21
|
+
|
|
22
|
+
// --- Registries ---
|
|
23
|
+
|
|
24
|
+
// 1. Global Symbol Registry (for Symbol.for/keyFor)
|
|
25
|
+
static std::unordered_map<std::string, JsSymbol*> ®istry()
|
|
26
|
+
{
|
|
27
|
+
static std::unordered_map<std::string, JsSymbol*> reg;
|
|
28
|
+
return reg;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 2. All Internal Keys Registry (for robust Object.keys filtering)
|
|
32
|
+
static std::unordered_set<std::string> &internal_keys_registry()
|
|
33
|
+
{
|
|
34
|
+
static std::unordered_set<std::string> keys;
|
|
35
|
+
return keys;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static bool is_internal_key(const std::string &k)
|
|
39
|
+
{
|
|
40
|
+
return internal_keys_registry().count(k) > 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// --- Constructors ---
|
|
44
|
+
|
|
45
|
+
// Standard Constructor (creates unique symbol)
|
|
46
|
+
JsSymbol(const std::string &desc) : description(desc)
|
|
47
|
+
{
|
|
48
|
+
static std::atomic<uint64_t> id_counter{0};
|
|
49
|
+
// Ensure unique internal key for property storage
|
|
50
|
+
key = "__Sym" + std::to_string(id_counter++) + "_" + desc;
|
|
51
|
+
|
|
52
|
+
// Register this key as a valid symbol key
|
|
53
|
+
internal_keys_registry().insert(key);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Constructor for Well-Known Symbols (fixed keys)
|
|
57
|
+
JsSymbol(const std::string &desc, const std::string &fixed_key)
|
|
58
|
+
: description(desc), key(fixed_key)
|
|
59
|
+
{
|
|
60
|
+
// Register this key as a valid symbol key
|
|
61
|
+
internal_keys_registry().insert(key);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// --- Global Registry API ---
|
|
65
|
+
|
|
66
|
+
// Implements Symbol.for(key)
|
|
67
|
+
static JsSymbol* for_global(const std::string ®istryKey)
|
|
68
|
+
{
|
|
69
|
+
auto ® = registry();
|
|
70
|
+
auto it = reg.find(registryKey);
|
|
71
|
+
if (it != reg.end())
|
|
72
|
+
{
|
|
73
|
+
return it->second;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Create new symbol with description = registryKey
|
|
77
|
+
auto newSym = new JsSymbol(registryKey);
|
|
78
|
+
newSym->ref(); // Keep it alive in registry
|
|
79
|
+
reg[registryKey] = newSym;
|
|
80
|
+
return newSym;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Implements Symbol.keyFor(sym)
|
|
84
|
+
static std::optional<std::string> key_for(const JsSymbol *sym)
|
|
85
|
+
{
|
|
86
|
+
auto ® = registry();
|
|
87
|
+
for (const auto &pair : reg)
|
|
88
|
+
{
|
|
89
|
+
if (pair.second == sym)
|
|
90
|
+
{
|
|
91
|
+
return pair.first;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return std::nullopt;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// --- Methods ---
|
|
98
|
+
std::string to_std_string() const;
|
|
99
|
+
AnyValue get_property(const std::string &key, const AnyValue &thisVal);
|
|
100
|
+
};
|
|
101
|
+
}
|
package/dist/cli/file-utils.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
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
|
-
}
|
package/dist/cli-utils/args.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import pkg from "../../package.json" with { type: "json" };
|
|
3
|
-
import { COLORS } from "./colors.js";
|
|
4
|
-
export function parseArgs(rawArgs) {
|
|
5
|
-
let jsFilePathArg = null;
|
|
6
|
-
let isRelease = false;
|
|
7
|
-
let keepCpp = false;
|
|
8
|
-
let outputExePath = null;
|
|
9
|
-
let scriptArgs = [];
|
|
10
|
-
for (let i = 0; i < rawArgs.length; i++) {
|
|
11
|
-
const arg = rawArgs[i];
|
|
12
|
-
if (!arg)
|
|
13
|
-
continue;
|
|
14
|
-
if (arg === "--") {
|
|
15
|
-
scriptArgs = rawArgs.slice(i + 1);
|
|
16
|
-
break;
|
|
17
|
-
}
|
|
18
|
-
if (arg === "--release") {
|
|
19
|
-
isRelease = true;
|
|
20
|
-
}
|
|
21
|
-
else if (arg === "--keep-cpp") {
|
|
22
|
-
keepCpp = true;
|
|
23
|
-
}
|
|
24
|
-
else if (arg === "-o" || arg === "--output") {
|
|
25
|
-
if (i + 1 < rawArgs.length) {
|
|
26
|
-
outputExePath = rawArgs[i + 1] ?? null;
|
|
27
|
-
i++;
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
console.error(`${COLORS.red}Error: --output requires a file path argument.${COLORS.reset}`);
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
else if (arg.startsWith("-")) {
|
|
35
|
-
console.warn(`${COLORS.yellow}Warning: Unknown argument '${arg}'${COLORS.reset}`);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
if (jsFilePathArg) {
|
|
39
|
-
console.error(`${COLORS.red}Error: Multiple input files specified.${COLORS.reset}`);
|
|
40
|
-
process.exit(1);
|
|
41
|
-
}
|
|
42
|
-
jsFilePathArg = arg;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (!jsFilePathArg) {
|
|
46
|
-
console.log(`${COLORS.bold}JSPP Compiler${COLORS.reset} ${COLORS.dim}v${pkg.version}${COLORS.reset}`);
|
|
47
|
-
console.log(`${COLORS.bold}Usage:${COLORS.reset} jspp <path-to-js-file> [--release] [--keep-cpp] [-o <output-path>] [-- <args...>]`);
|
|
48
|
-
process.exit(1);
|
|
49
|
-
}
|
|
50
|
-
return {
|
|
51
|
-
jsFilePath: path.resolve(process.cwd(), jsFilePathArg),
|
|
52
|
-
isRelease,
|
|
53
|
-
keepCpp,
|
|
54
|
-
outputExePath: outputExePath
|
|
55
|
-
? path.resolve(process.cwd(), outputExePath)
|
|
56
|
-
: null,
|
|
57
|
-
scriptArgs,
|
|
58
|
-
};
|
|
59
|
-
}
|
package/dist/cli-utils/colors.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { COLORS } from "./colors.js";
|
|
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
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from "child_process";
|
|
3
|
-
import fs from "fs/promises";
|
|
4
|
-
import path from "path";
|
|
5
|
-
import pkg from "../package.json" with { type: "json" };
|
|
6
|
-
import { parseArgs } from "./cli-utils/args.js";
|
|
7
|
-
import { COLORS } from "./cli-utils/colors.js";
|
|
8
|
-
import { getLatestMtime } from "./cli-utils/file-utils.js";
|
|
9
|
-
import { Spinner } from "./cli-utils/spinner.js";
|
|
10
|
-
import { Interpreter } from "./index.js";
|
|
11
|
-
const pkgDir = path.dirname(import.meta.dirname);
|
|
12
|
-
async function main() {
|
|
13
|
-
const { jsFilePath, isRelease, keepCpp, outputExePath, scriptArgs } = parseArgs(process.argv.slice(2));
|
|
14
|
-
const jsFileName = path.basename(jsFilePath, ".js");
|
|
15
|
-
const sourceDir = path.dirname(jsFilePath);
|
|
16
|
-
// Intermediate C++ file goes alongside the source JS file
|
|
17
|
-
const cppFilePath = path.join(sourceDir, `${jsFileName}.cpp`);
|
|
18
|
-
// Determine output executable path
|
|
19
|
-
let exeFilePath;
|
|
20
|
-
if (outputExePath) {
|
|
21
|
-
exeFilePath = outputExePath;
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
const ext = process.platform === "win32" ? ".exe" : "";
|
|
25
|
-
exeFilePath = path.join(sourceDir, `${jsFileName}${ext}`);
|
|
26
|
-
}
|
|
27
|
-
// Mode Configuration
|
|
28
|
-
const mode = isRelease ? "release" : "debug";
|
|
29
|
-
console.log(`${COLORS.bold}JSPP Compiler${COLORS.reset} ${COLORS.dim}v${pkg.version}${COLORS.reset}`);
|
|
30
|
-
console.log(`Mode: ${isRelease ? COLORS.green : COLORS.yellow}${mode.toUpperCase()}${COLORS.reset}\n`);
|
|
31
|
-
const flags = isRelease ? ["-O3", "-DNDEBUG"] : ["-O0"];
|
|
32
|
-
if (process.platform === "win32") {
|
|
33
|
-
flags.push("-Wa,-mbig-obj");
|
|
34
|
-
}
|
|
35
|
-
const pchDir = path.resolve(pkgDir, "prelude-build", mode);
|
|
36
|
-
const spinner = new Spinner("Initializing...");
|
|
37
|
-
try {
|
|
38
|
-
spinner.start();
|
|
39
|
-
// 1. Interpreter Phase
|
|
40
|
-
spinner.update(`Reading ${path.basename(jsFilePath)}...`);
|
|
41
|
-
const jsCode = await fs.readFile(jsFilePath, "utf-8");
|
|
42
|
-
spinner.update("Transpiling to C++...");
|
|
43
|
-
const interpreter = new Interpreter();
|
|
44
|
-
const { cppCode, preludePath } = interpreter.interpret(jsCode, jsFilePath);
|
|
45
|
-
// Ensure directory for cpp file exists (should exist as it's source dir, but for safety if we change logic)
|
|
46
|
-
await fs.mkdir(path.dirname(cppFilePath), { recursive: true });
|
|
47
|
-
await fs.writeFile(cppFilePath, cppCode);
|
|
48
|
-
spinner.succeed(`Generated cpp`);
|
|
49
|
-
// 2. Precompiled Header Check
|
|
50
|
-
spinner.text = "Checking precompiled headers...";
|
|
51
|
-
spinner.start();
|
|
52
|
-
const pchFile = path.join(pchDir, "index.hpp.gch");
|
|
53
|
-
let shouldRebuild = false;
|
|
54
|
-
try {
|
|
55
|
-
const pchStats = await fs.stat(pchFile);
|
|
56
|
-
const sourceMtime = await getLatestMtime(preludePath);
|
|
57
|
-
if (sourceMtime > pchStats.mtimeMs) {
|
|
58
|
-
shouldRebuild = true;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
catch (e) {
|
|
62
|
-
shouldRebuild = true;
|
|
63
|
-
}
|
|
64
|
-
if (shouldRebuild) {
|
|
65
|
-
spinner.update("Rebuilding precompiled headers (this may take a while)...");
|
|
66
|
-
// Use spawn (async) instead of spawnSync to keep spinner alive
|
|
67
|
-
const rebuild = spawn("bun", [
|
|
68
|
-
"run",
|
|
69
|
-
"scripts/precompile-headers.ts",
|
|
70
|
-
], {
|
|
71
|
-
cwd: pkgDir,
|
|
72
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
73
|
-
});
|
|
74
|
-
const stderrChunks = [];
|
|
75
|
-
if (rebuild.stderr) {
|
|
76
|
-
rebuild.stderr.on("data", (chunk) => stderrChunks.push(chunk));
|
|
77
|
-
}
|
|
78
|
-
const exitCode = await new Promise((resolve) => {
|
|
79
|
-
rebuild.on("close", (code) => resolve(code ?? 1));
|
|
80
|
-
});
|
|
81
|
-
if (exitCode !== 0) {
|
|
82
|
-
const stderr = Buffer.concat(stderrChunks).toString();
|
|
83
|
-
spinner.fail("Failed to rebuild precompiled headers");
|
|
84
|
-
console.error(stderr);
|
|
85
|
-
process.exit(1);
|
|
86
|
-
}
|
|
87
|
-
spinner.succeed("Precompiled headers updated");
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
spinner.succeed("Precompiled headers");
|
|
91
|
-
}
|
|
92
|
-
// 3. Compilation Phase
|
|
93
|
-
spinner.text = `Compiling binary...`;
|
|
94
|
-
spinner.start();
|
|
95
|
-
// Ensure output directory exists
|
|
96
|
-
await fs.mkdir(path.dirname(exeFilePath), { recursive: true });
|
|
97
|
-
const compile = spawn("g++", [
|
|
98
|
-
"-std=c++23",
|
|
99
|
-
...flags,
|
|
100
|
-
cppFilePath,
|
|
101
|
-
"-o",
|
|
102
|
-
exeFilePath,
|
|
103
|
-
"-I",
|
|
104
|
-
pchDir,
|
|
105
|
-
"-I",
|
|
106
|
-
preludePath,
|
|
107
|
-
], {
|
|
108
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
109
|
-
});
|
|
110
|
-
const compileStderrChunks = [];
|
|
111
|
-
if (compile.stderr) {
|
|
112
|
-
compile.stderr.on("data", (chunk) => compileStderrChunks.push(chunk));
|
|
113
|
-
}
|
|
114
|
-
const compileExitCode = await new Promise((resolve) => {
|
|
115
|
-
compile.on("close", (code) => resolve(code ?? 1));
|
|
116
|
-
});
|
|
117
|
-
if (compileExitCode !== 0) {
|
|
118
|
-
const stderr = Buffer.concat(compileStderrChunks).toString();
|
|
119
|
-
spinner.fail(`Compilation failed`);
|
|
120
|
-
console.error(stderr);
|
|
121
|
-
process.exit(1);
|
|
122
|
-
}
|
|
123
|
-
spinner.succeed(`Compiled to ${COLORS.green}${COLORS.bold}${path.basename(exeFilePath)}${COLORS.reset}`);
|
|
124
|
-
// Clean up C++ file if not requested to keep
|
|
125
|
-
if (!keepCpp) {
|
|
126
|
-
try {
|
|
127
|
-
await fs.unlink(cppFilePath);
|
|
128
|
-
}
|
|
129
|
-
catch (e) {
|
|
130
|
-
// Ignore error if file cannot be deleted
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
// 4. Execution Phase
|
|
134
|
-
console.log(`\n${COLORS.cyan}--- Running Output ---${COLORS.reset}`);
|
|
135
|
-
const run = spawn(exeFilePath, scriptArgs, {
|
|
136
|
-
stdio: "inherit",
|
|
137
|
-
});
|
|
138
|
-
const runExitCode = await new Promise((resolve) => {
|
|
139
|
-
run.on("close", (code) => resolve(code ?? 1));
|
|
140
|
-
});
|
|
141
|
-
console.log(`${COLORS.cyan}----------------------${COLORS.reset}\n`);
|
|
142
|
-
if (runExitCode !== 0) {
|
|
143
|
-
console.error(`${COLORS.red}Execution failed with exit code ${runExitCode}${COLORS.reset}`);
|
|
144
|
-
process.exit(1);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
catch (error) {
|
|
148
|
-
spinner.fail("An unexpected error occurred");
|
|
149
|
-
console.error(error);
|
|
150
|
-
process.exit(1);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
main();
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { DeclaredSymbols } from "../../ast/symbols.js";
|
|
2
|
-
import { generateLambdaComponents, generateNativeLambda, generateWrappedLambda, } from "./function-handlers.js";
|
|
3
|
-
import { escapeString, generateUniqueExceptionName, generateUniqueName, getDeclaredSymbols, getDerefCode, getJsVarName, getReturnCommand, getScopeForNode, hoistDeclaration, indent, isAsyncFunction, isBuiltinObject, isDeclarationCalledAsFunction, isDeclarationUsedAsValue, isDeclarationUsedBeforeInitialization, isGeneratorFunction, markSymbolAsInitialized, prepareScopeSymbolsForVisit, validateFunctionParams, } from "./helpers.js";
|
|
4
|
-
import { generateDestructuring } from "./destructuring-handlers.js";
|
|
5
|
-
import { visit } from "./visitor.js";
|
|
6
|
-
const MODULE_NAME = "__entry_point__";
|
|
7
|
-
export class CodeGenerator {
|
|
8
|
-
indentationLevel = 0;
|
|
9
|
-
typeAnalyzer;
|
|
10
|
-
isTypescript = false;
|
|
11
|
-
globalThisVar;
|
|
12
|
-
uniqueNameCounter = 0;
|
|
13
|
-
// visitor
|
|
14
|
-
visit = visit;
|
|
15
|
-
// helpers
|
|
16
|
-
getDeclaredSymbols = getDeclaredSymbols;
|
|
17
|
-
generateUniqueName = generateUniqueName;
|
|
18
|
-
generateUniqueExceptionName = generateUniqueExceptionName;
|
|
19
|
-
hoistDeclaration = hoistDeclaration;
|
|
20
|
-
getScopeForNode = getScopeForNode;
|
|
21
|
-
indent = indent;
|
|
22
|
-
escapeString = escapeString;
|
|
23
|
-
getJsVarName = getJsVarName;
|
|
24
|
-
getDerefCode = getDerefCode;
|
|
25
|
-
getReturnCommand = getReturnCommand;
|
|
26
|
-
isBuiltinObject = isBuiltinObject;
|
|
27
|
-
isGeneratorFunction = isGeneratorFunction;
|
|
28
|
-
isAsyncFunction = isAsyncFunction;
|
|
29
|
-
prepareScopeSymbolsForVisit = prepareScopeSymbolsForVisit;
|
|
30
|
-
markSymbolAsInitialized = markSymbolAsInitialized;
|
|
31
|
-
isDeclarationCalledAsFunction = isDeclarationCalledAsFunction;
|
|
32
|
-
isDeclarationUsedAsValue = isDeclarationUsedAsValue;
|
|
33
|
-
isDeclarationUsedBeforeInitialization = isDeclarationUsedBeforeInitialization;
|
|
34
|
-
validateFunctionParams = validateFunctionParams;
|
|
35
|
-
generateDestructuring = generateDestructuring;
|
|
36
|
-
// function handlers
|
|
37
|
-
generateLambdaComponents = generateLambdaComponents;
|
|
38
|
-
generateNativeLambda = generateNativeLambda;
|
|
39
|
-
generateWrappedLambda = generateWrappedLambda;
|
|
40
|
-
/**
|
|
41
|
-
* Main entry point for the code generation process.
|
|
42
|
-
*/
|
|
43
|
-
generate(ast, analyzer, isTypescript) {
|
|
44
|
-
this.typeAnalyzer = analyzer;
|
|
45
|
-
this.isTypescript = isTypescript;
|
|
46
|
-
this.globalThisVar = this.generateUniqueName("__this_val__", this.getDeclaredSymbols(ast));
|
|
47
|
-
const declarations = `#include "index.hpp"\n\n`;
|
|
48
|
-
let containerCode = `jspp::JsPromise ${MODULE_NAME}() {\n`;
|
|
49
|
-
this.indentationLevel++;
|
|
50
|
-
containerCode +=
|
|
51
|
-
`${this.indent()}jspp::AnyValue ${this.globalThisVar} = global;\n`;
|
|
52
|
-
containerCode += this.visit(ast, {
|
|
53
|
-
currentScopeNode: ast,
|
|
54
|
-
isMainContext: true,
|
|
55
|
-
isInsideFunction: true,
|
|
56
|
-
isFunctionBody: true,
|
|
57
|
-
isInsideAsyncFunction: true,
|
|
58
|
-
globalScopeSymbols: new DeclaredSymbols(),
|
|
59
|
-
localScopeSymbols: new DeclaredSymbols(),
|
|
60
|
-
});
|
|
61
|
-
this.indentationLevel--;
|
|
62
|
-
containerCode += " co_return jspp::Constants::UNDEFINED;\n";
|
|
63
|
-
containerCode += "}\n\n";
|
|
64
|
-
let mainCode = "int main(int argc, char** argv) {\n";
|
|
65
|
-
mainCode += ` try {\n`;
|
|
66
|
-
mainCode += ` jspp::setup_process_argv(argc, argv);\n`;
|
|
67
|
-
mainCode += ` auto p = ${MODULE_NAME}();\n`;
|
|
68
|
-
mainCode += ` p.then(nullptr, [](jspp::AnyValue err) {\n`;
|
|
69
|
-
mainCode +=
|
|
70
|
-
` auto error = std::make_shared<jspp::AnyValue>(err);\n`;
|
|
71
|
-
mainCode +=
|
|
72
|
-
` console.call_own_property("error", std::span<const jspp::AnyValue>((const jspp::AnyValue[]){*error}, 1));\n`;
|
|
73
|
-
mainCode += ` std::exit(1);\n`;
|
|
74
|
-
mainCode += ` });\n`;
|
|
75
|
-
mainCode += ` jspp::Scheduler::instance().run();\n`;
|
|
76
|
-
mainCode += ` } catch (const std::exception& ex) {\n`;
|
|
77
|
-
mainCode +=
|
|
78
|
-
" auto error = std::make_shared<jspp::AnyValue>(jspp::Exception::exception_to_any_value(ex));\n";
|
|
79
|
-
mainCode +=
|
|
80
|
-
` console.call_own_property("error", std::span<const jspp::AnyValue>((const jspp::AnyValue[]){*error}, 1));\n`;
|
|
81
|
-
mainCode += ` return 1;\n`;
|
|
82
|
-
mainCode += ` }\n`;
|
|
83
|
-
mainCode += " return 0;\n}";
|
|
84
|
-
return declarations + containerCode + mainCode;
|
|
85
|
-
}
|
|
86
|
-
}
|