@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.
Files changed (127) hide show
  1. package/LICENSE +25 -25
  2. package/README.md +20 -12
  3. package/dist/cli/args.js +22 -0
  4. package/dist/cli/compiler.js +53 -0
  5. package/dist/cli/index.js +43 -107
  6. package/dist/cli/pch.js +71 -0
  7. package/dist/cli/runner.js +23 -0
  8. package/dist/cli/spinner.js +27 -11
  9. package/dist/cli/transpiler.js +20 -0
  10. package/dist/cli/utils.js +59 -0
  11. package/dist/cli/wasm.js +70 -0
  12. package/dist/index.js +17 -6
  13. package/dist/{analysis → interpreter/analysis}/scope.js +38 -3
  14. package/dist/{analysis → interpreter/analysis}/typeAnalyzer.js +563 -28
  15. package/dist/{core → interpreter/core}/codegen/class-handlers.js +1 -1
  16. package/dist/{core → interpreter/core}/codegen/control-flow-handlers.js +12 -11
  17. package/dist/{core → interpreter/core}/codegen/declaration-handlers.js +28 -9
  18. package/dist/{core → interpreter/core}/codegen/destructuring-handlers.js +9 -4
  19. package/dist/{core → interpreter/core}/codegen/expression-handlers.js +82 -88
  20. package/dist/{core → interpreter/core}/codegen/function-handlers.js +159 -46
  21. package/dist/{core → interpreter/core}/codegen/helpers.js +170 -25
  22. package/dist/interpreter/core/codegen/index.js +156 -0
  23. package/dist/{core → interpreter/core}/codegen/literal-handlers.js +9 -0
  24. package/dist/{core → interpreter/core}/codegen/statement-handlers.js +47 -7
  25. package/package.json +6 -4
  26. package/scripts/precompile-headers.ts +293 -50
  27. package/scripts/setup-compiler.ts +63 -63
  28. package/scripts/setup-emsdk.ts +114 -0
  29. package/src/prelude/any_value.cpp +888 -0
  30. package/src/prelude/any_value.hpp +29 -24
  31. package/src/prelude/{exception_helpers.hpp → exception.cpp} +53 -53
  32. package/src/prelude/exception.hpp +27 -27
  33. package/src/prelude/iterator_instantiations.hpp +10 -0
  34. package/src/prelude/{index.hpp → jspp.hpp} +13 -17
  35. package/src/prelude/library/array.cpp +191 -0
  36. package/src/prelude/library/array.hpp +5 -178
  37. package/src/prelude/library/boolean.cpp +30 -0
  38. package/src/prelude/library/boolean.hpp +14 -0
  39. package/src/prelude/library/console.cpp +125 -0
  40. package/src/prelude/library/console.hpp +9 -97
  41. package/src/prelude/library/error.cpp +100 -0
  42. package/src/prelude/library/error.hpp +8 -108
  43. package/src/prelude/library/function.cpp +69 -0
  44. package/src/prelude/library/function.hpp +6 -5
  45. package/src/prelude/library/global.cpp +98 -0
  46. package/src/prelude/library/global.hpp +12 -28
  47. package/src/prelude/library/global_usings.hpp +15 -0
  48. package/src/prelude/library/math.cpp +261 -0
  49. package/src/prelude/library/math.hpp +8 -288
  50. package/src/prelude/library/object.cpp +379 -0
  51. package/src/prelude/library/object.hpp +5 -267
  52. package/src/prelude/library/performance.cpp +21 -0
  53. package/src/prelude/library/performance.hpp +5 -20
  54. package/src/prelude/library/process.cpp +38 -0
  55. package/src/prelude/library/process.hpp +3 -31
  56. package/src/prelude/library/promise.cpp +131 -0
  57. package/src/prelude/library/promise.hpp +5 -116
  58. package/src/prelude/library/symbol.cpp +56 -0
  59. package/src/prelude/library/symbol.hpp +5 -46
  60. package/src/prelude/library/timer.cpp +88 -0
  61. package/src/prelude/library/timer.hpp +11 -87
  62. package/src/prelude/runtime.cpp +19 -0
  63. package/src/prelude/types.hpp +26 -20
  64. package/src/prelude/utils/access.hpp +123 -32
  65. package/src/prelude/utils/assignment_operators.hpp +119 -99
  66. package/src/prelude/utils/log_any_value/array.hpp +61 -40
  67. package/src/prelude/utils/log_any_value/function.hpp +39 -39
  68. package/src/prelude/utils/log_any_value/log_any_value.hpp +1 -1
  69. package/src/prelude/utils/log_any_value/object.hpp +60 -3
  70. package/src/prelude/utils/log_any_value/primitives.hpp +1 -1
  71. package/src/prelude/utils/operators.hpp +109 -94
  72. package/src/prelude/utils/operators_native.hpp +349 -0
  73. package/src/prelude/utils/well_known_symbols.hpp +24 -24
  74. package/src/prelude/values/array.cpp +1399 -0
  75. package/src/prelude/values/array.hpp +4 -0
  76. package/src/prelude/values/async_iterator.cpp +251 -0
  77. package/src/prelude/values/async_iterator.hpp +60 -32
  78. package/src/prelude/values/boolean.cpp +64 -0
  79. package/src/prelude/values/function.cpp +262 -0
  80. package/src/prelude/values/function.hpp +10 -30
  81. package/src/prelude/values/iterator.cpp +309 -0
  82. package/src/prelude/values/iterator.hpp +33 -64
  83. package/src/prelude/values/number.cpp +221 -0
  84. package/src/prelude/values/object.cpp +200 -0
  85. package/src/prelude/values/object.hpp +4 -0
  86. package/src/prelude/values/promise.cpp +479 -0
  87. package/src/prelude/values/promise.hpp +9 -2
  88. package/src/prelude/values/prototypes/array.hpp +46 -1348
  89. package/src/prelude/values/prototypes/async_iterator.hpp +19 -61
  90. package/src/prelude/values/prototypes/boolean.hpp +24 -0
  91. package/src/prelude/values/prototypes/function.hpp +7 -46
  92. package/src/prelude/values/prototypes/iterator.hpp +15 -191
  93. package/src/prelude/values/prototypes/number.hpp +30 -210
  94. package/src/prelude/values/prototypes/object.hpp +7 -23
  95. package/src/prelude/values/prototypes/promise.hpp +8 -186
  96. package/src/prelude/values/prototypes/string.hpp +28 -553
  97. package/src/prelude/values/prototypes/symbol.hpp +9 -70
  98. package/src/prelude/values/shape.hpp +52 -52
  99. package/src/prelude/values/string.cpp +485 -0
  100. package/src/prelude/values/symbol.cpp +89 -0
  101. package/src/prelude/values/symbol.hpp +101 -101
  102. package/dist/cli/file-utils.js +0 -20
  103. package/dist/cli-utils/args.js +0 -59
  104. package/dist/cli-utils/colors.js +0 -9
  105. package/dist/cli-utils/file-utils.js +0 -20
  106. package/dist/cli-utils/spinner.js +0 -55
  107. package/dist/cli.js +0 -153
  108. package/dist/core/codegen/index.js +0 -86
  109. package/src/prelude/any_value_access.hpp +0 -170
  110. package/src/prelude/any_value_defines.hpp +0 -190
  111. package/src/prelude/any_value_helpers.hpp +0 -374
  112. package/src/prelude/utils/operators_primitive.hpp +0 -337
  113. package/src/prelude/values/helpers/array.hpp +0 -199
  114. package/src/prelude/values/helpers/async_iterator.hpp +0 -275
  115. package/src/prelude/values/helpers/function.hpp +0 -109
  116. package/src/prelude/values/helpers/iterator.hpp +0 -145
  117. package/src/prelude/values/helpers/object.hpp +0 -104
  118. package/src/prelude/values/helpers/promise.hpp +0 -254
  119. package/src/prelude/values/helpers/string.hpp +0 -37
  120. package/src/prelude/values/helpers/symbol.hpp +0 -21
  121. /package/dist/{ast → interpreter/ast}/symbols.js +0 -0
  122. /package/dist/{ast → interpreter/ast}/types.js +0 -0
  123. /package/dist/{core → interpreter/core}/codegen/visitor.js +0 -0
  124. /package/dist/{core → interpreter/core}/constants.js +0 -0
  125. /package/dist/{core → interpreter/core}/error.js +0 -0
  126. /package/dist/{core → interpreter/core}/parser.js +0 -0
  127. /package/dist/{core → interpreter/core}/traverser.js +0 -0
@@ -0,0 +1,70 @@
1
+ import { spawn } from "child_process";
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import { Spinner } from "./spinner.js";
5
+ export async function setupEmsdk(pkgDir, spinner) {
6
+ spinner.text = "Checking Emscripten SDK...";
7
+ spinner.start();
8
+ // Ensure emsdk is set up
9
+ const setupEmsdk = spawn("bun", ["run", "scripts/setup-emsdk.ts"], {
10
+ cwd: pkgDir,
11
+ stdio: ["ignore", "pipe", "pipe"],
12
+ });
13
+ const setupExitCode = await new Promise((resolve) => {
14
+ setupEmsdk.on("close", (code) => resolve(code ?? 1));
15
+ });
16
+ if (setupExitCode !== 0) {
17
+ spinner.fail("Emscripten SDK setup failed");
18
+ process.exit(1);
19
+ }
20
+ spinner.stop();
21
+ }
22
+ export async function postProcessWasm(exeFilePath, wasmExports) {
23
+ const outputDir = path.dirname(exeFilePath);
24
+ const outputBaseName = path.basename(exeFilePath, ".js");
25
+ // Generate .d.ts
26
+ let dtsContent = "";
27
+ for (const exp of wasmExports) {
28
+ const params = exp.params.map((p) => `${p.name}: ${p.type}`)
29
+ .join(", ");
30
+ dtsContent +=
31
+ `export declare function wasm_export_${exp.jsName}(${params}): ${exp.returnType};\n`;
32
+ }
33
+ dtsContent += `export declare const Module: Promise<any>;\n`;
34
+ dtsContent += `export declare const load: () => typeof Module;\n`;
35
+ dtsContent +=
36
+ `declare const jsppModule: (options?: any) => Promise<any>;\n`;
37
+ dtsContent += `export default jsppModule;\n`;
38
+ const dtsPath = path.join(outputDir, `${outputBaseName}.d.ts`);
39
+ await fs.writeFile(dtsPath, dtsContent);
40
+ // Append exports to .js glue code
41
+ let jsGlue = await fs.readFile(exeFilePath, "utf-8");
42
+ // Emscripten with -sEXPORT_ES6=1 adds this at the end
43
+ const defaultExportStr = "export default jsppModule;";
44
+ if (jsGlue.trim().endsWith(defaultExportStr)) {
45
+ jsGlue = jsGlue.trim().substring(0, jsGlue.trim().length - defaultExportStr.length);
46
+ }
47
+ jsGlue += `\n\n// JSPP Named Exports\n`;
48
+ jsGlue += `let _notLoaded = true;\n`;
49
+ jsGlue += `let _resolve = () => {};\n`;
50
+ jsGlue += `let _reject = () => {};\n`;
51
+ jsGlue += `let _instance;\n`;
52
+ jsGlue +=
53
+ `const _getinstance=()=>{if(!_instance)throw new Error("Module not loaded");return _instance}\n`;
54
+ jsGlue +=
55
+ `export const Module = new Promise((res,rej)=>{_resolve=res;_reject=rej});\n`;
56
+ jsGlue += `export const load = async () => {\n`;
57
+ jsGlue += ` if (_notLoaded) {\n`;
58
+ jsGlue += ` _notLoaded = false;\n`;
59
+ jsGlue +=
60
+ ` jsppModule().then(m=>{_instance=m;_resolve(m)}).catch(e=>{_notLoaded=true;_reject(e)});\n`;
61
+ jsGlue += ` }\n`;
62
+ jsGlue += ` return Module;\n`;
63
+ jsGlue += `};\n`;
64
+ for (const exp of wasmExports) {
65
+ jsGlue +=
66
+ `export const wasm_export_${exp.jsName} = (...args) => _getinstance()._wasm_export_${exp.jsName}(...args);\n`;
67
+ }
68
+ jsGlue += `export default jsppModule;\n`;
69
+ await fs.writeFile(exeFilePath, jsGlue);
70
+ }
package/dist/index.js CHANGED
@@ -1,19 +1,30 @@
1
1
  import path from "path";
2
- import { TypeAnalyzer } from "./analysis/typeAnalyzer.js";
3
- import { CodeGenerator } from "./core/codegen/index.js";
4
- import { Parser } from "./core/parser.js";
2
+ import { TypeAnalyzer } from "./interpreter/analysis/typeAnalyzer.js";
3
+ import { CodeGenerator } from "./interpreter/core/codegen/index.js";
4
+ import { Parser } from "./interpreter/core/parser.js";
5
5
  export class Interpreter {
6
6
  parser = new Parser();
7
7
  analyzer = new TypeAnalyzer();
8
8
  generator = new CodeGenerator();
9
- interpret(code, fileName) {
9
+ interpret(code, fileName, target = "native") {
10
10
  const ast = this.parser.parse(code, fileName);
11
11
  this.analyzer.analyze(ast);
12
12
  const isTypescript = fileName
13
13
  ? path.extname(fileName) === ".ts"
14
14
  : false;
15
- const cppCode = this.generator.generate(ast, this.analyzer, isTypescript);
15
+ const cppCode = this.generator.generate(ast, this.analyzer, isTypescript, target === "wasm");
16
16
  const preludePath = path.resolve(import.meta.dirname, "..", "src", "prelude");
17
- return { cppCode, preludePath };
17
+ return {
18
+ cppCode,
19
+ preludePath,
20
+ wasmExports: this.generator.wasmExports.map((e) => ({
21
+ jsName: e.jsName,
22
+ params: e.params.map((p) => ({
23
+ name: p.name.getText(),
24
+ type: this.analyzer.inferNodeReturnType(p),
25
+ })),
26
+ returnType: "number", // Currently always number as wrappers use double
27
+ })),
28
+ };
18
29
  }
19
30
  }
@@ -7,6 +7,41 @@ export const RESERVED_KEYWORDS = new Set([
7
7
  "co_return",
8
8
  "co_await",
9
9
  ]);
10
+ export const RESERVED_VAR_NAMES = new Set([
11
+ "arguments",
12
+ "class",
13
+ "const",
14
+ "let",
15
+ "var",
16
+ "enum",
17
+ "false",
18
+ "true",
19
+ "continue",
20
+ "debugger",
21
+ "default",
22
+ "delete",
23
+ "do",
24
+ "else",
25
+ "export",
26
+ "extends",
27
+ "finally",
28
+ "for",
29
+ "function",
30
+ "if",
31
+ "import",
32
+ "in",
33
+ "instanceof",
34
+ "new",
35
+ "return",
36
+ "super",
37
+ "switch",
38
+ "this",
39
+ "throw",
40
+ "try",
41
+ "catch",
42
+ "typeof",
43
+ "void",
44
+ ]);
10
45
  export const BUILTIN_OBJECTS = new Set([
11
46
  { name: "undefined", isConst: true },
12
47
  { name: "null", isConst: true },
@@ -25,6 +60,7 @@ export const BUILTIN_OBJECTS = new Set([
25
60
  { name: "clearInterval", isConst: false },
26
61
  { name: "Array", isConst: false },
27
62
  { name: "Object", isConst: false },
63
+ { name: "Boolean", isConst: false },
28
64
  { name: "Math", isConst: false },
29
65
  ]);
30
66
  // Represents a single scope (e.g., a function body or a block statement)
@@ -57,7 +93,6 @@ export class Scope {
57
93
  export class ScopeManager {
58
94
  currentScope;
59
95
  allScopes = []; // Array to store all created scopes
60
- reservedKeywords = new Set(RESERVED_KEYWORDS);
61
96
  constructor() {
62
97
  const rootScope = new Scope(null, null); // The global scope
63
98
  this.currentScope = rootScope;
@@ -86,7 +121,7 @@ export class ScopeManager {
86
121
  // Defines a variable in the current scope.
87
122
  define(name, type) {
88
123
  // if (name === "named" || name === "letVal") console.log("Defining", name, "in scope. isBuiltin:", type.isBuiltin, " type:", type.type);
89
- if (this.reservedKeywords.has(name) && !type.isBuiltin) {
124
+ if (RESERVED_KEYWORDS.has(name) && !type.isBuiltin) {
90
125
  if (type.declaration) {
91
126
  throw new CompilerError(`Unexpected reserved word "${name}"`, type.declaration, "SyntaxError");
92
127
  }
@@ -96,7 +131,7 @@ export class ScopeManager {
96
131
  }
97
132
  // Defines a `var` variable (hoisted to function or global scope).
98
133
  defineVar(name, type) {
99
- if (this.reservedKeywords.has(name) && !type.isBuiltin) {
134
+ if (RESERVED_KEYWORDS.has(name) && !type.isBuiltin) {
100
135
  if (type.declaration) {
101
136
  throw new CompilerError(`Unexpected reserved word "${name}"`, type.declaration, "SyntaxError");
102
137
  }