@ugo-studio/jspp 0.3.1 → 0.3.2
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/cli/args.js +22 -0
- package/dist/cli/compiler.js +53 -0
- package/dist/cli/index.js +43 -117
- package/dist/cli/pch.js +71 -0
- package/dist/cli/runner.js +23 -0
- package/dist/cli/spinner.js +27 -11
- package/dist/cli/transpiler.js +20 -0
- package/dist/cli/utils.js +25 -27
- package/dist/cli/wasm.js +70 -0
- package/dist/index.js +17 -6
- package/dist/{analysis → interpreter/analysis}/scope.js +34 -1
- package/dist/{analysis → interpreter/analysis}/typeAnalyzer.js +542 -3
- package/dist/{core → interpreter/core}/codegen/class-handlers.js +1 -1
- package/dist/{core → interpreter/core}/codegen/control-flow-handlers.js +2 -2
- package/dist/{core → interpreter/core}/codegen/declaration-handlers.js +21 -9
- package/dist/{core → interpreter/core}/codegen/destructuring-handlers.js +3 -3
- package/dist/{core → interpreter/core}/codegen/expression-handlers.js +44 -61
- package/dist/{core → interpreter/core}/codegen/function-handlers.js +108 -61
- package/dist/{core → interpreter/core}/codegen/helpers.js +79 -11
- package/dist/interpreter/core/codegen/index.js +156 -0
- package/dist/{core → interpreter/core}/codegen/literal-handlers.js +9 -0
- package/dist/{core → interpreter/core}/codegen/statement-handlers.js +39 -1
- package/package.json +6 -4
- package/scripts/precompile-headers.ts +63 -19
- package/scripts/setup-emsdk.ts +114 -0
- package/src/prelude/any_value.cpp +851 -599
- package/src/prelude/any_value.hpp +28 -30
- package/src/prelude/jspp.hpp +3 -1
- package/src/prelude/library/boolean.cpp +30 -0
- package/src/prelude/library/boolean.hpp +14 -0
- package/src/prelude/library/error.cpp +2 -2
- package/src/prelude/library/global.cpp +2 -0
- package/src/prelude/library/math.cpp +46 -43
- package/src/prelude/library/math.hpp +2 -0
- package/src/prelude/library/object.cpp +1 -1
- package/src/prelude/types.hpp +10 -9
- package/src/prelude/utils/access.hpp +2 -2
- package/src/prelude/utils/assignment_operators.hpp +40 -20
- package/src/prelude/utils/log_any_value/log_any_value.hpp +1 -1
- package/src/prelude/utils/log_any_value/primitives.hpp +1 -1
- package/src/prelude/utils/operators.hpp +87 -87
- package/src/prelude/utils/operators_native.hpp +349 -0
- package/src/prelude/utils/well_known_symbols.hpp +13 -13
- package/src/prelude/values/array.cpp +3 -3
- package/src/prelude/values/boolean.cpp +64 -0
- package/src/prelude/values/number.cpp +137 -92
- package/src/prelude/values/object.cpp +163 -122
- package/src/prelude/values/prototypes/boolean.hpp +24 -0
- package/src/prelude/values/prototypes/number.hpp +8 -1
- package/dist/cli/file-utils.js +0 -20
- package/dist/cli-utils/args.js +0 -59
- package/dist/cli-utils/colors.js +0 -9
- package/dist/cli-utils/file-utils.js +0 -20
- package/dist/cli-utils/spinner.js +0 -55
- package/dist/cli.js +0 -153
- package/dist/core/codegen/index.js +0 -88
- package/src/prelude/utils/operators_primitive.hpp +0 -337
- /package/dist/{ast → interpreter/ast}/symbols.js +0 -0
- /package/dist/{ast → interpreter/ast}/types.js +0 -0
- /package/dist/{core → interpreter/core}/codegen/visitor.js +0 -0
- /package/dist/{core → interpreter/core}/constants.js +0 -0
- /package/dist/{core → interpreter/core}/error.js +0 -0
- /package/dist/{core → interpreter/core}/parser.js +0 -0
- /package/dist/{core → interpreter/core}/traverser.js +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import {
|
|
2
|
+
import { RESERVED_VAR_NAMES } from "../../analysis/scope.js";
|
|
3
3
|
import { CompilerError } from "../error.js";
|
|
4
4
|
import { CodeGenerator } from "./index.js";
|
|
5
5
|
export function visitVariableDeclarationList(node, context) {
|
|
@@ -18,8 +18,8 @@ export function visitVariableDeclaration(node, context) {
|
|
|
18
18
|
return this.generateDestructuring(varDecl.name, rhsCode, context);
|
|
19
19
|
}
|
|
20
20
|
const name = varDecl.name.getText();
|
|
21
|
-
if (
|
|
22
|
-
throw new CompilerError(`Cannot declare a variable named '${name}'
|
|
21
|
+
if (RESERVED_VAR_NAMES.has(name)) {
|
|
22
|
+
throw new CompilerError(`Cannot declare a variable named '${name}'.`, varDecl.name, "SyntaxError");
|
|
23
23
|
}
|
|
24
24
|
const scope = this.getScopeForNode(varDecl);
|
|
25
25
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
|
|
@@ -53,7 +53,7 @@ export function visitVariableDeclaration(node, context) {
|
|
|
53
53
|
(ts.isFunctionExpression(initExpr) && !initExpr.name)) {
|
|
54
54
|
const initContext = {
|
|
55
55
|
...context,
|
|
56
|
-
|
|
56
|
+
functionName: name, // Use the variable name as function name
|
|
57
57
|
};
|
|
58
58
|
const nativeName = this.generateUniqueName(`__${name}_native_`, context.localScopeSymbols, context.globalScopeSymbols);
|
|
59
59
|
const scopeNode = ts.isVariableDeclarationList(varDecl.parent)
|
|
@@ -92,16 +92,28 @@ export function visitVariableDeclaration(node, context) {
|
|
|
92
92
|
return nativeLambdaCode;
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
-
initializer =
|
|
95
|
+
initializer = initText;
|
|
96
96
|
}
|
|
97
97
|
const isLetOrConst = (varDecl.parent.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
|
|
98
98
|
const shouldDeref = context.derefBeforeAssignment &&
|
|
99
99
|
(!context.localScopeSymbols.has(name));
|
|
100
|
-
|
|
100
|
+
let assignmentTarget = shouldDeref
|
|
101
101
|
? this.getDerefCode(name, name, context, typeInfo)
|
|
102
102
|
: (typeInfo?.needsHeapAllocation && !shouldSkipDeref
|
|
103
103
|
? `*${name}`
|
|
104
104
|
: name);
|
|
105
|
+
const sym = context.localScopeSymbols.get(name) ||
|
|
106
|
+
context.globalScopeSymbols.get(name);
|
|
107
|
+
if (sym?.checks.skippedHoisting) {
|
|
108
|
+
assignmentTarget = typeInfo?.needsHeapAllocation && !shouldSkipDeref
|
|
109
|
+
? `auto ${name}`
|
|
110
|
+
: `jspp::AnyValue ${name}`;
|
|
111
|
+
if (initializer) {
|
|
112
|
+
initializer = typeInfo?.needsHeapAllocation && !shouldSkipDeref
|
|
113
|
+
? `std::make_shared<jspp::AnyValue>(${initializer})`
|
|
114
|
+
: initializer;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
105
117
|
if (nativeLambdaCode)
|
|
106
118
|
nativeLambdaCode += `;\n${this.indent()}`;
|
|
107
119
|
if (isLetOrConst) {
|
|
@@ -116,19 +128,19 @@ export function visitVariableDeclaration(node, context) {
|
|
|
116
128
|
return `${nativeLambdaCode}${assignmentTarget} = jspp::Constants::UNDEFINED`;
|
|
117
129
|
}
|
|
118
130
|
}
|
|
119
|
-
return `${nativeLambdaCode}${assignmentTarget}${initializer}`;
|
|
131
|
+
return `${nativeLambdaCode}${assignmentTarget} = ${initializer}`;
|
|
120
132
|
}
|
|
121
133
|
// For 'var', it's a bit more complex.
|
|
122
134
|
if (context.isAssignmentOnly) {
|
|
123
135
|
if (!initializer)
|
|
124
136
|
return "";
|
|
125
|
-
return `${nativeLambdaCode}${assignmentTarget}${initializer}`;
|
|
137
|
+
return `${nativeLambdaCode}${assignmentTarget} = ${initializer}`;
|
|
126
138
|
}
|
|
127
139
|
else {
|
|
128
140
|
// This case should not be hit with the new hoisting logic,
|
|
129
141
|
// but is kept for safety.
|
|
130
142
|
const initValue = initializer
|
|
131
|
-
? initializer
|
|
143
|
+
? initializer
|
|
132
144
|
: "jspp::Constants::UNDEFINED";
|
|
133
145
|
if (typeInfo?.needsHeapAllocation) {
|
|
134
146
|
return `auto ${name} = std::make_shared<jspp::AnyValue>(${initValue})`;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import {
|
|
2
|
+
import { RESERVED_VAR_NAMES } from "../../analysis/scope.js";
|
|
3
3
|
import { CompilerError } from "../error.js";
|
|
4
4
|
import { visitObjectPropertyName } from "./expression-handlers.js";
|
|
5
5
|
import { CodeGenerator } from "./index.js";
|
|
@@ -13,8 +13,8 @@ export function generateDestructuring(lhs, rhsCode, context) {
|
|
|
13
13
|
const genAssignment = (pattern, valueCode) => {
|
|
14
14
|
if (ts.isIdentifier(pattern)) {
|
|
15
15
|
const name = pattern.text;
|
|
16
|
-
if (
|
|
17
|
-
throw new CompilerError(`Cannot destructure to a variable named '${name}'
|
|
16
|
+
if (RESERVED_VAR_NAMES.has(name)) {
|
|
17
|
+
throw new CompilerError(`Cannot destructure to a variable named '${name}'.`, pattern, "SyntaxError");
|
|
18
18
|
}
|
|
19
19
|
const scope = this.getScopeForNode(pattern);
|
|
20
20
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
|
|
@@ -607,7 +607,8 @@ export function visitBinaryExpression(node, context) {
|
|
|
607
607
|
finalLeft = this.getDerefCode(leftText, this.getJsVarName(binExpr.left), visitContext, typeInfo);
|
|
608
608
|
}
|
|
609
609
|
// Number optimizations
|
|
610
|
-
|
|
610
|
+
const nodeType = this.typeAnalyzer.inferNodeReturnType(binExpr.left);
|
|
611
|
+
if (nodeType === "number") {
|
|
611
612
|
finalLeft = `${finalLeft}.as_double()`;
|
|
612
613
|
}
|
|
613
614
|
}
|
|
@@ -623,7 +624,8 @@ export function visitBinaryExpression(node, context) {
|
|
|
623
624
|
finalRight = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), visitContext, typeInfo);
|
|
624
625
|
}
|
|
625
626
|
// Number optimizations
|
|
626
|
-
|
|
627
|
+
const nodeType = this.typeAnalyzer.inferNodeReturnType(binExpr.right);
|
|
628
|
+
if (nodeType === "number") {
|
|
627
629
|
finalRight = `${finalRight}.as_double()`;
|
|
628
630
|
}
|
|
629
631
|
}
|
|
@@ -642,101 +644,82 @@ export function visitBinaryExpression(node, context) {
|
|
|
642
644
|
if (opToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
|
|
643
645
|
return `jspp::nullish_coalesce(${finalLeft}, ${finalRight})`;
|
|
644
646
|
}
|
|
645
|
-
const isLiteral = (n) => ts.isNumericLiteral(n);
|
|
646
|
-
const supportsNativeBoolean = ts.isIfStatement(node.parent) ||
|
|
647
|
-
ts.isConditionalExpression(node.parent);
|
|
648
647
|
// Native values for lhs and rhs
|
|
649
|
-
const literalLeft =
|
|
648
|
+
const literalLeft = ts.isNumericLiteral(binExpr.left)
|
|
650
649
|
? binExpr.left.getText()
|
|
651
650
|
: finalLeft;
|
|
652
|
-
const literalRight =
|
|
651
|
+
const literalRight = ts.isNumericLiteral(binExpr.right)
|
|
653
652
|
? binExpr.right.getText()
|
|
654
653
|
: finalRight;
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
if (
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
funcName = "jspp::less_than_primitive";
|
|
673
|
-
}
|
|
674
|
-
if (opToken.kind === ts.SyntaxKind.LessThanEqualsToken) {
|
|
675
|
-
funcName = "jspp::less_than_or_equal_primitive";
|
|
676
|
-
}
|
|
677
|
-
if (opToken.kind === ts.SyntaxKind.GreaterThanToken) {
|
|
678
|
-
funcName = "jspp::greater_than_primitive";
|
|
679
|
-
}
|
|
680
|
-
if (opToken.kind === ts.SyntaxKind.GreaterThanEqualsToken) {
|
|
681
|
-
funcName = "jspp::greater_than_or_equal_primitive";
|
|
654
|
+
let supportsNativeValue = false;
|
|
655
|
+
const exprReturnType = this.typeAnalyzer.inferNodeReturnType(node);
|
|
656
|
+
if (exprReturnType === "boolean" &&
|
|
657
|
+
(ts.isIfStatement(node.parent) ||
|
|
658
|
+
ts.isConditionalExpression(node.parent))) {
|
|
659
|
+
supportsNativeValue = true;
|
|
660
|
+
}
|
|
661
|
+
else if (exprReturnType === "number" &&
|
|
662
|
+
context.isInsideNativeLambda &&
|
|
663
|
+
context.isInsideFunction) {
|
|
664
|
+
const funcDecl = this
|
|
665
|
+
.findEnclosingFunctionDeclarationFromReturnStatement(node);
|
|
666
|
+
if (funcDecl) {
|
|
667
|
+
const funcReturnType = this.typeAnalyzer.inferFunctionReturnType(funcDecl);
|
|
668
|
+
if (funcReturnType === "number") {
|
|
669
|
+
supportsNativeValue = true;
|
|
670
|
+
}
|
|
682
671
|
}
|
|
683
|
-
// For C++ primitive literals, standard operators are fine if they map directly,
|
|
684
|
-
// but we are safe using our functions (which handle doubles correctly).
|
|
685
|
-
// Actually, for pure numeric literals like "1 < 2", we can leave it as is if we want optimization,
|
|
686
|
-
// but consistency is safer.
|
|
687
|
-
// Let's stick to valid C++ syntax for literals if possible to avoid overhead?
|
|
688
|
-
// jspp::less_than(1, 2) works.
|
|
689
|
-
return `${funcName}(${literalLeft}, ${literalRight})`;
|
|
690
672
|
}
|
|
673
|
+
const method = supportsNativeValue ? "_native" : "";
|
|
691
674
|
// Return boxed value
|
|
692
675
|
if (opToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken) {
|
|
693
|
-
return `jspp::is_strictly_equal_to(${literalLeft}, ${literalRight})`;
|
|
676
|
+
return `jspp::is_strictly_equal_to${method}(${literalLeft}, ${literalRight})`;
|
|
694
677
|
}
|
|
695
678
|
if (opToken.kind === ts.SyntaxKind.EqualsEqualsToken) {
|
|
696
|
-
return `jspp::is_equal_to(${literalLeft}, ${literalRight})`;
|
|
679
|
+
return `jspp::is_equal_to${method}(${literalLeft}, ${literalRight})`;
|
|
697
680
|
}
|
|
698
681
|
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
|
|
699
|
-
return `jspp::not_strictly_equal_to(${literalLeft}, ${literalRight})`;
|
|
682
|
+
return `jspp::not_strictly_equal_to${method}(${literalLeft}, ${literalRight})`;
|
|
700
683
|
}
|
|
701
684
|
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsToken) {
|
|
702
|
-
return `jspp::not_equal_to(${literalLeft}, ${literalRight})`;
|
|
685
|
+
return `jspp::not_equal_to${method}(${literalLeft}, ${literalRight})`;
|
|
703
686
|
}
|
|
704
687
|
if (opToken.kind === ts.SyntaxKind.AsteriskAsteriskToken) {
|
|
705
|
-
return `jspp::pow(${literalLeft}, ${literalRight})`;
|
|
688
|
+
return `jspp::pow${method}(${literalLeft}, ${literalRight})`;
|
|
706
689
|
}
|
|
707
690
|
if (opToken.kind === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken) {
|
|
708
|
-
return `jspp::unsigned_right_shift(${literalLeft}, ${literalRight})`;
|
|
691
|
+
return `jspp::unsigned_right_shift${method}(${literalLeft}, ${literalRight})`;
|
|
709
692
|
}
|
|
710
693
|
// For other arithmetic and bitwise operations, use native operations if possible
|
|
711
694
|
switch (op) {
|
|
712
695
|
case "+":
|
|
713
|
-
return `jspp::add(${literalLeft}, ${literalRight})`;
|
|
696
|
+
return `jspp::add${method}(${literalLeft}, ${literalRight})`;
|
|
714
697
|
case "-":
|
|
715
|
-
return `jspp::sub(${literalLeft}, ${literalRight})`;
|
|
698
|
+
return `jspp::sub${method}(${literalLeft}, ${literalRight})`;
|
|
716
699
|
case "*":
|
|
717
|
-
return `jspp::mul(${literalLeft}, ${literalRight})`;
|
|
700
|
+
return `jspp::mul${method}(${literalLeft}, ${literalRight})`;
|
|
718
701
|
case "/":
|
|
719
|
-
return `jspp::div(${literalLeft}, ${literalRight})`;
|
|
702
|
+
return `jspp::div${method}(${literalLeft}, ${literalRight})`;
|
|
720
703
|
case "%":
|
|
721
|
-
return `jspp::mod(${literalLeft}, ${literalRight})`;
|
|
704
|
+
return `jspp::mod${method}(${literalLeft}, ${literalRight})`;
|
|
722
705
|
case "^":
|
|
723
|
-
return `jspp::bitwise_xor(${literalLeft}, ${literalRight})`;
|
|
706
|
+
return `jspp::bitwise_xor${method}(${literalLeft}, ${literalRight})`;
|
|
724
707
|
case "&":
|
|
725
|
-
return `jspp::bitwise_and(${literalLeft}, ${literalRight})`;
|
|
708
|
+
return `jspp::bitwise_and${method}(${literalLeft}, ${literalRight})`;
|
|
726
709
|
case "|":
|
|
727
|
-
return `jspp::bitwise_or(${literalLeft}, ${literalRight})`;
|
|
710
|
+
return `jspp::bitwise_or${method}(${literalLeft}, ${literalRight})`;
|
|
728
711
|
case "<<":
|
|
729
|
-
return `jspp::left_shift(${literalLeft}, ${literalRight})`;
|
|
712
|
+
return `jspp::left_shift${method}(${literalLeft}, ${literalRight})`;
|
|
730
713
|
case ">>":
|
|
731
|
-
return `jspp::right_shift(${literalLeft}, ${literalRight})`;
|
|
714
|
+
return `jspp::right_shift${method}(${literalLeft}, ${literalRight})`;
|
|
732
715
|
case "<":
|
|
733
|
-
return `jspp::less_than(${literalLeft}, ${literalRight})`;
|
|
716
|
+
return `jspp::less_than${method}(${literalLeft}, ${literalRight})`;
|
|
734
717
|
case ">":
|
|
735
|
-
return `jspp::greater_than(${literalLeft}, ${literalRight})`;
|
|
718
|
+
return `jspp::greater_than${method}(${literalLeft}, ${literalRight})`;
|
|
736
719
|
case "<=":
|
|
737
|
-
return `jspp::less_than_or_equal(${literalLeft}, ${literalRight})`;
|
|
720
|
+
return `jspp::less_than_or_equal${method}(${literalLeft}, ${literalRight})`;
|
|
738
721
|
case ">=":
|
|
739
|
-
return `jspp::greater_than_or_equal(${literalLeft}, ${literalRight})`;
|
|
722
|
+
return `jspp::greater_than_or_equal${method}(${literalLeft}, ${literalRight})`;
|
|
740
723
|
}
|
|
741
724
|
return `/* Unhandled Operator: ${finalLeft} ${op} ${finalRight} */`; // Default fallback
|
|
742
725
|
}
|
|
@@ -5,8 +5,18 @@ import { CodeGenerator } from "./index.js";
|
|
|
5
5
|
export function generateLambdaComponents(node, context, options) {
|
|
6
6
|
const declaredSymbols = this.getDeclaredSymbols(node);
|
|
7
7
|
const argsName = this.generateUniqueName("__args_", declaredSymbols, context.globalScopeSymbols, context.localScopeSymbols);
|
|
8
|
-
const nativeExcessArgsName = this.generateUniqueName(
|
|
9
|
-
|
|
8
|
+
// const nativeExcessArgsName = this.generateUniqueName(
|
|
9
|
+
// "__excess_args",
|
|
10
|
+
// declaredSymbols,
|
|
11
|
+
// context.globalScopeSymbols,
|
|
12
|
+
// context.localScopeSymbols,
|
|
13
|
+
// );
|
|
14
|
+
// const nativeTotalArgsSizeName = this.generateUniqueName(
|
|
15
|
+
// "__total_args_size",
|
|
16
|
+
// declaredSymbols,
|
|
17
|
+
// context.globalScopeSymbols,
|
|
18
|
+
// context.localScopeSymbols,
|
|
19
|
+
// );
|
|
10
20
|
const isInsideGeneratorFunction = this.isGeneratorFunction(node);
|
|
11
21
|
const isInsideAsyncFunction = this.isAsyncFunction(node);
|
|
12
22
|
const isArrow = ts.isArrowFunction(node);
|
|
@@ -14,15 +24,27 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
14
24
|
isInsideGeneratorFunction: isInsideGeneratorFunction,
|
|
15
25
|
isInsideAsyncFunction: isInsideAsyncFunction,
|
|
16
26
|
});
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
const getFuncReturnType = (isInsideNativeLambda) => {
|
|
28
|
+
if (isInsideGeneratorFunction && isInsideAsyncFunction) {
|
|
29
|
+
return "jspp::JsAsyncIterator<jspp::AnyValue>";
|
|
30
|
+
}
|
|
31
|
+
else if (isInsideGeneratorFunction) {
|
|
32
|
+
return "jspp::JsIterator<jspp::AnyValue>";
|
|
33
|
+
}
|
|
34
|
+
else if (isInsideAsyncFunction)
|
|
35
|
+
return "jspp::JsPromise";
|
|
36
|
+
else {
|
|
37
|
+
const inferedReturnType = this.typeAnalyzer.inferFunctionReturnType(node);
|
|
38
|
+
if (isInsideNativeLambda && inferedReturnType === "number") {
|
|
39
|
+
return "double";
|
|
40
|
+
}
|
|
41
|
+
return "jspp::AnyValue";
|
|
42
|
+
}
|
|
43
|
+
};
|
|
22
44
|
// Lambda arguments: regular functions use std::span for performance.
|
|
23
45
|
// Generators and async functions use std::vector to ensure they are safely copied into the coroutine frame.
|
|
24
46
|
const paramThisType = "jspp::AnyValue";
|
|
25
|
-
const paramArgsType =
|
|
47
|
+
const paramArgsType = isInsideGeneratorFunction || isInsideAsyncFunction
|
|
26
48
|
? "std::vector<jspp::AnyValue>"
|
|
27
49
|
: "std::span<const jspp::AnyValue>";
|
|
28
50
|
const globalScopeSymbols = this.prepareScopeSymbolsForVisit(context.globalScopeSymbols, context.localScopeSymbols);
|
|
@@ -31,7 +53,7 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
31
53
|
isMainContext: false,
|
|
32
54
|
isInsideFunction: true,
|
|
33
55
|
isFunctionBody: false,
|
|
34
|
-
|
|
56
|
+
functionName: undefined,
|
|
35
57
|
globalScopeSymbols,
|
|
36
58
|
localScopeSymbols: new DeclaredSymbols(),
|
|
37
59
|
superClassVar: context.superClassVar,
|
|
@@ -95,7 +117,8 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
95
117
|
`${this.indent()}auto ${name} = std::make_shared<jspp::AnyValue>(${signatureName});\n`;
|
|
96
118
|
}
|
|
97
119
|
else {
|
|
98
|
-
nativeParamsContent += this.generateDestructuring(p.name, signatureName, visitContext) +
|
|
120
|
+
nativeParamsContent += this.generateDestructuring(p.name, signatureName, visitContext) +
|
|
121
|
+
";\n";
|
|
99
122
|
}
|
|
100
123
|
}
|
|
101
124
|
});
|
|
@@ -114,8 +137,7 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
114
137
|
checks: { initialized: true },
|
|
115
138
|
});
|
|
116
139
|
const scope = this.getScopeForNode(p);
|
|
117
|
-
const typeInfo = this.typeAnalyzer.scopeManager
|
|
118
|
-
.lookupFromScope(name, scope);
|
|
140
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
|
|
119
141
|
// Handle rest parameters
|
|
120
142
|
if (!!p.dotDotDotToken) {
|
|
121
143
|
const initValue = `jspp::AnyValue::make_array(${argsName}.subspan(${i}))`;
|
|
@@ -148,39 +170,43 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
148
170
|
const initValue = `${argsName}.size() > ${i} ? ${argsName}[${i}] : ${defaultValue}`;
|
|
149
171
|
paramsCode +=
|
|
150
172
|
`${this.indent()}auto ${tempName} = ${initValue};\n`;
|
|
151
|
-
paramsCode +=
|
|
173
|
+
paramsCode +=
|
|
174
|
+
this.generateDestructuring(p.name, tempName, visitContext) +
|
|
175
|
+
";\n";
|
|
152
176
|
}
|
|
153
177
|
});
|
|
154
178
|
return paramsCode;
|
|
155
179
|
};
|
|
156
180
|
// Generate params and function body
|
|
157
181
|
let paramsContent = "";
|
|
158
|
-
let
|
|
182
|
+
let getBlockContentWithoutOpeningBrace = () => "";
|
|
159
183
|
// Generate `arguments` variable if it used in the function body
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
+
// TODO: compile arguments array from parameters
|
|
185
|
+
// if (
|
|
186
|
+
// this.isVariableUsedWithoutDeclaration("arguments", node.body as ts.Node)
|
|
187
|
+
// ) {
|
|
188
|
+
// // Add span parameter for holding the excess arguments from the caller of the native lambda
|
|
189
|
+
// nativeFuncArgs +=
|
|
190
|
+
// `, const std::size_t ${nativeTotalArgsSizeName}, std::span<const jspp::AnyValue> ${nativeExcessArgsName} = {}`;
|
|
191
|
+
// // this.indentationLevel++;
|
|
192
|
+
// // nativeParamsContent +=
|
|
193
|
+
// // `${this.indent()}jspp::AnyValue arguments = jspp::Constants::UNDEFINED;\n`;
|
|
194
|
+
// // nativeParamsContent += `${this.indent()}{\n`;
|
|
195
|
+
// // this.indentationLevel++;
|
|
196
|
+
// // nativeParamsContent +=
|
|
197
|
+
// // `${this.indent()}std::vector<jspp::AnyValue> ${argsName};\n`;
|
|
198
|
+
// // this.validateFunctionParams(node.parameters).forEach(
|
|
199
|
+
// // (p, i) => {
|
|
200
|
+
// // },
|
|
201
|
+
// // );
|
|
202
|
+
// // this.indentationLevel--;
|
|
203
|
+
// // nativeParamsContent += `${this.indent()}}\n`;
|
|
204
|
+
// // this.indentationLevel--;
|
|
205
|
+
// // this.indentationLevel++;
|
|
206
|
+
// // paramsContent =
|
|
207
|
+
// // `${this.indent()}jspp::AnyValue arguments = jspp::AnyValue::make_array(${argsName});\n`;
|
|
208
|
+
// // this.indentationLevel--;
|
|
209
|
+
// }
|
|
184
210
|
if (node.body) {
|
|
185
211
|
if (ts.isBlock(node.body)) {
|
|
186
212
|
// Hoist var declarations in the function body
|
|
@@ -202,34 +228,53 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
202
228
|
paramsContent += generateParamsBuilder();
|
|
203
229
|
this.indentationLevel--;
|
|
204
230
|
// The block visitor already adds braces, so we need to remove the opening brace to inject the preamble and param extraction.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
231
|
+
const properIndentationLevel = this.indentationLevel;
|
|
232
|
+
const nodeBody = node.body;
|
|
233
|
+
getBlockContentWithoutOpeningBrace = (isInsideNativeLambda) => {
|
|
234
|
+
const currentIndentationLevel = this.indentationLevel;
|
|
235
|
+
this.indentationLevel = properIndentationLevel;
|
|
236
|
+
const code = this.visit(nodeBody, {
|
|
237
|
+
...visitContext,
|
|
238
|
+
isMainContext: false,
|
|
239
|
+
isInsideFunction: true,
|
|
240
|
+
isFunctionBody: true,
|
|
241
|
+
isInsideGeneratorFunction,
|
|
242
|
+
isInsideAsyncFunction,
|
|
243
|
+
isInsideNativeLambda,
|
|
244
|
+
})
|
|
245
|
+
.trim()
|
|
246
|
+
.substring(2);
|
|
247
|
+
this.indentationLevel = currentIndentationLevel;
|
|
248
|
+
return code;
|
|
249
|
+
};
|
|
213
250
|
}
|
|
214
251
|
else {
|
|
215
252
|
this.indentationLevel++;
|
|
216
253
|
paramsContent += generateParamsBuilder();
|
|
217
|
-
|
|
218
|
-
|
|
254
|
+
const properIndentationLevel = this.indentationLevel;
|
|
255
|
+
const nodeBody = node.body;
|
|
256
|
+
getBlockContentWithoutOpeningBrace = (isInsideNativeLambda) => {
|
|
257
|
+
const currentIndentationLevel = this.indentationLevel;
|
|
258
|
+
this.indentationLevel = properIndentationLevel;
|
|
259
|
+
let code = `${this.indent()}${returnCommand} ${this.visit(nodeBody, {
|
|
219
260
|
...visitContext,
|
|
220
261
|
isMainContext: false,
|
|
221
262
|
isInsideFunction: true,
|
|
222
263
|
isFunctionBody: false,
|
|
223
|
-
isInsideGeneratorFunction
|
|
224
|
-
isInsideAsyncFunction
|
|
264
|
+
isInsideGeneratorFunction,
|
|
265
|
+
isInsideAsyncFunction,
|
|
266
|
+
isInsideNativeLambda,
|
|
225
267
|
})};\n`;
|
|
268
|
+
this.indentationLevel--;
|
|
269
|
+
code += `${this.indent()}}`;
|
|
270
|
+
this.indentationLevel = currentIndentationLevel;
|
|
271
|
+
return code;
|
|
272
|
+
};
|
|
226
273
|
this.indentationLevel--;
|
|
227
|
-
blockContentWithoutOpeningBrace += `${this.indent()}}`;
|
|
228
274
|
}
|
|
229
275
|
}
|
|
230
276
|
else {
|
|
231
|
-
|
|
232
|
-
`${returnCommand} jspp::Constants::UNDEFINED; }\n`;
|
|
277
|
+
getBlockContentWithoutOpeningBrace = () => `${returnCommand} jspp::Constants::UNDEFINED; }`;
|
|
233
278
|
}
|
|
234
279
|
return {
|
|
235
280
|
node,
|
|
@@ -239,37 +284,39 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
239
284
|
thisArgParam,
|
|
240
285
|
funcArgs,
|
|
241
286
|
nativeFuncArgs,
|
|
242
|
-
|
|
287
|
+
getFuncReturnType,
|
|
243
288
|
preamble,
|
|
244
289
|
nativePreamble,
|
|
245
290
|
paramsContent,
|
|
246
291
|
nativeParamsContent,
|
|
247
|
-
|
|
292
|
+
getBlockContentWithoutOpeningBrace,
|
|
248
293
|
isInsideGeneratorFunction,
|
|
249
294
|
isInsideAsyncFunction,
|
|
250
295
|
};
|
|
251
296
|
}
|
|
252
297
|
export function generateNativeLambda(comps) {
|
|
253
|
-
const { options, thisArgParam, nativeFuncArgs,
|
|
298
|
+
const { options, thisArgParam, nativeFuncArgs, getFuncReturnType, nativePreamble, nativeParamsContent, getBlockContentWithoutOpeningBrace, } = comps;
|
|
254
299
|
const capture = options?.capture || "[=]";
|
|
255
300
|
const nativeName = options?.nativeName;
|
|
256
301
|
const selfParam = nativeName ? `this auto&& ${nativeName}, ` : "";
|
|
257
302
|
const mutableLabel = nativeName ? "" : "mutable ";
|
|
303
|
+
const funcReturnType = getFuncReturnType(true);
|
|
258
304
|
let lambda = `${capture}(${selfParam}${thisArgParam}${nativeFuncArgs}) ${mutableLabel}-> ${funcReturnType} {\n`;
|
|
259
305
|
lambda += nativePreamble;
|
|
260
306
|
lambda += nativeParamsContent;
|
|
261
|
-
lambda +=
|
|
307
|
+
lambda += getBlockContentWithoutOpeningBrace(true);
|
|
262
308
|
return lambda;
|
|
263
309
|
}
|
|
264
310
|
export function generateWrappedLambda(comps) {
|
|
265
|
-
const { node, context, options, thisArgParam, funcArgs,
|
|
311
|
+
const { node, context, options, thisArgParam, funcArgs, getFuncReturnType, preamble, paramsContent, getBlockContentWithoutOpeningBrace, isInsideGeneratorFunction, isInsideAsyncFunction, } = comps;
|
|
266
312
|
const capture = options?.capture || "[=]";
|
|
267
313
|
const isAssignment = options?.isAssignment || false;
|
|
314
|
+
const funcReturnType = getFuncReturnType(false);
|
|
268
315
|
const noTypeSignature = options?.noTypeSignature || false;
|
|
269
316
|
let lambda = `${capture}(${thisArgParam}, ${funcArgs}) mutable -> ${funcReturnType} {\n`;
|
|
270
317
|
lambda += preamble;
|
|
271
318
|
lambda += paramsContent;
|
|
272
|
-
lambda +=
|
|
319
|
+
lambda += getBlockContentWithoutOpeningBrace(false);
|
|
273
320
|
let callable = lambda;
|
|
274
321
|
let method = "";
|
|
275
322
|
// Handle generator function
|
|
@@ -308,7 +355,7 @@ export function generateWrappedLambda(comps) {
|
|
|
308
355
|
method = `jspp::AnyValue::make_function`;
|
|
309
356
|
}
|
|
310
357
|
}
|
|
311
|
-
const funcName = context?.
|
|
358
|
+
const funcName = context?.functionName || node.name?.getText();
|
|
312
359
|
const hasName = !!funcName && funcName.length > 0;
|
|
313
360
|
let args = callable;
|
|
314
361
|
const isArrow = ts.isArrowFunction(node);
|
|
@@ -378,7 +425,7 @@ export function visitFunctionExpression(node, context) {
|
|
|
378
425
|
`${this.indent()}auto ${funcName} = std::make_shared<jspp::AnyValue>();\n`;
|
|
379
426
|
const lambda = this.generateWrappedLambda(this.generateLambdaComponents(funcExpr, {
|
|
380
427
|
...context,
|
|
381
|
-
|
|
428
|
+
functionName: funcName,
|
|
382
429
|
}, {
|
|
383
430
|
isAssignment: true,
|
|
384
431
|
capture: "[=]",
|