@ugo-studio/jspp 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -36
- package/dist/analysis/scope.js +7 -0
- package/dist/analysis/typeAnalyzer.js +96 -43
- package/dist/ast/symbols.js +34 -24
- package/dist/cli/args.js +59 -0
- package/dist/cli/colors.js +9 -0
- package/dist/cli/file-utils.js +20 -0
- package/dist/cli/index.js +160 -0
- package/dist/cli/spinner.js +55 -0
- package/dist/core/codegen/class-handlers.js +8 -8
- package/dist/core/codegen/control-flow-handlers.js +19 -9
- package/dist/core/codegen/declaration-handlers.js +30 -10
- package/dist/core/codegen/expression-handlers.js +649 -161
- package/dist/core/codegen/function-handlers.js +107 -103
- package/dist/core/codegen/helpers.js +61 -14
- package/dist/core/codegen/index.js +13 -9
- package/dist/core/codegen/literal-handlers.js +4 -2
- package/dist/core/codegen/statement-handlers.js +147 -55
- package/dist/core/codegen/visitor.js +22 -2
- package/dist/core/constants.js +16 -0
- package/dist/core/error.js +58 -0
- package/dist/index.js +6 -3
- package/package.json +3 -3
- package/src/prelude/any_value.hpp +89 -59
- package/src/prelude/any_value_access.hpp +1 -1
- package/src/prelude/any_value_helpers.hpp +85 -43
- package/src/prelude/index.hpp +1 -0
- package/src/prelude/library/array.hpp +3 -2
- package/src/prelude/scheduler.hpp +144 -144
- package/src/prelude/types.hpp +8 -8
- package/src/prelude/utils/access.hpp +62 -6
- package/src/prelude/utils/assignment_operators.hpp +14 -14
- package/src/prelude/utils/log_any_value/array.hpp +0 -15
- package/src/prelude/utils/log_any_value/object.hpp +12 -10
- package/src/prelude/utils/log_any_value/primitives.hpp +2 -0
- package/src/prelude/utils/operators.hpp +117 -474
- package/src/prelude/utils/operators_primitive.hpp +337 -0
- package/src/prelude/values/helpers/array.hpp +4 -4
- package/src/prelude/values/helpers/async_iterator.hpp +2 -2
- package/src/prelude/values/helpers/function.hpp +3 -3
- package/src/prelude/values/helpers/iterator.hpp +2 -2
- package/src/prelude/values/helpers/object.hpp +3 -3
- package/src/prelude/values/helpers/promise.hpp +1 -1
- package/src/prelude/values/helpers/string.hpp +1 -1
- package/src/prelude/values/helpers/symbol.hpp +1 -1
- package/src/prelude/values/prototypes/array.hpp +1125 -853
- package/src/prelude/values/prototypes/async_iterator.hpp +32 -14
- package/src/prelude/values/prototypes/function.hpp +30 -18
- package/src/prelude/values/prototypes/iterator.hpp +40 -17
- package/src/prelude/values/prototypes/number.hpp +119 -62
- package/src/prelude/values/prototypes/object.hpp +10 -4
- package/src/prelude/values/prototypes/promise.hpp +167 -109
- package/src/prelude/values/prototypes/string.hpp +407 -231
- package/src/prelude/values/prototypes/symbol.hpp +45 -23
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
+
import { constants } from "../constants.js";
|
|
3
|
+
import { CompilerError } from "../error.js";
|
|
2
4
|
import { CodeGenerator } from "./index.js";
|
|
5
|
+
/**
|
|
6
|
+
* Helper to recursively flatten static spread elements in arrays or call arguments.
|
|
7
|
+
*/
|
|
8
|
+
function flattenArrayElements(elements) {
|
|
9
|
+
const flattened = [];
|
|
10
|
+
for (const elem of elements) {
|
|
11
|
+
if (elem && ts.isSpreadElement(elem)) {
|
|
12
|
+
const expr = elem.expression;
|
|
13
|
+
if (ts.isArrayLiteralExpression(expr)) {
|
|
14
|
+
flattened.push(...flattenArrayElements(expr.elements));
|
|
15
|
+
}
|
|
16
|
+
else if (ts.isStringLiteral(expr) ||
|
|
17
|
+
ts.isNoSubstitutionTemplateLiteral(expr)) {
|
|
18
|
+
for (const char of expr.text) {
|
|
19
|
+
flattened.push(ts.factory.createStringLiteral(char));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
flattened.push({ dynamicSpread: expr });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
flattened.push(elem);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return flattened;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Helper to recursively flatten static spread assignments in object literals.
|
|
34
|
+
*/
|
|
35
|
+
function flattenObjectProperties(properties) {
|
|
36
|
+
const flattened = [];
|
|
37
|
+
for (const prop of properties) {
|
|
38
|
+
if (ts.isSpreadAssignment(prop)) {
|
|
39
|
+
const expr = prop.expression;
|
|
40
|
+
if (ts.isObjectLiteralExpression(expr)) {
|
|
41
|
+
flattened.push(...flattenObjectProperties(expr.properties));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
flattened.push(prop);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
flattened.push(prop);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return flattened;
|
|
52
|
+
}
|
|
3
53
|
export function visitObjectPropertyName(node, context) {
|
|
4
54
|
if (ts.isNumericLiteral(node)) {
|
|
5
55
|
return context.isBracketNotationPropertyAccess
|
|
@@ -27,11 +77,12 @@ export function visitObjectPropertyName(node, context) {
|
|
|
27
77
|
}
|
|
28
78
|
export function visitObjectLiteralExpression(node, context) {
|
|
29
79
|
const obj = node;
|
|
80
|
+
const properties = flattenObjectProperties(obj.properties);
|
|
30
81
|
const objVar = this.generateUniqueName("__obj_", this.getDeclaredSymbols(node));
|
|
31
|
-
if (!
|
|
82
|
+
if (!properties.some((prop) => ts.isPropertyAssignment(prop) ||
|
|
32
83
|
ts.isShorthandPropertyAssignment(prop) ||
|
|
33
84
|
ts.isMethodDeclaration(prop) || ts.isGetAccessor(prop) ||
|
|
34
|
-
ts.isSetAccessor(prop))) {
|
|
85
|
+
ts.isSetAccessor(prop) || ts.isSpreadAssignment(prop))) {
|
|
35
86
|
// Empty object
|
|
36
87
|
return `jspp::AnyValue::make_object_with_proto({}, ::Object.get_own_property("prototype"))`;
|
|
37
88
|
}
|
|
@@ -39,7 +90,7 @@ export function visitObjectLiteralExpression(node, context) {
|
|
|
39
90
|
code +=
|
|
40
91
|
`${this.indent()} auto ${objVar} = jspp::AnyValue::make_object_with_proto({}, ::Object.get_own_property("prototype"));\n`;
|
|
41
92
|
this.indentationLevel++;
|
|
42
|
-
for (const prop of
|
|
93
|
+
for (const prop of properties) {
|
|
43
94
|
if (ts.isPropertyAssignment(prop)) {
|
|
44
95
|
const key = visitObjectPropertyName.call(this, prop.name, {
|
|
45
96
|
...context,
|
|
@@ -76,10 +127,10 @@ export function visitObjectLiteralExpression(node, context) {
|
|
|
76
127
|
...context,
|
|
77
128
|
isObjectLiteralExpression: true,
|
|
78
129
|
});
|
|
79
|
-
const lambda = this.
|
|
130
|
+
const lambda = this.generateWrappedLambda(this.generateLambdaComponents(prop, {
|
|
80
131
|
...context,
|
|
81
132
|
isInsideFunction: true,
|
|
82
|
-
});
|
|
133
|
+
}));
|
|
83
134
|
code +=
|
|
84
135
|
`${this.indent()}${objVar}.define_data_property(${key}, ${lambda});\n`;
|
|
85
136
|
}
|
|
@@ -88,10 +139,10 @@ export function visitObjectLiteralExpression(node, context) {
|
|
|
88
139
|
...context,
|
|
89
140
|
isObjectLiteralExpression: true,
|
|
90
141
|
});
|
|
91
|
-
const lambda = this.
|
|
142
|
+
const lambda = this.generateWrappedLambda(this.generateLambdaComponents(prop, {
|
|
92
143
|
...context,
|
|
93
144
|
isInsideFunction: true,
|
|
94
|
-
});
|
|
145
|
+
}));
|
|
95
146
|
code +=
|
|
96
147
|
`${this.indent()}${objVar}.define_getter(${key}, ${lambda});\n`;
|
|
97
148
|
}
|
|
@@ -100,36 +151,96 @@ export function visitObjectLiteralExpression(node, context) {
|
|
|
100
151
|
...context,
|
|
101
152
|
isObjectLiteralExpression: true,
|
|
102
153
|
});
|
|
103
|
-
const lambda = this.
|
|
154
|
+
const lambda = this.generateWrappedLambda(this.generateLambdaComponents(prop, {
|
|
104
155
|
...context,
|
|
105
156
|
isInsideFunction: true,
|
|
106
|
-
});
|
|
157
|
+
}));
|
|
107
158
|
code +=
|
|
108
159
|
`${this.indent()}${objVar}.define_setter(${key}, ${lambda});\n`;
|
|
109
160
|
}
|
|
161
|
+
else if (ts.isSpreadAssignment(prop)) {
|
|
162
|
+
let spreadExpr = this.visit(prop.expression, context);
|
|
163
|
+
if (ts.isIdentifier(prop.expression)) {
|
|
164
|
+
const scope = this.getScopeForNode(prop.expression);
|
|
165
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(prop.expression.text, scope);
|
|
166
|
+
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
167
|
+
spreadExpr = this.getDerefCode(spreadExpr, this.getJsVarName(prop.expression), context, typeInfo);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
code +=
|
|
171
|
+
`${this.indent()}jspp::Access::spread_object(${objVar}, ${spreadExpr});\n`;
|
|
172
|
+
}
|
|
110
173
|
}
|
|
111
174
|
this.indentationLevel--;
|
|
112
175
|
code += `${this.indent()} return ${objVar};\n${this.indent()}})()`;
|
|
113
176
|
return code;
|
|
114
177
|
}
|
|
115
178
|
export function visitArrayLiteralExpression(node, context) {
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
179
|
+
const flattened = flattenArrayElements(node.elements);
|
|
180
|
+
const hasSpread = flattened.some((e) => typeof e === "object" && "dynamicSpread" in e);
|
|
181
|
+
if (!hasSpread) {
|
|
182
|
+
const elements = flattened
|
|
183
|
+
.map((elem) => {
|
|
184
|
+
const expr = elem;
|
|
185
|
+
let elemText = this.visit(expr, context);
|
|
186
|
+
if (ts.isIdentifier(expr)) {
|
|
187
|
+
const scope = this.getScopeForNode(expr);
|
|
188
|
+
const typeInfo = this.typeAnalyzer.scopeManager
|
|
189
|
+
.lookupFromScope(expr.text, scope);
|
|
190
|
+
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
191
|
+
elemText = this.getDerefCode(elemText, this.getJsVarName(expr), context, typeInfo);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (ts.isOmittedExpression(expr)) {
|
|
195
|
+
elemText = "jspp::Constants::UNINITIALIZED";
|
|
196
|
+
}
|
|
197
|
+
return elemText;
|
|
198
|
+
});
|
|
199
|
+
const elementsJoined = elements.join(", ");
|
|
200
|
+
const elementsSpan = elements.length > 0
|
|
201
|
+
? `std::span<const jspp::AnyValue>((const jspp::AnyValue[]){${elementsJoined}}, ${elements.length})`
|
|
202
|
+
: "std::span<const jspp::AnyValue>{}";
|
|
203
|
+
return `jspp::AnyValue::make_array_with_proto(${elementsSpan}, ::Array.get_own_property("prototype"))`;
|
|
204
|
+
}
|
|
205
|
+
const arrVar = this.generateUniqueName("__arr_", this.getDeclaredSymbols(node));
|
|
206
|
+
let code = `([&]() {\n`;
|
|
207
|
+
code += `${this.indent()} std::vector<jspp::AnyValue> ${arrVar};\n`;
|
|
208
|
+
this.indentationLevel++;
|
|
209
|
+
for (const elem of flattened) {
|
|
210
|
+
if (typeof elem === "object" && "dynamicSpread" in elem) {
|
|
211
|
+
const spreadExprSource = elem.dynamicSpread;
|
|
212
|
+
let spreadExpr = this.visit(spreadExprSource, context);
|
|
213
|
+
if (ts.isIdentifier(spreadExprSource)) {
|
|
214
|
+
const scope = this.getScopeForNode(spreadExprSource);
|
|
215
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(spreadExprSource.text, scope);
|
|
216
|
+
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
217
|
+
spreadExpr = this.getDerefCode(spreadExpr, this.getJsVarName(spreadExprSource), context, typeInfo);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
code +=
|
|
221
|
+
`${this.indent()}jspp::Access::spread_array(${arrVar}, ${spreadExpr});\n`;
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
const expr = elem;
|
|
225
|
+
let elemText = this.visit(expr, context);
|
|
226
|
+
if (ts.isIdentifier(expr)) {
|
|
227
|
+
const scope = this.getScopeForNode(expr);
|
|
228
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(expr.text, scope);
|
|
229
|
+
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
230
|
+
elemText = this.getDerefCode(elemText, this.getJsVarName(expr), context, typeInfo);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (ts.isOmittedExpression(expr)) {
|
|
234
|
+
elemText = "jspp::Constants::UNINITIALIZED";
|
|
124
235
|
}
|
|
236
|
+
code += `${this.indent()}${arrVar}.push_back(${elemText});\n`;
|
|
125
237
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return `jspp::AnyValue::make_array_with_proto(${elementsSpan}, ::Array.get_own_property("prototype"))`;
|
|
238
|
+
}
|
|
239
|
+
this.indentationLevel--;
|
|
240
|
+
code +=
|
|
241
|
+
`${this.indent()} return jspp::AnyValue::make_array_with_proto(std::move(${arrVar}), ::Array.get_own_property("prototype"));\n`;
|
|
242
|
+
code += `${this.indent()}})()`;
|
|
243
|
+
return code;
|
|
133
244
|
}
|
|
134
245
|
export function visitPrefixUnaryExpression(node, context) {
|
|
135
246
|
const prefixUnaryExpr = node;
|
|
@@ -149,6 +260,15 @@ export function visitPrefixUnaryExpression(node, context) {
|
|
|
149
260
|
}
|
|
150
261
|
return `${operator}(${target})`;
|
|
151
262
|
}
|
|
263
|
+
if (operator === "+") {
|
|
264
|
+
return `jspp::plus(${operand})`;
|
|
265
|
+
}
|
|
266
|
+
if (operator === "-") {
|
|
267
|
+
return `jspp::negate(${operand})`;
|
|
268
|
+
}
|
|
269
|
+
if (operator === "!") {
|
|
270
|
+
return `jspp::logical_not(${operand})`;
|
|
271
|
+
}
|
|
152
272
|
if (operator === "~") {
|
|
153
273
|
let target = operand;
|
|
154
274
|
if (ts.isIdentifier(prefixUnaryExpr.operand)) {
|
|
@@ -161,7 +281,7 @@ export function visitPrefixUnaryExpression(node, context) {
|
|
|
161
281
|
target = `*${operand}`;
|
|
162
282
|
}
|
|
163
283
|
}
|
|
164
|
-
return
|
|
284
|
+
return `jspp::bitwise_not(${target})`;
|
|
165
285
|
}
|
|
166
286
|
return `${operator}${operand}`;
|
|
167
287
|
}
|
|
@@ -190,7 +310,7 @@ export function visitPropertyAccessExpression(node, context) {
|
|
|
190
310
|
const propAccess = node;
|
|
191
311
|
if (propAccess.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
192
312
|
if (!context.superClassVar) {
|
|
193
|
-
throw new
|
|
313
|
+
throw new CompilerError("super.prop accessed but no super class variable found in context", propAccess.expression, "SyntaxError");
|
|
194
314
|
}
|
|
195
315
|
const propName = propAccess.name.getText();
|
|
196
316
|
return `jspp::AnyValue::resolve_property_for_read((${context.superClassVar}).get_own_property("prototype").get_own_property("${propName}"), ${this.globalThisVar}, "${this.escapeString(propName)}")`;
|
|
@@ -213,7 +333,7 @@ export function visitPropertyAccessExpression(node, context) {
|
|
|
213
333
|
finalExpr = this.getDerefCode(exprText, this.getJsVarName(propAccess.expression), context, typeInfo);
|
|
214
334
|
}
|
|
215
335
|
if (propAccess.questionDotToken) {
|
|
216
|
-
return `jspp::Access::
|
|
336
|
+
return `jspp::Access::get_optional_property(${finalExpr}, "${propName}")`;
|
|
217
337
|
}
|
|
218
338
|
return `${finalExpr}.get_own_property("${propName}")`;
|
|
219
339
|
}
|
|
@@ -251,14 +371,18 @@ export function visitElementAccessExpression(node, context) {
|
|
|
251
371
|
}
|
|
252
372
|
}
|
|
253
373
|
if (elemAccess.questionDotToken) {
|
|
254
|
-
return `jspp::Access::
|
|
374
|
+
return `jspp::Access::get_optional_element(${finalExpr}, ${argText})`;
|
|
255
375
|
}
|
|
256
376
|
return `${finalExpr}.get_own_property(${argText})`;
|
|
257
377
|
}
|
|
258
378
|
export function visitBinaryExpression(node, context) {
|
|
259
379
|
const binExpr = node;
|
|
260
380
|
const opToken = binExpr.operatorToken;
|
|
261
|
-
|
|
381
|
+
const op = opToken.getText();
|
|
382
|
+
const visitContext = {
|
|
383
|
+
...context,
|
|
384
|
+
supportedNativeLiterals: undefined,
|
|
385
|
+
};
|
|
262
386
|
const assignmentOperators = [
|
|
263
387
|
ts.SyntaxKind.PlusEqualsToken,
|
|
264
388
|
ts.SyntaxKind.MinusEqualsToken,
|
|
@@ -279,8 +403,8 @@ export function visitBinaryExpression(node, context) {
|
|
|
279
403
|
if (assignmentOperators.includes(opToken.kind)) {
|
|
280
404
|
if (opToken.kind ===
|
|
281
405
|
ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken) {
|
|
282
|
-
const leftText = this.visit(binExpr.left,
|
|
283
|
-
const rightText = this.visit(binExpr.right,
|
|
406
|
+
const leftText = this.visit(binExpr.left, visitContext);
|
|
407
|
+
const rightText = this.visit(binExpr.right, visitContext);
|
|
284
408
|
let target = leftText;
|
|
285
409
|
if (ts.isIdentifier(binExpr.left)) {
|
|
286
410
|
const scope = this.getScopeForNode(binExpr.left);
|
|
@@ -292,8 +416,8 @@ export function visitBinaryExpression(node, context) {
|
|
|
292
416
|
}
|
|
293
417
|
}
|
|
294
418
|
if (opToken.kind === ts.SyntaxKind.AsteriskAsteriskEqualsToken) {
|
|
295
|
-
const leftText = this.visit(binExpr.left,
|
|
296
|
-
const rightText = this.visit(binExpr.right,
|
|
419
|
+
const leftText = this.visit(binExpr.left, visitContext);
|
|
420
|
+
const rightText = this.visit(binExpr.right, visitContext);
|
|
297
421
|
let target = leftText;
|
|
298
422
|
if (ts.isIdentifier(binExpr.left)) {
|
|
299
423
|
const scope = this.getScopeForNode(binExpr.left);
|
|
@@ -308,8 +432,8 @@ export function visitBinaryExpression(node, context) {
|
|
|
308
432
|
if (opToken.kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken ||
|
|
309
433
|
opToken.kind === ts.SyntaxKind.BarBarEqualsToken ||
|
|
310
434
|
opToken.kind === ts.SyntaxKind.QuestionQuestionEqualsToken) {
|
|
311
|
-
const leftText = this.visit(binExpr.left,
|
|
312
|
-
const rightText = this.visit(binExpr.right,
|
|
435
|
+
const leftText = this.visit(binExpr.left, visitContext);
|
|
436
|
+
const rightText = this.visit(binExpr.right, visitContext);
|
|
313
437
|
let target = leftText;
|
|
314
438
|
if (ts.isIdentifier(binExpr.left)) {
|
|
315
439
|
const scope = this.getScopeForNode(binExpr.left);
|
|
@@ -328,21 +452,21 @@ export function visitBinaryExpression(node, context) {
|
|
|
328
452
|
}
|
|
329
453
|
}
|
|
330
454
|
}
|
|
331
|
-
const leftText = this.visit(binExpr.left,
|
|
455
|
+
const leftText = this.visit(binExpr.left, visitContext);
|
|
332
456
|
let rightText = ts.isNumericLiteral(binExpr.right)
|
|
333
457
|
? binExpr.right.getText()
|
|
334
|
-
: this.visit(binExpr.right,
|
|
458
|
+
: this.visit(binExpr.right, visitContext);
|
|
335
459
|
if (ts.isIdentifier(binExpr.right)) {
|
|
336
460
|
const scope = this.getScopeForNode(binExpr.right);
|
|
337
461
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.right.getText(), scope);
|
|
338
|
-
rightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right),
|
|
462
|
+
rightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), visitContext, typeInfo);
|
|
339
463
|
}
|
|
340
464
|
let target = leftText;
|
|
341
465
|
if (ts.isIdentifier(binExpr.left)) {
|
|
342
466
|
const scope = this.getScopeForNode(binExpr.left);
|
|
343
467
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.getText(), scope);
|
|
344
468
|
if (context.derefBeforeAssignment) {
|
|
345
|
-
target = this.getDerefCode(leftText, leftText,
|
|
469
|
+
target = this.getDerefCode(leftText, leftText, visitContext, typeInfo);
|
|
346
470
|
}
|
|
347
471
|
else if (typeInfo.needsHeapAllocation) {
|
|
348
472
|
target = `*${leftText}`;
|
|
@@ -350,8 +474,9 @@ export function visitBinaryExpression(node, context) {
|
|
|
350
474
|
}
|
|
351
475
|
return `${target} ${op} ${rightText}`;
|
|
352
476
|
}
|
|
477
|
+
// Assignment expression `a = 1`
|
|
353
478
|
if (opToken.kind === ts.SyntaxKind.EqualsToken) {
|
|
354
|
-
let rightText = this.visit(binExpr.right,
|
|
479
|
+
let rightText = this.visit(binExpr.right, visitContext);
|
|
355
480
|
if (ts.isPropertyAccessExpression(binExpr.left)) {
|
|
356
481
|
const propAccess = binExpr.left;
|
|
357
482
|
if (propAccess.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
@@ -365,13 +490,13 @@ export function visitBinaryExpression(node, context) {
|
|
|
365
490
|
if (rightTypeInfo &&
|
|
366
491
|
!rightTypeInfo.isParameter &&
|
|
367
492
|
!rightTypeInfo.isBuiltin) {
|
|
368
|
-
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right),
|
|
493
|
+
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), visitContext, rightTypeInfo);
|
|
369
494
|
}
|
|
370
495
|
}
|
|
371
496
|
// Approximate super assignment as setting property on 'this'
|
|
372
497
|
return `(${this.globalThisVar}).set_own_property("${propName}", ${finalRightText})`;
|
|
373
498
|
}
|
|
374
|
-
const objExprText = this.visit(propAccess.expression,
|
|
499
|
+
const objExprText = this.visit(propAccess.expression, visitContext);
|
|
375
500
|
const propName = propAccess.name.getText();
|
|
376
501
|
let finalObjExpr = objExprText;
|
|
377
502
|
if (ts.isIdentifier(propAccess.expression)) {
|
|
@@ -396,14 +521,14 @@ export function visitBinaryExpression(node, context) {
|
|
|
396
521
|
}
|
|
397
522
|
else if (ts.isElementAccessExpression(binExpr.left)) {
|
|
398
523
|
const elemAccess = binExpr.left;
|
|
399
|
-
const objExprText = this.visit(elemAccess.expression,
|
|
400
|
-
let argText = visitObjectPropertyName.call(this, elemAccess.argumentExpression, { ...
|
|
524
|
+
const objExprText = this.visit(elemAccess.expression, visitContext);
|
|
525
|
+
let argText = visitObjectPropertyName.call(this, elemAccess.argumentExpression, { ...visitContext, isBracketNotationPropertyAccess: true });
|
|
401
526
|
let finalObjExpr = objExprText;
|
|
402
527
|
if (ts.isIdentifier(elemAccess.expression)) {
|
|
403
528
|
const scope = this.getScopeForNode(elemAccess.expression);
|
|
404
529
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(elemAccess.expression.getText(), scope);
|
|
405
530
|
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
406
|
-
finalObjExpr = this.getDerefCode(objExprText, this.getJsVarName(elemAccess.expression),
|
|
531
|
+
finalObjExpr = this.getDerefCode(objExprText, this.getJsVarName(elemAccess.expression), visitContext, typeInfo);
|
|
407
532
|
}
|
|
408
533
|
}
|
|
409
534
|
if (ts.isIdentifier(elemAccess.argumentExpression)) {
|
|
@@ -413,7 +538,7 @@ export function visitBinaryExpression(node, context) {
|
|
|
413
538
|
if (argTypeInfo &&
|
|
414
539
|
!argTypeInfo.isParameter &&
|
|
415
540
|
!argTypeInfo.isBuiltin) {
|
|
416
|
-
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression),
|
|
541
|
+
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression), visitContext, argTypeInfo);
|
|
417
542
|
}
|
|
418
543
|
}
|
|
419
544
|
let finalRightText = rightText;
|
|
@@ -424,12 +549,12 @@ export function visitBinaryExpression(node, context) {
|
|
|
424
549
|
if (rightTypeInfo &&
|
|
425
550
|
!rightTypeInfo.isParameter &&
|
|
426
551
|
!rightTypeInfo.isBuiltin) {
|
|
427
|
-
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right),
|
|
552
|
+
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), visitContext, rightTypeInfo);
|
|
428
553
|
}
|
|
429
554
|
}
|
|
430
555
|
return `${finalObjExpr}.set_own_property(${argText}, ${finalRightText})`;
|
|
431
556
|
}
|
|
432
|
-
const leftText = this.visit(binExpr.left,
|
|
557
|
+
const leftText = this.visit(binExpr.left, visitContext);
|
|
433
558
|
const scope = this.getScopeForNode(binExpr.left);
|
|
434
559
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.text, scope);
|
|
435
560
|
if (!typeInfo && !this.isBuiltinObject(binExpr.left)) {
|
|
@@ -442,27 +567,29 @@ export function visitBinaryExpression(node, context) {
|
|
|
442
567
|
rightText = binExpr.right.getText();
|
|
443
568
|
}
|
|
444
569
|
const target = context.derefBeforeAssignment
|
|
445
|
-
? this.getDerefCode(leftText, leftText,
|
|
570
|
+
? this.getDerefCode(leftText, leftText, visitContext, typeInfo)
|
|
446
571
|
: (typeInfo.needsHeapAllocation ? `*${leftText}` : leftText);
|
|
447
572
|
// Update scope symbols on variable re-assignment
|
|
573
|
+
// Reset features
|
|
448
574
|
if (ts.isIdentifier(binExpr.left)) {
|
|
449
575
|
if (!ts.isFunctionDeclaration(binExpr.right)) {
|
|
450
576
|
if (context.localScopeSymbols.has(binExpr.left.text)) {
|
|
451
|
-
context.localScopeSymbols.
|
|
452
|
-
|
|
577
|
+
context.localScopeSymbols.set(binExpr.left.text, {
|
|
578
|
+
features: {},
|
|
453
579
|
});
|
|
454
580
|
}
|
|
455
581
|
else if (context.globalScopeSymbols.has(binExpr.left.text)) {
|
|
456
|
-
context.globalScopeSymbols.
|
|
457
|
-
|
|
582
|
+
context.globalScopeSymbols.set(binExpr.left.text, {
|
|
583
|
+
features: {},
|
|
458
584
|
});
|
|
459
585
|
}
|
|
460
586
|
}
|
|
461
587
|
}
|
|
462
588
|
return `${target} ${op} ${rightText}`;
|
|
463
589
|
}
|
|
464
|
-
const leftText = this.visit(binExpr.left,
|
|
465
|
-
const rightText = this.visit(binExpr.right,
|
|
590
|
+
const leftText = this.visit(binExpr.left, visitContext);
|
|
591
|
+
const rightText = this.visit(binExpr.right, visitContext);
|
|
592
|
+
// Generate lhs and rhs code
|
|
466
593
|
let finalLeft = leftText;
|
|
467
594
|
if (ts.isIdentifier(binExpr.left)) {
|
|
468
595
|
const scope = this.getScopeForNode(binExpr.left);
|
|
@@ -471,7 +598,11 @@ export function visitBinaryExpression(node, context) {
|
|
|
471
598
|
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(binExpr.left)})`;
|
|
472
599
|
}
|
|
473
600
|
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
474
|
-
finalLeft = this.getDerefCode(leftText, this.getJsVarName(binExpr.left),
|
|
601
|
+
finalLeft = this.getDerefCode(leftText, this.getJsVarName(binExpr.left), visitContext, typeInfo);
|
|
602
|
+
}
|
|
603
|
+
// Number optimizations
|
|
604
|
+
if (typeInfo && typeInfo.type === "number") {
|
|
605
|
+
finalLeft = `${finalLeft}.as_double()`;
|
|
475
606
|
}
|
|
476
607
|
}
|
|
477
608
|
let finalRight = rightText;
|
|
@@ -483,7 +614,11 @@ export function visitBinaryExpression(node, context) {
|
|
|
483
614
|
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(binExpr.right)})`;
|
|
484
615
|
}
|
|
485
616
|
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
486
|
-
finalRight = this.getDerefCode(rightText, this.getJsVarName(binExpr.right),
|
|
617
|
+
finalRight = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), visitContext, typeInfo);
|
|
618
|
+
}
|
|
619
|
+
// Number optimizations
|
|
620
|
+
if (typeInfo && typeInfo.type === "number") {
|
|
621
|
+
finalRight = `${finalRight}.as_double()`;
|
|
487
622
|
}
|
|
488
623
|
}
|
|
489
624
|
if (opToken.kind === ts.SyntaxKind.InKeyword) {
|
|
@@ -501,52 +636,111 @@ export function visitBinaryExpression(node, context) {
|
|
|
501
636
|
if (opToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
|
|
502
637
|
return `jspp::nullish_coalesce(${finalLeft}, ${finalRight})`;
|
|
503
638
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
639
|
+
const isLiteral = (n) => ts.isNumericLiteral(n);
|
|
640
|
+
const supportsNativeBoolean = context.supportedNativeLiterals?.includes("boolean") || false;
|
|
641
|
+
// Native values for lhs and rhs
|
|
642
|
+
const literalLeft = isLiteral(binExpr.left)
|
|
643
|
+
? binExpr.left.getText()
|
|
644
|
+
: finalLeft;
|
|
645
|
+
const literalRight = isLiteral(binExpr.right)
|
|
646
|
+
? binExpr.right.getText()
|
|
647
|
+
: finalRight;
|
|
648
|
+
// Operations that returns boolean should return the native boolean if supported
|
|
649
|
+
if (constants.booleanOperators.includes(opToken.kind) &&
|
|
650
|
+
supportsNativeBoolean) {
|
|
651
|
+
if (opToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken) {
|
|
652
|
+
return `jspp::is_strictly_equal_to_primitive(${literalLeft}, ${literalRight})`;
|
|
653
|
+
}
|
|
654
|
+
if (opToken.kind === ts.SyntaxKind.EqualsEqualsToken) {
|
|
655
|
+
return `jspp::is_equal_to_primitive(${literalLeft}, ${literalRight})`;
|
|
656
|
+
}
|
|
657
|
+
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
|
|
658
|
+
return `!jspp::is_strictly_equal_to_primitive(${literalLeft}, ${literalRight})`;
|
|
659
|
+
}
|
|
660
|
+
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsToken) {
|
|
661
|
+
return `!jspp::is_equal_to_primitive(${literalLeft}, ${literalRight})`;
|
|
662
|
+
}
|
|
663
|
+
let funcName = "";
|
|
664
|
+
if (opToken.kind === ts.SyntaxKind.LessThanToken) {
|
|
665
|
+
funcName = "jspp::less_than_primitive";
|
|
666
|
+
}
|
|
667
|
+
if (opToken.kind === ts.SyntaxKind.LessThanEqualsToken) {
|
|
668
|
+
funcName = "jspp::less_than_or_equal_primitive";
|
|
669
|
+
}
|
|
670
|
+
if (opToken.kind === ts.SyntaxKind.GreaterThanToken) {
|
|
671
|
+
funcName = "jspp::greater_than_primitive";
|
|
672
|
+
}
|
|
673
|
+
if (opToken.kind === ts.SyntaxKind.GreaterThanEqualsToken) {
|
|
674
|
+
funcName = "jspp::greater_than_or_equal_primitive";
|
|
675
|
+
}
|
|
676
|
+
// For C++ primitive literals, standard operators are fine if they map directly,
|
|
677
|
+
// but we are safe using our functions (which handle doubles correctly).
|
|
678
|
+
// Actually, for pure numeric literals like "1 < 2", we can leave it as is if we want optimization,
|
|
679
|
+
// but consistency is safer.
|
|
680
|
+
// Let's stick to valid C++ syntax for literals if possible to avoid overhead?
|
|
681
|
+
// jspp::less_than(1, 2) works.
|
|
682
|
+
return `${funcName}(${literalLeft}, ${literalRight})`;
|
|
510
683
|
}
|
|
684
|
+
// Return boxed value
|
|
511
685
|
if (opToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken) {
|
|
512
|
-
return `jspp::is_strictly_equal_to(${
|
|
686
|
+
return `jspp::is_strictly_equal_to(${literalLeft}, ${literalRight})`;
|
|
513
687
|
}
|
|
514
688
|
if (opToken.kind === ts.SyntaxKind.EqualsEqualsToken) {
|
|
515
|
-
return `jspp::is_equal_to(${
|
|
689
|
+
return `jspp::is_equal_to(${literalLeft}, ${literalRight})`;
|
|
516
690
|
}
|
|
517
691
|
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
|
|
518
|
-
return `jspp::not_strictly_equal_to(${
|
|
692
|
+
return `jspp::not_strictly_equal_to(${literalLeft}, ${literalRight})`;
|
|
519
693
|
}
|
|
520
694
|
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsToken) {
|
|
521
|
-
return `jspp::not_equal_to(${
|
|
695
|
+
return `jspp::not_equal_to(${literalLeft}, ${literalRight})`;
|
|
522
696
|
}
|
|
523
697
|
if (opToken.kind === ts.SyntaxKind.AsteriskAsteriskToken) {
|
|
524
|
-
return `jspp::pow(${
|
|
698
|
+
return `jspp::pow(${literalLeft}, ${literalRight})`;
|
|
525
699
|
}
|
|
526
700
|
if (opToken.kind === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken) {
|
|
527
|
-
return `jspp::unsigned_right_shift(${
|
|
528
|
-
}
|
|
529
|
-
//
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
701
|
+
return `jspp::unsigned_right_shift(${literalLeft}, ${literalRight})`;
|
|
702
|
+
}
|
|
703
|
+
// For other arithmetic and bitwise operations, use native operations if possible
|
|
704
|
+
switch (op) {
|
|
705
|
+
case "+":
|
|
706
|
+
return `jspp::add(${literalLeft}, ${literalRight})`;
|
|
707
|
+
case "-":
|
|
708
|
+
return `jspp::sub(${literalLeft}, ${literalRight})`;
|
|
709
|
+
case "*":
|
|
710
|
+
return `jspp::mul(${literalLeft}, ${literalRight})`;
|
|
711
|
+
case "/":
|
|
712
|
+
return `jspp::div(${literalLeft}, ${literalRight})`;
|
|
713
|
+
case "%":
|
|
714
|
+
return `jspp::mod(${literalLeft}, ${literalRight})`;
|
|
715
|
+
case "^":
|
|
716
|
+
return `jspp::bitwise_xor(${literalLeft}, ${literalRight})`;
|
|
717
|
+
case "&":
|
|
718
|
+
return `jspp::bitwise_and(${literalLeft}, ${literalRight})`;
|
|
719
|
+
case "|":
|
|
720
|
+
return `jspp::bitwise_or(${literalLeft}, ${literalRight})`;
|
|
721
|
+
case "<<":
|
|
722
|
+
return `jspp::left_shift(${literalLeft}, ${literalRight})`;
|
|
723
|
+
case ">>":
|
|
724
|
+
return `jspp::right_shift(${literalLeft}, ${literalRight})`;
|
|
725
|
+
case "<":
|
|
726
|
+
return `jspp::less_than(${literalLeft}, ${literalRight})`;
|
|
727
|
+
case ">":
|
|
728
|
+
return `jspp::greater_than(${literalLeft}, ${literalRight})`;
|
|
729
|
+
case "<=":
|
|
730
|
+
return `jspp::less_than_or_equal(${literalLeft}, ${literalRight})`;
|
|
731
|
+
case ">=":
|
|
732
|
+
return `jspp::greater_than_or_equal(${literalLeft}, ${literalRight})`;
|
|
733
|
+
}
|
|
734
|
+
return `/* Unhandled Operator: ${finalLeft} ${op} ${finalRight} */`; // Default fallback
|
|
546
735
|
}
|
|
547
736
|
export function visitConditionalExpression(node, context) {
|
|
548
737
|
const condExpr = node;
|
|
549
|
-
const
|
|
738
|
+
const isBinaryExpression = ts.isBinaryExpression(condExpr.condition) &&
|
|
739
|
+
constants.booleanOperators.includes(condExpr.condition.operatorToken.kind);
|
|
740
|
+
const condition = this.visit(condExpr.condition, {
|
|
741
|
+
...context,
|
|
742
|
+
supportedNativeLiterals: isBinaryExpression ? ["boolean"] : undefined,
|
|
743
|
+
});
|
|
550
744
|
const whenTrueStmt = this.visit(condExpr.whenTrue, {
|
|
551
745
|
...context,
|
|
552
746
|
isFunctionBody: false,
|
|
@@ -555,53 +749,147 @@ export function visitConditionalExpression(node, context) {
|
|
|
555
749
|
...context,
|
|
556
750
|
isFunctionBody: false,
|
|
557
751
|
});
|
|
752
|
+
if (isBinaryExpression) {
|
|
753
|
+
return `${condition} ? ${whenTrueStmt} : ${whenFalseStmt}`;
|
|
754
|
+
}
|
|
558
755
|
return `jspp::is_truthy(${condition}) ? ${whenTrueStmt} : ${whenFalseStmt}`;
|
|
559
756
|
}
|
|
560
757
|
export function visitCallExpression(node, context) {
|
|
561
758
|
const callExpr = node;
|
|
562
759
|
const callee = callExpr.expression;
|
|
760
|
+
const flattened = flattenArrayElements(callExpr.arguments);
|
|
761
|
+
const hasSpread = flattened.some((e) => typeof e === "object" && "dynamicSpread" in e);
|
|
563
762
|
if (callee.kind === ts.SyntaxKind.SuperKeyword) {
|
|
564
763
|
if (!context.superClassVar) {
|
|
565
|
-
throw new
|
|
764
|
+
throw new CompilerError("super() called but no super class variable found in context", callee, "SyntaxError");
|
|
765
|
+
}
|
|
766
|
+
if (!hasSpread) {
|
|
767
|
+
const args = flattened.map((arg) => this.visit(arg, context))
|
|
768
|
+
.join(", ");
|
|
769
|
+
return `(${context.superClassVar}).call(${this.globalThisVar}, (const jspp::AnyValue[]){${args}}, "super")`;
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
772
|
+
const argsVar = this.generateUniqueName("__args_", this.getDeclaredSymbols(node));
|
|
773
|
+
let code = `([&]() {\n`;
|
|
774
|
+
code +=
|
|
775
|
+
`${this.indent()} std::vector<jspp::AnyValue> ${argsVar};\n`;
|
|
776
|
+
this.indentationLevel++;
|
|
777
|
+
for (const arg of flattened) {
|
|
778
|
+
if (typeof arg === "object" && "dynamicSpread" in arg) {
|
|
779
|
+
const spreadExprSource = arg.dynamicSpread;
|
|
780
|
+
let spreadExpr = this.visit(spreadExprSource, context);
|
|
781
|
+
if (ts.isIdentifier(spreadExprSource)) {
|
|
782
|
+
const scope = this.getScopeForNode(spreadExprSource);
|
|
783
|
+
const typeInfo = this.typeAnalyzer.scopeManager
|
|
784
|
+
.lookupFromScope(spreadExprSource.text, scope);
|
|
785
|
+
spreadExpr = this.getDerefCode(spreadExpr, this.getJsVarName(spreadExprSource), context, typeInfo);
|
|
786
|
+
}
|
|
787
|
+
code +=
|
|
788
|
+
`${this.indent()}jspp::Access::spread_array(${argsVar}, ${spreadExpr});\n`;
|
|
789
|
+
}
|
|
790
|
+
else {
|
|
791
|
+
const expr = arg;
|
|
792
|
+
let argText = this.visit(expr, context);
|
|
793
|
+
if (ts.isIdentifier(expr)) {
|
|
794
|
+
const scope = this.getScopeForNode(expr);
|
|
795
|
+
const typeInfo = this.typeAnalyzer.scopeManager
|
|
796
|
+
.lookupFromScope(expr.text, scope);
|
|
797
|
+
argText = this.getDerefCode(argText, this.getJsVarName(expr), context, typeInfo);
|
|
798
|
+
}
|
|
799
|
+
code +=
|
|
800
|
+
`${this.indent()}${argsVar}.push_back(${argText});\n`;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
code +=
|
|
804
|
+
`${this.indent()} return (${context.superClassVar}).call(${this.globalThisVar}, ${argsVar}, "super");\n`;
|
|
805
|
+
this.indentationLevel--;
|
|
806
|
+
code += `${this.indent()}})()`;
|
|
807
|
+
return code;
|
|
566
808
|
}
|
|
567
|
-
const args = callExpr.arguments.map((arg) => this.visit(arg, context))
|
|
568
|
-
.join(", ");
|
|
569
|
-
return `(${context.superClassVar}).call(${this.globalThisVar}, (const jspp::AnyValue[]){${args}}, "super")`;
|
|
570
809
|
}
|
|
571
|
-
const
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
const
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
810
|
+
const generateArgsSpan = (args) => {
|
|
811
|
+
const argsArray = args
|
|
812
|
+
.map((arg) => {
|
|
813
|
+
const expr = arg;
|
|
814
|
+
const argText = this.visit(expr, context);
|
|
815
|
+
if (ts.isIdentifier(expr)) {
|
|
816
|
+
const scope = this.getScopeForNode(expr);
|
|
817
|
+
const typeInfo = this.typeAnalyzer.scopeManager
|
|
818
|
+
.lookupFromScope(expr.text, scope);
|
|
819
|
+
if (!typeInfo) {
|
|
820
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(expr)})`;
|
|
821
|
+
}
|
|
822
|
+
if (typeInfo && !typeInfo.isBuiltin) {
|
|
823
|
+
return this.getDerefCode(argText, this.getJsVarName(expr), context, typeInfo);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
return argText;
|
|
827
|
+
});
|
|
828
|
+
const argsJoined = argsArray.join(", ");
|
|
829
|
+
const argsCount = argsArray.length;
|
|
830
|
+
return argsCount > 0
|
|
831
|
+
? `std::span<const jspp::AnyValue>((const jspp::AnyValue[]){${argsJoined}}, ${argsCount})`
|
|
832
|
+
: "std::span<const jspp::AnyValue>{}";
|
|
833
|
+
};
|
|
834
|
+
const generateArgsVectorBuilder = (args, argsVar) => {
|
|
835
|
+
let code = `${this.indent()}std::vector<jspp::AnyValue> ${argsVar};\n`;
|
|
836
|
+
for (const arg of args) {
|
|
837
|
+
if (typeof arg === "object" && "dynamicSpread" in arg) {
|
|
838
|
+
const spreadExprSource = arg.dynamicSpread;
|
|
839
|
+
let spreadExpr = this.visit(spreadExprSource, context);
|
|
840
|
+
if (ts.isIdentifier(spreadExprSource)) {
|
|
841
|
+
const scope = this.getScopeForNode(spreadExprSource);
|
|
842
|
+
const typeInfo = this.typeAnalyzer.scopeManager
|
|
843
|
+
.lookupFromScope(spreadExprSource.text, scope);
|
|
844
|
+
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
845
|
+
spreadExpr = this.getDerefCode(spreadExpr, this.getJsVarName(spreadExprSource), context, typeInfo);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
code +=
|
|
849
|
+
`${this.indent()}jspp::Access::spread_array(${argsVar}, ${spreadExpr});\n`;
|
|
579
850
|
}
|
|
580
|
-
|
|
581
|
-
|
|
851
|
+
else {
|
|
852
|
+
const expr = arg;
|
|
853
|
+
let argText = this.visit(expr, context);
|
|
854
|
+
if (ts.isIdentifier(expr)) {
|
|
855
|
+
const scope = this.getScopeForNode(expr);
|
|
856
|
+
const typeInfo = this.typeAnalyzer.scopeManager
|
|
857
|
+
.lookupFromScope(expr.text, scope);
|
|
858
|
+
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
859
|
+
argText = this.getDerefCode(argText, this.getJsVarName(expr), context, typeInfo);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
code += `${this.indent()}${argsVar}.push_back(${argText});\n`;
|
|
582
863
|
}
|
|
583
864
|
}
|
|
584
|
-
return
|
|
585
|
-
}
|
|
586
|
-
const args = argsArray.join(", ");
|
|
587
|
-
const argsCount = argsArray.length;
|
|
588
|
-
const argsSpan = argsCount > 0
|
|
589
|
-
? `std::span<const jspp::AnyValue>((const jspp::AnyValue[]){${args}}, ${argsCount})`
|
|
590
|
-
: "std::span<const jspp::AnyValue>{}";
|
|
591
|
-
// Handle obj.method() -> pass obj as 'this'
|
|
865
|
+
return code;
|
|
866
|
+
};
|
|
592
867
|
if (ts.isPropertyAccessExpression(callee)) {
|
|
593
868
|
const propAccess = callee;
|
|
594
869
|
if (propAccess.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
595
870
|
if (!context.superClassVar) {
|
|
596
|
-
throw new
|
|
871
|
+
throw new CompilerError("super.method() called but no super class variable found in context", propAccess.expression, "SyntaxError");
|
|
597
872
|
}
|
|
598
873
|
const propName = propAccess.name.getText();
|
|
599
|
-
|
|
874
|
+
if (!hasSpread) {
|
|
875
|
+
const argsSpan = generateArgsSpan(flattened);
|
|
876
|
+
return `(${context.superClassVar}).get_own_property("prototype").get_own_property("${propName}").call(${this.globalThisVar}, ${argsSpan}, "${this.escapeString(propName)}")`;
|
|
877
|
+
}
|
|
878
|
+
else {
|
|
879
|
+
const argsVar = this.generateUniqueName("__args_", this.getDeclaredSymbols(node));
|
|
880
|
+
let code = `([&]() {\n`;
|
|
881
|
+
this.indentationLevel++;
|
|
882
|
+
code += generateArgsVectorBuilder(flattened, argsVar);
|
|
883
|
+
code +=
|
|
884
|
+
`${this.indent}return (${context.superClassVar}).get_own_property("prototype").get_own_property("${propName}").call(${this.globalThisVar}, ${argsVar}, "${this.escapeString(propName)}");\n`;
|
|
885
|
+
this.indentationLevel--;
|
|
886
|
+
code += `${this.indent()}})()`;
|
|
887
|
+
return code;
|
|
888
|
+
}
|
|
600
889
|
}
|
|
601
890
|
const objExpr = propAccess.expression;
|
|
602
891
|
const propName = propAccess.name.getText();
|
|
603
892
|
const objCode = this.visit(objExpr, context);
|
|
604
|
-
// We need to dereference the object expression if it's a variable
|
|
605
893
|
let derefObj = objCode;
|
|
606
894
|
if (ts.isIdentifier(objExpr)) {
|
|
607
895
|
const scope = this.getScopeForNode(objExpr);
|
|
@@ -613,12 +901,37 @@ export function visitCallExpression(node, context) {
|
|
|
613
901
|
derefObj = this.getDerefCode(objCode, this.getJsVarName(objExpr), context, typeInfo);
|
|
614
902
|
}
|
|
615
903
|
}
|
|
616
|
-
if (
|
|
617
|
-
|
|
904
|
+
if (!hasSpread) {
|
|
905
|
+
const argsSpan = generateArgsSpan(flattened);
|
|
906
|
+
if (propAccess.questionDotToken) {
|
|
907
|
+
const method = callExpr.questionDotToken
|
|
908
|
+
? "jspp::Access::call_optional_property_with_optional_call"
|
|
909
|
+
: "jspp::Access::call_optional_property";
|
|
910
|
+
return `${method}(${derefObj}, "${propName}", ${argsSpan}, "${this.escapeString(propName)}")`;
|
|
911
|
+
}
|
|
912
|
+
return `${derefObj}.call_own_property("${propName}", ${argsSpan})`;
|
|
913
|
+
}
|
|
914
|
+
else {
|
|
915
|
+
const argsVar = this.generateUniqueName("__args_", this.getDeclaredSymbols(node));
|
|
916
|
+
let code = `([&]() {\n`;
|
|
917
|
+
this.indentationLevel++;
|
|
918
|
+
code += generateArgsVectorBuilder(flattened, argsVar);
|
|
919
|
+
if (propAccess.questionDotToken) {
|
|
920
|
+
const method = callExpr.questionDotToken
|
|
921
|
+
? "jspp::Access::call_optional_property_with_optional_call"
|
|
922
|
+
: "jspp::Access::call_optional_property";
|
|
923
|
+
code +=
|
|
924
|
+
`${this.indent()}return ${method}(${derefObj}, "${propName}", ${argsVar}, "${this.escapeString(propName)}");\n`;
|
|
925
|
+
}
|
|
926
|
+
else {
|
|
927
|
+
code +=
|
|
928
|
+
`${this.indent()}return ${derefObj}.call_own_property("${propName}", ${argsVar});\n`;
|
|
929
|
+
}
|
|
930
|
+
this.indentationLevel--;
|
|
931
|
+
code += `${this.indent()}})()`;
|
|
932
|
+
return code;
|
|
618
933
|
}
|
|
619
|
-
return `${derefObj}.call_own_property("${propName}", ${argsSpan})`;
|
|
620
934
|
}
|
|
621
|
-
// Handle obj[method]() -> pass obj as 'this'
|
|
622
935
|
if (ts.isElementAccessExpression(callee)) {
|
|
623
936
|
const elemAccess = callee;
|
|
624
937
|
const objExpr = elemAccess.expression;
|
|
@@ -635,7 +948,6 @@ export function visitCallExpression(node, context) {
|
|
|
635
948
|
}
|
|
636
949
|
}
|
|
637
950
|
let argText = visitObjectPropertyName.call(this, elemAccess.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
638
|
-
// Dereference argument if needed (logic copied from visitElementAccessExpression)
|
|
639
951
|
if (ts.isIdentifier(elemAccess.argumentExpression)) {
|
|
640
952
|
const argScope = this.getScopeForNode(elemAccess.argumentExpression);
|
|
641
953
|
const argTypeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(elemAccess.argumentExpression.getText(), argScope);
|
|
@@ -648,39 +960,135 @@ export function visitCallExpression(node, context) {
|
|
|
648
960
|
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression), context, argTypeInfo);
|
|
649
961
|
}
|
|
650
962
|
}
|
|
651
|
-
if (
|
|
652
|
-
|
|
963
|
+
if (!hasSpread) {
|
|
964
|
+
const argsSpan = generateArgsSpan(flattened);
|
|
965
|
+
if (elemAccess.questionDotToken) {
|
|
966
|
+
const method = callExpr.questionDotToken
|
|
967
|
+
? "jspp::Access::call_optional_property_with_optional_call"
|
|
968
|
+
: "jspp::Access::call_optional_property";
|
|
969
|
+
return `${method}(${derefObj}, ${argText}, ${argsSpan})`;
|
|
970
|
+
}
|
|
971
|
+
return `${derefObj}.call_own_property(${argText}, ${argsSpan})`;
|
|
972
|
+
}
|
|
973
|
+
else {
|
|
974
|
+
const argsVar = this.generateUniqueName("__args_", this.getDeclaredSymbols(node));
|
|
975
|
+
let code = `([&]() {\n`;
|
|
976
|
+
this.indentationLevel++;
|
|
977
|
+
code += generateArgsVectorBuilder(flattened, argsVar);
|
|
978
|
+
if (elemAccess.questionDotToken) {
|
|
979
|
+
const method = callExpr.questionDotToken
|
|
980
|
+
? "jspp::Access::call_optional_property_with_optional_call"
|
|
981
|
+
: "jspp::Access::call_optional_property";
|
|
982
|
+
code +=
|
|
983
|
+
`${this.indent()}return ${method}(${derefObj}, ${argText}, ${argsVar});\n`;
|
|
984
|
+
}
|
|
985
|
+
else {
|
|
986
|
+
code +=
|
|
987
|
+
`${this.indent()}return ${derefObj}.call_own_property(${argText}, ${argsVar});\n`;
|
|
988
|
+
}
|
|
989
|
+
this.indentationLevel--;
|
|
990
|
+
code += `${this.indent()}})()`;
|
|
991
|
+
return code;
|
|
653
992
|
}
|
|
654
|
-
return `${derefObj}.call_own_property(${argText}, ${argsSpan})`;
|
|
655
993
|
}
|
|
656
994
|
const calleeCode = this.visit(callee, context);
|
|
657
995
|
let derefCallee = calleeCode;
|
|
996
|
+
let calleeTypeInfo = null;
|
|
658
997
|
if (ts.isIdentifier(callee)) {
|
|
659
998
|
const scope = this.getScopeForNode(callee);
|
|
660
|
-
|
|
661
|
-
if (!
|
|
999
|
+
calleeTypeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(callee.text, scope);
|
|
1000
|
+
if (!calleeTypeInfo && !this.isBuiltinObject(callee)) {
|
|
662
1001
|
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(callee)})`;
|
|
663
1002
|
}
|
|
664
|
-
if (
|
|
1003
|
+
if (calleeTypeInfo?.isBuiltin) {
|
|
665
1004
|
derefCallee = calleeCode;
|
|
666
1005
|
}
|
|
667
|
-
else if (
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
1006
|
+
else if (calleeTypeInfo) {
|
|
1007
|
+
derefCallee = this.getDerefCode(calleeCode, this.getJsVarName(callee), context, calleeTypeInfo);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
// Direct native lamda if available
|
|
1011
|
+
if (ts.isIdentifier(callee) && calleeTypeInfo) {
|
|
1012
|
+
const name = callee.getText();
|
|
1013
|
+
const symbol = context.localScopeSymbols.get(name) ??
|
|
1014
|
+
context.globalScopeSymbols.get(name);
|
|
1015
|
+
const nativeFeature = symbol?.features?.native;
|
|
1016
|
+
if (nativeFeature && nativeFeature.type === "lambda") {
|
|
1017
|
+
const nativeName = nativeFeature.name;
|
|
1018
|
+
const parameters = nativeFeature.parameters || [];
|
|
1019
|
+
if (!hasSpread) {
|
|
1020
|
+
let argsPart = "";
|
|
1021
|
+
if (parameters) {
|
|
1022
|
+
const argsArray = flattened.map((arg) => {
|
|
1023
|
+
const expr = arg;
|
|
1024
|
+
let argText = this.visit(expr, context);
|
|
1025
|
+
if (ts.isIdentifier(expr)) {
|
|
1026
|
+
const scope = this.getScopeForNode(expr);
|
|
1027
|
+
const typeInfo = this.typeAnalyzer.scopeManager
|
|
1028
|
+
.lookupFromScope(expr.text, scope);
|
|
1029
|
+
argText = this.getDerefCode(argText, this.getJsVarName(expr), context, typeInfo);
|
|
1030
|
+
}
|
|
1031
|
+
return argText;
|
|
1032
|
+
});
|
|
1033
|
+
const argsText = argsArray.slice(0, parameters.length)
|
|
1034
|
+
.filter((_, i) => !parameters[i]?.dotDotDotToken).join(", ");
|
|
1035
|
+
if (argsText)
|
|
1036
|
+
argsPart += `, ${argsText}`;
|
|
1037
|
+
if (argsArray.length > parameters.length &&
|
|
1038
|
+
!!parameters[parameters.length - 1]?.dotDotDotToken) {
|
|
1039
|
+
const restArgsText = `jspp::AnyValue::make_array(std::vector<jspp::AnyValue>{${argsArray.slice(parameters.length - 1).join(", ")}})`;
|
|
1040
|
+
argsPart += `, ${restArgsText}`;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
const callImplementation = `${nativeName}(jspp::Constants::UNDEFINED${argsPart})`;
|
|
1044
|
+
if (symbol.features.isGenerator) {
|
|
1045
|
+
if (symbol.features.isAsync) {
|
|
1046
|
+
return `jspp::AnyValue::from_async_iterator(${callImplementation})`;
|
|
677
1047
|
}
|
|
678
|
-
return `jspp::AnyValue::from_iterator(${
|
|
1048
|
+
return `jspp::AnyValue::from_iterator(${callImplementation})`;
|
|
679
1049
|
}
|
|
680
|
-
|
|
1050
|
+
if (symbol.features.isAsync) {
|
|
1051
|
+
return `jspp::AnyValue::from_promise(${callImplementation})`;
|
|
1052
|
+
}
|
|
1053
|
+
return callImplementation;
|
|
1054
|
+
}
|
|
1055
|
+
else {
|
|
1056
|
+
const argsVar = this.generateUniqueName("__args_", this.getDeclaredSymbols(node));
|
|
1057
|
+
let code = `([&]() {\n`;
|
|
1058
|
+
this.indentationLevel++;
|
|
1059
|
+
code += generateArgsVectorBuilder(flattened, argsVar);
|
|
1060
|
+
const callArgs = [];
|
|
1061
|
+
for (let i = 0; i < parameters.length; i++) {
|
|
1062
|
+
const p = parameters[i];
|
|
1063
|
+
if (!p)
|
|
1064
|
+
continue;
|
|
1065
|
+
if (p.dotDotDotToken) {
|
|
1066
|
+
callArgs.push(`jspp::AnyValue::make_array(std::vector<jspp::AnyValue>(${argsVar}.begin() + std::min((size_t)${i}, ${argsVar}.size()), ${argsVar}.end()))`);
|
|
1067
|
+
}
|
|
1068
|
+
else {
|
|
1069
|
+
callArgs.push(`(${argsVar}.size() > ${i} ? ${argsVar}[${i}] : jspp::Constants::UNDEFINED)`);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
let callExprStr = `${nativeName}(jspp::Constants::UNDEFINED${callArgs.length > 0 ? ", " + callArgs.join(", ") : ""})`;
|
|
1073
|
+
if (symbol.features.isGenerator) {
|
|
1074
|
+
if (symbol.features.isAsync) {
|
|
1075
|
+
callExprStr =
|
|
1076
|
+
`jspp::AnyValue::from_async_iterator(${callExprStr})`;
|
|
1077
|
+
}
|
|
1078
|
+
else {
|
|
1079
|
+
callExprStr =
|
|
1080
|
+
`jspp::AnyValue::from_iterator(${callExprStr})`;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
else if (symbol.features.isAsync) {
|
|
1084
|
+
callExprStr =
|
|
1085
|
+
`jspp::AnyValue::from_promise(${callExprStr})`;
|
|
1086
|
+
}
|
|
1087
|
+
code += `${this.indent()}return ${callExprStr};\n`;
|
|
1088
|
+
this.indentationLevel--;
|
|
1089
|
+
code += `${this.indent()}})()`;
|
|
1090
|
+
return code;
|
|
681
1091
|
}
|
|
682
|
-
// AnyValue function call
|
|
683
|
-
derefCallee = this.getDerefCode(calleeCode, this.getJsVarName(callee), context, typeInfo);
|
|
684
1092
|
}
|
|
685
1093
|
}
|
|
686
1094
|
let calleeName = "";
|
|
@@ -692,14 +1100,33 @@ export function visitCallExpression(node, context) {
|
|
|
692
1100
|
const funcExpr = callee.expression;
|
|
693
1101
|
calleeName = this.escapeString(funcExpr.name?.getText() || "");
|
|
694
1102
|
}
|
|
695
|
-
// Pass undefined as 'this' for normal function calls
|
|
696
1103
|
const calleeNamePart = calleeName && calleeName.length > 0
|
|
697
1104
|
? `, "${calleeName}"`
|
|
698
1105
|
: "";
|
|
699
|
-
if (
|
|
700
|
-
|
|
1106
|
+
if (!hasSpread) {
|
|
1107
|
+
const argsSpan = generateArgsSpan(flattened);
|
|
1108
|
+
if (callExpr.questionDotToken) {
|
|
1109
|
+
return `${derefCallee}.optional_call(jspp::Constants::UNDEFINED, ${argsSpan}${calleeNamePart})`;
|
|
1110
|
+
}
|
|
1111
|
+
return `${derefCallee}.call(jspp::Constants::UNDEFINED, ${argsSpan}${calleeNamePart})`;
|
|
1112
|
+
}
|
|
1113
|
+
else {
|
|
1114
|
+
const argsVar = this.generateUniqueName("__args_", this.getDeclaredSymbols(node));
|
|
1115
|
+
let code = `([&]() {\n`;
|
|
1116
|
+
this.indentationLevel++;
|
|
1117
|
+
code += generateArgsVectorBuilder(flattened, argsVar);
|
|
1118
|
+
if (callExpr.questionDotToken) {
|
|
1119
|
+
code +=
|
|
1120
|
+
`${this.indent()}return ${derefCallee}.optional_call(jspp::Constants::UNDEFINED, ${argsVar}${calleeNamePart});\n`;
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
code +=
|
|
1124
|
+
`${this.indent()}return ${derefCallee}.call(jspp::Constants::UNDEFINED, ${argsVar}${calleeNamePart});\n`;
|
|
1125
|
+
}
|
|
1126
|
+
this.indentationLevel--;
|
|
1127
|
+
code += `${this.indent()}})()`;
|
|
1128
|
+
return code;
|
|
701
1129
|
}
|
|
702
|
-
return `${derefCallee}.call(jspp::Constants::UNDEFINED, ${argsSpan}${calleeNamePart})`;
|
|
703
1130
|
}
|
|
704
1131
|
export function visitVoidExpression(node, context) {
|
|
705
1132
|
const voidExpr = node;
|
|
@@ -725,9 +1152,9 @@ export function visitTemplateExpression(node, context) {
|
|
|
725
1152
|
finalExpr = this.getDerefCode(exprText, this.getJsVarName(expr), context, typeInfo);
|
|
726
1153
|
}
|
|
727
1154
|
}
|
|
728
|
-
result
|
|
1155
|
+
result = `jspp::add(${result}, ${finalExpr})`;
|
|
729
1156
|
if (span.literal.text) {
|
|
730
|
-
result
|
|
1157
|
+
result = `jspp::add(${result}, jspp::AnyValue::make_string("${this.escapeString(span.literal.text)}"))`;
|
|
731
1158
|
}
|
|
732
1159
|
}
|
|
733
1160
|
return result;
|
|
@@ -735,6 +1162,8 @@ export function visitTemplateExpression(node, context) {
|
|
|
735
1162
|
export function visitNewExpression(node, context) {
|
|
736
1163
|
const newExpr = node;
|
|
737
1164
|
const exprText = this.visit(newExpr.expression, context);
|
|
1165
|
+
const flattened = flattenArrayElements(newExpr.arguments || []);
|
|
1166
|
+
const hasSpread = flattened.some((e) => typeof e === "object" && "dynamicSpread" in e);
|
|
738
1167
|
let derefExpr = exprText;
|
|
739
1168
|
let name = `"${exprText}"`;
|
|
740
1169
|
if (ts.isIdentifier(newExpr.expression)) {
|
|
@@ -749,30 +1178,77 @@ export function visitNewExpression(node, context) {
|
|
|
749
1178
|
derefExpr = this.getDerefCode(exprText, name, context, typeInfo);
|
|
750
1179
|
}
|
|
751
1180
|
}
|
|
752
|
-
|
|
753
|
-
|
|
1181
|
+
if (!hasSpread) {
|
|
1182
|
+
const argsArray = flattened
|
|
754
1183
|
.map((arg) => {
|
|
755
|
-
const
|
|
756
|
-
|
|
757
|
-
|
|
1184
|
+
const expr = arg;
|
|
1185
|
+
const argText = this.visit(expr, context);
|
|
1186
|
+
if (ts.isIdentifier(expr)) {
|
|
1187
|
+
const scope = this.getScopeForNode(expr);
|
|
758
1188
|
const typeInfo = this.typeAnalyzer.scopeManager
|
|
759
|
-
.lookupFromScope(
|
|
1189
|
+
.lookupFromScope(expr.text, scope);
|
|
760
1190
|
if (!typeInfo) {
|
|
761
|
-
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(
|
|
1191
|
+
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(expr)})`;
|
|
762
1192
|
}
|
|
763
|
-
if (typeInfo && !typeInfo.isParameter &&
|
|
764
|
-
|
|
1193
|
+
if (typeInfo && !typeInfo.isParameter &&
|
|
1194
|
+
!typeInfo.isBuiltin) {
|
|
1195
|
+
return this.getDerefCode(argText, this.getJsVarName(expr), context, typeInfo);
|
|
765
1196
|
}
|
|
766
1197
|
}
|
|
767
1198
|
return argText;
|
|
768
|
-
})
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
1199
|
+
});
|
|
1200
|
+
const args = argsArray.join(", ");
|
|
1201
|
+
const argsCount = argsArray.length;
|
|
1202
|
+
const argsSpan = argsCount > 0
|
|
1203
|
+
? `std::span<const jspp::AnyValue>((const jspp::AnyValue[]){${args}}, ${argsCount})`
|
|
1204
|
+
: "std::span<const jspp::AnyValue>{}";
|
|
1205
|
+
return `${derefExpr}.construct(${argsSpan}, ${name})`;
|
|
1206
|
+
}
|
|
1207
|
+
else {
|
|
1208
|
+
const argsVar = this.generateUniqueName("__args_", this.getDeclaredSymbols(node));
|
|
1209
|
+
let code = `([&]() {\n`;
|
|
1210
|
+
this.indentationLevel++;
|
|
1211
|
+
code += `${this.indent()}std::vector<jspp::AnyValue> ${argsVar};\n`;
|
|
1212
|
+
if (newExpr.arguments) {
|
|
1213
|
+
for (const arg of flattened) {
|
|
1214
|
+
if (typeof arg === "object" && "dynamicSpread" in arg) {
|
|
1215
|
+
const spreadExprSource = arg.dynamicSpread;
|
|
1216
|
+
let spreadExpr = this.visit(spreadExprSource, context);
|
|
1217
|
+
if (ts.isIdentifier(spreadExprSource)) {
|
|
1218
|
+
const scope = this.getScopeForNode(spreadExprSource);
|
|
1219
|
+
const typeInfo = this.typeAnalyzer.scopeManager
|
|
1220
|
+
.lookupFromScope(spreadExprSource.text, scope);
|
|
1221
|
+
if (typeInfo && !typeInfo.isBuiltin &&
|
|
1222
|
+
!typeInfo.isParameter) {
|
|
1223
|
+
spreadExpr = this.getDerefCode(spreadExpr, this.getJsVarName(spreadExprSource), context, typeInfo);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
code +=
|
|
1227
|
+
`${this.indent()}jspp::Access::spread_array(${argsVar}, ${spreadExpr});\n`;
|
|
1228
|
+
}
|
|
1229
|
+
else {
|
|
1230
|
+
const expr = arg;
|
|
1231
|
+
let argText = this.visit(expr, context);
|
|
1232
|
+
if (ts.isIdentifier(expr)) {
|
|
1233
|
+
const scope = this.getScopeForNode(expr);
|
|
1234
|
+
const typeInfo = this.typeAnalyzer.scopeManager
|
|
1235
|
+
.lookupFromScope(expr.text, scope);
|
|
1236
|
+
if (typeInfo && !typeInfo.isBuiltin &&
|
|
1237
|
+
!typeInfo.isParameter) {
|
|
1238
|
+
argText = this.getDerefCode(argText, this.getJsVarName(expr), context, typeInfo);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
code +=
|
|
1242
|
+
`${this.indent()}${argsVar}.push_back(${argText});\n`;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
code +=
|
|
1247
|
+
`${this.indent()} return ${derefExpr}.construct(${argsVar}, ${name});\n`;
|
|
1248
|
+
this.indentationLevel--;
|
|
1249
|
+
code += `${this.indent()}})()`;
|
|
1250
|
+
return code;
|
|
1251
|
+
}
|
|
776
1252
|
}
|
|
777
1253
|
export function visitTypeOfExpression(node, context) {
|
|
778
1254
|
const typeOfExpr = node;
|
|
@@ -827,3 +1303,15 @@ export function visitDeleteExpression(node, context) {
|
|
|
827
1303
|
}
|
|
828
1304
|
return "jspp::Constants::TRUE"; // delete on non-property is true in JS
|
|
829
1305
|
}
|
|
1306
|
+
export function visitAsExpression(node, context) {
|
|
1307
|
+
return this.visit(node.expression, context);
|
|
1308
|
+
}
|
|
1309
|
+
export function visitTypeAssertionExpression(node, context) {
|
|
1310
|
+
return this.visit(node.expression, context);
|
|
1311
|
+
}
|
|
1312
|
+
export function visitNonNullExpression(node, context) {
|
|
1313
|
+
return this.visit(node.expression, context);
|
|
1314
|
+
}
|
|
1315
|
+
export function visitSatisfiesExpression(node, context) {
|
|
1316
|
+
return this.visit(node.expression, context);
|
|
1317
|
+
}
|