@ugo-studio/jspp 0.1.5 → 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.
- package/dist/ast/symbols.js +3 -0
- package/dist/cli.js +2 -2
- package/dist/core/codegen/control-flow-handlers.js +28 -9
- package/dist/core/codegen/expression-handlers.js +7 -4
- package/dist/core/codegen/function-handlers.js +45 -27
- package/dist/core/codegen/helpers.js +24 -17
- package/dist/core/codegen/index.js +16 -9
- package/dist/core/codegen/statement-handlers.js +242 -58
- package/package.json +1 -1
- package/src/prelude/any_value.hpp +27 -1
- package/src/prelude/any_value_access.hpp +161 -122
- package/src/prelude/any_value_helpers.hpp +2 -0
- package/src/prelude/index.hpp +3 -0
- package/src/prelude/library/promise.hpp +6 -14
- package/src/prelude/types.hpp +6 -0
- package/src/prelude/utils/access.hpp +35 -2
- package/src/prelude/values/async_iterator.hpp +79 -0
- package/src/prelude/values/function.hpp +2 -1
- package/src/prelude/values/helpers/async_iterator.hpp +275 -0
- package/src/prelude/values/helpers/function.hpp +4 -0
- package/src/prelude/values/helpers/promise.hpp +10 -3
- package/src/prelude/values/promise.hpp +4 -8
- package/src/prelude/values/prototypes/async_iterator.hpp +50 -0
package/dist/ast/symbols.js
CHANGED
package/dist/cli.js
CHANGED
|
@@ -42,7 +42,7 @@ async function main() {
|
|
|
42
42
|
// Ensure directory for cpp file exists (should exist as it's source dir, but for safety if we change logic)
|
|
43
43
|
await fs.mkdir(path.dirname(cppFilePath), { recursive: true });
|
|
44
44
|
await fs.writeFile(cppFilePath, cppCode);
|
|
45
|
-
spinner.succeed(`Generated
|
|
45
|
+
spinner.succeed(`Generated cpp`);
|
|
46
46
|
// 2. Precompiled Header Check
|
|
47
47
|
spinner.text = "Checking precompiled headers...";
|
|
48
48
|
spinner.start();
|
|
@@ -76,7 +76,7 @@ async function main() {
|
|
|
76
76
|
spinner.succeed("Precompiled headers updated");
|
|
77
77
|
}
|
|
78
78
|
else {
|
|
79
|
-
spinner.succeed("Precompiled headers
|
|
79
|
+
spinner.succeed("Precompiled headers");
|
|
80
80
|
}
|
|
81
81
|
// 3. Compilation Phase
|
|
82
82
|
spinner.text = `Compiling binary...`;
|
|
@@ -70,7 +70,7 @@ export function visitForStatement(node, context) {
|
|
|
70
70
|
...context,
|
|
71
71
|
currentLabel: undefined,
|
|
72
72
|
isFunctionBody: false,
|
|
73
|
-
});
|
|
73
|
+
}).trim();
|
|
74
74
|
if (ts.isBlock(node.statement)) {
|
|
75
75
|
let blockContent = statementCode.substring(1, statementCode.length - 2); // remove curly braces
|
|
76
76
|
if (context.currentLabel) {
|
|
@@ -218,14 +218,27 @@ export function visitForOfStatement(node, context) {
|
|
|
218
218
|
const iterator = this.generateUniqueName("__iter", declaredSymbols);
|
|
219
219
|
const nextFunc = this.generateUniqueName("__next_func", declaredSymbols);
|
|
220
220
|
const nextRes = this.generateUniqueName("__next_res", declaredSymbols);
|
|
221
|
+
const isAwait = forOf.awaitModifier !== undefined;
|
|
221
222
|
const varName = this.getJsVarName(forOf.expression);
|
|
222
223
|
code += `${this.indent()}auto ${iterableRef} = ${derefIterable};\n`;
|
|
223
|
-
|
|
224
|
-
|
|
224
|
+
if (isAwait) {
|
|
225
|
+
code +=
|
|
226
|
+
`${this.indent()}auto ${iterator} = jspp::Access::get_async_object_value_iterator(${iterableRef}, ${varName});\n`;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
code +=
|
|
230
|
+
`${this.indent()}auto ${iterator} = jspp::Access::get_object_value_iterator(${iterableRef}, ${varName});\n`;
|
|
231
|
+
}
|
|
225
232
|
code +=
|
|
226
233
|
`${this.indent()}auto ${nextFunc} = ${iterator}.get_own_property("next");\n`;
|
|
227
|
-
|
|
228
|
-
|
|
234
|
+
if (isAwait) {
|
|
235
|
+
code +=
|
|
236
|
+
`${this.indent()}auto ${nextRes} = co_await ${nextFunc}.call(${iterator}, {}, "next");\n`;
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
code +=
|
|
240
|
+
`${this.indent()}auto ${nextRes} = ${nextFunc}.call(${iterator}, {}, "next");\n`;
|
|
241
|
+
}
|
|
229
242
|
code +=
|
|
230
243
|
`${this.indent()}while (!is_truthy(${nextRes}.get_own_property("done"))) {\n`;
|
|
231
244
|
this.indentationLevel++;
|
|
@@ -239,8 +252,14 @@ export function visitForOfStatement(node, context) {
|
|
|
239
252
|
if (context.currentLabel) {
|
|
240
253
|
code += `${this.indent()}${context.currentLabel}_continue:;\n`;
|
|
241
254
|
}
|
|
242
|
-
|
|
243
|
-
|
|
255
|
+
if (isAwait) {
|
|
256
|
+
code +=
|
|
257
|
+
`${this.indent()}${nextRes} = co_await ${nextFunc}.call(${iterator}, {}, "next");\n`;
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
code +=
|
|
261
|
+
`${this.indent()}${nextRes} = ${nextFunc}.call(${iterator}, {}, "next");\n`;
|
|
262
|
+
}
|
|
244
263
|
this.indentationLevel--;
|
|
245
264
|
code += `${this.indent()}}\n`;
|
|
246
265
|
this.indentationLevel--; // Exit the scope for the for-of loop
|
|
@@ -269,7 +288,7 @@ export function visitWhileStatement(node, context) {
|
|
|
269
288
|
...context,
|
|
270
289
|
currentLabel: undefined,
|
|
271
290
|
isFunctionBody: false,
|
|
272
|
-
});
|
|
291
|
+
}).trim();
|
|
273
292
|
if (ts.isBlock(node.statement)) {
|
|
274
293
|
let blockContent = statementCode.substring(1, statementCode.length - 2); // remove curly braces
|
|
275
294
|
if (context.currentLabel) {
|
|
@@ -309,7 +328,7 @@ export function visitDoStatement(node, context) {
|
|
|
309
328
|
...context,
|
|
310
329
|
currentLabel: undefined,
|
|
311
330
|
isFunctionBody: false,
|
|
312
|
-
});
|
|
331
|
+
}).trim();
|
|
313
332
|
if (ts.isBlock(node.statement)) {
|
|
314
333
|
let blockContent = statementCode.substring(1, statementCode.length - 2); // remove curly braces
|
|
315
334
|
if (context.currentLabel) {
|
|
@@ -28,8 +28,9 @@ export function visitObjectPropertyName(node, context) {
|
|
|
28
28
|
export function visitObjectLiteralExpression(node, context) {
|
|
29
29
|
const obj = node;
|
|
30
30
|
const objVar = this.generateUniqueName("__obj_", this.getDeclaredSymbols(node));
|
|
31
|
-
let code = `([&]() {
|
|
32
|
-
|
|
31
|
+
let code = `([&]() {\n`;
|
|
32
|
+
code +=
|
|
33
|
+
`${this.indent()} auto ${objVar} = jspp::AnyValue::make_object_with_proto({}, ::Object.get_own_property("prototype"));\n`;
|
|
33
34
|
this.indentationLevel++;
|
|
34
35
|
for (const prop of obj.properties) {
|
|
35
36
|
if (ts.isPropertyAssignment(prop)) {
|
|
@@ -101,6 +102,8 @@ ${this.indent()} auto ${objVar} = jspp::AnyValue::make_object_with_proto({}, ::
|
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
104
|
this.indentationLevel--;
|
|
105
|
+
// code +=
|
|
106
|
+
// `${this.indent()} ${returnCmd} ${objVar};\n${this.indent()}} )() ))`;
|
|
104
107
|
code += `${this.indent()} return ${objVar};\n${this.indent()}})()`;
|
|
105
108
|
return code;
|
|
106
109
|
}
|
|
@@ -593,7 +596,7 @@ export function visitCallExpression(node, context) {
|
|
|
593
596
|
if (callExpr.questionDotToken) {
|
|
594
597
|
return `jspp::Access::optional_call(${derefObj}.get_own_property("${propName}"), ${derefObj}, ${argsSpan}, "${this.escapeString(propName)}")`;
|
|
595
598
|
}
|
|
596
|
-
return
|
|
599
|
+
return `${derefObj}.call_own_property("${propName}", ${argsSpan})`;
|
|
597
600
|
}
|
|
598
601
|
// Handle obj[method]() -> pass obj as 'this'
|
|
599
602
|
if (ts.isElementAccessExpression(callee)) {
|
|
@@ -628,7 +631,7 @@ export function visitCallExpression(node, context) {
|
|
|
628
631
|
if (callExpr.questionDotToken) {
|
|
629
632
|
return `jspp::Access::optional_call(${derefObj}.get_own_property(${argText}), ${derefObj}, ${argsSpan})`;
|
|
630
633
|
}
|
|
631
|
-
return
|
|
634
|
+
return `${derefObj}.call_own_property(${argText}, ${argsSpan})`;
|
|
632
635
|
}
|
|
633
636
|
const calleeCode = this.visit(callee, context);
|
|
634
637
|
let derefCallee = calleeCode;
|
|
@@ -13,9 +13,11 @@ export function generateLambda(node, context, options) {
|
|
|
13
13
|
isInsideGeneratorFunction: isInsideGeneratorFunction,
|
|
14
14
|
isInsideAsyncFunction: isInsideAsyncFunction,
|
|
15
15
|
});
|
|
16
|
-
const funcReturnType = isInsideGeneratorFunction
|
|
17
|
-
? "jspp::
|
|
18
|
-
: (
|
|
16
|
+
const funcReturnType = (isInsideGeneratorFunction && isInsideAsyncFunction)
|
|
17
|
+
? "jspp::JsAsyncIterator<jspp::AnyValue>"
|
|
18
|
+
: (isInsideGeneratorFunction
|
|
19
|
+
? "jspp::JsIterator<jspp::AnyValue>"
|
|
20
|
+
: (isInsideAsyncFunction ? "jspp::JsPromise" : "jspp::AnyValue"));
|
|
19
21
|
const isArrow = ts.isArrowFunction(node);
|
|
20
22
|
// Lambda arguments are ALWAYS const references/spans to avoid copy overhead for normal functions.
|
|
21
23
|
// For generators/async, we manually copy them inside the body.
|
|
@@ -34,8 +36,10 @@ export function generateLambda(node, context, options) {
|
|
|
34
36
|
topLevelScopeSymbols,
|
|
35
37
|
localScopeSymbols: new DeclaredSymbols(),
|
|
36
38
|
superClassVar: context.superClassVar,
|
|
39
|
+
isInsideGeneratorFunction: isInsideGeneratorFunction,
|
|
40
|
+
isInsideAsyncFunction: isInsideAsyncFunction,
|
|
37
41
|
};
|
|
38
|
-
// Name of 'this' and 'args' to be used in the body.
|
|
42
|
+
// Name of 'this' and 'args' to be used in the body.
|
|
39
43
|
// If generator/async, we use the copied versions.
|
|
40
44
|
let bodyThisVar = this.globalThisVar;
|
|
41
45
|
let bodyArgsVar = argsName;
|
|
@@ -45,40 +49,42 @@ export function generateLambda(node, context, options) {
|
|
|
45
49
|
const thisCopy = this.generateUniqueName("__this_copy", declaredSymbols);
|
|
46
50
|
const argsCopy = this.generateUniqueName("__args_copy", declaredSymbols);
|
|
47
51
|
if (!isArrow) {
|
|
48
|
-
preamble +=
|
|
52
|
+
preamble +=
|
|
53
|
+
`${this.indent()}jspp::AnyValue ${thisCopy} = ${this.globalThisVar};\n`;
|
|
49
54
|
bodyThisVar = thisCopy;
|
|
50
55
|
}
|
|
51
|
-
preamble +=
|
|
56
|
+
preamble +=
|
|
57
|
+
`${this.indent()}std::vector<jspp::AnyValue> ${argsCopy}(${argsName}.begin(), ${argsName}.end());\n`;
|
|
52
58
|
bodyArgsVar = argsCopy;
|
|
53
|
-
// Update visitContext to use the new 'this' variable if needed?
|
|
54
|
-
// CodeGenerator.globalThisVar is a member of the class, so we can't easily change it for the recursive visit
|
|
59
|
+
// Update visitContext to use the new 'this' variable if needed?
|
|
60
|
+
// CodeGenerator.globalThisVar is a member of the class, so we can't easily change it for the recursive visit
|
|
55
61
|
// without changing the class state or passing it down.
|
|
56
|
-
// BUT: visitThisKeyword uses `this.globalThisVar`.
|
|
62
|
+
// BUT: visitThisKeyword uses `this.globalThisVar`.
|
|
57
63
|
// We need to temporarily swap `this.globalThisVar` or handle it.
|
|
58
64
|
// Actually, `this.globalThisVar` is set once in `generate`.
|
|
59
65
|
// Wait, `visitThisKeyword` uses `this.globalThisVar`.
|
|
60
66
|
// If we change the variable name for 'this', we must ensure `visitThisKeyword` generates the correct name.
|
|
61
67
|
// `generateLambda` does NOT create a new CodeGenerator instance, so `this.globalThisVar` is the global one.
|
|
62
|
-
//
|
|
68
|
+
//
|
|
63
69
|
// We need to support shadowing `globalThisVar` for the duration of the visit.
|
|
64
|
-
// The current `CodeGenerator` doesn't seem to support changing `globalThisVar` recursively easily
|
|
70
|
+
// The current `CodeGenerator` doesn't seem to support changing `globalThisVar` recursively easily
|
|
65
71
|
// because it's a property of the class, not `VisitContext`.
|
|
66
|
-
//
|
|
72
|
+
//
|
|
67
73
|
// However, `visitFunctionDeclaration` etc don't update `globalThisVar`.
|
|
68
74
|
// `visitThisKeyword` just returns `this.globalThisVar`.
|
|
69
|
-
//
|
|
75
|
+
//
|
|
70
76
|
// If we are inside a function, `this` should refer to the function's `this`.
|
|
71
77
|
// `this.globalThisVar` is generated in `generate()`: `__this_val__...`.
|
|
72
78
|
// And `generateLambda` uses `this.globalThisVar` as the parameter name.
|
|
73
|
-
//
|
|
79
|
+
//
|
|
74
80
|
// So, if we copy it to `__this_copy`, `visitThisKeyword` will still print `__this_val__...`.
|
|
75
81
|
// This is BAD for generators because `__this_val__...` is a reference that dies.
|
|
76
|
-
//
|
|
82
|
+
//
|
|
77
83
|
// FIX: We must reuse the SAME name for the local copy, and shadow the parameter.
|
|
78
84
|
// But we can't declare a variable with the same name as the parameter in the same scope.
|
|
79
|
-
//
|
|
85
|
+
//
|
|
80
86
|
// We can rename the PARAMETER to something else, and declare the local variable with `this.globalThisVar`.
|
|
81
|
-
//
|
|
87
|
+
//
|
|
82
88
|
}
|
|
83
89
|
// Adjust parameter names for generator/async to allow shadowing/copying
|
|
84
90
|
let finalThisParamName = isArrow ? "" : this.globalThisVar;
|
|
@@ -93,16 +99,19 @@ export function generateLambda(node, context, options) {
|
|
|
93
99
|
? "const jspp::AnyValue&"
|
|
94
100
|
: `${paramThisType} ${finalThisParamName}`;
|
|
95
101
|
// Re-construct lambda header with potentially new param names
|
|
96
|
-
lambda =
|
|
102
|
+
lambda =
|
|
103
|
+
`${capture}(${thisArgParamFinal}, ${paramArgsType} ${finalArgsParamName}) mutable -> ${funcReturnType} `;
|
|
97
104
|
// Regenerate preamble
|
|
98
105
|
preamble = "";
|
|
99
106
|
if (isInsideGeneratorFunction || isInsideAsyncFunction) {
|
|
100
107
|
if (!isArrow) {
|
|
101
|
-
preamble +=
|
|
108
|
+
preamble +=
|
|
109
|
+
`${this.indent()}jspp::AnyValue ${this.globalThisVar} = ${finalThisParamName};\n`;
|
|
102
110
|
}
|
|
103
|
-
preamble +=
|
|
111
|
+
preamble +=
|
|
112
|
+
`${this.indent()}std::vector<jspp::AnyValue> ${argsName}(${finalArgsParamName}.begin(), ${finalArgsParamName}.end());\n`;
|
|
104
113
|
}
|
|
105
|
-
// Now 'argsName' refers to the vector (if copied) or the span (if not).
|
|
114
|
+
// Now 'argsName' refers to the vector (if copied) or the span (if not).
|
|
106
115
|
// And 'this.globalThisVar' refers to the copy (if copied) or the param (if not).
|
|
107
116
|
// So subsequent code using `argsName` and `visit` (using `globalThisVar`) works correctly.
|
|
108
117
|
const paramExtractor = (parameters) => {
|
|
@@ -168,7 +177,7 @@ export function generateLambda(node, context, options) {
|
|
|
168
177
|
if (ts.isBlock(node.body)) {
|
|
169
178
|
// Hoist var declarations in the function body
|
|
170
179
|
const varDecls = collectFunctionScopedDeclarations(node.body);
|
|
171
|
-
varDecls.forEach(decl => {
|
|
180
|
+
varDecls.forEach((decl) => {
|
|
172
181
|
preamble += this.hoistDeclaration(decl, visitContext.localScopeSymbols);
|
|
173
182
|
});
|
|
174
183
|
this.indentationLevel++;
|
|
@@ -183,7 +192,8 @@ export function generateLambda(node, context, options) {
|
|
|
183
192
|
isInsideAsyncFunction: isInsideAsyncFunction,
|
|
184
193
|
});
|
|
185
194
|
// The block visitor already adds braces, so we need to inject the preamble and param extraction.
|
|
186
|
-
lambda += "{\n" + preamble + paramExtraction +
|
|
195
|
+
lambda += "{\n" + preamble + paramExtraction +
|
|
196
|
+
blockContent.trimStart().substring(2);
|
|
187
197
|
}
|
|
188
198
|
else {
|
|
189
199
|
lambda += "{\n";
|
|
@@ -210,10 +220,18 @@ export function generateLambda(node, context, options) {
|
|
|
210
220
|
let method = "";
|
|
211
221
|
// Handle generator function
|
|
212
222
|
if (isInsideGeneratorFunction) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
223
|
+
if (isInsideAsyncFunction) {
|
|
224
|
+
signature =
|
|
225
|
+
"jspp::JsAsyncIterator<jspp::AnyValue>(const jspp::AnyValue&, std::span<const jspp::AnyValue>)";
|
|
226
|
+
callable = `std::function<${signature}>(${lambda})`;
|
|
227
|
+
method = `jspp::AnyValue::make_async_generator`;
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
signature =
|
|
231
|
+
"jspp::JsIterator<jspp::AnyValue>(const jspp::AnyValue&, std::span<const jspp::AnyValue>)";
|
|
232
|
+
callable = `std::function<${signature}>(${lambda})`;
|
|
233
|
+
method = `jspp::AnyValue::make_generator`;
|
|
234
|
+
}
|
|
217
235
|
} // Handle async function
|
|
218
236
|
else if (isInsideAsyncFunction) {
|
|
219
237
|
signature =
|
|
@@ -34,22 +34,20 @@ export function getDeclaredSymbols(node) {
|
|
|
34
34
|
return symbols;
|
|
35
35
|
}
|
|
36
36
|
export function generateUniqueName(prefix, ...namesToAvoid) {
|
|
37
|
-
let name = `${prefix}${this.
|
|
37
|
+
let name = `${prefix}${this.uniqueNameCounter}`;
|
|
38
38
|
while (namesToAvoid.some((names) => names.has(name))) {
|
|
39
|
-
this.
|
|
40
|
-
name = `${prefix}${this.
|
|
39
|
+
this.uniqueNameCounter++;
|
|
40
|
+
name = `${prefix}${this.uniqueNameCounter}`;
|
|
41
41
|
}
|
|
42
|
-
this.
|
|
42
|
+
this.uniqueNameCounter++;
|
|
43
43
|
return name;
|
|
44
44
|
}
|
|
45
|
-
export function generateUniqueExceptionName(
|
|
46
|
-
let
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
exceptionName = `__caught_exception_${this.exceptionCounter}`;
|
|
45
|
+
export function generateUniqueExceptionName(exceptionNameToAvoid, ...otherNamesToAvoid) {
|
|
46
|
+
let prefix = `__caught_exception_`;
|
|
47
|
+
if (exceptionNameToAvoid) {
|
|
48
|
+
prefix += exceptionNameToAvoid;
|
|
50
49
|
}
|
|
51
|
-
this.
|
|
52
|
-
return exceptionName;
|
|
50
|
+
return this.generateUniqueName(prefix, ...otherNamesToAvoid);
|
|
53
51
|
}
|
|
54
52
|
export function getScopeForNode(node) {
|
|
55
53
|
let current = node;
|
|
@@ -189,14 +187,16 @@ export function collectFunctionScopedDeclarations(node) {
|
|
|
189
187
|
const decls = [];
|
|
190
188
|
function visit(n) {
|
|
191
189
|
if (ts.isVariableStatement(n)) {
|
|
192
|
-
const isLetOrConst = (n.declarationList.flags &
|
|
190
|
+
const isLetOrConst = (n.declarationList.flags &
|
|
191
|
+
(ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
|
|
193
192
|
if (!isLetOrConst) {
|
|
194
193
|
decls.push(...n.declarationList.declarations);
|
|
195
194
|
}
|
|
196
195
|
}
|
|
197
196
|
else if (ts.isForStatement(n)) {
|
|
198
197
|
if (n.initializer && ts.isVariableDeclarationList(n.initializer)) {
|
|
199
|
-
const isLetOrConst = (n.initializer.flags &
|
|
198
|
+
const isLetOrConst = (n.initializer.flags &
|
|
199
|
+
(ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
|
|
200
200
|
if (!isLetOrConst) {
|
|
201
201
|
decls.push(...n.initializer.declarations);
|
|
202
202
|
}
|
|
@@ -204,7 +204,8 @@ export function collectFunctionScopedDeclarations(node) {
|
|
|
204
204
|
}
|
|
205
205
|
else if (ts.isForInStatement(n)) {
|
|
206
206
|
if (ts.isVariableDeclarationList(n.initializer)) {
|
|
207
|
-
const isLetOrConst = (n.initializer.flags &
|
|
207
|
+
const isLetOrConst = (n.initializer.flags &
|
|
208
|
+
(ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
|
|
208
209
|
if (!isLetOrConst) {
|
|
209
210
|
decls.push(...n.initializer.declarations);
|
|
210
211
|
}
|
|
@@ -212,14 +213,19 @@ export function collectFunctionScopedDeclarations(node) {
|
|
|
212
213
|
}
|
|
213
214
|
else if (ts.isForOfStatement(n)) {
|
|
214
215
|
if (ts.isVariableDeclarationList(n.initializer)) {
|
|
215
|
-
const isLetOrConst = (n.initializer.flags &
|
|
216
|
+
const isLetOrConst = (n.initializer.flags &
|
|
217
|
+
(ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
|
|
216
218
|
if (!isLetOrConst) {
|
|
217
219
|
decls.push(...n.initializer.declarations);
|
|
218
220
|
}
|
|
219
221
|
}
|
|
220
222
|
}
|
|
221
223
|
// Stop recursion at function boundaries (but not the root node if it is a function)
|
|
222
|
-
if (n !== node &&
|
|
224
|
+
if (n !== node &&
|
|
225
|
+
(ts.isFunctionDeclaration(n) || ts.isFunctionExpression(n) ||
|
|
226
|
+
ts.isArrowFunction(n) || ts.isMethodDeclaration(n) ||
|
|
227
|
+
ts.isGetAccessor(n) || ts.isSetAccessor(n) ||
|
|
228
|
+
ts.isClassDeclaration(n))) {
|
|
223
229
|
return;
|
|
224
230
|
}
|
|
225
231
|
ts.forEachChild(n, visit);
|
|
@@ -231,7 +237,8 @@ export function collectBlockScopedDeclarations(statements) {
|
|
|
231
237
|
const decls = [];
|
|
232
238
|
for (const stmt of statements) {
|
|
233
239
|
if (ts.isVariableStatement(stmt)) {
|
|
234
|
-
const isLetOrConst = (stmt.declarationList.flags &
|
|
240
|
+
const isLetOrConst = (stmt.declarationList.flags &
|
|
241
|
+
(ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
|
|
235
242
|
if (isLetOrConst) {
|
|
236
243
|
decls.push(...stmt.declarationList.declarations);
|
|
237
244
|
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { TypeAnalyzer } from "../../analysis/typeAnalyzer";
|
|
2
1
|
import { DeclaredSymbols } from "../../ast/symbols";
|
|
3
2
|
import { generateLambda } from "./function-handlers";
|
|
4
3
|
import { escapeString, generateUniqueExceptionName, generateUniqueName, getDeclaredSymbols, getDerefCode, getJsVarName, getReturnCommand, getScopeForNode, hoistDeclaration, indent, isAsyncFunction, isBuiltinObject, isGeneratorFunction, markSymbolAsChecked, prepareScopeSymbolsForVisit, } from "./helpers";
|
|
5
4
|
import { visit } from "./visitor";
|
|
6
|
-
const
|
|
5
|
+
const MODULE_NAME = "__main_function__";
|
|
7
6
|
export class CodeGenerator {
|
|
8
7
|
indentationLevel = 0;
|
|
9
8
|
typeAnalyzer;
|
|
10
9
|
globalThisVar;
|
|
11
|
-
|
|
10
|
+
uniqueNameCounter = 0;
|
|
12
11
|
// visitor
|
|
13
12
|
visit = visit;
|
|
14
13
|
// helpers
|
|
@@ -36,7 +35,7 @@ export class CodeGenerator {
|
|
|
36
35
|
this.typeAnalyzer = analyzer;
|
|
37
36
|
this.globalThisVar = this.generateUniqueName("__this_val__", this.getDeclaredSymbols(ast));
|
|
38
37
|
const declarations = `#include "index.hpp"\n\n`;
|
|
39
|
-
let containerCode = `jspp::
|
|
38
|
+
let containerCode = `jspp::JsPromise ${MODULE_NAME}() {\n`;
|
|
40
39
|
this.indentationLevel++;
|
|
41
40
|
containerCode +=
|
|
42
41
|
`${this.indent()}jspp::AnyValue ${this.globalThisVar} = global;\n`;
|
|
@@ -44,23 +43,31 @@ export class CodeGenerator {
|
|
|
44
43
|
isMainContext: true,
|
|
45
44
|
isInsideFunction: true,
|
|
46
45
|
isFunctionBody: true,
|
|
46
|
+
isInsideAsyncFunction: true,
|
|
47
47
|
topLevelScopeSymbols: new DeclaredSymbols(),
|
|
48
48
|
localScopeSymbols: new DeclaredSymbols(),
|
|
49
49
|
});
|
|
50
50
|
this.indentationLevel--;
|
|
51
|
-
containerCode += "
|
|
51
|
+
containerCode += " co_return jspp::Constants::UNDEFINED;\n";
|
|
52
52
|
containerCode += "}\n\n";
|
|
53
53
|
let mainCode = "int main(int argc, char** argv) {\n";
|
|
54
54
|
mainCode += ` try {\n`;
|
|
55
55
|
mainCode += ` jspp::setup_process_argv(argc, argv);\n`;
|
|
56
|
-
mainCode += ` ${
|
|
56
|
+
mainCode += ` auto p = ${MODULE_NAME}();\n`;
|
|
57
|
+
mainCode += ` p.then(nullptr, [](const jspp::AnyValue& err) {\n`;
|
|
58
|
+
mainCode +=
|
|
59
|
+
` auto error = std::make_shared<jspp::AnyValue>(err);\n`;
|
|
60
|
+
mainCode +=
|
|
61
|
+
` console.call_own_property("error", std::span<const jspp::AnyValue>((const jspp::AnyValue[]){*error}, 1));\n`;
|
|
62
|
+
mainCode += ` std::exit(1);\n`;
|
|
63
|
+
mainCode += ` });\n`;
|
|
57
64
|
mainCode += ` jspp::Scheduler::instance().run();\n`;
|
|
58
65
|
mainCode += ` } catch (const std::exception& ex) {\n`;
|
|
59
66
|
mainCode +=
|
|
60
|
-
" auto error = std::make_shared<jspp::AnyValue>(jspp::Exception::exception_to_any_value(ex));\n{\n";
|
|
67
|
+
" auto error = std::make_shared<jspp::AnyValue>(jspp::Exception::exception_to_any_value(ex));\n {\n";
|
|
61
68
|
mainCode +=
|
|
62
|
-
`
|
|
63
|
-
mainCode += `
|
|
69
|
+
` console.call_own_property("error", std::span<const jspp::AnyValue>((const jspp::AnyValue[]){*error}, 1));\n`;
|
|
70
|
+
mainCode += ` return 1;\n }\n`;
|
|
64
71
|
mainCode += ` }\n`;
|
|
65
72
|
mainCode += " return 0;\n}";
|
|
66
73
|
return declarations + containerCode + mainCode;
|