@ugo-studio/jspp 0.1.2 → 0.1.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 +5 -3
- package/dist/analysis/scope.js +38 -15
- package/dist/analysis/typeAnalyzer.js +257 -23
- package/dist/ast/types.js +6 -0
- package/dist/cli.js +3 -4
- package/dist/core/codegen/class-handlers.js +127 -0
- package/dist/core/codegen/control-flow-handlers.js +464 -0
- package/dist/core/codegen/declaration-handlers.js +31 -14
- package/dist/core/codegen/expression-handlers.js +432 -116
- package/dist/core/codegen/function-handlers.js +110 -13
- package/dist/core/codegen/helpers.js +76 -8
- package/dist/core/codegen/index.js +18 -5
- package/dist/core/codegen/literal-handlers.js +3 -0
- package/dist/core/codegen/statement-handlers.js +152 -186
- package/dist/core/codegen/visitor.js +35 -3
- package/package.json +3 -3
- package/src/prelude/any_value.hpp +658 -734
- package/src/prelude/any_value_access.hpp +103 -0
- package/src/prelude/any_value_defines.hpp +151 -0
- package/src/prelude/any_value_helpers.hpp +246 -0
- package/src/prelude/exception.hpp +31 -0
- package/src/prelude/exception_helpers.hpp +49 -0
- package/src/prelude/index.hpp +35 -12
- package/src/prelude/library/console.hpp +20 -20
- package/src/prelude/library/error.hpp +111 -0
- package/src/prelude/library/global.hpp +15 -4
- package/src/prelude/library/performance.hpp +25 -0
- package/src/prelude/library/promise.hpp +121 -0
- package/src/prelude/library/symbol.hpp +60 -4
- package/src/prelude/library/timer.hpp +92 -0
- package/src/prelude/scheduler.hpp +145 -0
- package/src/prelude/types.hpp +33 -6
- package/src/prelude/utils/access.hpp +174 -0
- package/src/prelude/utils/log_any_value/array.hpp +245 -0
- package/src/prelude/utils/log_any_value/config.hpp +32 -0
- package/src/prelude/utils/log_any_value/function.hpp +37 -0
- package/src/prelude/utils/log_any_value/fwd.hpp +15 -0
- package/src/prelude/utils/log_any_value/helpers.hpp +62 -0
- package/src/prelude/utils/log_any_value/log_any_value.hpp +94 -0
- package/src/prelude/utils/log_any_value/object.hpp +119 -0
- package/src/prelude/utils/log_any_value/primitives.hpp +41 -0
- package/src/prelude/{operators.hpp → utils/operators.hpp} +31 -12
- package/src/prelude/utils/well_known_symbols.hpp +13 -0
- package/src/prelude/values/array.hpp +5 -2
- package/src/prelude/{descriptors.hpp → values/descriptors.hpp} +2 -2
- package/src/prelude/values/function.hpp +76 -19
- package/src/prelude/values/{operators → helpers}/array.hpp +30 -14
- package/src/prelude/values/helpers/function.hpp +125 -0
- package/src/prelude/values/helpers/iterator.hpp +107 -0
- package/src/prelude/values/helpers/object.hpp +64 -0
- package/src/prelude/values/helpers/promise.hpp +181 -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 +96 -0
- package/src/prelude/values/object.hpp +8 -3
- package/src/prelude/values/promise.hpp +73 -0
- package/src/prelude/values/prototypes/array.hpp +23 -16
- package/src/prelude/values/prototypes/function.hpp +26 -0
- package/src/prelude/values/prototypes/iterator.hpp +58 -0
- package/src/prelude/values/prototypes/object.hpp +26 -0
- package/src/prelude/values/prototypes/promise.hpp +124 -0
- package/src/prelude/values/prototypes/string.hpp +366 -357
- package/src/prelude/values/prototypes/symbol.hpp +41 -0
- package/src/prelude/values/string.hpp +25 -0
- package/src/prelude/values/symbol.hpp +102 -0
- package/src/prelude/access.hpp +0 -86
- package/src/prelude/error.hpp +0 -31
- package/src/prelude/error_helpers.hpp +0 -59
- package/src/prelude/log_string.hpp +0 -403
- package/src/prelude/values/operators/function.hpp +0 -34
- package/src/prelude/values/operators/object.hpp +0 -34
- package/src/prelude/well_known_symbols.hpp +0 -10
|
@@ -1,13 +1,41 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
2
|
import { CodeGenerator } from "./";
|
|
3
|
-
export function generateLambda(node,
|
|
3
|
+
export function generateLambda(node, context, options) {
|
|
4
|
+
const isAssignment = options?.isAssignment || false;
|
|
5
|
+
const capture = options?.capture || "[=]";
|
|
4
6
|
const declaredSymbols = this.getDeclaredSymbols(node);
|
|
5
7
|
const argsName = this.generateUniqueName("__args_", declaredSymbols);
|
|
6
|
-
|
|
8
|
+
const isInsideGeneratorFunction = this.isGeneratorFunction(node);
|
|
9
|
+
const isInsideAsyncFunction = this.isAsyncFunction(node);
|
|
10
|
+
const returnCmd = this.getReturnCommand({
|
|
11
|
+
isInsideGeneratorFunction: isInsideGeneratorFunction,
|
|
12
|
+
isInsideAsyncFunction: isInsideAsyncFunction,
|
|
13
|
+
});
|
|
14
|
+
const funcReturnType = isInsideGeneratorFunction
|
|
15
|
+
? "jspp::JsIterator<jspp::AnyValue>"
|
|
16
|
+
: (isInsideAsyncFunction ? "jspp::JsPromise" : "jspp::AnyValue");
|
|
17
|
+
const isArrow = ts.isArrowFunction(node);
|
|
18
|
+
// For generators and async functions, we MUST copy arguments because the coroutine suspends immediately
|
|
19
|
+
// and references to temporary arguments would dangle.
|
|
20
|
+
const paramThisType = (isInsideGeneratorFunction || isInsideAsyncFunction)
|
|
21
|
+
? "jspp::AnyValue"
|
|
22
|
+
: "const jspp::AnyValue&";
|
|
23
|
+
const paramArgsType = (isInsideGeneratorFunction || isInsideAsyncFunction)
|
|
24
|
+
? "std::vector<jspp::AnyValue>"
|
|
25
|
+
: "const std::vector<jspp::AnyValue>&";
|
|
26
|
+
const thisArgParam = isArrow
|
|
27
|
+
? "const jspp::AnyValue&" // Arrow functions are never generators in this parser
|
|
28
|
+
: `${paramThisType} ${this.globalThisVar}`;
|
|
29
|
+
let lambda = `${capture}(${thisArgParam}, ${paramArgsType} ${argsName}) mutable -> ${funcReturnType} `;
|
|
30
|
+
const topLevelScopeSymbols = this.prepareScopeSymbolsForVisit(context.topLevelScopeSymbols, context.currentScopeSymbols);
|
|
7
31
|
const visitContext = {
|
|
8
32
|
isMainContext: false,
|
|
9
33
|
isInsideFunction: true,
|
|
10
34
|
isFunctionBody: false,
|
|
35
|
+
lambdaName: undefined,
|
|
36
|
+
topLevelScopeSymbols,
|
|
37
|
+
currentScopeSymbols: new Map(),
|
|
38
|
+
superClassVar: context.superClassVar,
|
|
11
39
|
};
|
|
12
40
|
if (node.body) {
|
|
13
41
|
if (ts.isBlock(node.body)) {
|
|
@@ -18,14 +46,49 @@ export function generateLambda(node, isAssignment = false, capture = "[=]") {
|
|
|
18
46
|
const defaultValue = p.initializer
|
|
19
47
|
? this.visit(p.initializer, visitContext)
|
|
20
48
|
: "jspp::AnyValue::make_undefined()";
|
|
21
|
-
|
|
22
|
-
|
|
49
|
+
if (!!p.dotDotDotToken) {
|
|
50
|
+
if (node.parameters.length - 1 !== i) {
|
|
51
|
+
throw new SyntaxError("Rest parameter must be last formal parameter.");
|
|
52
|
+
}
|
|
53
|
+
const tempName = `temp_${name}`;
|
|
54
|
+
paramExtraction +=
|
|
55
|
+
`${this.indent()}auto ${name} = jspp::AnyValue::make_undefined();\n`;
|
|
56
|
+
paramExtraction += `${this.indent()}{\n`;
|
|
57
|
+
this.indentationLevel++;
|
|
58
|
+
paramExtraction +=
|
|
59
|
+
`${this.indent()}std::vector<std::optional<jspp::AnyValue>> ${tempName};\n`;
|
|
60
|
+
paramExtraction +=
|
|
61
|
+
`${this.indent()}if (${argsName}.size() > ${i}) {\n`;
|
|
62
|
+
this.indentationLevel++;
|
|
63
|
+
paramExtraction +=
|
|
64
|
+
`${this.indent()}${tempName}.reserve(${argsName}.size() - ${i});\n`;
|
|
65
|
+
this.indentationLevel--;
|
|
66
|
+
paramExtraction += `${this.indent()}}\n`;
|
|
67
|
+
paramExtraction +=
|
|
68
|
+
`${this.indent()}for (size_t i = ${i}; i < ${argsName}.size(); i++) {\n`;
|
|
69
|
+
this.indentationLevel++;
|
|
70
|
+
paramExtraction +=
|
|
71
|
+
`${this.indent()}${tempName}.push_back(${argsName}[i]);\n`;
|
|
72
|
+
this.indentationLevel--;
|
|
73
|
+
paramExtraction += `${this.indent()}}\n`;
|
|
74
|
+
paramExtraction +=
|
|
75
|
+
`${this.indent()}${name} = jspp::AnyValue::make_array(std::move(${tempName}));\n`;
|
|
76
|
+
this.indentationLevel--;
|
|
77
|
+
paramExtraction += `${this.indent()}}\n`;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
paramExtraction +=
|
|
81
|
+
`${this.indent()}auto ${name} = ${argsName}.size() > ${i} ? ${argsName}[${i}] : ${defaultValue};\n`;
|
|
82
|
+
}
|
|
23
83
|
});
|
|
24
84
|
this.indentationLevel--;
|
|
25
85
|
const blockContent = this.visit(node.body, {
|
|
86
|
+
...visitContext,
|
|
26
87
|
isMainContext: false,
|
|
27
88
|
isInsideFunction: true,
|
|
28
89
|
isFunctionBody: true,
|
|
90
|
+
isInsideGeneratorFunction: isInsideGeneratorFunction,
|
|
91
|
+
isInsideAsyncFunction: isInsideAsyncFunction,
|
|
29
92
|
});
|
|
30
93
|
// The block visitor already adds braces, so we need to inject the param extraction.
|
|
31
94
|
lambda += "{\n" + paramExtraction + blockContent.substring(2);
|
|
@@ -41,10 +104,13 @@ export function generateLambda(node, isAssignment = false, capture = "[=]") {
|
|
|
41
104
|
lambda +=
|
|
42
105
|
`${this.indent()}auto ${name} = ${argsName}.size() > ${i} ? ${argsName}[${i}] : ${defaultValue};\n`;
|
|
43
106
|
});
|
|
44
|
-
lambda += `${this.indent()}
|
|
107
|
+
lambda += `${this.indent()}${returnCmd} ${this.visit(node.body, {
|
|
108
|
+
...visitContext,
|
|
45
109
|
isMainContext: false,
|
|
46
110
|
isInsideFunction: true,
|
|
47
111
|
isFunctionBody: false,
|
|
112
|
+
isInsideGeneratorFunction: isInsideGeneratorFunction,
|
|
113
|
+
isInsideAsyncFunction: isInsideAsyncFunction,
|
|
48
114
|
})};
|
|
49
115
|
`;
|
|
50
116
|
this.indentationLevel--;
|
|
@@ -52,12 +118,37 @@ export function generateLambda(node, isAssignment = false, capture = "[=]") {
|
|
|
52
118
|
}
|
|
53
119
|
}
|
|
54
120
|
else {
|
|
55
|
-
lambda +=
|
|
121
|
+
lambda += `{ ${returnCmd} jspp::AnyValue::make_undefined(); }\n`;
|
|
122
|
+
}
|
|
123
|
+
let signature = "";
|
|
124
|
+
let callable = "";
|
|
125
|
+
let method = "";
|
|
126
|
+
// Handle generator function
|
|
127
|
+
if (isInsideGeneratorFunction) {
|
|
128
|
+
signature =
|
|
129
|
+
"jspp::JsIterator<jspp::AnyValue>(const jspp::AnyValue&, const std::vector<jspp::AnyValue>&)";
|
|
130
|
+
callable = `std::function<${signature}>(${lambda})`;
|
|
131
|
+
method = `jspp::AnyValue::make_generator`;
|
|
132
|
+
} // Handle async function
|
|
133
|
+
else if (isInsideAsyncFunction) {
|
|
134
|
+
signature =
|
|
135
|
+
"jspp::JsPromise(const jspp::AnyValue&, const std::vector<jspp::AnyValue>&)";
|
|
136
|
+
callable = `std::function<${signature}>(${lambda})`;
|
|
137
|
+
method = `jspp::AnyValue::make_async_function`;
|
|
138
|
+
} // Handle normal function
|
|
139
|
+
else {
|
|
140
|
+
signature =
|
|
141
|
+
`jspp::AnyValue(const jspp::AnyValue&, const std::vector<jspp::AnyValue>&)`;
|
|
142
|
+
callable = `std::function<${signature}>(${lambda})`;
|
|
143
|
+
if (options?.isClass) {
|
|
144
|
+
method = `jspp::AnyValue::make_class`;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
method = `jspp::AnyValue::make_function`;
|
|
148
|
+
}
|
|
56
149
|
}
|
|
57
|
-
const signature = `jspp::AnyValue(const std::vector<jspp::AnyValue>&)`;
|
|
58
|
-
const callable = `std::function<${signature}>(${lambda})`;
|
|
59
150
|
const funcName = node.name?.getText();
|
|
60
|
-
const fullExpression =
|
|
151
|
+
const fullExpression = `${method}(${callable}, "${context?.lambdaName || funcName || ""}")`;
|
|
61
152
|
if (ts.isFunctionDeclaration(node) && !isAssignment && funcName) {
|
|
62
153
|
return `${this.indent()}auto ${funcName} = ${fullExpression};\n`;
|
|
63
154
|
}
|
|
@@ -68,12 +159,12 @@ export function visitFunctionDeclaration(node, context) {
|
|
|
68
159
|
// This will now be handled by the Block visitor for hoisting.
|
|
69
160
|
// However, we still need to generate the lambda for assignment.
|
|
70
161
|
// The block visitor will wrap this in an assignment.
|
|
71
|
-
return this.generateLambda(node);
|
|
162
|
+
return this.generateLambda(node, context);
|
|
72
163
|
}
|
|
73
164
|
return "";
|
|
74
165
|
}
|
|
75
166
|
export function visitArrowFunction(node, context) {
|
|
76
|
-
return this.generateLambda(node);
|
|
167
|
+
return this.generateLambda(node, context);
|
|
77
168
|
}
|
|
78
169
|
export function visitFunctionExpression(node, context) {
|
|
79
170
|
const funcExpr = node;
|
|
@@ -83,12 +174,18 @@ export function visitFunctionExpression(node, context) {
|
|
|
83
174
|
this.indentationLevel++;
|
|
84
175
|
code +=
|
|
85
176
|
`${this.indent()}auto ${funcName} = std::make_shared<jspp::AnyValue>();\n`;
|
|
86
|
-
const lambda = this.generateLambda(funcExpr,
|
|
177
|
+
const lambda = this.generateLambda(funcExpr, {
|
|
178
|
+
...context,
|
|
179
|
+
lambdaName: funcName,
|
|
180
|
+
}, {
|
|
181
|
+
isAssignment: true,
|
|
182
|
+
capture: "[=]",
|
|
183
|
+
});
|
|
87
184
|
code += `${this.indent()}*${funcName} = ${lambda};\n`;
|
|
88
185
|
code += `${this.indent()}return *${funcName};\n`;
|
|
89
186
|
this.indentationLevel--;
|
|
90
187
|
code += `${this.indent()}})()`;
|
|
91
188
|
return code;
|
|
92
189
|
}
|
|
93
|
-
return this.generateLambda(node);
|
|
190
|
+
return this.generateLambda(node, context);
|
|
94
191
|
}
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import { Scope } from "../../analysis/scope";
|
|
2
|
+
import { BUILTIN_OBJECTS, Scope } from "../../analysis/scope";
|
|
3
|
+
import { DeclaredSymbolType } from "../../ast/types";
|
|
3
4
|
import { CodeGenerator } from "./";
|
|
4
|
-
const BUILTIN_OBJECTS = new Set([
|
|
5
|
-
"global",
|
|
6
|
-
"globalThis",
|
|
7
|
-
"console",
|
|
8
|
-
"Symbol",
|
|
9
|
-
]);
|
|
10
5
|
export function isBuiltinObject(node) {
|
|
11
|
-
return BUILTIN_OBJECTS.
|
|
6
|
+
return BUILTIN_OBJECTS.values().some((obj) => obj.name === node.text);
|
|
12
7
|
}
|
|
13
8
|
export function getDeclaredSymbols(node) {
|
|
14
9
|
const symbols = new Set();
|
|
@@ -21,6 +16,10 @@ export function getDeclaredSymbols(node) {
|
|
|
21
16
|
// Handles function declarations
|
|
22
17
|
symbols.add(child.name.getText());
|
|
23
18
|
}
|
|
19
|
+
else if (ts.isClassDeclaration(child) && child.name) {
|
|
20
|
+
// Handles class declarations
|
|
21
|
+
symbols.add(child.name.getText());
|
|
22
|
+
}
|
|
24
23
|
else if (ts.isParameter(child)) {
|
|
25
24
|
// Handles function parameters
|
|
26
25
|
symbols.add(child.name.getText());
|
|
@@ -81,3 +80,72 @@ export function escapeString(str) {
|
|
|
81
80
|
export function getJsVarName(node) {
|
|
82
81
|
return `"${node.text}"`;
|
|
83
82
|
}
|
|
83
|
+
export function getDerefCode(nodeText, varName, typeInfo) {
|
|
84
|
+
// Make sure varName is incased in quotes
|
|
85
|
+
if (!varName.startsWith('"'))
|
|
86
|
+
varName = '"' + varName;
|
|
87
|
+
if (!varName.endsWith('"'))
|
|
88
|
+
varName = varName + '"';
|
|
89
|
+
if (typeInfo && typeInfo.needsHeapAllocation) {
|
|
90
|
+
return `jspp::Access::deref_ptr(${nodeText}, ${varName})`;
|
|
91
|
+
}
|
|
92
|
+
return `jspp::Access::deref_stack(${nodeText}, ${varName})`;
|
|
93
|
+
}
|
|
94
|
+
export function getReturnCommand(context) {
|
|
95
|
+
return (context.isInsideGeneratorFunction || context.isInsideAsyncFunction) ? "co_return" : "return";
|
|
96
|
+
}
|
|
97
|
+
export function hoistDeclaration(decl, hoistedSymbols) {
|
|
98
|
+
const name = decl.name?.getText();
|
|
99
|
+
if (!name) {
|
|
100
|
+
return `/* Unknown declaration name: ${ts.SyntaxKind[decl.kind]} */`;
|
|
101
|
+
}
|
|
102
|
+
const isLetOrConst = (decl.parent.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const)) !==
|
|
103
|
+
0;
|
|
104
|
+
const symbolType = isLetOrConst
|
|
105
|
+
? DeclaredSymbolType.letOrConst
|
|
106
|
+
: (ts.isFunctionDeclaration(decl)
|
|
107
|
+
? DeclaredSymbolType.function
|
|
108
|
+
: (ts.isClassDeclaration(decl) ? DeclaredSymbolType.letOrConst : DeclaredSymbolType.var));
|
|
109
|
+
if (hoistedSymbols.has(name)) {
|
|
110
|
+
const existingType = hoistedSymbols.get(name);
|
|
111
|
+
// Don't allow multiple declaration of `letOrConst` or `function` or `class` variables
|
|
112
|
+
if (existingType === DeclaredSymbolType.letOrConst ||
|
|
113
|
+
existingType === DeclaredSymbolType.function ||
|
|
114
|
+
existingType !== symbolType) {
|
|
115
|
+
throw new SyntaxError(`Identifier '${name}' has already been declared`);
|
|
116
|
+
}
|
|
117
|
+
// `var` variables can be declared multiple times
|
|
118
|
+
return "";
|
|
119
|
+
}
|
|
120
|
+
hoistedSymbols.set(name, symbolType);
|
|
121
|
+
const scope = this.getScopeForNode(decl);
|
|
122
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
|
|
123
|
+
const initializer = isLetOrConst || ts.isClassDeclaration(decl)
|
|
124
|
+
? "jspp::AnyValue::make_uninitialized()"
|
|
125
|
+
: "jspp::AnyValue::make_undefined()";
|
|
126
|
+
if (typeInfo.needsHeapAllocation) {
|
|
127
|
+
return `${this.indent()}auto ${name} = std::make_shared<jspp::AnyValue>(${initializer});\n`;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
return `${this.indent()}jspp::AnyValue ${name} = ${initializer};\n`;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export function isGeneratorFunction(node) {
|
|
134
|
+
return ((ts.isFunctionDeclaration(node) ||
|
|
135
|
+
ts.isFunctionExpression(node) ||
|
|
136
|
+
ts.isMethodDeclaration(node)) &&
|
|
137
|
+
!!node.asteriskToken // generator indicator
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
export function isAsyncFunction(node) {
|
|
141
|
+
return ((ts.isFunctionDeclaration(node) ||
|
|
142
|
+
ts.isFunctionExpression(node) ||
|
|
143
|
+
ts.isMethodDeclaration(node) ||
|
|
144
|
+
ts.isArrowFunction(node)) &&
|
|
145
|
+
(ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Async) !== 0);
|
|
146
|
+
}
|
|
147
|
+
export function prepareScopeSymbolsForVisit(topLevel, local) {
|
|
148
|
+
const newTopLevel = new Map(topLevel);
|
|
149
|
+
local.forEach((v, k) => newTopLevel.set(k, v));
|
|
150
|
+
return newTopLevel;
|
|
151
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
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, getDerefCode, getJsVarName, getReturnCommand, getScopeForNode, hoistDeclaration, indent, isAsyncFunction, isBuiltinObject, isGeneratorFunction, prepareScopeSymbolsForVisit, } from "./helpers";
|
|
4
4
|
import { visit } from "./visitor";
|
|
5
5
|
const CONTAINER_FUNCTION_NAME = "__container__";
|
|
6
6
|
export class CodeGenerator {
|
|
7
7
|
indentationLevel = 0;
|
|
8
8
|
typeAnalyzer;
|
|
9
|
+
globalThisVar;
|
|
9
10
|
exceptionCounter = 0;
|
|
10
11
|
// visitor
|
|
11
12
|
visit = visit;
|
|
@@ -13,11 +14,17 @@ export class CodeGenerator {
|
|
|
13
14
|
getDeclaredSymbols = getDeclaredSymbols;
|
|
14
15
|
generateUniqueName = generateUniqueName;
|
|
15
16
|
generateUniqueExceptionName = generateUniqueExceptionName;
|
|
17
|
+
hoistDeclaration = hoistDeclaration;
|
|
16
18
|
getScopeForNode = getScopeForNode;
|
|
17
19
|
indent = indent;
|
|
18
20
|
escapeString = escapeString;
|
|
19
21
|
getJsVarName = getJsVarName;
|
|
22
|
+
getDerefCode = getDerefCode;
|
|
23
|
+
getReturnCommand = getReturnCommand;
|
|
20
24
|
isBuiltinObject = isBuiltinObject;
|
|
25
|
+
isGeneratorFunction = isGeneratorFunction;
|
|
26
|
+
isAsyncFunction = isAsyncFunction;
|
|
27
|
+
prepareScopeSymbolsForVisit = prepareScopeSymbolsForVisit;
|
|
21
28
|
// function handlers
|
|
22
29
|
generateLambda = generateLambda;
|
|
23
30
|
/**
|
|
@@ -25,27 +32,33 @@ export class CodeGenerator {
|
|
|
25
32
|
*/
|
|
26
33
|
generate(ast, analyzer) {
|
|
27
34
|
this.typeAnalyzer = analyzer;
|
|
35
|
+
this.globalThisVar = this.generateUniqueName("__this_val__", this.getDeclaredSymbols(ast));
|
|
28
36
|
const declarations = `#include "index.hpp"\n\n`;
|
|
29
37
|
let containerCode = `jspp::AnyValue ${CONTAINER_FUNCTION_NAME}() {\n`;
|
|
30
38
|
this.indentationLevel++;
|
|
39
|
+
containerCode +=
|
|
40
|
+
`${this.indent()}jspp::AnyValue ${this.globalThisVar} = global;\n`;
|
|
31
41
|
containerCode += this.visit(ast, {
|
|
32
42
|
isMainContext: true,
|
|
33
43
|
isInsideFunction: true,
|
|
34
44
|
isFunctionBody: true,
|
|
45
|
+
topLevelScopeSymbols: new Map(),
|
|
46
|
+
currentScopeSymbols: new Map(),
|
|
35
47
|
});
|
|
36
48
|
this.indentationLevel--;
|
|
37
49
|
containerCode += " return jspp::AnyValue::make_undefined();\n";
|
|
38
50
|
containerCode += "}\n\n";
|
|
39
51
|
let mainCode = "int main() {\n";
|
|
40
|
-
|
|
41
|
-
|
|
52
|
+
// std::ios::sync_with_stdio(false); // Removed to fix console output buffering
|
|
53
|
+
// std::cin.tie(nullptr); // Removed to fix console output buffering
|
|
42
54
|
mainCode += ` try {\n`;
|
|
43
55
|
mainCode += ` ${CONTAINER_FUNCTION_NAME}();\n`;
|
|
56
|
+
mainCode += ` jspp::Scheduler::instance().run();\n`;
|
|
44
57
|
mainCode += ` } catch (const std::exception& ex) {\n`;
|
|
45
58
|
mainCode +=
|
|
46
|
-
" auto error = std::make_shared<jspp::AnyValue>(jspp::
|
|
59
|
+
" auto error = std::make_shared<jspp::AnyValue>(jspp::Exception::exception_to_any_value(ex));\n{\n";
|
|
47
60
|
mainCode +=
|
|
48
|
-
` console.get_own_property("error").as_function("console.error")->call({*error});\n`;
|
|
61
|
+
` ([&](){ auto __obj = console; return __obj.get_own_property("error").as_function("console.error")->call(__obj, {*error}); })();\n`;
|
|
49
62
|
mainCode += ` return 1;\n}\n`;
|
|
50
63
|
mainCode += ` }\n`;
|
|
51
64
|
mainCode += " return 0;\n}";
|