@ugo-studio/jspp 0.1.2 → 0.1.3
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 +3 -1
- package/dist/analysis/scope.js +22 -11
- package/dist/analysis/typeAnalyzer.js +4 -3
- package/dist/cli.js +2 -2
- package/dist/core/codegen/expression-handlers.js +10 -6
- package/dist/core/codegen/function-handlers.js +27 -6
- package/dist/core/codegen/helpers.js +12 -8
- package/dist/core/codegen/index.js +3 -1
- package/dist/core/codegen/statement-handlers.js +53 -16
- package/dist/core/codegen/visitor.js +7 -1
- package/package.json +1 -1
- package/src/prelude/access.hpp +8 -3
- package/src/prelude/any_value.hpp +141 -241
- package/src/prelude/any_value_helpers.hpp +225 -0
- package/src/prelude/error_helpers.hpp +3 -3
- package/src/prelude/index.hpp +17 -3
- package/src/prelude/library/console.hpp +7 -7
- package/src/prelude/library/performance.hpp +25 -0
- package/src/prelude/library/symbol.hpp +60 -3
- package/src/prelude/log_string.hpp +10 -6
- package/src/prelude/operators.hpp +2 -2
- package/src/prelude/types.hpp +24 -6
- package/src/prelude/values/array.hpp +2 -0
- package/src/prelude/values/function.hpp +33 -1
- package/src/prelude/values/{operators → helpers}/array.hpp +14 -7
- package/src/prelude/values/helpers/function.hpp +77 -0
- package/src/prelude/values/helpers/iterator.hpp +101 -0
- package/src/prelude/values/helpers/string.hpp +50 -0
- package/src/prelude/values/helpers/symbol.hpp +23 -0
- package/src/prelude/values/iterator.hpp +88 -0
- package/src/prelude/values/object.hpp +2 -1
- package/src/prelude/values/prototypes/array.hpp +18 -11
- package/src/prelude/values/prototypes/function.hpp +26 -0
- package/src/prelude/values/prototypes/iterator.hpp +57 -0
- package/src/prelude/values/prototypes/string.hpp +366 -357
- package/src/prelude/values/prototypes/symbol.hpp +39 -0
- package/src/prelude/values/string.hpp +25 -0
- package/src/prelude/values/symbol.hpp +102 -0
- package/src/prelude/well_known_symbols.hpp +7 -3
- package/src/prelude/values/operators/function.hpp +0 -34
- /package/src/prelude/values/{operators → helpers}/object.hpp +0 -0
package/README.md
CHANGED
|
@@ -33,6 +33,8 @@ JSPP reserves certain keywords to avoid conflicts with the generated C++ code an
|
|
|
33
33
|
|
|
34
34
|
- `std`: Reserved to prevent conflicts with the C++ standard library namespace.
|
|
35
35
|
- `jspp`: Reserved for internal use by the JSPP transpiler.
|
|
36
|
+
- `co_yield`: Reserved to prevent conflicts with the c++ generator functions.
|
|
37
|
+
- `co_return`: Reserved to prevent conflicts with the c++ generator functions.
|
|
36
38
|
|
|
37
39
|
Using these keywords as variable names will result in a `SyntaxError`.
|
|
38
40
|
|
|
@@ -45,7 +47,7 @@ The transpilation process is a classic three-stage pipeline:
|
|
|
45
47
|
2. **Analysis:** The `TypeAnalyzer` traverses the AST. While it doesn't perform traditional static type checking, it plays a crucial role in understanding the code's structure. It identifies scopes (global, function, block) and detects when variables are "captured" by closures.
|
|
46
48
|
|
|
47
49
|
3. **Code Generation:** The `CodeGenerator` performs a final traversal of the AST. It translates each node into its C++ equivalent.
|
|
48
|
-
- All variables are declared as `std::shared_ptr<AnyValue>` (where `AnyValue` uses a [Tagged Union](https://en.wikipedia.org/wiki/Tagged_union)
|
|
50
|
+
- All variables are declared as `std::shared_ptr<AnyValue>` (where `AnyValue` uses a [Tagged Union](https://en.wikipedia.org/wiki/Tagged_union) method for managing dynamic types like JavaScript). This approach elegantly mimics JavaScript's dynamic types and reference-based memory model.
|
|
49
51
|
- Closures are implemented as C++ lambdas that capture `shared_ptr`s by value, ensuring variable lifetimes are correctly extended beyond their original scope.
|
|
50
52
|
- The entire script is wrapped into a single `main` function, with hoisting logic carefully replicated to ensure correct execution order.
|
|
51
53
|
|
package/dist/analysis/scope.js
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
const RESERVED_KEYWORDS = [
|
|
1
|
+
export const RESERVED_KEYWORDS = new Set([
|
|
2
|
+
"jspp",
|
|
3
|
+
"std",
|
|
4
|
+
"co_yield",
|
|
5
|
+
"co_return",
|
|
6
|
+
]);
|
|
7
|
+
export const BUILTIN_OBJECTS = new Set([
|
|
8
|
+
{ name: "undefined", isConst: true },
|
|
9
|
+
{ name: "null", isConst: true },
|
|
10
|
+
{ name: "Symbol", isConst: false },
|
|
11
|
+
{ name: "console", isConst: false },
|
|
12
|
+
{ name: "performance", isConst: false },
|
|
13
|
+
{ name: "global", isConst: false },
|
|
14
|
+
{ name: "globalThis", isConst: false },
|
|
15
|
+
]);
|
|
2
16
|
// Represents a single scope (e.g., a function body or a block statement)
|
|
3
17
|
export class Scope {
|
|
4
18
|
parent;
|
|
@@ -31,16 +45,13 @@ export class ScopeManager {
|
|
|
31
45
|
const rootScope = new Scope(null); // The global scope
|
|
32
46
|
this.currentScope = rootScope;
|
|
33
47
|
this.allScopes.push(rootScope); // Add the root scope to our list
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
isConst: true,
|
|
42
|
-
isBuiltin: true,
|
|
43
|
-
});
|
|
48
|
+
for (const { name, isConst } of BUILTIN_OBJECTS) {
|
|
49
|
+
this.define(name, {
|
|
50
|
+
type: name,
|
|
51
|
+
isConst: isConst,
|
|
52
|
+
isBuiltin: true,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
44
55
|
}
|
|
45
56
|
// Enters a new, nested scope.
|
|
46
57
|
enterScope() {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as ts from "typescript";
|
|
2
|
+
import { isBuiltinObject } from "../core/codegen/helpers";
|
|
2
3
|
import { Traverser } from "../core/traverser";
|
|
3
4
|
import { Scope, ScopeManager } from "./scope";
|
|
4
5
|
export class TypeAnalyzer {
|
|
@@ -55,7 +56,8 @@ export class TypeAnalyzer {
|
|
|
55
56
|
const varDecl = forIn.initializer.declarations[0];
|
|
56
57
|
if (varDecl) {
|
|
57
58
|
const name = varDecl.name.getText();
|
|
58
|
-
const isConst = (varDecl.parent.flags & ts.NodeFlags.Const) !==
|
|
59
|
+
const isConst = (varDecl.parent.flags & ts.NodeFlags.Const) !==
|
|
60
|
+
0;
|
|
59
61
|
const typeInfo = {
|
|
60
62
|
type: "string", // Keys are always strings
|
|
61
63
|
declaration: varDecl,
|
|
@@ -186,9 +188,8 @@ export class TypeAnalyzer {
|
|
|
186
188
|
Identifier: {
|
|
187
189
|
enter: (node, parent) => {
|
|
188
190
|
if (ts.isIdentifier(node)) {
|
|
189
|
-
if (
|
|
191
|
+
if (isBuiltinObject.call(this, node))
|
|
190
192
|
return;
|
|
191
|
-
}
|
|
192
193
|
const currentFuncNode = this.functionStack[this.functionStack.length - 1];
|
|
193
194
|
if (currentFuncNode &&
|
|
194
195
|
(ts.isFunctionDeclaration(currentFuncNode) ||
|
package/dist/cli.js
CHANGED
|
@@ -25,13 +25,13 @@ async function main() {
|
|
|
25
25
|
const compile = Bun.spawnSync({
|
|
26
26
|
cmd: [
|
|
27
27
|
"g++",
|
|
28
|
-
"-std=c++
|
|
28
|
+
"-std=c++23",
|
|
29
29
|
cppFilePath,
|
|
30
30
|
"-o",
|
|
31
31
|
exeFilePath,
|
|
32
32
|
"-I",
|
|
33
33
|
preludePath,
|
|
34
|
-
"-
|
|
34
|
+
"-O3",
|
|
35
35
|
"-DNDEBUG",
|
|
36
36
|
// "-include",
|
|
37
37
|
// path.join(process.cwd(), "prelude-build", "index.hpp"),
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
2
|
import { CodeGenerator } from "./";
|
|
3
3
|
function visitObjectPropertyName(node, context) {
|
|
4
|
-
if (ts.
|
|
4
|
+
if (ts.isNumericLiteral(node)) {
|
|
5
|
+
return node.getText();
|
|
6
|
+
}
|
|
7
|
+
else if (ts.isStringLiteral(node)) {
|
|
5
8
|
return `"${node.getText().substring(1, node.getText().length - 1) // remove trailing "' from original name
|
|
6
9
|
}"`;
|
|
7
10
|
}
|
|
@@ -12,9 +15,12 @@ function visitObjectPropertyName(node, context) {
|
|
|
12
15
|
name += ".to_std_string()";
|
|
13
16
|
return name;
|
|
14
17
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
else if (context.isPropertyNameAccess) {
|
|
19
|
+
return this.visit(node, context);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
return `"${node.getText()}"`;
|
|
23
|
+
}
|
|
18
24
|
}
|
|
19
25
|
export function visitObjectLiteralExpression(node, context) {
|
|
20
26
|
const obj = node;
|
|
@@ -86,7 +92,6 @@ export function visitPropertyAccessExpression(node, context) {
|
|
|
86
92
|
finalExpr = exprText;
|
|
87
93
|
}
|
|
88
94
|
return `${finalExpr}.get_own_property("${propName}")`;
|
|
89
|
-
// return `${finalExpr}["${propName}"]`;
|
|
90
95
|
}
|
|
91
96
|
export function visitElementAccessExpression(node, context) {
|
|
92
97
|
const elemAccess = node;
|
|
@@ -116,7 +121,6 @@ export function visitElementAccessExpression(node, context) {
|
|
|
116
121
|
}
|
|
117
122
|
}
|
|
118
123
|
return `${finalExpr}.get_own_property(${argText})`;
|
|
119
|
-
// return `${finalExpr}[${argText}]`;
|
|
120
124
|
}
|
|
121
125
|
export function visitBinaryExpression(node, context) {
|
|
122
126
|
const binExpr = node;
|
|
@@ -3,7 +3,14 @@ import { CodeGenerator } from "./";
|
|
|
3
3
|
export function generateLambda(node, isAssignment = false, capture = "[=]") {
|
|
4
4
|
const declaredSymbols = this.getDeclaredSymbols(node);
|
|
5
5
|
const argsName = this.generateUniqueName("__args_", declaredSymbols);
|
|
6
|
-
|
|
6
|
+
const isInsideGeneratorFunction = this.isGeneratorFunction(node);
|
|
7
|
+
const returnCmd = this.getReturnCmd({
|
|
8
|
+
isInsideGeneratorFunction: isInsideGeneratorFunction,
|
|
9
|
+
});
|
|
10
|
+
const funcReturnType = isInsideGeneratorFunction
|
|
11
|
+
? "jspp::JsIterator<jspp::AnyValue>"
|
|
12
|
+
: "jspp::AnyValue";
|
|
13
|
+
let lambda = `${capture}(const std::vector<jspp::AnyValue>& ${argsName}) mutable -> ${funcReturnType} `;
|
|
7
14
|
const visitContext = {
|
|
8
15
|
isMainContext: false,
|
|
9
16
|
isInsideFunction: true,
|
|
@@ -26,6 +33,7 @@ export function generateLambda(node, isAssignment = false, capture = "[=]") {
|
|
|
26
33
|
isMainContext: false,
|
|
27
34
|
isInsideFunction: true,
|
|
28
35
|
isFunctionBody: true,
|
|
36
|
+
isInsideGeneratorFunction: isInsideGeneratorFunction,
|
|
29
37
|
});
|
|
30
38
|
// The block visitor already adds braces, so we need to inject the param extraction.
|
|
31
39
|
lambda += "{\n" + paramExtraction + blockContent.substring(2);
|
|
@@ -41,7 +49,7 @@ export function generateLambda(node, isAssignment = false, capture = "[=]") {
|
|
|
41
49
|
lambda +=
|
|
42
50
|
`${this.indent()}auto ${name} = ${argsName}.size() > ${i} ? ${argsName}[${i}] : ${defaultValue};\n`;
|
|
43
51
|
});
|
|
44
|
-
lambda += `${this.indent()}
|
|
52
|
+
lambda += `${this.indent()}${returnCmd} ${this.visit(node.body, {
|
|
45
53
|
isMainContext: false,
|
|
46
54
|
isInsideFunction: true,
|
|
47
55
|
isFunctionBody: false,
|
|
@@ -52,12 +60,25 @@ export function generateLambda(node, isAssignment = false, capture = "[=]") {
|
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
else {
|
|
55
|
-
lambda +=
|
|
63
|
+
lambda += `{ ${returnCmd} jspp::AnyValue::make_undefined(); }\n`;
|
|
64
|
+
}
|
|
65
|
+
let signature = "";
|
|
66
|
+
let callable = "";
|
|
67
|
+
let method = "";
|
|
68
|
+
// Handle generator function
|
|
69
|
+
if (isInsideGeneratorFunction) {
|
|
70
|
+
signature =
|
|
71
|
+
"jspp::JsIterator<jspp::AnyValue>(const std::vector<jspp::AnyValue>&)";
|
|
72
|
+
callable = `std::function<${signature}>(${lambda})`;
|
|
73
|
+
method = `jspp::AnyValue::make_function`;
|
|
74
|
+
} // Handle normal function
|
|
75
|
+
else {
|
|
76
|
+
signature = `jspp::AnyValue(const std::vector<jspp::AnyValue>&)`;
|
|
77
|
+
callable = `std::function<${signature}>(${lambda})`;
|
|
78
|
+
method = `jspp::AnyValue::make_function`;
|
|
56
79
|
}
|
|
57
|
-
const signature = `jspp::AnyValue(const std::vector<jspp::AnyValue>&)`;
|
|
58
|
-
const callable = `std::function<${signature}>(${lambda})`;
|
|
59
80
|
const funcName = node.name?.getText();
|
|
60
|
-
const fullExpression =
|
|
81
|
+
const fullExpression = `${method}(${callable}, "${funcName || ""}")`;
|
|
61
82
|
if (ts.isFunctionDeclaration(node) && !isAssignment && funcName) {
|
|
62
83
|
return `${this.indent()}auto ${funcName} = ${fullExpression};\n`;
|
|
63
84
|
}
|
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import { Scope } from "../../analysis/scope";
|
|
2
|
+
import { BUILTIN_OBJECTS, Scope } from "../../analysis/scope";
|
|
3
3
|
import { CodeGenerator } from "./";
|
|
4
|
-
const BUILTIN_OBJECTS = new Set([
|
|
5
|
-
"global",
|
|
6
|
-
"globalThis",
|
|
7
|
-
"console",
|
|
8
|
-
"Symbol",
|
|
9
|
-
]);
|
|
10
4
|
export function isBuiltinObject(node) {
|
|
11
|
-
return BUILTIN_OBJECTS.
|
|
5
|
+
return BUILTIN_OBJECTS.values().some((obj) => obj.name === node.text);
|
|
12
6
|
}
|
|
13
7
|
export function getDeclaredSymbols(node) {
|
|
14
8
|
const symbols = new Set();
|
|
@@ -81,3 +75,13 @@ export function escapeString(str) {
|
|
|
81
75
|
export function getJsVarName(node) {
|
|
82
76
|
return `"${node.text}"`;
|
|
83
77
|
}
|
|
78
|
+
export function getReturnCmd(context) {
|
|
79
|
+
return context.isInsideGeneratorFunction ? "co_return" : "return";
|
|
80
|
+
}
|
|
81
|
+
export function isGeneratorFunction(node) {
|
|
82
|
+
return ((ts.isFunctionDeclaration(node) ||
|
|
83
|
+
ts.isFunctionExpression(node) ||
|
|
84
|
+
ts.isMethodDeclaration(node)) &&
|
|
85
|
+
!!node.asteriskToken // generator indicator
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TypeAnalyzer } from "../../analysis/typeAnalyzer";
|
|
2
2
|
import { generateLambda } from "./function-handlers";
|
|
3
|
-
import { escapeString, generateUniqueExceptionName, generateUniqueName, getDeclaredSymbols, getJsVarName, getScopeForNode, indent, isBuiltinObject, } from "./helpers";
|
|
3
|
+
import { escapeString, generateUniqueExceptionName, generateUniqueName, getDeclaredSymbols, getJsVarName, getReturnCmd, getScopeForNode, indent, isBuiltinObject, isGeneratorFunction, } from "./helpers";
|
|
4
4
|
import { visit } from "./visitor";
|
|
5
5
|
const CONTAINER_FUNCTION_NAME = "__container__";
|
|
6
6
|
export class CodeGenerator {
|
|
@@ -17,7 +17,9 @@ export class CodeGenerator {
|
|
|
17
17
|
indent = indent;
|
|
18
18
|
escapeString = escapeString;
|
|
19
19
|
getJsVarName = getJsVarName;
|
|
20
|
+
getReturnCmd = getReturnCmd;
|
|
20
21
|
isBuiltinObject = isBuiltinObject;
|
|
22
|
+
isGeneratorFunction = isGeneratorFunction;
|
|
21
23
|
// function handlers
|
|
22
24
|
generateLambda = generateLambda;
|
|
23
25
|
/**
|
|
@@ -130,8 +130,7 @@ export function visitBlock(node, context) {
|
|
|
130
130
|
if (context.isFunctionBody) {
|
|
131
131
|
const lastStatement = block.statements[block.statements.length - 1];
|
|
132
132
|
if (!lastStatement || !ts.isReturnStatement(lastStatement)) {
|
|
133
|
-
code +=
|
|
134
|
-
`${this.indent()}return jspp::AnyValue::make_undefined();\n`;
|
|
133
|
+
code += `${this.indent()}${this.getReturnCmd(context)} jspp::AnyValue::make_undefined();\n`;
|
|
135
134
|
}
|
|
136
135
|
}
|
|
137
136
|
this.indentationLevel--;
|
|
@@ -250,32 +249,49 @@ export function visitForOfStatement(node, context) {
|
|
|
250
249
|
varName = decl.name.getText();
|
|
251
250
|
// Declare the shared_ptr before the loop
|
|
252
251
|
code +=
|
|
253
|
-
`${this.indent()}auto ${varName} = std::make_shared<jspp::AnyValue>(jspp::AnyValue::make_undefined());\n`;
|
|
252
|
+
`${this.indent()}{ auto ${varName} = std::make_shared<jspp::AnyValue>(jspp::AnyValue::make_undefined());\n`;
|
|
254
253
|
}
|
|
255
254
|
}
|
|
256
255
|
else if (ts.isIdentifier(forOf.initializer)) {
|
|
257
256
|
varName = forOf.initializer.getText();
|
|
258
257
|
// Assume it's already declared in an outer scope, just assign to it.
|
|
259
258
|
// No explicit declaration here.
|
|
259
|
+
code += `${this.indent()}{\n`;
|
|
260
260
|
}
|
|
261
261
|
const iterableExpr = this.visit(forOf.expression, context);
|
|
262
|
-
const derefIterable =
|
|
263
|
-
|
|
262
|
+
const derefIterable = ts.isIdentifier(forOf.expression)
|
|
263
|
+
? `jspp::Access::deref(${iterableExpr}, ${this.getJsVarName(forOf.expression)})`
|
|
264
|
+
: iterableExpr;
|
|
265
|
+
const iteratorFn = this.generateUniqueName("__iter_fn_", new Set());
|
|
266
|
+
const iteratorPtr = this.generateUniqueName("__iter_ptr_", new Set());
|
|
267
|
+
const nextRes = this.generateUniqueName("__res__", new Set());
|
|
264
268
|
code +=
|
|
265
|
-
`${this.indent()}
|
|
269
|
+
`${this.indent()}auto ${iteratorFn} = ${derefIterable}.get_own_property(Symbol.get_own_property("iterator"));\n`;
|
|
266
270
|
code +=
|
|
267
|
-
`${this.indent()}
|
|
271
|
+
`${this.indent()}if (!${iteratorFn}.is_generator()) { throw jspp::RuntimeError::make_error("${iterableExpr} is not iterable", "TypeError"); }\n`;
|
|
272
|
+
code +=
|
|
273
|
+
`${this.indent()}auto ${iteratorPtr} = ${iteratorFn}.as_function()->call({}).as_iterator();\n`;
|
|
274
|
+
code += `${this.indent()}auto ${nextRes} = ${iteratorPtr}->next();\n`;
|
|
275
|
+
code += `${this.indent()}while (!${nextRes}.done) {\n`;
|
|
268
276
|
this.indentationLevel++;
|
|
269
|
-
code +=
|
|
277
|
+
code +=
|
|
278
|
+
`${this.indent()}*${varName} = ${nextRes}.value.value_or(jspp::AnyValue::make_undefined());\n`;
|
|
270
279
|
code += this.visit(forOf.statement, {
|
|
271
280
|
...context,
|
|
272
281
|
isFunctionBody: false,
|
|
273
282
|
});
|
|
283
|
+
code += `${this.indent()}${nextRes} = ${iteratorPtr}->next();\n`;
|
|
274
284
|
this.indentationLevel--;
|
|
275
285
|
code += `${this.indent()}}}\n`;
|
|
276
286
|
this.indentationLevel--; // Exit the scope for the for-of loop
|
|
277
287
|
return code;
|
|
278
288
|
}
|
|
289
|
+
export function visitBreakStatement(node, context) {
|
|
290
|
+
return "break;";
|
|
291
|
+
}
|
|
292
|
+
export function visitContinueStatement(node, context) {
|
|
293
|
+
return "continue;";
|
|
294
|
+
}
|
|
279
295
|
export function visitIfStatement(node, context) {
|
|
280
296
|
const ifStmt = node;
|
|
281
297
|
const condition = this.visit(ifStmt.expression, context);
|
|
@@ -355,7 +371,7 @@ export function visitTryStatement(node, context) {
|
|
|
355
371
|
else {
|
|
356
372
|
code += `${this.indent()}catch (...) { throw; }\n`;
|
|
357
373
|
}
|
|
358
|
-
code += `${this.indent()}
|
|
374
|
+
code += `${this.indent()}${this.getReturnCmd(context)} jspp::AnyValue::make_undefined();\n`;
|
|
359
375
|
this.indentationLevel--;
|
|
360
376
|
code += `${this.indent()}})();\n`;
|
|
361
377
|
this.indentationLevel--;
|
|
@@ -427,11 +443,32 @@ export function visitCatchClause(node, context) {
|
|
|
427
443
|
return code;
|
|
428
444
|
}
|
|
429
445
|
}
|
|
446
|
+
export function visitYieldExpression(node, context) {
|
|
447
|
+
if (node.expression) {
|
|
448
|
+
const expr = node.expression;
|
|
449
|
+
const exprText = this.visit(expr, context);
|
|
450
|
+
if (ts.isIdentifier(expr)) {
|
|
451
|
+
const scope = this.getScopeForNode(expr);
|
|
452
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(expr.text, scope);
|
|
453
|
+
if (!typeInfo) {
|
|
454
|
+
return `${this.indent()}jspp::RuntimeError::throw_unresolved_reference_error(${this.getJsVarName(expr)})\n`; // THROWS, not returns
|
|
455
|
+
}
|
|
456
|
+
if (typeInfo &&
|
|
457
|
+
!typeInfo.isParameter &&
|
|
458
|
+
!typeInfo.isBuiltin) {
|
|
459
|
+
return `${this.indent()}co_yield jspp::Access::deref(${exprText}, ${this.getJsVarName(expr)})`;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return `${this.indent()}co_yield ${exprText}`;
|
|
463
|
+
}
|
|
464
|
+
return `${this.indent()}co_yield jspp::AnyValue::make_undefined()`;
|
|
465
|
+
}
|
|
430
466
|
export function visitReturnStatement(node, context) {
|
|
431
467
|
if (context.isMainContext) {
|
|
432
468
|
return `${this.indent()}jspp::RuntimeError::throw_invalid_return_statement_error();\n`;
|
|
433
469
|
}
|
|
434
470
|
const returnStmt = node;
|
|
471
|
+
const returnCmd = this.getReturnCmd(context);
|
|
435
472
|
if (context.isInsideTryCatchLambda && context.hasReturnedFlag) {
|
|
436
473
|
let returnCode = `${this.indent()}${context.hasReturnedFlag} = true;\n`;
|
|
437
474
|
if (returnStmt.expression) {
|
|
@@ -448,19 +485,19 @@ export function visitReturnStatement(node, context) {
|
|
|
448
485
|
!typeInfo.isParameter &&
|
|
449
486
|
!typeInfo.isBuiltin) {
|
|
450
487
|
returnCode +=
|
|
451
|
-
`${this.indent()}
|
|
488
|
+
`${this.indent()}${returnCmd} jspp::Access::deref(${exprText}, ${this.getJsVarName(expr)});\n`;
|
|
452
489
|
}
|
|
453
490
|
else {
|
|
454
|
-
returnCode += `${this.indent()}
|
|
491
|
+
returnCode += `${this.indent()}${returnCmd} ${exprText};\n`;
|
|
455
492
|
}
|
|
456
493
|
}
|
|
457
494
|
else {
|
|
458
|
-
returnCode += `${this.indent()}
|
|
495
|
+
returnCode += `${this.indent()}${returnCmd} ${exprText};\n`;
|
|
459
496
|
}
|
|
460
497
|
}
|
|
461
498
|
else {
|
|
462
499
|
returnCode +=
|
|
463
|
-
`${this.indent()}
|
|
500
|
+
`${this.indent()}${returnCmd} jspp::AnyValue::make_undefined();\n`;
|
|
464
501
|
}
|
|
465
502
|
return returnCode;
|
|
466
503
|
}
|
|
@@ -476,10 +513,10 @@ export function visitReturnStatement(node, context) {
|
|
|
476
513
|
if (typeInfo &&
|
|
477
514
|
!typeInfo.isParameter &&
|
|
478
515
|
!typeInfo.isBuiltin) {
|
|
479
|
-
return `${this.indent()}
|
|
516
|
+
return `${this.indent()}${returnCmd} jspp::Access::deref(${exprText}, ${this.getJsVarName(expr)});\n`;
|
|
480
517
|
}
|
|
481
518
|
}
|
|
482
|
-
return `${this.indent()}
|
|
519
|
+
return `${this.indent()}${returnCmd} ${exprText};\n`;
|
|
483
520
|
}
|
|
484
|
-
return `${this.indent()}
|
|
521
|
+
return `${this.indent()}${returnCmd} jspp::AnyValue::make_undefined();\n`;
|
|
485
522
|
}
|
|
@@ -4,7 +4,7 @@ import { visitVariableDeclaration, visitVariableDeclarationList, } from "./decla
|
|
|
4
4
|
import { visitArrayLiteralExpression, visitBinaryExpression, visitCallExpression, visitElementAccessExpression, visitObjectLiteralExpression, visitParenthesizedExpression, visitPostfixUnaryExpression, visitPrefixUnaryExpression, visitPropertyAccessExpression, visitTemplateExpression, visitVoidExpression, } from "./expression-handlers";
|
|
5
5
|
import { visitArrowFunction, visitFunctionDeclaration, visitFunctionExpression, } from "./function-handlers";
|
|
6
6
|
import { visitFalseKeyword, visitIdentifier, visitNoSubstitutionTemplateLiteral, visitNullKeyword, visitNumericLiteral, visitStringLiteral, visitTrueKeyword, visitUndefinedKeyword, } from "./literal-handlers";
|
|
7
|
-
import { visitBlock, visitCatchClause, visitExpressionStatement, visitForInStatement, visitForOfStatement, visitForStatement, visitIfStatement, visitReturnStatement, visitSourceFile, visitThrowStatement, visitTryStatement, visitVariableStatement, } from "./statement-handlers";
|
|
7
|
+
import { visitBlock, visitBreakStatement, visitCatchClause, visitContinueStatement, visitExpressionStatement, visitForInStatement, visitForOfStatement, visitForStatement, visitIfStatement, visitReturnStatement, visitSourceFile, visitThrowStatement, visitTryStatement, visitVariableStatement, visitYieldExpression, } from "./statement-handlers";
|
|
8
8
|
export function visit(node, context) {
|
|
9
9
|
if (ts.isFunctionDeclaration(node)) {
|
|
10
10
|
return visitFunctionDeclaration.call(this, node, context);
|
|
@@ -34,6 +34,10 @@ export function visit(node, context) {
|
|
|
34
34
|
return visitForInStatement.call(this, node, context);
|
|
35
35
|
case ts.SyntaxKind.ForOfStatement:
|
|
36
36
|
return visitForOfStatement.call(this, node, context);
|
|
37
|
+
case ts.SyntaxKind.BreakStatement:
|
|
38
|
+
return visitBreakStatement.call(this, node, context);
|
|
39
|
+
case ts.SyntaxKind.ContinueStatement:
|
|
40
|
+
return visitContinueStatement.call(this, node, context);
|
|
37
41
|
case ts.SyntaxKind.IfStatement:
|
|
38
42
|
return visitIfStatement.call(this, node, context);
|
|
39
43
|
case ts.SyntaxKind.PrefixUnaryExpression:
|
|
@@ -58,6 +62,8 @@ export function visit(node, context) {
|
|
|
58
62
|
return visitCatchClause.call(this, node, context);
|
|
59
63
|
case ts.SyntaxKind.CallExpression:
|
|
60
64
|
return visitCallExpression.call(this, node, context);
|
|
65
|
+
case ts.SyntaxKind.YieldExpression:
|
|
66
|
+
return visitYieldExpression.call(this, node, context);
|
|
61
67
|
case ts.SyntaxKind.ReturnStatement:
|
|
62
68
|
return visitReturnStatement.call(this, node, context);
|
|
63
69
|
case ts.SyntaxKind.Identifier:
|
package/package.json
CHANGED
package/src/prelude/access.hpp
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
#include "types.hpp"
|
|
4
|
+
#include "well_known_symbols.hpp"
|
|
4
5
|
#include "values/function.hpp"
|
|
6
|
+
#include "values/symbol.hpp"
|
|
5
7
|
#include "error.hpp"
|
|
8
|
+
#include "any_value.hpp"
|
|
6
9
|
#include <ranges>
|
|
7
10
|
|
|
8
11
|
namespace jspp
|
|
@@ -52,7 +55,8 @@ namespace jspp
|
|
|
52
55
|
auto ptr = obj.as_object();
|
|
53
56
|
for (const auto &pair : ptr->props)
|
|
54
57
|
{
|
|
55
|
-
|
|
58
|
+
if (!JsSymbol::is_internal_key(pair.first))
|
|
59
|
+
keys.push_back(pair.first);
|
|
56
60
|
}
|
|
57
61
|
}
|
|
58
62
|
if (obj.is_function())
|
|
@@ -60,7 +64,8 @@ namespace jspp
|
|
|
60
64
|
auto ptr = obj.as_function();
|
|
61
65
|
for (const auto &pair : ptr->props)
|
|
62
66
|
{
|
|
63
|
-
|
|
67
|
+
if (!JsSymbol::is_internal_key(pair.first))
|
|
68
|
+
keys.push_back(pair.first);
|
|
64
69
|
}
|
|
65
70
|
}
|
|
66
71
|
if (obj.is_array())
|
|
@@ -73,7 +78,7 @@ namespace jspp
|
|
|
73
78
|
}
|
|
74
79
|
if (obj.is_string())
|
|
75
80
|
{
|
|
76
|
-
auto len = obj.as_string()->length();
|
|
81
|
+
auto len = obj.as_string()->value.length();
|
|
77
82
|
for (auto i = 0; i < len; ++i)
|
|
78
83
|
{
|
|
79
84
|
keys.push_back(std::to_string(i));
|