@ugo-studio/jspp 0.2.2 → 0.2.4
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/README.md +4 -4
- package/dist/analysis/typeAnalyzer.js +25 -14
- package/dist/cli-utils/args.js +2 -2
- package/dist/cli-utils/spinner.js +1 -1
- package/dist/cli.js +8 -8
- package/dist/core/codegen/class-handlers.js +2 -2
- package/dist/core/codegen/control-flow-handlers.js +2 -2
- package/dist/core/codegen/declaration-handlers.js +1 -1
- package/dist/core/codegen/expression-handlers.js +1 -1
- package/dist/core/codegen/function-handlers.js +3 -3
- package/dist/core/codegen/helpers.js +3 -3
- package/dist/core/codegen/index.js +4 -4
- package/dist/core/codegen/literal-handlers.js +1 -1
- package/dist/core/codegen/statement-handlers.js +3 -3
- package/dist/core/codegen/visitor.js +8 -8
- package/dist/index.js +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,8 +51,8 @@ To contribute to JSPP or run its test suite, follow these steps:
|
|
|
51
51
|
|
|
52
52
|
### Prerequisites
|
|
53
53
|
|
|
54
|
-
- **
|
|
55
|
-
- [Install
|
|
54
|
+
- **Node.js:** This project uses Node.js for package management and script execution.
|
|
55
|
+
- [Install Node.js >= v20.0.0](https://nodejs.org/)
|
|
56
56
|
- **C++ Compiler:** A compiler with support for C++23 is required. This project is tested with `g++`.
|
|
57
57
|
- `g++` (MinGW on Windows, or available via build-essentials on Linux)
|
|
58
58
|
|
|
@@ -64,7 +64,7 @@ To contribute to JSPP or run its test suite, follow these steps:
|
|
|
64
64
|
```
|
|
65
65
|
2. Install dependencies:
|
|
66
66
|
```sh
|
|
67
|
-
|
|
67
|
+
npm install
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
## Usage
|
|
@@ -88,7 +88,7 @@ The transpiled C++ file and executable will be generated in the same directory a
|
|
|
88
88
|
You can also run the test suite, which will transpile all the JavaScript test cases in `test/cases/`, build the resulting C++ files, and run them.
|
|
89
89
|
|
|
90
90
|
```sh
|
|
91
|
-
|
|
91
|
+
npm test
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
## Roadmap
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as ts from "typescript";
|
|
2
|
-
import { isBuiltinObject } from "../core/codegen/helpers";
|
|
3
|
-
import { Traverser } from "../core/traverser";
|
|
4
|
-
import { Scope, ScopeManager } from "./scope";
|
|
2
|
+
import { isBuiltinObject } from "../core/codegen/helpers.js";
|
|
3
|
+
import { Traverser } from "../core/traverser.js";
|
|
4
|
+
import { Scope, ScopeManager } from "./scope.js";
|
|
5
5
|
export class TypeAnalyzer {
|
|
6
6
|
traverser = new Traverser();
|
|
7
7
|
scopeManager = new ScopeManager();
|
|
@@ -19,7 +19,8 @@ export class TypeAnalyzer {
|
|
|
19
19
|
const definingScope = this.scopeManager.currentScope
|
|
20
20
|
.findScopeFor(name);
|
|
21
21
|
if (definingScope) {
|
|
22
|
-
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
22
|
+
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
23
|
+
null;
|
|
23
24
|
const definingFunc = definingScope.ownerFunction;
|
|
24
25
|
if (definingFunc !== currentFuncNode) {
|
|
25
26
|
const typeInfo = this.scopeManager.lookup(name);
|
|
@@ -34,7 +35,8 @@ export class TypeAnalyzer {
|
|
|
34
35
|
// Enter new scope for any block-like structure
|
|
35
36
|
Block: {
|
|
36
37
|
enter: (node, parent) => {
|
|
37
|
-
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
38
|
+
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
39
|
+
null;
|
|
38
40
|
this.scopeManager.enterScope(currentFuncNode);
|
|
39
41
|
this.nodeToScope.set(node, this.scopeManager.currentScope);
|
|
40
42
|
if (parent && ts.isCatchClause(parent) &&
|
|
@@ -57,7 +59,8 @@ export class TypeAnalyzer {
|
|
|
57
59
|
ForStatement: {
|
|
58
60
|
enter: (node) => {
|
|
59
61
|
this.loopDepth++;
|
|
60
|
-
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
62
|
+
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
63
|
+
null;
|
|
61
64
|
this.scopeManager.enterScope(currentFuncNode);
|
|
62
65
|
this.nodeToScope.set(node, this.scopeManager.currentScope);
|
|
63
66
|
},
|
|
@@ -69,7 +72,8 @@ export class TypeAnalyzer {
|
|
|
69
72
|
ForOfStatement: {
|
|
70
73
|
enter: (node) => {
|
|
71
74
|
this.loopDepth++;
|
|
72
|
-
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
75
|
+
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
76
|
+
null;
|
|
73
77
|
this.scopeManager.enterScope(currentFuncNode);
|
|
74
78
|
this.nodeToScope.set(node, this.scopeManager.currentScope);
|
|
75
79
|
},
|
|
@@ -81,7 +85,8 @@ export class TypeAnalyzer {
|
|
|
81
85
|
ForInStatement: {
|
|
82
86
|
enter: (node) => {
|
|
83
87
|
this.loopDepth++;
|
|
84
|
-
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
88
|
+
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
89
|
+
null;
|
|
85
90
|
this.scopeManager.enterScope(currentFuncNode);
|
|
86
91
|
this.nodeToScope.set(node, this.scopeManager.currentScope);
|
|
87
92
|
const forIn = node;
|
|
@@ -112,7 +117,8 @@ export class TypeAnalyzer {
|
|
|
112
117
|
WhileStatement: {
|
|
113
118
|
enter: (node) => {
|
|
114
119
|
this.loopDepth++;
|
|
115
|
-
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
120
|
+
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
121
|
+
null;
|
|
116
122
|
this.scopeManager.enterScope(currentFuncNode);
|
|
117
123
|
this.nodeToScope.set(node, this.scopeManager.currentScope);
|
|
118
124
|
},
|
|
@@ -124,7 +130,8 @@ export class TypeAnalyzer {
|
|
|
124
130
|
DoStatement: {
|
|
125
131
|
enter: (node) => {
|
|
126
132
|
this.loopDepth++;
|
|
127
|
-
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
133
|
+
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
134
|
+
null;
|
|
128
135
|
this.scopeManager.enterScope(currentFuncNode);
|
|
129
136
|
this.nodeToScope.set(node, this.scopeManager.currentScope);
|
|
130
137
|
},
|
|
@@ -136,7 +143,8 @@ export class TypeAnalyzer {
|
|
|
136
143
|
SwitchStatement: {
|
|
137
144
|
enter: (node) => {
|
|
138
145
|
this.switchDepth++;
|
|
139
|
-
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
146
|
+
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
147
|
+
null;
|
|
140
148
|
this.scopeManager.enterScope(currentFuncNode);
|
|
141
149
|
this.nodeToScope.set(node, this.scopeManager.currentScope);
|
|
142
150
|
},
|
|
@@ -292,7 +300,8 @@ export class TypeAnalyzer {
|
|
|
292
300
|
};
|
|
293
301
|
this.scopeManager.define(name, typeInfo);
|
|
294
302
|
}
|
|
295
|
-
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
303
|
+
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
304
|
+
null;
|
|
296
305
|
this.scopeManager.enterScope(currentFuncNode);
|
|
297
306
|
this.nodeToScope.set(node, this.scopeManager.currentScope);
|
|
298
307
|
},
|
|
@@ -362,7 +371,8 @@ export class TypeAnalyzer {
|
|
|
362
371
|
enter: (node) => {
|
|
363
372
|
if (ts.isVariableDeclaration(node)) {
|
|
364
373
|
const name = node.name.getText();
|
|
365
|
-
const isBlockScoped = (node.parent.flags &
|
|
374
|
+
const isBlockScoped = (node.parent.flags &
|
|
375
|
+
(ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
|
|
366
376
|
const isConst = (node.parent.flags & ts.NodeFlags.Const) !== 0;
|
|
367
377
|
let type = "auto";
|
|
368
378
|
let needsHeap = false;
|
|
@@ -396,7 +406,8 @@ export class TypeAnalyzer {
|
|
|
396
406
|
if (ts.isIdentifier(node)) {
|
|
397
407
|
if (isBuiltinObject.call(this, node))
|
|
398
408
|
return;
|
|
399
|
-
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
409
|
+
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
410
|
+
null;
|
|
400
411
|
if (currentFuncNode &&
|
|
401
412
|
(ts.isFunctionDeclaration(currentFuncNode) ||
|
|
402
413
|
ts.isFunctionExpression(currentFuncNode)) &&
|
package/dist/cli-utils/args.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
-
import pkg from "../../package.json";
|
|
3
|
-
import { COLORS } from "./colors";
|
|
2
|
+
import pkg from "../../package.json" with { type: "json" };
|
|
3
|
+
import { COLORS } from "./colors.js";
|
|
4
4
|
export function parseArgs(rawArgs) {
|
|
5
5
|
let jsFilePathArg = null;
|
|
6
6
|
let isRelease = false;
|
package/dist/cli.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
import { spawn } from "child_process";
|
|
3
3
|
import fs from "fs/promises";
|
|
4
4
|
import path from "path";
|
|
5
|
-
import pkg from "../package.json";
|
|
6
|
-
import { parseArgs } from "./cli-utils/args";
|
|
7
|
-
import { COLORS } from "./cli-utils/colors";
|
|
8
|
-
import { getLatestMtime } from "./cli-utils/file-utils";
|
|
9
|
-
import { Spinner } from "./cli-utils/spinner";
|
|
10
|
-
import { Interpreter } from "./index";
|
|
11
|
-
const pkgDir = path.dirname(
|
|
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
12
|
async function main() {
|
|
13
13
|
const { jsFilePath, isRelease, keepCpp, outputExePath, scriptArgs } = parseArgs(process.argv.slice(2));
|
|
14
14
|
const jsFileName = path.basename(jsFilePath, ".js");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { visitObjectPropertyName } from "./expression-handlers.js";
|
|
3
|
+
import { CodeGenerator } from "./index.js";
|
|
4
4
|
export function visitClassDeclaration(node, context) {
|
|
5
5
|
const className = node.name.getText();
|
|
6
6
|
// Check extends
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import { DeclaredSymbols, DeclaredSymbolType } from "../../ast/symbols";
|
|
3
|
-
import { CodeGenerator } from "./";
|
|
2
|
+
import { DeclaredSymbols, DeclaredSymbolType } from "../../ast/symbols.js";
|
|
3
|
+
import { CodeGenerator } from "./index.js";
|
|
4
4
|
export function visitForStatement(node, context) {
|
|
5
5
|
const forStmt = node;
|
|
6
6
|
let code = "";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import { DeclaredSymbols } from "../../ast/symbols";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { DeclaredSymbols } from "../../ast/symbols.js";
|
|
3
|
+
import { collectFunctionScopedDeclarations } from "./helpers.js";
|
|
4
|
+
import { CodeGenerator } from "./index.js";
|
|
5
5
|
export function generateLambda(node, context, options) {
|
|
6
6
|
const isAssignment = options?.isAssignment || false;
|
|
7
7
|
const capture = options?.capture || "[=]";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import { BUILTIN_OBJECTS, Scope } from "../../analysis/scope";
|
|
3
|
-
import { DeclaredSymbols, DeclaredSymbolType } from "../../ast/symbols";
|
|
4
|
-
import { CodeGenerator } from "./";
|
|
2
|
+
import { BUILTIN_OBJECTS, Scope } from "../../analysis/scope.js";
|
|
3
|
+
import { DeclaredSymbols, DeclaredSymbolType } from "../../ast/symbols.js";
|
|
4
|
+
import { CodeGenerator } from "./index.js";
|
|
5
5
|
export function isBuiltinObject(node) {
|
|
6
6
|
return BUILTIN_OBJECTS.values().some((obj) => obj.name === node.text);
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { DeclaredSymbols } from "../../ast/symbols";
|
|
2
|
-
import { generateLambda } from "./function-handlers";
|
|
3
|
-
import { escapeString, generateUniqueExceptionName, generateUniqueName, getDeclaredSymbols, getDerefCode, getJsVarName, getReturnCommand, getScopeForNode, hoistDeclaration, indent, isAsyncFunction, isBuiltinObject, isGeneratorFunction, markSymbolAsChecked, prepareScopeSymbolsForVisit, } from "./helpers";
|
|
4
|
-
import { visit } from "./visitor";
|
|
1
|
+
import { DeclaredSymbols } from "../../ast/symbols.js";
|
|
2
|
+
import { generateLambda } from "./function-handlers.js";
|
|
3
|
+
import { escapeString, generateUniqueExceptionName, generateUniqueName, getDeclaredSymbols, getDerefCode, getJsVarName, getReturnCommand, getScopeForNode, hoistDeclaration, indent, isAsyncFunction, isBuiltinObject, isGeneratorFunction, markSymbolAsChecked, prepareScopeSymbolsForVisit, } from "./helpers.js";
|
|
4
|
+
import { visit } from "./visitor.js";
|
|
5
5
|
const MODULE_NAME = "__main_function__";
|
|
6
6
|
export class CodeGenerator {
|
|
7
7
|
indentationLevel = 0;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import { DeclaredSymbols } from "../../ast/symbols";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { DeclaredSymbols } from "../../ast/symbols.js";
|
|
3
|
+
import { collectBlockScopedDeclarations, collectFunctionScopedDeclarations, } from "./helpers.js";
|
|
4
|
+
import { CodeGenerator } from "./index.js";
|
|
5
5
|
export function visitSourceFile(node, context) {
|
|
6
6
|
const sourceFile = node;
|
|
7
7
|
let code = "";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { visitFalseKeyword, visitIdentifier, visitNoSubstitutionTemplateLiteral, visitNullKeyword, visitNumericLiteral, visitStringLiteral, visitThisKeyword, visitTrueKeyword, visitUndefinedKeyword, } from "./literal-handlers";
|
|
9
|
-
import { visitBlock, visitBreakStatement, visitCatchClause, visitContinueStatement, visitExpressionStatement, visitIfStatement, visitLabeledStatement, visitReturnStatement, visitSourceFile, visitThrowStatement, visitTryStatement, visitVariableStatement, visitYieldExpression, } from "./statement-handlers";
|
|
2
|
+
import { visitClassDeclaration } from "./class-handlers.js";
|
|
3
|
+
import { visitCaseClause, visitDefaultClause, visitDoStatement, visitForInStatement, visitForOfStatement, visitForStatement, visitSwitchStatement, visitWhileStatement, } from "./control-flow-handlers.js";
|
|
4
|
+
import { visitVariableDeclaration, visitVariableDeclarationList, } from "./declaration-handlers.js";
|
|
5
|
+
import { visitArrayLiteralExpression, visitAwaitExpression, visitBinaryExpression, visitCallExpression, visitConditionalExpression, visitDeleteExpression, visitElementAccessExpression, visitNewExpression, visitObjectLiteralExpression, visitParenthesizedExpression, visitPostfixUnaryExpression, visitPrefixUnaryExpression, visitPropertyAccessExpression, visitTemplateExpression, visitTypeOfExpression, visitVoidExpression, } from "./expression-handlers.js";
|
|
6
|
+
import { visitArrowFunction, visitFunctionDeclaration, visitFunctionExpression, } from "./function-handlers.js";
|
|
7
|
+
import { CodeGenerator } from "./index.js";
|
|
8
|
+
import { visitFalseKeyword, visitIdentifier, visitNoSubstitutionTemplateLiteral, visitNullKeyword, visitNumericLiteral, visitStringLiteral, visitThisKeyword, visitTrueKeyword, visitUndefinedKeyword, } from "./literal-handlers.js";
|
|
9
|
+
import { visitBlock, visitBreakStatement, visitCatchClause, visitContinueStatement, visitExpressionStatement, visitIfStatement, visitLabeledStatement, visitReturnStatement, visitSourceFile, visitThrowStatement, visitTryStatement, visitVariableStatement, visitYieldExpression, } from "./statement-handlers.js";
|
|
10
10
|
export function visit(node, context) {
|
|
11
11
|
if (ts.isFunctionDeclaration(node)) {
|
|
12
12
|
return visitFunctionDeclaration.call(this, node, context);
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
-
import { TypeAnalyzer } from "./analysis/typeAnalyzer";
|
|
3
|
-
import { CodeGenerator } from "./core/codegen";
|
|
4
|
-
import { Parser } from "./core/parser";
|
|
2
|
+
import { TypeAnalyzer } from "./analysis/typeAnalyzer.js";
|
|
3
|
+
import { CodeGenerator } from "./core/codegen/index.js";
|
|
4
|
+
import { Parser } from "./core/parser.js";
|
|
5
5
|
export class Interpreter {
|
|
6
6
|
parser = new Parser();
|
|
7
7
|
analyzer = new TypeAnalyzer();
|
|
@@ -10,7 +10,7 @@ export class Interpreter {
|
|
|
10
10
|
const ast = this.parser.parse(jsCode);
|
|
11
11
|
this.analyzer.analyze(ast);
|
|
12
12
|
const cppCode = this.generator.generate(ast, this.analyzer);
|
|
13
|
-
const preludePath = path.resolve(
|
|
13
|
+
const preludePath = path.resolve(import.meta.dirname, "..", "src", "prelude");
|
|
14
14
|
return { cppCode, preludePath };
|
|
15
15
|
}
|
|
16
16
|
}
|
package/package.json
CHANGED