@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.
Files changed (41) hide show
  1. package/dist/analysis/typeAnalyzer.js +42 -27
  2. package/dist/core/codegen/class-handlers.js +2 -2
  3. package/dist/core/codegen/control-flow-handlers.js +4 -4
  4. package/dist/core/codegen/declaration-handlers.js +21 -3
  5. package/dist/core/codegen/destructuring-handlers.js +187 -0
  6. package/dist/core/codegen/expression-handlers.js +7 -0
  7. package/dist/core/codegen/function-handlers.js +58 -36
  8. package/dist/core/codegen/helpers.js +288 -52
  9. package/dist/core/codegen/index.js +7 -4
  10. package/dist/core/codegen/statement-handlers.js +42 -22
  11. package/package.json +1 -1
  12. package/scripts/precompile-headers.ts +19 -4
  13. package/src/prelude/any_value.hpp +26 -25
  14. package/src/prelude/any_value_access.hpp +7 -7
  15. package/src/prelude/any_value_defines.hpp +17 -17
  16. package/src/prelude/any_value_helpers.hpp +16 -7
  17. package/src/prelude/library/array.hpp +7 -7
  18. package/src/prelude/library/console.hpp +5 -5
  19. package/src/prelude/library/error.hpp +3 -3
  20. package/src/prelude/library/function.hpp +1 -1
  21. package/src/prelude/library/math.hpp +38 -38
  22. package/src/prelude/library/object.hpp +16 -16
  23. package/src/prelude/library/performance.hpp +1 -1
  24. package/src/prelude/library/process.hpp +1 -1
  25. package/src/prelude/library/promise.hpp +8 -8
  26. package/src/prelude/library/symbol.hpp +3 -3
  27. package/src/prelude/library/timer.hpp +4 -4
  28. package/src/prelude/types.hpp +4 -4
  29. package/src/prelude/utils/access.hpp +24 -6
  30. package/src/prelude/utils/operators.hpp +7 -0
  31. package/src/prelude/values/async_iterator.hpp +5 -3
  32. package/src/prelude/values/function.hpp +3 -3
  33. package/src/prelude/values/helpers/async_iterator.hpp +7 -3
  34. package/src/prelude/values/helpers/function.hpp +10 -10
  35. package/src/prelude/values/helpers/iterator.hpp +39 -2
  36. package/src/prelude/values/helpers/promise.hpp +9 -9
  37. package/src/prelude/values/helpers/string.hpp +17 -3
  38. package/src/prelude/values/iterator.hpp +32 -5
  39. package/src/prelude/values/promise.hpp +7 -7
  40. package/src/prelude/values/prototypes/array.hpp +41 -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
- let type = "auto";
458
- let needsHeap = false;
459
- if (node.initializer) {
460
- if (ts.isArrayLiteralExpression(node.initializer)) {
461
- type = "array";
462
- }
463
- else if (ts.isArrowFunction(node.initializer) ||
464
- ts.isFunctionExpression(node.initializer)) {
465
- type = "function";
466
- needsHeap = true;
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 if (ts.isIdentifier(node.initializer)) {
469
- const typeInfo = this.scopeManager.lookup(node.initializer.text);
470
- needsHeap = typeInfo?.needsHeapAllocation ??
471
- false;
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
- if (isBlockScoped) {
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([=](const jspp::AnyValue& ${this.globalThisVar}, std::span<const jspp::AnyValue> args) mutable -> jspp::AnyValue {
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([=](const jspp::AnyValue& ${this.globalThisVar}, std::span<const jspp::AnyValue> args) mutable -> jspp::AnyValue {
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::get_async_object_value_iterator(${iterableRef}, ${varName});\n`;
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::get_object_value_iterator(${iterableRef}, ${varName});\n`;
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.isFunctionUsedAsValue(stmt, node) ||
463
- this.isFunctionUsedBeforeDeclaration(funcName, node)) {
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
- nativeLambdaCode = `auto ${nativeName} = ${nativeLambda}`;
75
+ if (this.isDeclarationCalledAsFunction(varDecl, scopeNode)) {
76
+ const nativeLambda = this.generateNativeLambda(lambdaComps);
77
+ nativeLambdaCode = `auto ${nativeName} = ${nativeLambda}`;
78
+ }
67
79
  // Generate AnyValue wrapper
68
- initText = this.generateWrappedLambda(lambdaComps);
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 are ALWAYS const references/spans to avoid copy overhead for normal functions.
21
- // For generators/async, we manually copy them inside the body.
22
- const paramThisType = "const jspp::AnyValue&";
23
- const paramArgsType = "std::span<const jspp::AnyValue>";
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
- ? "const jspp::AnyValue&" // Arrow functions use captured 'this' or are never generators in this parser context
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: Do not add argument copy to native lambda
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()}std::vector<jspp::AnyValue> ${argsName}(${finalArgsParamName}.begin(), ${finalArgsParamName}.end());\n`;
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.getText();
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 += `, const jspp::AnyValue& ${name} = ${defaultValue}`;
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
- const name = p.name.getText();
81
- const defaultValue = p.initializer
82
- ? this.visit(p.initializer, visitContext)
83
- : "jspp::Constants::UNDEFINED";
84
- // Add paramerter to local context
85
- visitContext.localScopeSymbols.add(name, {
86
- type: DeclarationType.let,
87
- checks: { initialized: true },
88
- });
89
- const scope = this.getScopeForNode(p);
90
- const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
91
- // Handle rest parameters
92
- if (!!p.dotDotDotToken) {
93
- const initValue = `jspp::AnyValue::make_array(${argsName}.subspan(${i}))`;
94
- if (typeInfo.needsHeapAllocation) {
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()}jspp::AnyValue ${name} = ${initValue};\n`;
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>(const jspp::AnyValue&, std::span<const 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>(const jspp::AnyValue&, std::span<const 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(const jspp::AnyValue&, std::span<const jspp::AnyValue>)";
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(const jspp::AnyValue&, std::span<const 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) {