@ugo-studio/jspp 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/args.js +22 -0
- package/dist/cli/compiler.js +53 -0
- package/dist/cli/index.js +43 -117
- package/dist/cli/pch.js +71 -0
- package/dist/cli/runner.js +23 -0
- package/dist/cli/spinner.js +27 -11
- package/dist/cli/transpiler.js +20 -0
- package/dist/cli/utils.js +25 -27
- package/dist/cli/wasm.js +70 -0
- package/dist/index.js +17 -6
- package/dist/{analysis → interpreter/analysis}/scope.js +34 -1
- package/dist/{analysis → interpreter/analysis}/typeAnalyzer.js +542 -3
- package/dist/{core → interpreter/core}/codegen/class-handlers.js +1 -1
- package/dist/{core → interpreter/core}/codegen/control-flow-handlers.js +2 -2
- package/dist/{core → interpreter/core}/codegen/declaration-handlers.js +21 -9
- package/dist/{core → interpreter/core}/codegen/destructuring-handlers.js +3 -3
- package/dist/{core → interpreter/core}/codegen/expression-handlers.js +136 -82
- package/dist/{core → interpreter/core}/codegen/function-handlers.js +108 -61
- package/dist/{core → interpreter/core}/codegen/helpers.js +79 -11
- package/dist/interpreter/core/codegen/index.js +156 -0
- package/dist/{core → interpreter/core}/codegen/literal-handlers.js +9 -0
- package/dist/{core → interpreter/core}/codegen/statement-handlers.js +39 -1
- package/package.json +6 -4
- package/scripts/precompile-headers.ts +71 -19
- package/scripts/setup-emsdk.ts +114 -0
- package/src/prelude/any_value.cpp +851 -599
- package/src/prelude/any_value.hpp +28 -30
- package/src/prelude/jspp.hpp +3 -1
- package/src/prelude/library/boolean.cpp +30 -0
- package/src/prelude/library/boolean.hpp +14 -0
- package/src/prelude/library/error.cpp +2 -2
- package/src/prelude/library/global.cpp +2 -0
- package/src/prelude/library/math.cpp +46 -43
- package/src/prelude/library/math.hpp +2 -0
- package/src/prelude/library/object.cpp +1 -1
- package/src/prelude/types.hpp +10 -9
- package/src/prelude/utils/access.hpp +2 -36
- package/src/prelude/utils/assignment_operators.hpp +136 -20
- package/src/prelude/utils/log_any_value/log_any_value.hpp +1 -1
- package/src/prelude/utils/log_any_value/primitives.hpp +1 -1
- package/src/prelude/utils/operators.hpp +123 -88
- package/src/prelude/utils/operators_native.hpp +360 -0
- package/src/prelude/utils/well_known_symbols.hpp +13 -13
- package/src/prelude/values/array.cpp +3 -3
- package/src/prelude/values/boolean.cpp +64 -0
- package/src/prelude/values/iterator.cpp +262 -210
- package/src/prelude/values/number.cpp +137 -92
- package/src/prelude/values/object.cpp +163 -122
- package/src/prelude/values/prototypes/boolean.hpp +24 -0
- package/src/prelude/values/prototypes/number.hpp +8 -1
- package/dist/cli/file-utils.js +0 -20
- package/dist/cli-utils/args.js +0 -59
- package/dist/cli-utils/colors.js +0 -9
- package/dist/cli-utils/file-utils.js +0 -20
- package/dist/cli-utils/spinner.js +0 -55
- package/dist/cli.js +0 -153
- package/dist/core/codegen/index.js +0 -88
- package/src/prelude/utils/operators_primitive.hpp +0 -337
- /package/dist/{ast → interpreter/ast}/symbols.js +0 -0
- /package/dist/{ast → interpreter/ast}/types.js +0 -0
- /package/dist/{core → interpreter/core}/codegen/visitor.js +0 -0
- /package/dist/{core → interpreter/core}/constants.js +0 -0
- /package/dist/{core → interpreter/core}/error.js +0 -0
- /package/dist/{core → interpreter/core}/parser.js +0 -0
- /package/dist/{core → interpreter/core}/traverser.js +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import {
|
|
2
|
+
import { RESERVED_VAR_NAMES } from "../../analysis/scope.js";
|
|
3
3
|
import { CompilerError } from "../error.js";
|
|
4
4
|
import { CodeGenerator } from "./index.js";
|
|
5
5
|
export function visitVariableDeclarationList(node, context) {
|
|
@@ -18,8 +18,8 @@ export function visitVariableDeclaration(node, context) {
|
|
|
18
18
|
return this.generateDestructuring(varDecl.name, rhsCode, context);
|
|
19
19
|
}
|
|
20
20
|
const name = varDecl.name.getText();
|
|
21
|
-
if (
|
|
22
|
-
throw new CompilerError(`Cannot declare a variable named '${name}'
|
|
21
|
+
if (RESERVED_VAR_NAMES.has(name)) {
|
|
22
|
+
throw new CompilerError(`Cannot declare a variable named '${name}'.`, varDecl.name, "SyntaxError");
|
|
23
23
|
}
|
|
24
24
|
const scope = this.getScopeForNode(varDecl);
|
|
25
25
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
|
|
@@ -53,7 +53,7 @@ export function visitVariableDeclaration(node, context) {
|
|
|
53
53
|
(ts.isFunctionExpression(initExpr) && !initExpr.name)) {
|
|
54
54
|
const initContext = {
|
|
55
55
|
...context,
|
|
56
|
-
|
|
56
|
+
functionName: name, // Use the variable name as function name
|
|
57
57
|
};
|
|
58
58
|
const nativeName = this.generateUniqueName(`__${name}_native_`, context.localScopeSymbols, context.globalScopeSymbols);
|
|
59
59
|
const scopeNode = ts.isVariableDeclarationList(varDecl.parent)
|
|
@@ -92,16 +92,28 @@ export function visitVariableDeclaration(node, context) {
|
|
|
92
92
|
return nativeLambdaCode;
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
-
initializer =
|
|
95
|
+
initializer = initText;
|
|
96
96
|
}
|
|
97
97
|
const isLetOrConst = (varDecl.parent.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
|
|
98
98
|
const shouldDeref = context.derefBeforeAssignment &&
|
|
99
99
|
(!context.localScopeSymbols.has(name));
|
|
100
|
-
|
|
100
|
+
let assignmentTarget = shouldDeref
|
|
101
101
|
? this.getDerefCode(name, name, context, typeInfo)
|
|
102
102
|
: (typeInfo?.needsHeapAllocation && !shouldSkipDeref
|
|
103
103
|
? `*${name}`
|
|
104
104
|
: name);
|
|
105
|
+
const sym = context.localScopeSymbols.get(name) ||
|
|
106
|
+
context.globalScopeSymbols.get(name);
|
|
107
|
+
if (sym?.checks.skippedHoisting) {
|
|
108
|
+
assignmentTarget = typeInfo?.needsHeapAllocation && !shouldSkipDeref
|
|
109
|
+
? `auto ${name}`
|
|
110
|
+
: `jspp::AnyValue ${name}`;
|
|
111
|
+
if (initializer) {
|
|
112
|
+
initializer = typeInfo?.needsHeapAllocation && !shouldSkipDeref
|
|
113
|
+
? `std::make_shared<jspp::AnyValue>(${initializer})`
|
|
114
|
+
: initializer;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
105
117
|
if (nativeLambdaCode)
|
|
106
118
|
nativeLambdaCode += `;\n${this.indent()}`;
|
|
107
119
|
if (isLetOrConst) {
|
|
@@ -116,19 +128,19 @@ export function visitVariableDeclaration(node, context) {
|
|
|
116
128
|
return `${nativeLambdaCode}${assignmentTarget} = jspp::Constants::UNDEFINED`;
|
|
117
129
|
}
|
|
118
130
|
}
|
|
119
|
-
return `${nativeLambdaCode}${assignmentTarget}${initializer}`;
|
|
131
|
+
return `${nativeLambdaCode}${assignmentTarget} = ${initializer}`;
|
|
120
132
|
}
|
|
121
133
|
// For 'var', it's a bit more complex.
|
|
122
134
|
if (context.isAssignmentOnly) {
|
|
123
135
|
if (!initializer)
|
|
124
136
|
return "";
|
|
125
|
-
return `${nativeLambdaCode}${assignmentTarget}${initializer}`;
|
|
137
|
+
return `${nativeLambdaCode}${assignmentTarget} = ${initializer}`;
|
|
126
138
|
}
|
|
127
139
|
else {
|
|
128
140
|
// This case should not be hit with the new hoisting logic,
|
|
129
141
|
// but is kept for safety.
|
|
130
142
|
const initValue = initializer
|
|
131
|
-
? initializer
|
|
143
|
+
? initializer
|
|
132
144
|
: "jspp::Constants::UNDEFINED";
|
|
133
145
|
if (typeInfo?.needsHeapAllocation) {
|
|
134
146
|
return `auto ${name} = std::make_shared<jspp::AnyValue>(${initValue})`;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import {
|
|
2
|
+
import { RESERVED_VAR_NAMES } from "../../analysis/scope.js";
|
|
3
3
|
import { CompilerError } from "../error.js";
|
|
4
4
|
import { visitObjectPropertyName } from "./expression-handlers.js";
|
|
5
5
|
import { CodeGenerator } from "./index.js";
|
|
@@ -13,8 +13,8 @@ export function generateDestructuring(lhs, rhsCode, context) {
|
|
|
13
13
|
const genAssignment = (pattern, valueCode) => {
|
|
14
14
|
if (ts.isIdentifier(pattern)) {
|
|
15
15
|
const name = pattern.text;
|
|
16
|
-
if (
|
|
17
|
-
throw new CompilerError(`Cannot destructure to a variable named '${name}'
|
|
16
|
+
if (RESERVED_VAR_NAMES.has(name)) {
|
|
17
|
+
throw new CompilerError(`Cannot destructure to a variable named '${name}'.`, pattern, "SyntaxError");
|
|
18
18
|
}
|
|
19
19
|
const scope = this.getScopeForNode(pattern);
|
|
20
20
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
|
|
@@ -247,6 +247,17 @@ export function visitPrefixUnaryExpression(node, context) {
|
|
|
247
247
|
const operand = this.visit(prefixUnaryExpr.operand, context);
|
|
248
248
|
const operator = ts.tokenToString(prefixUnaryExpr.operator);
|
|
249
249
|
if (operator === "++" || operator === "--") {
|
|
250
|
+
const opFunc = operator === "++" ? "add" : "sub";
|
|
251
|
+
if (ts.isPropertyAccessExpression(prefixUnaryExpr.operand)) {
|
|
252
|
+
const obj = this.visit(prefixUnaryExpr.operand.expression, context);
|
|
253
|
+
const prop = visitObjectPropertyName.call(this, prefixUnaryExpr.operand.name, context);
|
|
254
|
+
return `${obj}.set_own_property(${prop}, jspp::${opFunc}(${obj}.get_own_property(${prop}), 1.0))`;
|
|
255
|
+
}
|
|
256
|
+
else if (ts.isElementAccessExpression(prefixUnaryExpr.operand)) {
|
|
257
|
+
const obj = this.visit(prefixUnaryExpr.operand.expression, context);
|
|
258
|
+
const prop = visitObjectPropertyName.call(this, prefixUnaryExpr.operand.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
259
|
+
return `${obj}.set_own_property(${prop}, jspp::${opFunc}(${obj}.get_own_property(${prop}), 1.0))`;
|
|
260
|
+
}
|
|
250
261
|
let target = operand;
|
|
251
262
|
if (ts.isIdentifier(prefixUnaryExpr.operand)) {
|
|
252
263
|
const scope = this.getScopeForNode(prefixUnaryExpr.operand);
|
|
@@ -289,6 +300,20 @@ export function visitPostfixUnaryExpression(node, context) {
|
|
|
289
300
|
const postfixUnaryExpr = node;
|
|
290
301
|
const operand = this.visit(postfixUnaryExpr.operand, context);
|
|
291
302
|
const operator = ts.tokenToString(postfixUnaryExpr.operator);
|
|
303
|
+
if (ts.isPropertyAccessExpression(postfixUnaryExpr.operand)) {
|
|
304
|
+
const obj = this.visit(postfixUnaryExpr.operand.expression, context);
|
|
305
|
+
const prop = visitObjectPropertyName.call(this, postfixUnaryExpr.operand.name, context);
|
|
306
|
+
const opFunc = operator === "++" ? "add" : "sub";
|
|
307
|
+
// Postfix needs IILE to return old value
|
|
308
|
+
return `([&]() { auto oldVal = ${obj}.get_own_property(${prop}); ${obj}.set_own_property(${prop}, jspp::${opFunc}(oldVal, 1.0)); return oldVal; })()`;
|
|
309
|
+
}
|
|
310
|
+
else if (ts.isElementAccessExpression(postfixUnaryExpr.operand)) {
|
|
311
|
+
const obj = this.visit(postfixUnaryExpr.operand.expression, context);
|
|
312
|
+
const prop = visitObjectPropertyName.call(this, postfixUnaryExpr.operand.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
313
|
+
const opFunc = operator === "++" ? "add" : "sub";
|
|
314
|
+
// Postfix needs IILE to return old value
|
|
315
|
+
return `([&]() { auto oldVal = ${obj}.get_own_property(${prop}); ${obj}.set_own_property(${prop}, jspp::${opFunc}(oldVal, 1.0)); return oldVal; })()`;
|
|
316
|
+
}
|
|
292
317
|
let target = operand;
|
|
293
318
|
if (ts.isIdentifier(postfixUnaryExpr.operand)) {
|
|
294
319
|
const scope = this.getScopeForNode(postfixUnaryExpr.operand);
|
|
@@ -402,42 +427,36 @@ export function visitBinaryExpression(node, context) {
|
|
|
402
427
|
if (assignmentOperators.includes(opToken.kind)) {
|
|
403
428
|
if (opToken.kind ===
|
|
404
429
|
ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken) {
|
|
405
|
-
const leftText = this.visit(binExpr.left, visitContext);
|
|
406
430
|
const rightText = this.visit(binExpr.right, visitContext);
|
|
407
|
-
let target = leftText;
|
|
408
431
|
if (ts.isIdentifier(binExpr.left)) {
|
|
432
|
+
const leftText = this.visit(binExpr.left, visitContext);
|
|
409
433
|
const scope = this.getScopeForNode(binExpr.left);
|
|
410
434
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.text, scope);
|
|
411
|
-
target = typeInfo?.needsHeapAllocation
|
|
435
|
+
const target = typeInfo?.needsHeapAllocation
|
|
412
436
|
? `*${leftText}`
|
|
413
437
|
: leftText;
|
|
414
|
-
return
|
|
438
|
+
return `jspp::unsigned_right_shift_assign(${target}, ${rightText})`;
|
|
415
439
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
if (ts.
|
|
422
|
-
const
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
? `*${leftText}`
|
|
426
|
-
: leftText;
|
|
427
|
-
return `${target} = jspp::pow(${target}, ${rightText})`;
|
|
440
|
+
else if (ts.isPropertyAccessExpression(binExpr.left)) {
|
|
441
|
+
const obj = this.visit(binExpr.left.expression, context);
|
|
442
|
+
const prop = visitObjectPropertyName.call(this, binExpr.left.name, context);
|
|
443
|
+
return `${obj}.set_own_property(${prop}, jspp::unsigned_right_shift(${obj}.get_own_property(${prop}), ${rightText}))`;
|
|
444
|
+
}
|
|
445
|
+
else if (ts.isElementAccessExpression(binExpr.left)) {
|
|
446
|
+
const obj = this.visit(binExpr.left.expression, context);
|
|
447
|
+
const prop = visitObjectPropertyName.call(this, binExpr.left.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
448
|
+
return `${obj}.set_own_property(${prop}, jspp::unsigned_right_shift(${obj}.get_own_property(${prop}), ${rightText}))`;
|
|
428
449
|
}
|
|
429
|
-
// For complex LHS, we need a different approach, but this is a start.
|
|
430
450
|
}
|
|
431
451
|
if (opToken.kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken ||
|
|
432
452
|
opToken.kind === ts.SyntaxKind.BarBarEqualsToken ||
|
|
433
453
|
opToken.kind === ts.SyntaxKind.QuestionQuestionEqualsToken) {
|
|
434
|
-
const leftText = this.visit(binExpr.left, visitContext);
|
|
435
454
|
const rightText = this.visit(binExpr.right, visitContext);
|
|
436
|
-
let target = leftText;
|
|
437
455
|
if (ts.isIdentifier(binExpr.left)) {
|
|
456
|
+
const leftText = this.visit(binExpr.left, visitContext);
|
|
438
457
|
const scope = this.getScopeForNode(binExpr.left);
|
|
439
458
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.text, scope);
|
|
440
|
-
target = typeInfo?.needsHeapAllocation
|
|
459
|
+
const target = typeInfo?.needsHeapAllocation
|
|
441
460
|
? `*${leftText}`
|
|
442
461
|
: leftText;
|
|
443
462
|
if (opToken.kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken) {
|
|
@@ -450,6 +469,29 @@ export function visitBinaryExpression(node, context) {
|
|
|
450
469
|
return `jspp::nullish_coalesce_assign(${target}, ${rightText})`;
|
|
451
470
|
}
|
|
452
471
|
}
|
|
472
|
+
else if (ts.isPropertyAccessExpression(binExpr.left)) {
|
|
473
|
+
const obj = this.visit(binExpr.left.expression, context);
|
|
474
|
+
const prop = visitObjectPropertyName.call(this, binExpr.left.name, context);
|
|
475
|
+
const func = opToken.kind ===
|
|
476
|
+
ts.SyntaxKind.AmpersandAmpersandEqualsToken
|
|
477
|
+
? "logical_and"
|
|
478
|
+
: (opToken.kind === ts.SyntaxKind.BarBarEqualsToken
|
|
479
|
+
? "logical_or"
|
|
480
|
+
: "nullish_coalesce");
|
|
481
|
+
// Logical assignments return newVal, set_own_property returns newVal.
|
|
482
|
+
return `${obj}.set_own_property(${prop}, jspp::${func}(${obj}.get_own_property(${prop}), ${rightText}))`;
|
|
483
|
+
}
|
|
484
|
+
else if (ts.isElementAccessExpression(binExpr.left)) {
|
|
485
|
+
const obj = this.visit(binExpr.left.expression, context);
|
|
486
|
+
const prop = visitObjectPropertyName.call(this, binExpr.left.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
487
|
+
const func = opToken.kind ===
|
|
488
|
+
ts.SyntaxKind.AmpersandAmpersandEqualsToken
|
|
489
|
+
? "logical_and"
|
|
490
|
+
: (opToken.kind === ts.SyntaxKind.BarBarEqualsToken
|
|
491
|
+
? "logical_or"
|
|
492
|
+
: "nullish_coalesce");
|
|
493
|
+
return `${obj}.set_own_property(${prop}, jspp::${func}(${obj}.get_own_property(${prop}), ${rightText}))`;
|
|
494
|
+
}
|
|
453
495
|
}
|
|
454
496
|
const leftText = this.visit(binExpr.left, visitContext);
|
|
455
497
|
let rightText = ts.isNumericLiteral(binExpr.right)
|
|
@@ -460,6 +502,35 @@ export function visitBinaryExpression(node, context) {
|
|
|
460
502
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.right.getText(), scope);
|
|
461
503
|
rightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), visitContext, typeInfo);
|
|
462
504
|
}
|
|
505
|
+
if (ts.isPropertyAccessExpression(binExpr.left)) {
|
|
506
|
+
const obj = this.visit(binExpr.left.expression, context);
|
|
507
|
+
const prop = visitObjectPropertyName.call(this, binExpr.left.name, context);
|
|
508
|
+
const opBase = op.slice(0, -1); // "+=", "-=" -> "+", "-"
|
|
509
|
+
const opFunc = opBase === "+" ? "add" : (opBase === "-" ? "sub" : (opBase === "*" ? "mul" : (opBase === "/" ? "div" : (opBase === "%" ? "mod" : (opBase === "&" ? "bitwise_and" : (opBase === "|" ? "bitwise_or" : (opBase === "^" ? "bitwise_xor" : (opBase === "<<" ? "left_shift" : (opBase === ">>"
|
|
510
|
+
? "right_shift"
|
|
511
|
+
: "")))))))));
|
|
512
|
+
if (opFunc) {
|
|
513
|
+
return `${obj}.set_own_property(${prop}, jspp::${opFunc}(${obj}.get_own_property(${prop}), ${rightText}))`;
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
// Fallback to IILE if we don't have an opFunc mapping
|
|
517
|
+
return `([&]() { auto val = ${obj}.get_own_property(${prop}); val ${op} ${rightText}; ${obj}.set_own_property(${prop}, val); return val; })()`;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
else if (ts.isElementAccessExpression(binExpr.left)) {
|
|
521
|
+
const obj = this.visit(binExpr.left.expression, context);
|
|
522
|
+
const prop = visitObjectPropertyName.call(this, binExpr.left.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
523
|
+
const opBase = op.slice(0, -1);
|
|
524
|
+
const opFunc = opBase === "+" ? "add" : (opBase === "-" ? "sub" : (opBase === "*" ? "mul" : (opBase === "/" ? "div" : (opBase === "%" ? "mod" : (opBase === "&" ? "bitwise_and" : (opBase === "|" ? "bitwise_or" : (opBase === "^" ? "bitwise_xor" : (opBase === "<<" ? "left_shift" : (opBase === ">>"
|
|
525
|
+
? "right_shift"
|
|
526
|
+
: "")))))))));
|
|
527
|
+
if (opFunc) {
|
|
528
|
+
return `${obj}.set_own_property(${prop}, jspp::${opFunc}(${obj}.get_own_property(${prop}), ${rightText}))`;
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
return `([&]() { auto val = ${obj}.get_own_property(${prop}); val ${op} ${rightText}; ${obj}.set_own_property(${prop}, val); return val; })()`;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
463
534
|
let target = leftText;
|
|
464
535
|
if (ts.isIdentifier(binExpr.left)) {
|
|
465
536
|
const scope = this.getScopeForNode(binExpr.left);
|
|
@@ -607,7 +678,8 @@ export function visitBinaryExpression(node, context) {
|
|
|
607
678
|
finalLeft = this.getDerefCode(leftText, this.getJsVarName(binExpr.left), visitContext, typeInfo);
|
|
608
679
|
}
|
|
609
680
|
// Number optimizations
|
|
610
|
-
|
|
681
|
+
const nodeType = this.typeAnalyzer.inferNodeReturnType(binExpr.left);
|
|
682
|
+
if (nodeType === "number") {
|
|
611
683
|
finalLeft = `${finalLeft}.as_double()`;
|
|
612
684
|
}
|
|
613
685
|
}
|
|
@@ -623,7 +695,8 @@ export function visitBinaryExpression(node, context) {
|
|
|
623
695
|
finalRight = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), visitContext, typeInfo);
|
|
624
696
|
}
|
|
625
697
|
// Number optimizations
|
|
626
|
-
|
|
698
|
+
const nodeType = this.typeAnalyzer.inferNodeReturnType(binExpr.right);
|
|
699
|
+
if (nodeType === "number") {
|
|
627
700
|
finalRight = `${finalRight}.as_double()`;
|
|
628
701
|
}
|
|
629
702
|
}
|
|
@@ -642,101 +715,82 @@ export function visitBinaryExpression(node, context) {
|
|
|
642
715
|
if (opToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
|
|
643
716
|
return `jspp::nullish_coalesce(${finalLeft}, ${finalRight})`;
|
|
644
717
|
}
|
|
645
|
-
const isLiteral = (n) => ts.isNumericLiteral(n);
|
|
646
|
-
const supportsNativeBoolean = ts.isIfStatement(node.parent) ||
|
|
647
|
-
ts.isConditionalExpression(node.parent);
|
|
648
718
|
// Native values for lhs and rhs
|
|
649
|
-
const literalLeft =
|
|
719
|
+
const literalLeft = ts.isNumericLiteral(binExpr.left)
|
|
650
720
|
? binExpr.left.getText()
|
|
651
721
|
: finalLeft;
|
|
652
|
-
const literalRight =
|
|
722
|
+
const literalRight = ts.isNumericLiteral(binExpr.right)
|
|
653
723
|
? binExpr.right.getText()
|
|
654
724
|
: finalRight;
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
if (
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
funcName = "jspp::less_than_primitive";
|
|
673
|
-
}
|
|
674
|
-
if (opToken.kind === ts.SyntaxKind.LessThanEqualsToken) {
|
|
675
|
-
funcName = "jspp::less_than_or_equal_primitive";
|
|
676
|
-
}
|
|
677
|
-
if (opToken.kind === ts.SyntaxKind.GreaterThanToken) {
|
|
678
|
-
funcName = "jspp::greater_than_primitive";
|
|
679
|
-
}
|
|
680
|
-
if (opToken.kind === ts.SyntaxKind.GreaterThanEqualsToken) {
|
|
681
|
-
funcName = "jspp::greater_than_or_equal_primitive";
|
|
725
|
+
let supportsNativeValue = false;
|
|
726
|
+
const exprReturnType = this.typeAnalyzer.inferNodeReturnType(node);
|
|
727
|
+
if (exprReturnType === "boolean" &&
|
|
728
|
+
(ts.isIfStatement(node.parent) ||
|
|
729
|
+
ts.isConditionalExpression(node.parent))) {
|
|
730
|
+
supportsNativeValue = true;
|
|
731
|
+
}
|
|
732
|
+
else if (exprReturnType === "number" &&
|
|
733
|
+
context.isInsideNativeLambda &&
|
|
734
|
+
context.isInsideFunction) {
|
|
735
|
+
const funcDecl = this
|
|
736
|
+
.findEnclosingFunctionDeclarationFromReturnStatement(node);
|
|
737
|
+
if (funcDecl) {
|
|
738
|
+
const funcReturnType = this.typeAnalyzer.inferFunctionReturnType(funcDecl);
|
|
739
|
+
if (funcReturnType === "number") {
|
|
740
|
+
supportsNativeValue = true;
|
|
741
|
+
}
|
|
682
742
|
}
|
|
683
|
-
// For C++ primitive literals, standard operators are fine if they map directly,
|
|
684
|
-
// but we are safe using our functions (which handle doubles correctly).
|
|
685
|
-
// Actually, for pure numeric literals like "1 < 2", we can leave it as is if we want optimization,
|
|
686
|
-
// but consistency is safer.
|
|
687
|
-
// Let's stick to valid C++ syntax for literals if possible to avoid overhead?
|
|
688
|
-
// jspp::less_than(1, 2) works.
|
|
689
|
-
return `${funcName}(${literalLeft}, ${literalRight})`;
|
|
690
743
|
}
|
|
744
|
+
const method = supportsNativeValue ? "_native" : "";
|
|
691
745
|
// Return boxed value
|
|
692
746
|
if (opToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken) {
|
|
693
|
-
return `jspp::is_strictly_equal_to(${literalLeft}, ${literalRight})`;
|
|
747
|
+
return `jspp::is_strictly_equal_to${method}(${literalLeft}, ${literalRight})`;
|
|
694
748
|
}
|
|
695
749
|
if (opToken.kind === ts.SyntaxKind.EqualsEqualsToken) {
|
|
696
|
-
return `jspp::is_equal_to(${literalLeft}, ${literalRight})`;
|
|
750
|
+
return `jspp::is_equal_to${method}(${literalLeft}, ${literalRight})`;
|
|
697
751
|
}
|
|
698
752
|
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
|
|
699
|
-
return `jspp::not_strictly_equal_to(${literalLeft}, ${literalRight})`;
|
|
753
|
+
return `jspp::not_strictly_equal_to${method}(${literalLeft}, ${literalRight})`;
|
|
700
754
|
}
|
|
701
755
|
if (opToken.kind === ts.SyntaxKind.ExclamationEqualsToken) {
|
|
702
|
-
return `jspp::not_equal_to(${literalLeft}, ${literalRight})`;
|
|
756
|
+
return `jspp::not_equal_to${method}(${literalLeft}, ${literalRight})`;
|
|
703
757
|
}
|
|
704
758
|
if (opToken.kind === ts.SyntaxKind.AsteriskAsteriskToken) {
|
|
705
|
-
return `jspp::pow(${literalLeft}, ${literalRight})`;
|
|
759
|
+
return `jspp::pow${method}(${literalLeft}, ${literalRight})`;
|
|
706
760
|
}
|
|
707
761
|
if (opToken.kind === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken) {
|
|
708
|
-
return `jspp::unsigned_right_shift(${literalLeft}, ${literalRight})`;
|
|
762
|
+
return `jspp::unsigned_right_shift${method}(${literalLeft}, ${literalRight})`;
|
|
709
763
|
}
|
|
710
764
|
// For other arithmetic and bitwise operations, use native operations if possible
|
|
711
765
|
switch (op) {
|
|
712
766
|
case "+":
|
|
713
|
-
return `jspp::add(${literalLeft}, ${literalRight})`;
|
|
767
|
+
return `jspp::add${method}(${literalLeft}, ${literalRight})`;
|
|
714
768
|
case "-":
|
|
715
|
-
return `jspp::sub(${literalLeft}, ${literalRight})`;
|
|
769
|
+
return `jspp::sub${method}(${literalLeft}, ${literalRight})`;
|
|
716
770
|
case "*":
|
|
717
|
-
return `jspp::mul(${literalLeft}, ${literalRight})`;
|
|
771
|
+
return `jspp::mul${method}(${literalLeft}, ${literalRight})`;
|
|
718
772
|
case "/":
|
|
719
|
-
return `jspp::div(${literalLeft}, ${literalRight})`;
|
|
773
|
+
return `jspp::div${method}(${literalLeft}, ${literalRight})`;
|
|
720
774
|
case "%":
|
|
721
|
-
return `jspp::mod(${literalLeft}, ${literalRight})`;
|
|
775
|
+
return `jspp::mod${method}(${literalLeft}, ${literalRight})`;
|
|
722
776
|
case "^":
|
|
723
|
-
return `jspp::bitwise_xor(${literalLeft}, ${literalRight})`;
|
|
777
|
+
return `jspp::bitwise_xor${method}(${literalLeft}, ${literalRight})`;
|
|
724
778
|
case "&":
|
|
725
|
-
return `jspp::bitwise_and(${literalLeft}, ${literalRight})`;
|
|
779
|
+
return `jspp::bitwise_and${method}(${literalLeft}, ${literalRight})`;
|
|
726
780
|
case "|":
|
|
727
|
-
return `jspp::bitwise_or(${literalLeft}, ${literalRight})`;
|
|
781
|
+
return `jspp::bitwise_or${method}(${literalLeft}, ${literalRight})`;
|
|
728
782
|
case "<<":
|
|
729
|
-
return `jspp::left_shift(${literalLeft}, ${literalRight})`;
|
|
783
|
+
return `jspp::left_shift${method}(${literalLeft}, ${literalRight})`;
|
|
730
784
|
case ">>":
|
|
731
|
-
return `jspp::right_shift(${literalLeft}, ${literalRight})`;
|
|
785
|
+
return `jspp::right_shift${method}(${literalLeft}, ${literalRight})`;
|
|
732
786
|
case "<":
|
|
733
|
-
return `jspp::less_than(${literalLeft}, ${literalRight})`;
|
|
787
|
+
return `jspp::less_than${method}(${literalLeft}, ${literalRight})`;
|
|
734
788
|
case ">":
|
|
735
|
-
return `jspp::greater_than(${literalLeft}, ${literalRight})`;
|
|
789
|
+
return `jspp::greater_than${method}(${literalLeft}, ${literalRight})`;
|
|
736
790
|
case "<=":
|
|
737
|
-
return `jspp::less_than_or_equal(${literalLeft}, ${literalRight})`;
|
|
791
|
+
return `jspp::less_than_or_equal${method}(${literalLeft}, ${literalRight})`;
|
|
738
792
|
case ">=":
|
|
739
|
-
return `jspp::greater_than_or_equal(${literalLeft}, ${literalRight})`;
|
|
793
|
+
return `jspp::greater_than_or_equal${method}(${literalLeft}, ${literalRight})`;
|
|
740
794
|
}
|
|
741
795
|
return `/* Unhandled Operator: ${finalLeft} ${op} ${finalRight} */`; // Default fallback
|
|
742
796
|
}
|
|
@@ -1283,7 +1337,7 @@ export function visitTypeOfExpression(node, context) {
|
|
|
1283
1337
|
derefExpr = this.getDerefCode(exprText, this.getJsVarName(typeOfExpr.expression), context, typeInfo);
|
|
1284
1338
|
}
|
|
1285
1339
|
}
|
|
1286
|
-
return `jspp::
|
|
1340
|
+
return `jspp::type_of(${derefExpr})`;
|
|
1287
1341
|
}
|
|
1288
1342
|
export function visitAwaitExpression(node, context) {
|
|
1289
1343
|
const awaitExpr = node;
|