@ugo-studio/jspp 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/scope.js +17 -0
- package/dist/analysis/typeAnalyzer.js +7 -1
- package/dist/ast/symbols.js +32 -0
- package/dist/ast/types.js +0 -6
- package/dist/cli-utils/args.js +57 -0
- package/dist/cli-utils/colors.js +9 -0
- package/dist/cli-utils/file-utils.js +20 -0
- package/dist/cli-utils/spinner.js +55 -0
- package/dist/cli.js +105 -30
- package/dist/core/codegen/class-handlers.js +10 -6
- package/dist/core/codegen/control-flow-handlers.js +57 -28
- package/dist/core/codegen/declaration-handlers.js +10 -6
- package/dist/core/codegen/expression-handlers.js +206 -61
- package/dist/core/codegen/function-handlers.js +203 -76
- package/dist/core/codegen/helpers.js +125 -28
- package/dist/core/codegen/index.js +23 -15
- package/dist/core/codegen/literal-handlers.js +15 -6
- package/dist/core/codegen/statement-handlers.js +282 -84
- package/dist/core/codegen/visitor.js +3 -1
- package/package.json +1 -1
- package/src/prelude/any_value.hpp +221 -342
- package/src/prelude/any_value_access.hpp +168 -81
- package/src/prelude/any_value_defines.hpp +74 -35
- package/src/prelude/any_value_helpers.hpp +75 -180
- package/src/prelude/exception.hpp +1 -0
- package/src/prelude/exception_helpers.hpp +4 -4
- package/src/prelude/index.hpp +12 -2
- package/src/prelude/library/array.hpp +190 -0
- package/src/prelude/library/console.hpp +6 -5
- package/src/prelude/library/error.hpp +10 -8
- package/src/prelude/library/function.hpp +10 -0
- package/src/prelude/library/global.hpp +20 -0
- package/src/prelude/library/math.hpp +308 -0
- package/src/prelude/library/object.hpp +288 -0
- package/src/prelude/library/performance.hpp +1 -1
- package/src/prelude/library/process.hpp +39 -0
- package/src/prelude/library/promise.hpp +57 -55
- package/src/prelude/library/symbol.hpp +45 -57
- package/src/prelude/library/timer.hpp +6 -6
- package/src/prelude/types.hpp +54 -0
- package/src/prelude/utils/access.hpp +215 -11
- package/src/prelude/utils/assignment_operators.hpp +99 -0
- package/src/prelude/utils/log_any_value/array.hpp +8 -8
- package/src/prelude/utils/log_any_value/function.hpp +6 -4
- package/src/prelude/utils/log_any_value/object.hpp +41 -24
- package/src/prelude/utils/log_any_value/primitives.hpp +3 -1
- package/src/prelude/utils/operators.hpp +750 -274
- package/src/prelude/utils/well_known_symbols.hpp +12 -0
- package/src/prelude/values/array.hpp +8 -6
- package/src/prelude/values/async_iterator.hpp +79 -0
- package/src/prelude/values/descriptors.hpp +2 -2
- package/src/prelude/values/function.hpp +72 -62
- package/src/prelude/values/helpers/array.hpp +64 -28
- package/src/prelude/values/helpers/async_iterator.hpp +275 -0
- package/src/prelude/values/helpers/function.hpp +81 -92
- package/src/prelude/values/helpers/iterator.hpp +3 -3
- package/src/prelude/values/helpers/object.hpp +54 -9
- package/src/prelude/values/helpers/promise.hpp +13 -6
- package/src/prelude/values/iterator.hpp +1 -1
- package/src/prelude/values/object.hpp +10 -3
- package/src/prelude/values/promise.hpp +7 -11
- package/src/prelude/values/prototypes/array.hpp +851 -12
- package/src/prelude/values/prototypes/async_iterator.hpp +50 -0
- package/src/prelude/values/prototypes/function.hpp +2 -2
- package/src/prelude/values/prototypes/iterator.hpp +5 -5
- package/src/prelude/values/prototypes/number.hpp +153 -0
- package/src/prelude/values/prototypes/object.hpp +2 -2
- package/src/prelude/values/prototypes/promise.hpp +40 -30
- package/src/prelude/values/prototypes/string.hpp +28 -28
- package/src/prelude/values/prototypes/symbol.hpp +20 -3
- package/src/prelude/values/shape.hpp +52 -0
|
@@ -16,7 +16,7 @@ export function visitObjectPropertyName(node, context) {
|
|
|
16
16
|
if (ts.isIdentifier(compExpr)) {
|
|
17
17
|
const scope = this.getScopeForNode(compExpr);
|
|
18
18
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(compExpr.getText(), scope);
|
|
19
|
-
propName = this.getDerefCode(propName, this.getJsVarName(compExpr), typeInfo);
|
|
19
|
+
propName = this.getDerefCode(propName, this.getJsVarName(compExpr), context, typeInfo);
|
|
20
20
|
}
|
|
21
21
|
return propName;
|
|
22
22
|
}
|
|
@@ -28,8 +28,9 @@ export function visitObjectPropertyName(node, context) {
|
|
|
28
28
|
export function visitObjectLiteralExpression(node, context) {
|
|
29
29
|
const obj = node;
|
|
30
30
|
const objVar = this.generateUniqueName("__obj_", this.getDeclaredSymbols(node));
|
|
31
|
-
let code = `([&]() {
|
|
32
|
-
|
|
31
|
+
let code = `([&]() {\n`;
|
|
32
|
+
code +=
|
|
33
|
+
`${this.indent()} auto ${objVar} = jspp::AnyValue::make_object_with_proto({}, ::Object.get_own_property("prototype"));\n`;
|
|
33
34
|
this.indentationLevel++;
|
|
34
35
|
for (const prop of obj.properties) {
|
|
35
36
|
if (ts.isPropertyAssignment(prop)) {
|
|
@@ -43,7 +44,7 @@ ${this.indent()} auto ${objVar} = jspp::AnyValue::make_object({});\n`;
|
|
|
43
44
|
const scope = this.getScopeForNode(initializer);
|
|
44
45
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(initializer.text, scope);
|
|
45
46
|
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
46
|
-
value = this.getDerefCode(value, this.getJsVarName(initializer), typeInfo);
|
|
47
|
+
value = this.getDerefCode(value, this.getJsVarName(initializer), context, typeInfo);
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
code +=
|
|
@@ -58,7 +59,7 @@ ${this.indent()} auto ${objVar} = jspp::AnyValue::make_object({});\n`;
|
|
|
58
59
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(prop.name.text, scope);
|
|
59
60
|
let value = this.visit(prop.name, context);
|
|
60
61
|
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
61
|
-
value = this.getDerefCode(value, this.getJsVarName(prop.name), typeInfo);
|
|
62
|
+
value = this.getDerefCode(value, this.getJsVarName(prop.name), context, typeInfo);
|
|
62
63
|
}
|
|
63
64
|
code +=
|
|
64
65
|
`${this.indent()}${objVar}.define_data_property(${key}, ${value});\n`;
|
|
@@ -101,6 +102,8 @@ ${this.indent()} auto ${objVar} = jspp::AnyValue::make_object({});\n`;
|
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
104
|
this.indentationLevel--;
|
|
105
|
+
// code +=
|
|
106
|
+
// `${this.indent()} ${returnCmd} ${objVar};\n${this.indent()}} )() ))`;
|
|
104
107
|
code += `${this.indent()} return ${objVar};\n${this.indent()}})()`;
|
|
105
108
|
return code;
|
|
106
109
|
}
|
|
@@ -112,13 +115,16 @@ export function visitArrayLiteralExpression(node, context) {
|
|
|
112
115
|
const scope = this.getScopeForNode(elem);
|
|
113
116
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(elem.text, scope);
|
|
114
117
|
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
115
|
-
elemText = this.getDerefCode(elemText, this.getJsVarName(elem), typeInfo);
|
|
118
|
+
elemText = this.getDerefCode(elemText, this.getJsVarName(elem), context, typeInfo);
|
|
116
119
|
}
|
|
117
120
|
}
|
|
118
121
|
return elemText;
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
|
|
122
|
+
});
|
|
123
|
+
const elementsJoined = elements.join(", ");
|
|
124
|
+
const elementsSpan = elements.length > 0
|
|
125
|
+
? `std::span<const jspp::AnyValue>((const jspp::AnyValue[]){${elementsJoined}}, ${elements.length})`
|
|
126
|
+
: "std::span<const jspp::AnyValue>{}";
|
|
127
|
+
return `jspp::AnyValue::make_array_with_proto(${elementsSpan}, ::Array.get_own_property("prototype"))`;
|
|
122
128
|
}
|
|
123
129
|
export function visitPrefixUnaryExpression(node, context) {
|
|
124
130
|
const prefixUnaryExpr = node;
|
|
@@ -130,7 +136,7 @@ export function visitPrefixUnaryExpression(node, context) {
|
|
|
130
136
|
const scope = this.getScopeForNode(prefixUnaryExpr.operand);
|
|
131
137
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(prefixUnaryExpr.operand.getText(), scope);
|
|
132
138
|
if (context.derefBeforeAssignment) {
|
|
133
|
-
target = this.getDerefCode(operand, operand, typeInfo);
|
|
139
|
+
target = this.getDerefCode(operand, operand, context, typeInfo);
|
|
134
140
|
}
|
|
135
141
|
else if (typeInfo.needsHeapAllocation) {
|
|
136
142
|
target = `*${operand}`;
|
|
@@ -144,7 +150,7 @@ export function visitPrefixUnaryExpression(node, context) {
|
|
|
144
150
|
const scope = this.getScopeForNode(prefixUnaryExpr.operand);
|
|
145
151
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(prefixUnaryExpr.operand.getText(), scope);
|
|
146
152
|
if (context.derefBeforeAssignment) {
|
|
147
|
-
target = this.getDerefCode(operand, operand, typeInfo);
|
|
153
|
+
target = this.getDerefCode(operand, operand, context, typeInfo);
|
|
148
154
|
}
|
|
149
155
|
else if (typeInfo.needsHeapAllocation) {
|
|
150
156
|
target = `*${operand}`;
|
|
@@ -163,7 +169,7 @@ export function visitPostfixUnaryExpression(node, context) {
|
|
|
163
169
|
const scope = this.getScopeForNode(postfixUnaryExpr.operand);
|
|
164
170
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(postfixUnaryExpr.operand.getText(), scope);
|
|
165
171
|
if (context.derefBeforeAssignment) {
|
|
166
|
-
target = this.getDerefCode(operand, operand, typeInfo);
|
|
172
|
+
target = this.getDerefCode(operand, operand, context, typeInfo);
|
|
167
173
|
}
|
|
168
174
|
else if (typeInfo.needsHeapAllocation) {
|
|
169
175
|
target = `*${operand}`;
|
|
@@ -199,7 +205,10 @@ export function visitPropertyAccessExpression(node, context) {
|
|
|
199
205
|
!typeInfo.isParameter &&
|
|
200
206
|
!typeInfo.isBuiltin &&
|
|
201
207
|
ts.isIdentifier(propAccess.expression)) {
|
|
202
|
-
finalExpr = this.getDerefCode(exprText, this.getJsVarName(propAccess.expression), typeInfo);
|
|
208
|
+
finalExpr = this.getDerefCode(exprText, this.getJsVarName(propAccess.expression), context, typeInfo);
|
|
209
|
+
}
|
|
210
|
+
if (propAccess.questionDotToken) {
|
|
211
|
+
return `jspp::Access::optional_get_property(${finalExpr}, "${propName}")`;
|
|
203
212
|
}
|
|
204
213
|
return `${finalExpr}.get_own_property("${propName}")`;
|
|
205
214
|
}
|
|
@@ -221,7 +230,7 @@ export function visitElementAccessExpression(node, context) {
|
|
|
221
230
|
!exprTypeInfo.isParameter &&
|
|
222
231
|
!exprTypeInfo.isBuiltin &&
|
|
223
232
|
ts.isIdentifier(elemAccess.expression)) {
|
|
224
|
-
finalExpr = this.getDerefCode(exprText, this.getJsVarName(elemAccess.expression), exprTypeInfo);
|
|
233
|
+
finalExpr = this.getDerefCode(exprText, this.getJsVarName(elemAccess.expression), context, exprTypeInfo);
|
|
225
234
|
}
|
|
226
235
|
// Dereference the argument expression if it's an identifier
|
|
227
236
|
if (ts.isIdentifier(elemAccess.argumentExpression)) {
|
|
@@ -233,9 +242,12 @@ export function visitElementAccessExpression(node, context) {
|
|
|
233
242
|
if (argTypeInfo &&
|
|
234
243
|
!argTypeInfo.isParameter &&
|
|
235
244
|
!argTypeInfo.isBuiltin) {
|
|
236
|
-
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression), argTypeInfo);
|
|
245
|
+
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression), context, argTypeInfo);
|
|
237
246
|
}
|
|
238
247
|
}
|
|
248
|
+
if (elemAccess.questionDotToken) {
|
|
249
|
+
return `jspp::Access::optional_get_element(${finalExpr}, ${argText})`;
|
|
250
|
+
}
|
|
239
251
|
return `${finalExpr}.get_own_property(${argText})`;
|
|
240
252
|
}
|
|
241
253
|
export function visitBinaryExpression(node, context) {
|
|
@@ -248,21 +260,84 @@ export function visitBinaryExpression(node, context) {
|
|
|
248
260
|
ts.SyntaxKind.AsteriskEqualsToken,
|
|
249
261
|
ts.SyntaxKind.SlashEqualsToken,
|
|
250
262
|
ts.SyntaxKind.PercentEqualsToken,
|
|
263
|
+
ts.SyntaxKind.AsteriskAsteriskEqualsToken,
|
|
264
|
+
ts.SyntaxKind.LessThanLessThanEqualsToken,
|
|
265
|
+
ts.SyntaxKind.GreaterThanGreaterThanEqualsToken,
|
|
266
|
+
ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken,
|
|
267
|
+
ts.SyntaxKind.AmpersandEqualsToken,
|
|
268
|
+
ts.SyntaxKind.BarEqualsToken,
|
|
269
|
+
ts.SyntaxKind.CaretEqualsToken,
|
|
270
|
+
ts.SyntaxKind.AmpersandAmpersandEqualsToken,
|
|
271
|
+
ts.SyntaxKind.BarBarEqualsToken,
|
|
272
|
+
ts.SyntaxKind.QuestionQuestionEqualsToken,
|
|
251
273
|
];
|
|
252
274
|
if (assignmentOperators.includes(opToken.kind)) {
|
|
275
|
+
if (opToken.kind ===
|
|
276
|
+
ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken) {
|
|
277
|
+
const leftText = this.visit(binExpr.left, context);
|
|
278
|
+
const rightText = this.visit(binExpr.right, context);
|
|
279
|
+
let target = leftText;
|
|
280
|
+
if (ts.isIdentifier(binExpr.left)) {
|
|
281
|
+
const scope = this.getScopeForNode(binExpr.left);
|
|
282
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.text, scope);
|
|
283
|
+
target = typeInfo.needsHeapAllocation
|
|
284
|
+
? `*${leftText}`
|
|
285
|
+
: leftText;
|
|
286
|
+
return `${target} = jspp::unsigned_right_shift(${target}, ${rightText})`;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (opToken.kind === ts.SyntaxKind.AsteriskAsteriskEqualsToken) {
|
|
290
|
+
const leftText = this.visit(binExpr.left, context);
|
|
291
|
+
const rightText = this.visit(binExpr.right, context);
|
|
292
|
+
let target = leftText;
|
|
293
|
+
if (ts.isIdentifier(binExpr.left)) {
|
|
294
|
+
const scope = this.getScopeForNode(binExpr.left);
|
|
295
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.text, scope);
|
|
296
|
+
target = typeInfo.needsHeapAllocation
|
|
297
|
+
? `*${leftText}`
|
|
298
|
+
: leftText;
|
|
299
|
+
return `${target} = jspp::pow(${target}, ${rightText})`;
|
|
300
|
+
}
|
|
301
|
+
// For complex LHS, we need a different approach, but this is a start.
|
|
302
|
+
}
|
|
303
|
+
if (opToken.kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken ||
|
|
304
|
+
opToken.kind === ts.SyntaxKind.BarBarEqualsToken ||
|
|
305
|
+
opToken.kind === ts.SyntaxKind.QuestionQuestionEqualsToken) {
|
|
306
|
+
const leftText = this.visit(binExpr.left, context);
|
|
307
|
+
const rightText = this.visit(binExpr.right, context);
|
|
308
|
+
let target = leftText;
|
|
309
|
+
if (ts.isIdentifier(binExpr.left)) {
|
|
310
|
+
const scope = this.getScopeForNode(binExpr.left);
|
|
311
|
+
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.text, scope);
|
|
312
|
+
target = typeInfo.needsHeapAllocation
|
|
313
|
+
? `*${leftText}`
|
|
314
|
+
: leftText;
|
|
315
|
+
if (opToken.kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken) {
|
|
316
|
+
return `jspp::logical_and_assign(${target}, ${rightText})`;
|
|
317
|
+
}
|
|
318
|
+
else if (opToken.kind === ts.SyntaxKind.BarBarEqualsToken) {
|
|
319
|
+
return `jspp::logical_or_assign(${target}, ${rightText})`;
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
return `jspp::nullish_coalesce_assign(${target}, ${rightText})`;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
253
326
|
const leftText = this.visit(binExpr.left, context);
|
|
254
|
-
let rightText =
|
|
327
|
+
let rightText = ts.isNumericLiteral(binExpr.right)
|
|
328
|
+
? binExpr.right.getText()
|
|
329
|
+
: this.visit(binExpr.right, context);
|
|
255
330
|
if (ts.isIdentifier(binExpr.right)) {
|
|
256
331
|
const scope = this.getScopeForNode(binExpr.right);
|
|
257
332
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.right.getText(), scope);
|
|
258
|
-
rightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), typeInfo);
|
|
333
|
+
rightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), context, typeInfo);
|
|
259
334
|
}
|
|
260
335
|
let target = leftText;
|
|
261
336
|
if (ts.isIdentifier(binExpr.left)) {
|
|
262
337
|
const scope = this.getScopeForNode(binExpr.left);
|
|
263
338
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.getText(), scope);
|
|
264
339
|
if (context.derefBeforeAssignment) {
|
|
265
|
-
target = this.getDerefCode(leftText, leftText, typeInfo);
|
|
340
|
+
target = this.getDerefCode(leftText, leftText, context, typeInfo);
|
|
266
341
|
}
|
|
267
342
|
else if (typeInfo.needsHeapAllocation) {
|
|
268
343
|
target = `*${leftText}`;
|
|
@@ -271,7 +346,7 @@ export function visitBinaryExpression(node, context) {
|
|
|
271
346
|
return `${target} ${op} ${rightText}`;
|
|
272
347
|
}
|
|
273
348
|
if (opToken.kind === ts.SyntaxKind.EqualsToken) {
|
|
274
|
-
|
|
349
|
+
let rightText = this.visit(binExpr.right, context);
|
|
275
350
|
if (ts.isPropertyAccessExpression(binExpr.left)) {
|
|
276
351
|
const propAccess = binExpr.left;
|
|
277
352
|
if (propAccess.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
@@ -285,7 +360,7 @@ export function visitBinaryExpression(node, context) {
|
|
|
285
360
|
if (rightTypeInfo &&
|
|
286
361
|
!rightTypeInfo.isParameter &&
|
|
287
362
|
!rightTypeInfo.isBuiltin) {
|
|
288
|
-
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), rightTypeInfo);
|
|
363
|
+
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), context, rightTypeInfo);
|
|
289
364
|
}
|
|
290
365
|
}
|
|
291
366
|
// Approximate super assignment as setting property on 'this'
|
|
@@ -298,7 +373,7 @@ export function visitBinaryExpression(node, context) {
|
|
|
298
373
|
const scope = this.getScopeForNode(propAccess.expression);
|
|
299
374
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(propAccess.expression.getText(), scope);
|
|
300
375
|
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
301
|
-
finalObjExpr = this.getDerefCode(objExprText, this.getJsVarName(propAccess.expression), typeInfo);
|
|
376
|
+
finalObjExpr = this.getDerefCode(objExprText, this.getJsVarName(propAccess.expression), context, typeInfo);
|
|
302
377
|
}
|
|
303
378
|
}
|
|
304
379
|
let finalRightText = rightText;
|
|
@@ -309,7 +384,7 @@ export function visitBinaryExpression(node, context) {
|
|
|
309
384
|
if (rightTypeInfo &&
|
|
310
385
|
!rightTypeInfo.isParameter &&
|
|
311
386
|
!rightTypeInfo.isBuiltin) {
|
|
312
|
-
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), rightTypeInfo);
|
|
387
|
+
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), context, rightTypeInfo);
|
|
313
388
|
}
|
|
314
389
|
}
|
|
315
390
|
return `${finalObjExpr}.set_own_property("${propName}", ${finalRightText})`;
|
|
@@ -323,7 +398,7 @@ export function visitBinaryExpression(node, context) {
|
|
|
323
398
|
const scope = this.getScopeForNode(elemAccess.expression);
|
|
324
399
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(elemAccess.expression.getText(), scope);
|
|
325
400
|
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
326
|
-
finalObjExpr = this.getDerefCode(objExprText, this.getJsVarName(elemAccess.expression), typeInfo);
|
|
401
|
+
finalObjExpr = this.getDerefCode(objExprText, this.getJsVarName(elemAccess.expression), context, typeInfo);
|
|
327
402
|
}
|
|
328
403
|
}
|
|
329
404
|
if (ts.isIdentifier(elemAccess.argumentExpression)) {
|
|
@@ -333,7 +408,7 @@ export function visitBinaryExpression(node, context) {
|
|
|
333
408
|
if (argTypeInfo &&
|
|
334
409
|
!argTypeInfo.isParameter &&
|
|
335
410
|
!argTypeInfo.isBuiltin) {
|
|
336
|
-
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression), argTypeInfo);
|
|
411
|
+
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression), context, argTypeInfo);
|
|
337
412
|
}
|
|
338
413
|
}
|
|
339
414
|
let finalRightText = rightText;
|
|
@@ -344,7 +419,7 @@ export function visitBinaryExpression(node, context) {
|
|
|
344
419
|
if (rightTypeInfo &&
|
|
345
420
|
!rightTypeInfo.isParameter &&
|
|
346
421
|
!rightTypeInfo.isBuiltin) {
|
|
347
|
-
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), rightTypeInfo);
|
|
422
|
+
finalRightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), context, rightTypeInfo);
|
|
348
423
|
}
|
|
349
424
|
}
|
|
350
425
|
return `${finalObjExpr}.set_own_property(${argText}, ${finalRightText})`;
|
|
@@ -358,8 +433,11 @@ export function visitBinaryExpression(node, context) {
|
|
|
358
433
|
if (typeInfo?.isConst) {
|
|
359
434
|
return `jspp::Exception::throw_immutable_assignment()`;
|
|
360
435
|
}
|
|
436
|
+
if (ts.isNumericLiteral(binExpr.right)) {
|
|
437
|
+
rightText = binExpr.right.getText();
|
|
438
|
+
}
|
|
361
439
|
const target = context.derefBeforeAssignment
|
|
362
|
-
? this.getDerefCode(leftText, leftText, typeInfo)
|
|
440
|
+
? this.getDerefCode(leftText, leftText, context, typeInfo)
|
|
363
441
|
: (typeInfo.needsHeapAllocation ? `*${leftText}` : leftText);
|
|
364
442
|
return `${target} ${op} ${rightText}`;
|
|
365
443
|
}
|
|
@@ -373,7 +451,7 @@ export function visitBinaryExpression(node, context) {
|
|
|
373
451
|
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(binExpr.left)})`;
|
|
374
452
|
}
|
|
375
453
|
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
376
|
-
finalLeft = this.getDerefCode(leftText, this.getJsVarName(binExpr.left), typeInfo);
|
|
454
|
+
finalLeft = this.getDerefCode(leftText, this.getJsVarName(binExpr.left), context, typeInfo);
|
|
377
455
|
}
|
|
378
456
|
}
|
|
379
457
|
let finalRight = rightText;
|
|
@@ -385,24 +463,53 @@ export function visitBinaryExpression(node, context) {
|
|
|
385
463
|
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(binExpr.right)})`;
|
|
386
464
|
}
|
|
387
465
|
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
388
|
-
finalRight = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), typeInfo);
|
|
466
|
+
finalRight = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), context, typeInfo);
|
|
389
467
|
}
|
|
390
468
|
}
|
|
469
|
+
if (opToken.kind === ts.SyntaxKind.InKeyword) {
|
|
470
|
+
return `jspp::Access::in(${finalLeft}, ${finalRight})`;
|
|
471
|
+
}
|
|
472
|
+
if (opToken.kind === ts.SyntaxKind.InstanceOfKeyword) {
|
|
473
|
+
return `jspp::Access::instance_of(${finalLeft}, ${finalRight})`;
|
|
474
|
+
}
|
|
475
|
+
if (opToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {
|
|
476
|
+
return `jspp::logical_and(${finalLeft}, ${finalRight})`;
|
|
477
|
+
}
|
|
478
|
+
if (opToken.kind === ts.SyntaxKind.BarBarToken) {
|
|
479
|
+
return `jspp::logical_or(${finalLeft}, ${finalRight})`;
|
|
480
|
+
}
|
|
481
|
+
if (opToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
|
|
482
|
+
return `jspp::nullish_coalesce(${finalLeft}, ${finalRight})`;
|
|
483
|
+
}
|
|
484
|
+
// Optimizations to prevent calling make_number multiple times
|
|
485
|
+
if (ts.isNumericLiteral(binExpr.left)) {
|
|
486
|
+
finalLeft = binExpr.left.getText();
|
|
487
|
+
}
|
|
488
|
+
if (ts.isNumericLiteral(binExpr.right)) {
|
|
489
|
+
finalRight = binExpr.right.getText();
|
|
490
|
+
}
|
|
391
491
|
if (opToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken) {
|
|
392
|
-
return
|
|
492
|
+
return `jspp::is_strictly_equal_to(${finalLeft}, ${finalRight})`;
|
|
393
493
|
}
|
|
394
494
|
if (opToken.kind === ts.SyntaxKind.EqualsEqualsToken) {
|
|
395
|
-
return
|
|
495
|
+
return `jspp::is_equal_to(${finalLeft}, ${finalRight})`;
|
|
396
496
|
}
|
|
397
497
|
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
|
|
398
|
-
return
|
|
498
|
+
return `jspp::not_strictly_equal_to(${finalLeft}, ${finalRight})`;
|
|
399
499
|
}
|
|
400
500
|
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsToken) {
|
|
401
|
-
return
|
|
501
|
+
return `jspp::not_equal_to(${finalLeft}, ${finalRight})`;
|
|
402
502
|
}
|
|
403
503
|
if (opToken.kind === ts.SyntaxKind.AsteriskAsteriskToken) {
|
|
404
504
|
return `jspp::pow(${finalLeft}, ${finalRight})`;
|
|
405
505
|
}
|
|
506
|
+
if (opToken.kind === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken) {
|
|
507
|
+
return `jspp::unsigned_right_shift(${finalLeft}, ${finalRight})`;
|
|
508
|
+
}
|
|
509
|
+
// Optimizations to prevent calling make_number multiple times
|
|
510
|
+
if (ts.isNumericLiteral(binExpr.left) && ts.isNumericLiteral(binExpr.right)) {
|
|
511
|
+
return `jspp::AnyValue::make_number(${finalLeft} ${op} ${finalRight})`;
|
|
512
|
+
}
|
|
406
513
|
if (op === "+" ||
|
|
407
514
|
op === "-" ||
|
|
408
515
|
op === "*" ||
|
|
@@ -410,7 +517,9 @@ export function visitBinaryExpression(node, context) {
|
|
|
410
517
|
op === "%" ||
|
|
411
518
|
op === "^" ||
|
|
412
519
|
op === "&" ||
|
|
413
|
-
op === "|"
|
|
520
|
+
op === "|" ||
|
|
521
|
+
op === "<<" ||
|
|
522
|
+
op === ">>") {
|
|
414
523
|
return `(${finalLeft} ${op} ${finalRight})`;
|
|
415
524
|
}
|
|
416
525
|
return `${finalLeft} ${op} ${finalRight}`;
|
|
@@ -426,7 +535,7 @@ export function visitConditionalExpression(node, context) {
|
|
|
426
535
|
...context,
|
|
427
536
|
isFunctionBody: false,
|
|
428
537
|
});
|
|
429
|
-
return `(${condition})
|
|
538
|
+
return `is_truthy(${condition}) ? ${whenTrueStmt} : ${whenFalseStmt}`;
|
|
430
539
|
}
|
|
431
540
|
export function visitCallExpression(node, context) {
|
|
432
541
|
const callExpr = node;
|
|
@@ -437,9 +546,9 @@ export function visitCallExpression(node, context) {
|
|
|
437
546
|
}
|
|
438
547
|
const args = callExpr.arguments.map((arg) => this.visit(arg, context))
|
|
439
548
|
.join(", ");
|
|
440
|
-
return `(${context.superClassVar}).
|
|
549
|
+
return `(${context.superClassVar}).call(${this.globalThisVar}, (const jspp::AnyValue[]){${args}}, "super")`;
|
|
441
550
|
}
|
|
442
|
-
const
|
|
551
|
+
const argsArray = callExpr.arguments
|
|
443
552
|
.map((arg) => {
|
|
444
553
|
const argText = this.visit(arg, context);
|
|
445
554
|
if (ts.isIdentifier(arg)) {
|
|
@@ -448,13 +557,17 @@ export function visitCallExpression(node, context) {
|
|
|
448
557
|
if (!typeInfo) {
|
|
449
558
|
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(arg)})`;
|
|
450
559
|
}
|
|
451
|
-
if (typeInfo && !typeInfo.
|
|
452
|
-
return this.getDerefCode(argText, this.getJsVarName(arg), typeInfo);
|
|
560
|
+
if (typeInfo && !typeInfo.isBuiltin) {
|
|
561
|
+
return this.getDerefCode(argText, this.getJsVarName(arg), context, typeInfo);
|
|
453
562
|
}
|
|
454
563
|
}
|
|
455
564
|
return argText;
|
|
456
|
-
})
|
|
457
|
-
|
|
565
|
+
});
|
|
566
|
+
const args = argsArray.join(", ");
|
|
567
|
+
const argsCount = argsArray.length;
|
|
568
|
+
const argsSpan = argsCount > 0
|
|
569
|
+
? `std::span<const jspp::AnyValue>((const jspp::AnyValue[]){${args}}, ${argsCount})`
|
|
570
|
+
: "std::span<const jspp::AnyValue>{}";
|
|
458
571
|
// Handle obj.method() -> pass obj as 'this'
|
|
459
572
|
if (ts.isPropertyAccessExpression(callee)) {
|
|
460
573
|
const propAccess = callee;
|
|
@@ -463,7 +576,7 @@ export function visitCallExpression(node, context) {
|
|
|
463
576
|
throw new Error("super.method() called but no super class variable found in context");
|
|
464
577
|
}
|
|
465
578
|
const propName = propAccess.name.getText();
|
|
466
|
-
return `(${context.superClassVar}).get_own_property("prototype").get_own_property("${propName}").
|
|
579
|
+
return `(${context.superClassVar}).get_own_property("prototype").get_own_property("${propName}").call(${this.globalThisVar}, ${argsSpan}, "${this.escapeString(propName)}")`;
|
|
467
580
|
}
|
|
468
581
|
const objExpr = propAccess.expression;
|
|
469
582
|
const propName = propAccess.name.getText();
|
|
@@ -477,10 +590,13 @@ export function visitCallExpression(node, context) {
|
|
|
477
590
|
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(objExpr)})`;
|
|
478
591
|
}
|
|
479
592
|
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
480
|
-
derefObj = this.getDerefCode(objCode, this.getJsVarName(objExpr), typeInfo);
|
|
593
|
+
derefObj = this.getDerefCode(objCode, this.getJsVarName(objExpr), context, typeInfo);
|
|
481
594
|
}
|
|
482
595
|
}
|
|
483
|
-
|
|
596
|
+
if (callExpr.questionDotToken) {
|
|
597
|
+
return `jspp::Access::optional_call(${derefObj}.get_own_property("${propName}"), ${derefObj}, ${argsSpan}, "${this.escapeString(propName)}")`;
|
|
598
|
+
}
|
|
599
|
+
return `${derefObj}.call_own_property("${propName}", ${argsSpan})`;
|
|
484
600
|
}
|
|
485
601
|
// Handle obj[method]() -> pass obj as 'this'
|
|
486
602
|
if (ts.isElementAccessExpression(callee)) {
|
|
@@ -495,7 +611,7 @@ export function visitCallExpression(node, context) {
|
|
|
495
611
|
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(objExpr)})`;
|
|
496
612
|
}
|
|
497
613
|
if (typeInfo && !typeInfo.isBuiltin && !typeInfo.isParameter) {
|
|
498
|
-
derefObj = this.getDerefCode(objCode, this.getJsVarName(objExpr), typeInfo);
|
|
614
|
+
derefObj = this.getDerefCode(objCode, this.getJsVarName(objExpr), context, typeInfo);
|
|
499
615
|
}
|
|
500
616
|
}
|
|
501
617
|
let argText = visitObjectPropertyName.call(this, elemAccess.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
@@ -509,10 +625,13 @@ export function visitCallExpression(node, context) {
|
|
|
509
625
|
}
|
|
510
626
|
if (argTypeInfo && !argTypeInfo.isParameter &&
|
|
511
627
|
!argTypeInfo.isBuiltin) {
|
|
512
|
-
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression), argTypeInfo);
|
|
628
|
+
argText = this.getDerefCode(argText, this.getJsVarName(elemAccess.argumentExpression), context, argTypeInfo);
|
|
513
629
|
}
|
|
514
630
|
}
|
|
515
|
-
|
|
631
|
+
if (callExpr.questionDotToken) {
|
|
632
|
+
return `jspp::Access::optional_call(${derefObj}.get_own_property(${argText}), ${derefObj}, ${argsSpan})`;
|
|
633
|
+
}
|
|
634
|
+
return `${derefObj}.call_own_property(${argText}, ${argsSpan})`;
|
|
516
635
|
}
|
|
517
636
|
const calleeCode = this.visit(callee, context);
|
|
518
637
|
let derefCallee = calleeCode;
|
|
@@ -526,7 +645,7 @@ export function visitCallExpression(node, context) {
|
|
|
526
645
|
derefCallee = calleeCode;
|
|
527
646
|
}
|
|
528
647
|
else if (typeInfo) {
|
|
529
|
-
derefCallee = this.getDerefCode(calleeCode, this.getJsVarName(callee), typeInfo);
|
|
648
|
+
derefCallee = this.getDerefCode(calleeCode, this.getJsVarName(callee), context, typeInfo);
|
|
530
649
|
}
|
|
531
650
|
}
|
|
532
651
|
let calleeName = "";
|
|
@@ -539,12 +658,18 @@ export function visitCallExpression(node, context) {
|
|
|
539
658
|
calleeName = this.escapeString(funcExpr.name?.getText() || "");
|
|
540
659
|
}
|
|
541
660
|
// Pass undefined as 'this' for normal function calls
|
|
542
|
-
|
|
661
|
+
const calleeNamePart = calleeName && calleeName.length > 0
|
|
662
|
+
? `, "${calleeName}"`
|
|
663
|
+
: "";
|
|
664
|
+
if (callExpr.questionDotToken) {
|
|
665
|
+
return `jspp::Access::optional_call(${derefCallee}, jspp::Constants::UNDEFINED, ${argsSpan}${calleeNamePart})`;
|
|
666
|
+
}
|
|
667
|
+
return `${derefCallee}.call(jspp::Constants::UNDEFINED, ${argsSpan}${calleeNamePart})`;
|
|
543
668
|
}
|
|
544
669
|
export function visitVoidExpression(node, context) {
|
|
545
670
|
const voidExpr = node;
|
|
546
671
|
const exprText = this.visit(voidExpr.expression, context);
|
|
547
|
-
return `(${exprText}, jspp::
|
|
672
|
+
return `(${exprText}, jspp::Constants::UNDEFINED)`;
|
|
548
673
|
}
|
|
549
674
|
export function visitTemplateExpression(node, context) {
|
|
550
675
|
const templateExpr = node;
|
|
@@ -562,7 +687,7 @@ export function visitTemplateExpression(node, context) {
|
|
|
562
687
|
else if (typeInfo &&
|
|
563
688
|
!typeInfo.isParameter &&
|
|
564
689
|
!typeInfo.isBuiltin) {
|
|
565
|
-
finalExpr = this.getDerefCode(exprText, this.getJsVarName(expr), typeInfo);
|
|
690
|
+
finalExpr = this.getDerefCode(exprText, this.getJsVarName(expr), context, typeInfo);
|
|
566
691
|
}
|
|
567
692
|
}
|
|
568
693
|
result += ` + (${finalExpr})`;
|
|
@@ -576,18 +701,20 @@ export function visitNewExpression(node, context) {
|
|
|
576
701
|
const newExpr = node;
|
|
577
702
|
const exprText = this.visit(newExpr.expression, context);
|
|
578
703
|
let derefExpr = exprText;
|
|
704
|
+
let name = `"${exprText}"`;
|
|
579
705
|
if (ts.isIdentifier(newExpr.expression)) {
|
|
706
|
+
name = this.getJsVarName(newExpr.expression);
|
|
580
707
|
const scope = this.getScopeForNode(newExpr.expression);
|
|
581
708
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(newExpr.expression.getText(), scope);
|
|
582
709
|
if (!typeInfo &&
|
|
583
710
|
!this.isBuiltinObject(newExpr.expression)) {
|
|
584
|
-
return `jspp::Exception::throw_unresolved_reference(${
|
|
711
|
+
return `jspp::Exception::throw_unresolved_reference(${name})`;
|
|
585
712
|
}
|
|
586
713
|
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
587
|
-
derefExpr = this.getDerefCode(exprText,
|
|
714
|
+
derefExpr = this.getDerefCode(exprText, name, context, typeInfo);
|
|
588
715
|
}
|
|
589
716
|
}
|
|
590
|
-
const
|
|
717
|
+
const argsArray = newExpr.arguments
|
|
591
718
|
? newExpr.arguments
|
|
592
719
|
.map((arg) => {
|
|
593
720
|
const argText = this.visit(arg, context);
|
|
@@ -599,14 +726,18 @@ export function visitNewExpression(node, context) {
|
|
|
599
726
|
return `jspp::Exception::throw_unresolved_reference(${this.getJsVarName(arg)})`;
|
|
600
727
|
}
|
|
601
728
|
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
602
|
-
return this.getDerefCode(argText, this.getJsVarName(arg), typeInfo);
|
|
729
|
+
return this.getDerefCode(argText, this.getJsVarName(arg), context, typeInfo);
|
|
603
730
|
}
|
|
604
731
|
}
|
|
605
732
|
return argText;
|
|
606
733
|
})
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
734
|
+
: [];
|
|
735
|
+
const args = argsArray.join(", ");
|
|
736
|
+
const argsCount = argsArray.length;
|
|
737
|
+
const argsSpan = argsCount > 0
|
|
738
|
+
? `std::span<const jspp::AnyValue>((const jspp::AnyValue[]){${args}}, ${argsCount})`
|
|
739
|
+
: "std::span<const jspp::AnyValue>{}";
|
|
740
|
+
return `${derefExpr}.construct(${argsSpan}, ${name})`;
|
|
610
741
|
}
|
|
611
742
|
export function visitTypeOfExpression(node, context) {
|
|
612
743
|
const typeOfExpr = node;
|
|
@@ -620,10 +751,10 @@ export function visitTypeOfExpression(node, context) {
|
|
|
620
751
|
derefExpr = `/* undeclared variable: ${this.getJsVarName(typeOfExpr.expression)} */`; // typeof undeclared variable is 'undefined'
|
|
621
752
|
}
|
|
622
753
|
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
623
|
-
derefExpr = this.getDerefCode(exprText, this.getJsVarName(typeOfExpr.expression), typeInfo);
|
|
754
|
+
derefExpr = this.getDerefCode(exprText, this.getJsVarName(typeOfExpr.expression), context, typeInfo);
|
|
624
755
|
}
|
|
625
756
|
}
|
|
626
|
-
return `jspp::Access::
|
|
757
|
+
return `jspp::Access::type_of(${derefExpr})`;
|
|
627
758
|
}
|
|
628
759
|
export function visitAwaitExpression(node, context) {
|
|
629
760
|
const awaitExpr = node;
|
|
@@ -639,11 +770,25 @@ export function visitAwaitExpression(node, context) {
|
|
|
639
770
|
// We can just throw before co_await.
|
|
640
771
|
// But we need to return a string expression.
|
|
641
772
|
// Using comma operator: (throw..., AnyValue())
|
|
642
|
-
return `(jspp::Exception::throw_unresolved_reference(${this.getJsVarName(awaitExpr.expression)}), co_await jspp::
|
|
773
|
+
return `(jspp::Exception::throw_unresolved_reference(${this.getJsVarName(awaitExpr.expression)}), co_await jspp::Constants::UNDEFINED)`;
|
|
643
774
|
}
|
|
644
775
|
if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
|
|
645
|
-
derefExpr = this.getDerefCode(exprText, this.getJsVarName(awaitExpr.expression), typeInfo);
|
|
776
|
+
derefExpr = this.getDerefCode(exprText, this.getJsVarName(awaitExpr.expression), context, typeInfo);
|
|
646
777
|
}
|
|
647
778
|
}
|
|
648
779
|
return `co_await ${derefExpr}`;
|
|
649
780
|
}
|
|
781
|
+
export function visitDeleteExpression(node, context) {
|
|
782
|
+
const expr = node.expression;
|
|
783
|
+
if (ts.isPropertyAccessExpression(expr)) {
|
|
784
|
+
const obj = this.visit(expr.expression, context);
|
|
785
|
+
const prop = `jspp::AnyValue::make_string("${expr.name.getText()}")`;
|
|
786
|
+
return `jspp::Access::delete_property(${obj}, ${prop})`;
|
|
787
|
+
}
|
|
788
|
+
else if (ts.isElementAccessExpression(expr)) {
|
|
789
|
+
const obj = this.visit(expr.expression, context);
|
|
790
|
+
const prop = this.visit(expr.argumentExpression, context);
|
|
791
|
+
return `jspp::Access::delete_property(${obj}, ${prop})`;
|
|
792
|
+
}
|
|
793
|
+
return "jspp::Constants::TRUE"; // delete on non-property is true in JS
|
|
794
|
+
}
|