@ugo-studio/jspp 0.2.7 → 0.2.9
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/analysis/typeAnalyzer.js +42 -27
- package/dist/core/codegen/class-handlers.js +2 -2
- package/dist/core/codegen/control-flow-handlers.js +4 -4
- package/dist/core/codegen/declaration-handlers.js +21 -3
- package/dist/core/codegen/destructuring-handlers.js +187 -0
- package/dist/core/codegen/expression-handlers.js +7 -0
- package/dist/core/codegen/function-handlers.js +58 -36
- package/dist/core/codegen/helpers.js +288 -52
- package/dist/core/codegen/index.js +7 -4
- package/dist/core/codegen/statement-handlers.js +42 -22
- package/package.json +1 -1
- package/scripts/precompile-headers.ts +19 -4
- package/src/prelude/any_value.hpp +26 -25
- package/src/prelude/any_value_access.hpp +7 -7
- package/src/prelude/any_value_defines.hpp +17 -17
- package/src/prelude/any_value_helpers.hpp +16 -7
- package/src/prelude/library/array.hpp +7 -7
- package/src/prelude/library/console.hpp +5 -5
- package/src/prelude/library/error.hpp +3 -3
- package/src/prelude/library/function.hpp +1 -1
- package/src/prelude/library/math.hpp +38 -38
- package/src/prelude/library/object.hpp +16 -16
- package/src/prelude/library/performance.hpp +1 -1
- package/src/prelude/library/process.hpp +1 -1
- package/src/prelude/library/promise.hpp +8 -8
- package/src/prelude/library/symbol.hpp +3 -3
- package/src/prelude/library/timer.hpp +4 -4
- package/src/prelude/types.hpp +4 -4
- package/src/prelude/utils/access.hpp +24 -6
- package/src/prelude/utils/operators.hpp +7 -0
- package/src/prelude/values/async_iterator.hpp +5 -3
- package/src/prelude/values/function.hpp +3 -3
- package/src/prelude/values/helpers/async_iterator.hpp +7 -3
- package/src/prelude/values/helpers/function.hpp +10 -10
- package/src/prelude/values/helpers/iterator.hpp +39 -2
- package/src/prelude/values/helpers/promise.hpp +9 -9
- package/src/prelude/values/helpers/string.hpp +17 -3
- package/src/prelude/values/iterator.hpp +32 -5
- package/src/prelude/values/promise.hpp +7 -7
- package/src/prelude/values/prototypes/array.hpp +41 -41
- package/src/prelude/values/prototypes/iterator.hpp +128 -1
|
@@ -450,39 +450,54 @@ export class TypeAnalyzer {
|
|
|
450
450
|
}
|
|
451
451
|
if (isAmbient)
|
|
452
452
|
return;
|
|
453
|
-
const name = node.name.getText();
|
|
454
453
|
const isBlockScoped = (node.parent.flags &
|
|
455
454
|
(ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
|
|
456
455
|
const isConst = (node.parent.flags & ts.NodeFlags.Const) !== 0;
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
456
|
+
const defineName = (nameNode) => {
|
|
457
|
+
if (ts.isIdentifier(nameNode)) {
|
|
458
|
+
const name = nameNode.text;
|
|
459
|
+
let type = "auto";
|
|
460
|
+
let needsHeap = false;
|
|
461
|
+
// Type inference only for simple identifiers
|
|
462
|
+
if (nameNode === node.name && node.initializer) {
|
|
463
|
+
if (ts.isArrayLiteralExpression(node.initializer)) {
|
|
464
|
+
type = "array";
|
|
465
|
+
}
|
|
466
|
+
else if (ts.isArrowFunction(node.initializer) ||
|
|
467
|
+
ts.isFunctionExpression(node.initializer)) {
|
|
468
|
+
type = "function";
|
|
469
|
+
needsHeap = true;
|
|
470
|
+
}
|
|
471
|
+
else if (ts.isIdentifier(node.initializer)) {
|
|
472
|
+
const typeInfo = this.scopeManager
|
|
473
|
+
.lookup(node.initializer.text);
|
|
474
|
+
needsHeap =
|
|
475
|
+
typeInfo?.needsHeapAllocation ??
|
|
476
|
+
false;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const typeInfo = {
|
|
480
|
+
type,
|
|
481
|
+
declaration: node,
|
|
482
|
+
isConst,
|
|
483
|
+
needsHeapAllocation: needsHeap,
|
|
484
|
+
};
|
|
485
|
+
if (isBlockScoped) {
|
|
486
|
+
this.scopeManager.define(name, typeInfo);
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
this.scopeManager.defineVar(name, typeInfo);
|
|
490
|
+
}
|
|
467
491
|
}
|
|
468
|
-
else
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
492
|
+
else {
|
|
493
|
+
nameNode.elements.forEach((element) => {
|
|
494
|
+
if (ts.isBindingElement(element)) {
|
|
495
|
+
defineName(element.name);
|
|
496
|
+
}
|
|
497
|
+
});
|
|
472
498
|
}
|
|
473
|
-
}
|
|
474
|
-
const typeInfo = {
|
|
475
|
-
type,
|
|
476
|
-
declaration: node,
|
|
477
|
-
isConst,
|
|
478
|
-
needsHeapAllocation: needsHeap,
|
|
479
499
|
};
|
|
480
|
-
|
|
481
|
-
this.scopeManager.define(name, typeInfo);
|
|
482
|
-
}
|
|
483
|
-
else {
|
|
484
|
-
this.scopeManager.defineVar(name, typeInfo);
|
|
485
|
-
}
|
|
500
|
+
defineName(node.name);
|
|
486
501
|
}
|
|
487
502
|
},
|
|
488
503
|
},
|
|
@@ -42,7 +42,7 @@ export function visitClassDeclaration(node, context) {
|
|
|
42
42
|
// Default constructor
|
|
43
43
|
if (parentName) {
|
|
44
44
|
constructorLambda =
|
|
45
|
-
`jspp::AnyValue::make_class([=](
|
|
45
|
+
`jspp::AnyValue::make_class([=](jspp::AnyValue ${this.globalThisVar}, std::span<const jspp::AnyValue> args) mutable -> jspp::AnyValue {
|
|
46
46
|
auto __parent = ${parentName};
|
|
47
47
|
__parent.call(${this.globalThisVar}, args, "super");
|
|
48
48
|
return jspp::Constants::UNDEFINED;
|
|
@@ -50,7 +50,7 @@ export function visitClassDeclaration(node, context) {
|
|
|
50
50
|
}
|
|
51
51
|
else {
|
|
52
52
|
constructorLambda =
|
|
53
|
-
`jspp::AnyValue::make_class([=](
|
|
53
|
+
`jspp::AnyValue::make_class([=](jspp::AnyValue ${this.globalThisVar}, std::span<const jspp::AnyValue> args) mutable -> jspp::AnyValue {
|
|
54
54
|
return jspp::Constants::UNDEFINED;
|
|
55
55
|
}, "${className}")`;
|
|
56
56
|
}
|
|
@@ -234,11 +234,11 @@ export function visitForOfStatement(node, context) {
|
|
|
234
234
|
code += `${this.indent()}auto ${iterableRef} = ${derefIterable};\n`;
|
|
235
235
|
if (isAwait) {
|
|
236
236
|
code +=
|
|
237
|
-
`${this.indent()}auto ${iterator} = jspp::Access::
|
|
237
|
+
`${this.indent()}auto ${iterator} = jspp::Access::get_object_async_iterator(${iterableRef}, ${varName});\n`;
|
|
238
238
|
}
|
|
239
239
|
else {
|
|
240
240
|
code +=
|
|
241
|
-
`${this.indent()}auto ${iterator} = jspp::Access::
|
|
241
|
+
`${this.indent()}auto ${iterator} = jspp::Access::get_object_iterator(${iterableRef}, ${varName});\n`;
|
|
242
242
|
}
|
|
243
243
|
code +=
|
|
244
244
|
`${this.indent()}auto ${nextFunc} = ${iterator}.get_own_property("next");\n`;
|
|
@@ -459,8 +459,8 @@ export function visitSwitchStatement(node, context) {
|
|
|
459
459
|
const nativeLambda = this.generateNativeLambda(lambdaComps);
|
|
460
460
|
code += `${this.indent()}auto ${nativeName} = ${nativeLambda};\n`;
|
|
461
461
|
// Generate AnyValue wrapper
|
|
462
|
-
if (this.
|
|
463
|
-
this.
|
|
462
|
+
if (this.isDeclarationUsedAsValue(stmt, node) ||
|
|
463
|
+
this.isDeclarationUsedBeforeInitialization(funcName, node)) {
|
|
464
464
|
const wrappedLambda = this.generateWrappedLambda(lambdaComps);
|
|
465
465
|
code += `${this.indent()}*${funcName} = ${wrappedLambda};\n`;
|
|
466
466
|
}
|
|
@@ -9,6 +9,13 @@ export function visitVariableDeclarationList(node, context) {
|
|
|
9
9
|
}
|
|
10
10
|
export function visitVariableDeclaration(node, context) {
|
|
11
11
|
const varDecl = node;
|
|
12
|
+
if (!ts.isIdentifier(varDecl.name)) {
|
|
13
|
+
// Handle destructuring
|
|
14
|
+
const rhsCode = varDecl.initializer
|
|
15
|
+
? this.visit(varDecl.initializer, context)
|
|
16
|
+
: "jspp::Constants::UNDEFINED";
|
|
17
|
+
return this.generateDestructuring(varDecl.name, rhsCode, context);
|
|
18
|
+
}
|
|
12
19
|
const name = varDecl.name.getText();
|
|
13
20
|
const scope = this.getScopeForNode(varDecl);
|
|
14
21
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
|
|
@@ -45,6 +52,9 @@ export function visitVariableDeclaration(node, context) {
|
|
|
45
52
|
lambdaName: name, // Use the variable name as function name
|
|
46
53
|
};
|
|
47
54
|
const nativeName = this.generateUniqueName(`__${name}_native_`, context.localScopeSymbols, context.globalScopeSymbols);
|
|
55
|
+
const scopeNode = ts.isVariableDeclarationList(varDecl.parent)
|
|
56
|
+
? varDecl.parent.parent.parent
|
|
57
|
+
: varDecl.parent;
|
|
48
58
|
// Mark before further visits
|
|
49
59
|
context.localScopeSymbols.update(name, {
|
|
50
60
|
features: {
|
|
@@ -61,11 +71,19 @@ export function visitVariableDeclaration(node, context) {
|
|
|
61
71
|
nativeName,
|
|
62
72
|
noTypeSignature: true,
|
|
63
73
|
});
|
|
64
|
-
const nativeLambda = this.generateNativeLambda(lambdaComps);
|
|
65
74
|
// Generate native lambda
|
|
66
|
-
|
|
75
|
+
if (this.isDeclarationCalledAsFunction(varDecl, scopeNode)) {
|
|
76
|
+
const nativeLambda = this.generateNativeLambda(lambdaComps);
|
|
77
|
+
nativeLambdaCode = `auto ${nativeName} = ${nativeLambda}`;
|
|
78
|
+
}
|
|
67
79
|
// Generate AnyValue wrapper
|
|
68
|
-
|
|
80
|
+
if (this.isDeclarationUsedAsValue(varDecl, scopeNode) ||
|
|
81
|
+
this.isDeclarationUsedBeforeInitialization(name, scopeNode)) {
|
|
82
|
+
initText = this.generateWrappedLambda(lambdaComps);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
return nativeLambdaCode;
|
|
86
|
+
}
|
|
69
87
|
}
|
|
70
88
|
initializer = " = " + initText;
|
|
71
89
|
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { visitObjectPropertyName } from "./expression-handlers.js";
|
|
3
|
+
import { CodeGenerator } from "./index.js";
|
|
4
|
+
import {} from "./visitor.js";
|
|
5
|
+
export function generateDestructuring(lhs, rhsCode, context) {
|
|
6
|
+
const declaredSymbols = this.getDeclaredSymbols(lhs);
|
|
7
|
+
const sourceVar = this.generateUniqueName("__destruct_src", declaredSymbols, context.localScopeSymbols, context.globalScopeSymbols);
|
|
8
|
+
let code = `([&]() {\n`;
|
|
9
|
+
this.indentationLevel++;
|
|
10
|
+
code += `${this.indent()}auto ${sourceVar} = ${rhsCode};\n`;
|
|
11
|
+
const genAssignment = (pattern, valueCode) => {
|
|
12
|
+
if (ts.isIdentifier(pattern)) {
|
|
13
|
+
const name = pattern.text;
|
|
14
|
+
const scope = this.getScopeForNode(pattern);
|
|
15
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
|
|
16
|
+
// Mark initialized if it's a declaration
|
|
17
|
+
this.markSymbolAsInitialized(name, context.globalScopeSymbols, context.localScopeSymbols);
|
|
18
|
+
let target = this.visit(pattern, context);
|
|
19
|
+
if (typeInfo?.needsHeapAllocation) {
|
|
20
|
+
target = `(*${target})`;
|
|
21
|
+
}
|
|
22
|
+
return `${this.indent()}${target} = ${valueCode};\n`;
|
|
23
|
+
}
|
|
24
|
+
else if (ts.isPropertyAccessExpression(pattern)) {
|
|
25
|
+
const objCode = this.visit(pattern.expression, context);
|
|
26
|
+
const propName = visitObjectPropertyName.call(this, pattern.name, context);
|
|
27
|
+
return `${this.indent()}${objCode}.set_own_property(${propName}, ${valueCode});\n`;
|
|
28
|
+
}
|
|
29
|
+
else if (ts.isElementAccessExpression(pattern)) {
|
|
30
|
+
const objCode = this.visit(pattern.expression, context);
|
|
31
|
+
const argCode = visitObjectPropertyName.call(this, pattern.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
32
|
+
return `${this.indent()}${objCode}.set_own_property(${argCode}, ${valueCode});\n`;
|
|
33
|
+
}
|
|
34
|
+
else if (ts.isArrayBindingPattern(pattern) ||
|
|
35
|
+
ts.isArrayLiteralExpression(pattern)) {
|
|
36
|
+
let innerCode = "";
|
|
37
|
+
const elements = ts.isArrayBindingPattern(pattern)
|
|
38
|
+
? pattern.elements
|
|
39
|
+
: pattern.elements;
|
|
40
|
+
const iterVar = this.generateUniqueName("__destruct_iter", declaredSymbols, context.localScopeSymbols, context.globalScopeSymbols);
|
|
41
|
+
const nextVar = this.generateUniqueName("__destruct_next", declaredSymbols, context.localScopeSymbols, context.globalScopeSymbols);
|
|
42
|
+
innerCode +=
|
|
43
|
+
`${this.indent()}auto ${iterVar} = jspp::Access::get_object_iterator(${valueCode}, "destructuring");\n`;
|
|
44
|
+
innerCode +=
|
|
45
|
+
`${this.indent()}auto ${nextVar} = ${iterVar}.get_own_property("next");\n`;
|
|
46
|
+
elements.forEach((element) => {
|
|
47
|
+
if (ts.isOmittedExpression(element)) {
|
|
48
|
+
innerCode +=
|
|
49
|
+
`${this.indent()}${nextVar}.call(${iterVar}, {}, "next");\n`;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
let target;
|
|
53
|
+
let initializer;
|
|
54
|
+
let isRest = false;
|
|
55
|
+
if (ts.isBindingElement(element)) {
|
|
56
|
+
target = element.name;
|
|
57
|
+
initializer = element.initializer;
|
|
58
|
+
isRest = !!element.dotDotDotToken;
|
|
59
|
+
}
|
|
60
|
+
else if (ts.isSpreadElement(element)) {
|
|
61
|
+
target = element.expression;
|
|
62
|
+
isRest = true;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
target = element;
|
|
66
|
+
}
|
|
67
|
+
if (isRest) {
|
|
68
|
+
const restVecVar = this.generateUniqueName("__rest_vec", declaredSymbols, context.localScopeSymbols, context.globalScopeSymbols);
|
|
69
|
+
innerCode +=
|
|
70
|
+
`${this.indent()}std::vector<jspp::AnyValue> ${restVecVar};\n`;
|
|
71
|
+
innerCode += `${this.indent()}while(true) {\n`;
|
|
72
|
+
this.indentationLevel++;
|
|
73
|
+
const resVar = this.generateUniqueName("__res", declaredSymbols, context.localScopeSymbols, context.globalScopeSymbols);
|
|
74
|
+
innerCode +=
|
|
75
|
+
`${this.indent()}auto ${resVar} = ${nextVar}.call(${iterVar}, {}, "next");\n`;
|
|
76
|
+
innerCode +=
|
|
77
|
+
`${this.indent()}if (jspp::is_truthy(${resVar}.get_own_property("done"))) break;\n`;
|
|
78
|
+
innerCode +=
|
|
79
|
+
`${this.indent()}${restVecVar}.push_back(${resVar}.get_own_property("value"));\n`;
|
|
80
|
+
this.indentationLevel--;
|
|
81
|
+
innerCode += `${this.indent()}}\n`;
|
|
82
|
+
innerCode += genAssignment(target, `jspp::AnyValue::make_array(std::move(${restVecVar}))`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
const resVar = this.generateUniqueName("__res", declaredSymbols, context.localScopeSymbols, context.globalScopeSymbols);
|
|
86
|
+
innerCode +=
|
|
87
|
+
`${this.indent()}auto ${resVar} = ${nextVar}.call(${iterVar}, {}, "next");\n`;
|
|
88
|
+
let elementValueCode;
|
|
89
|
+
if (initializer) {
|
|
90
|
+
const valVar = this.generateUniqueName("__val", declaredSymbols, context.localScopeSymbols, context.globalScopeSymbols);
|
|
91
|
+
innerCode +=
|
|
92
|
+
`${this.indent()}auto ${valVar} = (jspp::is_truthy(${resVar}.get_own_property("done")) ? jspp::Constants::UNDEFINED : ${resVar}.get_own_property("value"));\n`;
|
|
93
|
+
const initCode = this.visit(initializer, context);
|
|
94
|
+
elementValueCode =
|
|
95
|
+
`(${valVar}.is_undefined() ? ${initCode} : ${valVar})`;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
elementValueCode =
|
|
99
|
+
`(jspp::is_truthy(${resVar}.get_own_property("done")) ? jspp::Constants::UNDEFINED : ${resVar}.get_own_property("value"))`;
|
|
100
|
+
}
|
|
101
|
+
innerCode += genAssignment(target, elementValueCode);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
// Call the return method to clean resources
|
|
105
|
+
innerCode +=
|
|
106
|
+
`${this.indent()}jspp::Access::call_optional_property_with_optional_call(${iterVar}, "return", {}, "return");\n`;
|
|
107
|
+
return innerCode;
|
|
108
|
+
}
|
|
109
|
+
else if (ts.isObjectBindingPattern(pattern) ||
|
|
110
|
+
ts.isObjectLiteralExpression(pattern)) {
|
|
111
|
+
let innerCode = "";
|
|
112
|
+
const properties = ts.isObjectBindingPattern(pattern)
|
|
113
|
+
? pattern.elements
|
|
114
|
+
: pattern.properties;
|
|
115
|
+
const seenKeys = [];
|
|
116
|
+
properties.forEach((prop) => {
|
|
117
|
+
let target;
|
|
118
|
+
let propertyName;
|
|
119
|
+
let initializer;
|
|
120
|
+
let isRest = false;
|
|
121
|
+
if (ts.isBindingElement(prop)) {
|
|
122
|
+
if (prop.dotDotDotToken) {
|
|
123
|
+
isRest = true;
|
|
124
|
+
target = prop.name;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
target = prop.name;
|
|
128
|
+
propertyName = prop.propertyName
|
|
129
|
+
? visitObjectPropertyName.call(this, prop.propertyName, context)
|
|
130
|
+
: (ts.isIdentifier(prop.name)
|
|
131
|
+
? `"${prop.name.text}"`
|
|
132
|
+
: undefined);
|
|
133
|
+
initializer = prop.initializer;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else if (ts.isPropertyAssignment(prop)) {
|
|
137
|
+
target = prop.initializer;
|
|
138
|
+
propertyName = visitObjectPropertyName.call(this, prop.name, context);
|
|
139
|
+
}
|
|
140
|
+
else if (ts.isShorthandPropertyAssignment(prop)) {
|
|
141
|
+
target = prop.name;
|
|
142
|
+
propertyName = `"${prop.name.text}"`;
|
|
143
|
+
}
|
|
144
|
+
else if (ts.isSpreadAssignment(prop)) {
|
|
145
|
+
isRest = true;
|
|
146
|
+
target = prop.expression;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (isRest) {
|
|
152
|
+
const keysArray = `{${seenKeys.map((k) => k.startsWith('"') && k.endsWith('"')
|
|
153
|
+
? k
|
|
154
|
+
: `(${k}).to_property_key()`).join(", ")}}`;
|
|
155
|
+
const restValueCode = `jspp::Access::get_rest_object(${valueCode}, std::vector<std::string>${keysArray})`;
|
|
156
|
+
innerCode += genAssignment(target, restValueCode);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
if (propertyName) {
|
|
160
|
+
seenKeys.push(propertyName);
|
|
161
|
+
let elementValueCode;
|
|
162
|
+
if (initializer) {
|
|
163
|
+
const valVar = this.generateUniqueName("__val", declaredSymbols, context.localScopeSymbols, context.globalScopeSymbols);
|
|
164
|
+
innerCode +=
|
|
165
|
+
`${this.indent()}auto ${valVar} = ${valueCode}.get_own_property(${propertyName});\n`;
|
|
166
|
+
const initCode = this.visit(initializer, context);
|
|
167
|
+
elementValueCode =
|
|
168
|
+
`(${valVar}.is_undefined() ? ${initCode} : ${valVar})`;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
elementValueCode =
|
|
172
|
+
`${valueCode}.get_own_property(${propertyName})`;
|
|
173
|
+
}
|
|
174
|
+
innerCode += genAssignment(target, elementValueCode);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
return innerCode;
|
|
179
|
+
}
|
|
180
|
+
return "";
|
|
181
|
+
};
|
|
182
|
+
code += genAssignment(lhs, sourceVar);
|
|
183
|
+
code += `${this.indent()}return ${sourceVar};\n`;
|
|
184
|
+
this.indentationLevel--;
|
|
185
|
+
code += `${this.indent()}})()`;
|
|
186
|
+
return code;
|
|
187
|
+
}
|
|
@@ -554,6 +554,13 @@ export function visitBinaryExpression(node, context) {
|
|
|
554
554
|
}
|
|
555
555
|
return `${finalObjExpr}.set_own_property(${argText}, ${finalRightText})`;
|
|
556
556
|
}
|
|
557
|
+
// Array/Object destructuring assignment
|
|
558
|
+
if (ts.isArrayLiteralExpression(binExpr.left) ||
|
|
559
|
+
ts.isObjectLiteralExpression(binExpr.left)) {
|
|
560
|
+
const rhsCode = this.visit(binExpr.right, visitContext);
|
|
561
|
+
return this.generateDestructuring(binExpr.left, rhsCode, visitContext);
|
|
562
|
+
}
|
|
563
|
+
// Simple variable or property assignment
|
|
557
564
|
const leftText = this.visit(binExpr.left, visitContext);
|
|
558
565
|
const scope = this.getScopeForNode(binExpr.left);
|
|
559
566
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.text, scope);
|
|
@@ -17,10 +17,12 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
17
17
|
: (isInsideGeneratorFunction
|
|
18
18
|
? "jspp::JsIterator<jspp::AnyValue>"
|
|
19
19
|
: (isInsideAsyncFunction ? "jspp::JsPromise" : "jspp::AnyValue"));
|
|
20
|
-
// Lambda arguments
|
|
21
|
-
//
|
|
22
|
-
const paramThisType = "
|
|
23
|
-
const paramArgsType =
|
|
20
|
+
// Lambda arguments: regular functions use std::span for performance.
|
|
21
|
+
// Generators and async functions use std::vector to ensure they are safely copied into the coroutine frame.
|
|
22
|
+
const paramThisType = "jspp::AnyValue";
|
|
23
|
+
const paramArgsType = (isInsideGeneratorFunction || isInsideAsyncFunction)
|
|
24
|
+
? "std::vector<jspp::AnyValue>"
|
|
25
|
+
: "std::span<const jspp::AnyValue>";
|
|
24
26
|
const globalScopeSymbols = this.prepareScopeSymbolsForVisit(context.globalScopeSymbols, context.localScopeSymbols);
|
|
25
27
|
const visitContext = {
|
|
26
28
|
currentScopeNode: context.currentScopeNode,
|
|
@@ -44,7 +46,7 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
44
46
|
finalArgsParamName = this.generateUniqueName("__args_ref", declaredSymbols);
|
|
45
47
|
}
|
|
46
48
|
const thisArgParam = isArrow
|
|
47
|
-
? "
|
|
49
|
+
? "jspp::AnyValue" // Arrow functions use captured 'this' or are never generators in this parser context
|
|
48
50
|
: `${paramThisType} ${finalThisParamName}`;
|
|
49
51
|
const funcArgs = `${paramArgsType} ${finalArgsParamName}`;
|
|
50
52
|
// Preamble to copy arguments for coroutines
|
|
@@ -57,41 +59,62 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
57
59
|
nativePreamble +=
|
|
58
60
|
`${this.indent()}jspp::AnyValue ${this.globalThisVar} = ${finalThisParamName};\n`;
|
|
59
61
|
}
|
|
60
|
-
// Note:
|
|
62
|
+
// Note: Arguments are now automatically copied into the coroutine frame because
|
|
63
|
+
// the lambda parameter is passed by value (std::vector).
|
|
64
|
+
// We just need to define argsName as a reference to the parameter.
|
|
61
65
|
preamble +=
|
|
62
|
-
`${this.indent()}
|
|
66
|
+
`${this.indent()}auto& ${argsName} = ${finalArgsParamName};\n`;
|
|
63
67
|
}
|
|
64
68
|
// Native function arguments for native lambda
|
|
65
69
|
let nativeFuncArgs = "";
|
|
66
70
|
let nativeParamsContent = "";
|
|
67
71
|
this.validateFunctionParams(node.parameters).forEach((p, i) => {
|
|
68
|
-
const name = p.name
|
|
72
|
+
const name = ts.isIdentifier(p.name)
|
|
73
|
+
? p.name.text
|
|
74
|
+
: this.generateUniqueName(`__param_native_${i}_`, visitContext.localScopeSymbols);
|
|
69
75
|
const defaultValue = p.initializer
|
|
70
76
|
? this.visit(p.initializer, visitContext)
|
|
71
77
|
: !!p.dotDotDotToken
|
|
72
78
|
? "jspp::AnyValue::make_array(std::vector<jspp::AnyValue>{})"
|
|
73
79
|
: "jspp::Constants::UNDEFINED";
|
|
74
|
-
nativeFuncArgs += `,
|
|
80
|
+
nativeFuncArgs += `, jspp::AnyValue ${name} = ${defaultValue}`;
|
|
81
|
+
if (!ts.isIdentifier(p.name)) {
|
|
82
|
+
nativeParamsContent += this.generateDestructuring(p.name, name, visitContext) + ";\n";
|
|
83
|
+
}
|
|
75
84
|
});
|
|
76
85
|
// Extract lambda parameters from arguments span/vector
|
|
77
86
|
const generateParamsBuilder = () => {
|
|
78
87
|
let paramsCode = "";
|
|
79
88
|
this.validateFunctionParams(node.parameters).forEach((p, i) => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (
|
|
89
|
+
if (ts.isIdentifier(p.name)) {
|
|
90
|
+
const name = p.name.text;
|
|
91
|
+
const defaultValue = p.initializer
|
|
92
|
+
? this.visit(p.initializer, visitContext)
|
|
93
|
+
: "jspp::Constants::UNDEFINED";
|
|
94
|
+
// Add paramerter to local context
|
|
95
|
+
visitContext.localScopeSymbols.add(name, {
|
|
96
|
+
type: DeclarationType.let,
|
|
97
|
+
checks: { initialized: true },
|
|
98
|
+
});
|
|
99
|
+
const scope = this.getScopeForNode(p);
|
|
100
|
+
const typeInfo = this.typeAnalyzer.scopeManager
|
|
101
|
+
.lookupFromScope(name, scope);
|
|
102
|
+
// Handle rest parameters
|
|
103
|
+
if (!!p.dotDotDotToken) {
|
|
104
|
+
const initValue = `jspp::AnyValue::make_array(${argsName}.subspan(${i}))`;
|
|
105
|
+
if (typeInfo.needsHeapAllocation) {
|
|
106
|
+
paramsCode +=
|
|
107
|
+
`${this.indent()}auto ${name} = std::make_shared<jspp::AnyValue>(${initValue});\n`;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
paramsCode +=
|
|
111
|
+
`${this.indent()}jspp::AnyValue ${name} = ${initValue};\n`;
|
|
112
|
+
}
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
// Normal parameter
|
|
116
|
+
const initValue = `${argsName}.size() > ${i} ? ${argsName}[${i}] : ${defaultValue}`;
|
|
117
|
+
if (typeInfo && typeInfo.needsHeapAllocation) {
|
|
95
118
|
paramsCode +=
|
|
96
119
|
`${this.indent()}auto ${name} = std::make_shared<jspp::AnyValue>(${initValue});\n`;
|
|
97
120
|
}
|
|
@@ -99,17 +122,16 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
99
122
|
paramsCode +=
|
|
100
123
|
`${this.indent()}jspp::AnyValue ${name} = ${initValue};\n`;
|
|
101
124
|
}
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
// Normal parameter
|
|
105
|
-
const initValue = `${argsName}.size() > ${i} ? ${argsName}[${i}] : ${defaultValue}`;
|
|
106
|
-
if (typeInfo && typeInfo.needsHeapAllocation) {
|
|
107
|
-
paramsCode +=
|
|
108
|
-
`${this.indent()}auto ${name} = std::make_shared<jspp::AnyValue>(${initValue});\n`;
|
|
109
125
|
}
|
|
110
126
|
else {
|
|
127
|
+
const tempName = this.generateUniqueName(`__param_tmp_${i}_`, visitContext.localScopeSymbols);
|
|
128
|
+
const defaultValue = p.initializer
|
|
129
|
+
? this.visit(p.initializer, visitContext)
|
|
130
|
+
: "jspp::Constants::UNDEFINED";
|
|
131
|
+
const initValue = `${argsName}.size() > ${i} ? ${argsName}[${i}] : ${defaultValue}`;
|
|
111
132
|
paramsCode +=
|
|
112
|
-
`${this.indent()}
|
|
133
|
+
`${this.indent()}auto ${tempName} = ${initValue};\n`;
|
|
134
|
+
paramsCode += this.generateDestructuring(p.name, tempName, visitContext) + ";\n";
|
|
113
135
|
}
|
|
114
136
|
});
|
|
115
137
|
return paramsCode;
|
|
@@ -204,14 +226,14 @@ export function generateWrappedLambda(comps) {
|
|
|
204
226
|
if (isInsideGeneratorFunction) {
|
|
205
227
|
if (isInsideAsyncFunction) {
|
|
206
228
|
if (!noTypeSignature) {
|
|
207
|
-
const signature = "jspp::JsAsyncIterator<jspp::AnyValue>(
|
|
229
|
+
const signature = "jspp::JsAsyncIterator<jspp::AnyValue>(jspp::AnyValue, std::vector<jspp::AnyValue>)";
|
|
208
230
|
callable = `std::function<${signature}>(${lambda})`;
|
|
209
231
|
}
|
|
210
232
|
method = `jspp::AnyValue::make_async_generator`;
|
|
211
233
|
}
|
|
212
234
|
else {
|
|
213
235
|
if (!noTypeSignature) {
|
|
214
|
-
const signature = "jspp::JsIterator<jspp::AnyValue>(
|
|
236
|
+
const signature = "jspp::JsIterator<jspp::AnyValue>(jspp::AnyValue, std::vector<jspp::AnyValue>)";
|
|
215
237
|
callable = `std::function<${signature}>(${lambda})`;
|
|
216
238
|
}
|
|
217
239
|
method = `jspp::AnyValue::make_generator`;
|
|
@@ -219,14 +241,14 @@ export function generateWrappedLambda(comps) {
|
|
|
219
241
|
} // Handle async function
|
|
220
242
|
else if (isInsideAsyncFunction) {
|
|
221
243
|
if (!noTypeSignature) {
|
|
222
|
-
const signature = "jspp::JsPromise(
|
|
244
|
+
const signature = "jspp::JsPromise(jspp::AnyValue, std::vector<jspp::AnyValue>)";
|
|
223
245
|
callable = `std::function<${signature}>(${lambda})`;
|
|
224
246
|
}
|
|
225
247
|
method = `jspp::AnyValue::make_async_function`;
|
|
226
248
|
} // Handle normal function
|
|
227
249
|
else {
|
|
228
250
|
if (!noTypeSignature) {
|
|
229
|
-
const signature = `jspp::AnyValue(
|
|
251
|
+
const signature = `jspp::AnyValue(jspp::AnyValue, std::span<const jspp::AnyValue>)`;
|
|
230
252
|
callable = `std::function<${signature}>(${lambda})`;
|
|
231
253
|
}
|
|
232
254
|
if (options?.isClass) {
|