@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.
Files changed (71) hide show
  1. package/dist/analysis/scope.js +17 -0
  2. package/dist/analysis/typeAnalyzer.js +7 -1
  3. package/dist/ast/symbols.js +32 -0
  4. package/dist/ast/types.js +0 -6
  5. package/dist/cli-utils/args.js +57 -0
  6. package/dist/cli-utils/colors.js +9 -0
  7. package/dist/cli-utils/file-utils.js +20 -0
  8. package/dist/cli-utils/spinner.js +55 -0
  9. package/dist/cli.js +105 -30
  10. package/dist/core/codegen/class-handlers.js +10 -6
  11. package/dist/core/codegen/control-flow-handlers.js +57 -28
  12. package/dist/core/codegen/declaration-handlers.js +10 -6
  13. package/dist/core/codegen/expression-handlers.js +206 -61
  14. package/dist/core/codegen/function-handlers.js +203 -76
  15. package/dist/core/codegen/helpers.js +125 -28
  16. package/dist/core/codegen/index.js +23 -15
  17. package/dist/core/codegen/literal-handlers.js +15 -6
  18. package/dist/core/codegen/statement-handlers.js +282 -84
  19. package/dist/core/codegen/visitor.js +3 -1
  20. package/package.json +1 -1
  21. package/src/prelude/any_value.hpp +221 -342
  22. package/src/prelude/any_value_access.hpp +168 -81
  23. package/src/prelude/any_value_defines.hpp +74 -35
  24. package/src/prelude/any_value_helpers.hpp +75 -180
  25. package/src/prelude/exception.hpp +1 -0
  26. package/src/prelude/exception_helpers.hpp +4 -4
  27. package/src/prelude/index.hpp +12 -2
  28. package/src/prelude/library/array.hpp +190 -0
  29. package/src/prelude/library/console.hpp +6 -5
  30. package/src/prelude/library/error.hpp +10 -8
  31. package/src/prelude/library/function.hpp +10 -0
  32. package/src/prelude/library/global.hpp +20 -0
  33. package/src/prelude/library/math.hpp +308 -0
  34. package/src/prelude/library/object.hpp +288 -0
  35. package/src/prelude/library/performance.hpp +1 -1
  36. package/src/prelude/library/process.hpp +39 -0
  37. package/src/prelude/library/promise.hpp +57 -55
  38. package/src/prelude/library/symbol.hpp +45 -57
  39. package/src/prelude/library/timer.hpp +6 -6
  40. package/src/prelude/types.hpp +54 -0
  41. package/src/prelude/utils/access.hpp +215 -11
  42. package/src/prelude/utils/assignment_operators.hpp +99 -0
  43. package/src/prelude/utils/log_any_value/array.hpp +8 -8
  44. package/src/prelude/utils/log_any_value/function.hpp +6 -4
  45. package/src/prelude/utils/log_any_value/object.hpp +41 -24
  46. package/src/prelude/utils/log_any_value/primitives.hpp +3 -1
  47. package/src/prelude/utils/operators.hpp +750 -274
  48. package/src/prelude/utils/well_known_symbols.hpp +12 -0
  49. package/src/prelude/values/array.hpp +8 -6
  50. package/src/prelude/values/async_iterator.hpp +79 -0
  51. package/src/prelude/values/descriptors.hpp +2 -2
  52. package/src/prelude/values/function.hpp +72 -62
  53. package/src/prelude/values/helpers/array.hpp +64 -28
  54. package/src/prelude/values/helpers/async_iterator.hpp +275 -0
  55. package/src/prelude/values/helpers/function.hpp +81 -92
  56. package/src/prelude/values/helpers/iterator.hpp +3 -3
  57. package/src/prelude/values/helpers/object.hpp +54 -9
  58. package/src/prelude/values/helpers/promise.hpp +13 -6
  59. package/src/prelude/values/iterator.hpp +1 -1
  60. package/src/prelude/values/object.hpp +10 -3
  61. package/src/prelude/values/promise.hpp +7 -11
  62. package/src/prelude/values/prototypes/array.hpp +851 -12
  63. package/src/prelude/values/prototypes/async_iterator.hpp +50 -0
  64. package/src/prelude/values/prototypes/function.hpp +2 -2
  65. package/src/prelude/values/prototypes/iterator.hpp +5 -5
  66. package/src/prelude/values/prototypes/number.hpp +153 -0
  67. package/src/prelude/values/prototypes/object.hpp +2 -2
  68. package/src/prelude/values/prototypes/promise.hpp +40 -30
  69. package/src/prelude/values/prototypes/string.hpp +28 -28
  70. package/src/prelude/values/prototypes/symbol.hpp +20 -3
  71. package/src/prelude/values/shape.hpp +52 -0
@@ -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
- this.scopeManager.define(name, typeInfo);
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,9 @@
1
+ export const COLORS = {
2
+ reset: "\x1b[0m",
3
+ cyan: "\x1b[36m",
4
+ green: "\x1b[32m",
5
+ yellow: "\x1b[33m",
6
+ red: "\x1b[31m",
7
+ dim: "\x1b[2m",
8
+ bold: "\x1b[1m",
9
+ };
@@ -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 args = process.argv.slice(2);
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 outputDir = path.dirname(jsFilePath);
14
- const cppFilePath = path.join(outputDir, `${jsFileName}.cpp`);
15
- const exeFilePath = path.join(outputDir, `${jsFileName}.exe`);
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
- console.log(`Generated C++ code ${cppFilePath}...`);
21
- await fs.mkdir(outputDir, { recursive: true });
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
- console.log(`Compiling ${cppFilePath}...`);
24
- const compile = Bun.spawnSync({
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: "inherit",
39
- stderr: "inherit",
99
+ stdout: "pipe",
100
+ stderr: "pipe",
40
101
  });
41
- if (compile.exitCode !== 0) {
42
- console.error(`Compilation failed for ${cppFilePath}`);
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
- console.log(`Running ${exeFilePath}...`);
46
- console.log("\x1b[32m\n------start------\x1b[0m");
47
- const run = Bun.spawnSync({
48
- cmd: [exeFilePath],
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
- console.log("\x1b[32m\n------end--------\x1b[0m");
53
- if (run.exitCode !== 0) {
54
- console.error(`Execution failed for ${exeFilePath}`);
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
- console.error(`Error: ${error.message}`);
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}, const std::vector<jspp::AnyValue>& args) mutable -> jspp::AnyValue {
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.as_function("super")->call(${this.globalThisVar}, args);
48
- return jspp::AnyValue::make_undefined();
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}, const std::vector<jspp::AnyValue>& args) mutable -> jspp::AnyValue {
54
- return jspp::AnyValue::make_undefined();
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)) {