@ugo-studio/jspp 0.3.3 → 0.3.4
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 +2 -6
- package/dist/cli/args.js +5 -0
- package/dist/cli/compiler.js +1 -1
- package/dist/cli/index.js +4 -2
- package/dist/interpreter/analysis/typeAnalyzer.js +62 -25
- package/dist/interpreter/core/codegen/control-flow-handlers.js +34 -10
- package/dist/interpreter/core/codegen/function-handlers.js +16 -11
- package/dist/interpreter/core/codegen/helpers.js +5 -1
- package/dist/interpreter/core/codegen/index.js +1 -1
- package/dist/interpreter/core/codegen/statement-handlers.js +15 -11
- package/dist/interpreter/core/traverser.js +1 -2
- package/package.json +2 -2
- package/src/prelude/library/array.cpp +2 -2
- package/src/prelude/library/math.cpp +8 -8
- package/src/prelude/utils/operators.hpp +3 -3
- package/src/prelude/utils/operators_native.hpp +64 -64
- package/src/prelude/values/array.cpp +17 -17
- package/src/prelude/values/number.cpp +4 -4
- package/src/prelude/values/string.cpp +13 -13
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ Using these keywords as variable names will result in a `SyntaxError`.
|
|
|
61
61
|
To use JSPP as a command-line tool, install it globally via npm:
|
|
62
62
|
|
|
63
63
|
```sh
|
|
64
|
-
npm i @ugo-studio/jspp -g
|
|
64
|
+
npm i @ugo-studio/jspp@latest -g
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
## For Developers
|
|
@@ -86,7 +86,7 @@ To contribute to JSPP or run its test suite, follow these steps:
|
|
|
86
86
|
```sh
|
|
87
87
|
bun install
|
|
88
88
|
```
|
|
89
|
-
*Note: The `postinstall` script will automatically check for your C++ compiler and
|
|
89
|
+
*Note: The `postinstall` script will automatically check for your C++ compiler and setup emsdk for wasm support.*
|
|
90
90
|
|
|
91
91
|
## Usage
|
|
92
92
|
|
|
@@ -106,10 +106,6 @@ jspp my-code/test.ts
|
|
|
106
106
|
|
|
107
107
|
The transpiled C++ file and executable will be generated in the same directory as the input file and cleaned up after execution (unless `--keep-cpp` is used).
|
|
108
108
|
|
|
109
|
-
### Timing and Reports
|
|
110
|
-
|
|
111
|
-
In debug mode (default), JSPP provides a compilation time report using GCC's `-ftime-report`. This helps track the performance of the transpilation and compilation phases.
|
|
112
|
-
|
|
113
109
|
## Roadmap
|
|
114
110
|
|
|
115
111
|
This project is ambitious, and there is a long and exciting road ahead. Here is a high-level overview of the planned features and the project's current standing.
|
package/dist/cli/args.js
CHANGED
|
@@ -5,6 +5,7 @@ export function parseArgs(rawArgs) {
|
|
|
5
5
|
let jsFilePathArg = null;
|
|
6
6
|
let isRelease = false;
|
|
7
7
|
let keepCpp = false;
|
|
8
|
+
let shouldRunOutput = false;
|
|
8
9
|
let outputExePath = null;
|
|
9
10
|
let scriptArgs = [];
|
|
10
11
|
let target = "native";
|
|
@@ -22,6 +23,9 @@ export function parseArgs(rawArgs) {
|
|
|
22
23
|
else if (arg === "--keep-cpp") {
|
|
23
24
|
keepCpp = true;
|
|
24
25
|
}
|
|
26
|
+
else if (arg === "--run-output") {
|
|
27
|
+
shouldRunOutput = true;
|
|
28
|
+
}
|
|
25
29
|
else if (arg === "-t" || arg === "--target") {
|
|
26
30
|
if (i + 1 < rawArgs.length) {
|
|
27
31
|
const targetValue = rawArgs[i + 1]?.toLowerCase();
|
|
@@ -72,6 +76,7 @@ export function parseArgs(rawArgs) {
|
|
|
72
76
|
jsFilePath: path.resolve(process.cwd(), jsFilePathArg),
|
|
73
77
|
isRelease,
|
|
74
78
|
keepCpp,
|
|
79
|
+
shouldRunOutput,
|
|
75
80
|
outputExePath: outputExePath
|
|
76
81
|
? path.resolve(process.cwd(), outputExePath)
|
|
77
82
|
: null,
|
package/dist/cli/compiler.js
CHANGED
|
@@ -49,5 +49,5 @@ export async function compileCpp(cppFilePath, exeFilePath, pchDir, preludePath,
|
|
|
49
49
|
}
|
|
50
50
|
const compileEndTime = performance.now();
|
|
51
51
|
const compileTime = msToHumanReadable(compileEndTime - compileStartTime);
|
|
52
|
-
spinner.succeed(`Compiled to ${COLORS.green}${COLORS.bold}${
|
|
52
|
+
spinner.succeed(`Compiled to ${COLORS.green}${COLORS.bold}${exeFilePath}${COLORS.reset} ${COLORS.dim}[${compileTime}]${COLORS.reset}`);
|
|
53
53
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -17,7 +17,7 @@ const emsdkEnv = {
|
|
|
17
17
|
PATH: `${path.join(pkgDir, ".emsdk")}${path.delimiter}${path.join(pkgDir, ".emsdk", "upstream", "emscripten")}${path.delimiter}${process.env.PATH}`,
|
|
18
18
|
};
|
|
19
19
|
async function main() {
|
|
20
|
-
const { jsFilePath, isRelease, keepCpp, outputExePath, scriptArgs, target, } = parseArgs(process.argv.slice(2));
|
|
20
|
+
const { jsFilePath, isRelease, keepCpp, shouldRunOutput, outputExePath, scriptArgs, target, } = parseArgs(process.argv.slice(2));
|
|
21
21
|
const isWasm = target === "wasm";
|
|
22
22
|
const ext = path.extname(jsFilePath);
|
|
23
23
|
const jsFileName = path.basename(jsFilePath, ext);
|
|
@@ -80,7 +80,9 @@ async function main() {
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
// 4. Execution Phase
|
|
83
|
-
|
|
83
|
+
if (shouldRunOutput) {
|
|
84
|
+
await runOutput(exeFilePath, scriptArgs, isWasm);
|
|
85
|
+
}
|
|
84
86
|
}
|
|
85
87
|
catch (error) {
|
|
86
88
|
if (error instanceof CompilerError) {
|
|
@@ -568,7 +568,7 @@ export class TypeAnalyzer {
|
|
|
568
568
|
};
|
|
569
569
|
const visitor = {
|
|
570
570
|
// Enter new scope for any block-like structure
|
|
571
|
-
Block: {
|
|
571
|
+
[ts.SyntaxKind.Block]: {
|
|
572
572
|
enter: (node, parent) => {
|
|
573
573
|
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
574
574
|
null;
|
|
@@ -591,7 +591,7 @@ export class TypeAnalyzer {
|
|
|
591
591
|
},
|
|
592
592
|
exit: () => this.scopeManager.exitScope(),
|
|
593
593
|
},
|
|
594
|
-
ForStatement: {
|
|
594
|
+
[ts.SyntaxKind.ForStatement]: {
|
|
595
595
|
enter: (node) => {
|
|
596
596
|
this.loopDepth++;
|
|
597
597
|
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
@@ -604,7 +604,7 @@ export class TypeAnalyzer {
|
|
|
604
604
|
this.scopeManager.exitScope();
|
|
605
605
|
},
|
|
606
606
|
},
|
|
607
|
-
ForOfStatement: {
|
|
607
|
+
[ts.SyntaxKind.ForOfStatement]: {
|
|
608
608
|
enter: (node) => {
|
|
609
609
|
this.loopDepth++;
|
|
610
610
|
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
@@ -617,7 +617,7 @@ export class TypeAnalyzer {
|
|
|
617
617
|
this.scopeManager.exitScope();
|
|
618
618
|
},
|
|
619
619
|
},
|
|
620
|
-
ForInStatement: {
|
|
620
|
+
[ts.SyntaxKind.ForInStatement]: {
|
|
621
621
|
enter: (node) => {
|
|
622
622
|
this.loopDepth++;
|
|
623
623
|
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
@@ -649,7 +649,7 @@ export class TypeAnalyzer {
|
|
|
649
649
|
this.scopeManager.exitScope();
|
|
650
650
|
},
|
|
651
651
|
},
|
|
652
|
-
WhileStatement: {
|
|
652
|
+
[ts.SyntaxKind.WhileStatement]: {
|
|
653
653
|
enter: (node) => {
|
|
654
654
|
this.loopDepth++;
|
|
655
655
|
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
@@ -662,7 +662,7 @@ export class TypeAnalyzer {
|
|
|
662
662
|
this.scopeManager.exitScope();
|
|
663
663
|
},
|
|
664
664
|
},
|
|
665
|
-
DoStatement: {
|
|
665
|
+
[ts.SyntaxKind.DoStatement]: {
|
|
666
666
|
enter: (node) => {
|
|
667
667
|
this.loopDepth++;
|
|
668
668
|
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
@@ -675,7 +675,7 @@ export class TypeAnalyzer {
|
|
|
675
675
|
this.scopeManager.exitScope();
|
|
676
676
|
},
|
|
677
677
|
},
|
|
678
|
-
SwitchStatement: {
|
|
678
|
+
[ts.SyntaxKind.SwitchStatement]: {
|
|
679
679
|
enter: (node) => {
|
|
680
680
|
this.switchDepth++;
|
|
681
681
|
const currentFuncNode = this.functionStack[this.functionStack.length - 1] ??
|
|
@@ -688,7 +688,7 @@ export class TypeAnalyzer {
|
|
|
688
688
|
this.scopeManager.exitScope();
|
|
689
689
|
},
|
|
690
690
|
},
|
|
691
|
-
LabeledStatement: {
|
|
691
|
+
[ts.SyntaxKind.LabeledStatement]: {
|
|
692
692
|
enter: (node) => {
|
|
693
693
|
this.nodeToScope.set(node, this.scopeManager.currentScope);
|
|
694
694
|
this.labelStack.push(node.label.text);
|
|
@@ -697,7 +697,7 @@ export class TypeAnalyzer {
|
|
|
697
697
|
this.labelStack.pop();
|
|
698
698
|
},
|
|
699
699
|
},
|
|
700
|
-
BreakStatement: {
|
|
700
|
+
[ts.SyntaxKind.BreakStatement]: {
|
|
701
701
|
enter: (node) => {
|
|
702
702
|
const breakNode = node;
|
|
703
703
|
if (breakNode.label) {
|
|
@@ -712,7 +712,7 @@ export class TypeAnalyzer {
|
|
|
712
712
|
}
|
|
713
713
|
},
|
|
714
714
|
},
|
|
715
|
-
ContinueStatement: {
|
|
715
|
+
[ts.SyntaxKind.ContinueStatement]: {
|
|
716
716
|
enter: (node) => {
|
|
717
717
|
const continueNode = node;
|
|
718
718
|
if (continueNode.label) {
|
|
@@ -729,7 +729,7 @@ export class TypeAnalyzer {
|
|
|
729
729
|
}
|
|
730
730
|
},
|
|
731
731
|
},
|
|
732
|
-
ArrowFunction: {
|
|
732
|
+
[ts.SyntaxKind.ArrowFunction]: {
|
|
733
733
|
enter: (node) => {
|
|
734
734
|
if (ts.isArrowFunction(node)) {
|
|
735
735
|
const funcType = {
|
|
@@ -760,7 +760,7 @@ export class TypeAnalyzer {
|
|
|
760
760
|
this.scopeManager.exitScope();
|
|
761
761
|
},
|
|
762
762
|
},
|
|
763
|
-
FunctionExpression: {
|
|
763
|
+
[ts.SyntaxKind.FunctionExpression]: {
|
|
764
764
|
enter: (node) => {
|
|
765
765
|
if (ts.isFunctionExpression(node)) {
|
|
766
766
|
const funcType = {
|
|
@@ -795,7 +795,7 @@ export class TypeAnalyzer {
|
|
|
795
795
|
this.scopeManager.exitScope();
|
|
796
796
|
},
|
|
797
797
|
},
|
|
798
|
-
FunctionDeclaration: {
|
|
798
|
+
[ts.SyntaxKind.FunctionDeclaration]: {
|
|
799
799
|
enter: (node) => {
|
|
800
800
|
if (ts.isFunctionDeclaration(node)) {
|
|
801
801
|
// Define the function in the current scope.
|
|
@@ -831,7 +831,44 @@ export class TypeAnalyzer {
|
|
|
831
831
|
this.scopeManager.exitScope();
|
|
832
832
|
},
|
|
833
833
|
},
|
|
834
|
-
|
|
834
|
+
[ts.SyntaxKind.GetAccessor]: {
|
|
835
|
+
enter: (node) => {
|
|
836
|
+
if (ts.isGetAccessorDeclaration(node)) {
|
|
837
|
+
this.scopeManager.enterScope(node);
|
|
838
|
+
this.nodeToScope.set(node, this.scopeManager.currentScope);
|
|
839
|
+
this.functionStack.push(node);
|
|
840
|
+
}
|
|
841
|
+
},
|
|
842
|
+
exit: (node) => {
|
|
843
|
+
if (ts.isGetAccessorDeclaration(node)) {
|
|
844
|
+
this.functionStack.pop();
|
|
845
|
+
}
|
|
846
|
+
this.scopeManager.exitScope();
|
|
847
|
+
},
|
|
848
|
+
},
|
|
849
|
+
[ts.SyntaxKind.SetAccessor]: {
|
|
850
|
+
enter: (node) => {
|
|
851
|
+
if (ts.isSetAccessorDeclaration(node)) {
|
|
852
|
+
this.scopeManager.enterScope(node);
|
|
853
|
+
this.nodeToScope.set(node, this.scopeManager.currentScope);
|
|
854
|
+
// Define parameters in the new scope
|
|
855
|
+
node.parameters.forEach((p) => {
|
|
856
|
+
if (p.getText() == "this") { // Catch invalid parameters
|
|
857
|
+
throw new CompilerError("Cannot use 'this' as a parameter name.", p, "SyntaxError");
|
|
858
|
+
}
|
|
859
|
+
this.defineParameter(p.name, p);
|
|
860
|
+
});
|
|
861
|
+
this.functionStack.push(node);
|
|
862
|
+
}
|
|
863
|
+
},
|
|
864
|
+
exit: (node) => {
|
|
865
|
+
if (ts.isSetAccessorDeclaration(node)) {
|
|
866
|
+
this.functionStack.pop();
|
|
867
|
+
}
|
|
868
|
+
this.scopeManager.exitScope();
|
|
869
|
+
},
|
|
870
|
+
},
|
|
871
|
+
[ts.SyntaxKind.ClassDeclaration]: {
|
|
835
872
|
enter: (node) => {
|
|
836
873
|
const classNode = node;
|
|
837
874
|
if (classNode.name) {
|
|
@@ -853,7 +890,7 @@ export class TypeAnalyzer {
|
|
|
853
890
|
this.scopeManager.exitScope();
|
|
854
891
|
},
|
|
855
892
|
},
|
|
856
|
-
EnumDeclaration: {
|
|
893
|
+
[ts.SyntaxKind.EnumDeclaration]: {
|
|
857
894
|
enter: (node) => {
|
|
858
895
|
const enumNode = node;
|
|
859
896
|
if (enumNode.name) {
|
|
@@ -872,7 +909,7 @@ export class TypeAnalyzer {
|
|
|
872
909
|
this.nodeToScope.set(node, this.scopeManager.currentScope);
|
|
873
910
|
},
|
|
874
911
|
},
|
|
875
|
-
MethodDeclaration: {
|
|
912
|
+
[ts.SyntaxKind.MethodDeclaration]: {
|
|
876
913
|
enter: (node) => {
|
|
877
914
|
if (ts.isMethodDeclaration(node)) {
|
|
878
915
|
const funcType = {
|
|
@@ -898,7 +935,7 @@ export class TypeAnalyzer {
|
|
|
898
935
|
this.scopeManager.exitScope();
|
|
899
936
|
},
|
|
900
937
|
},
|
|
901
|
-
Constructor: {
|
|
938
|
+
[ts.SyntaxKind.Constructor]: {
|
|
902
939
|
enter: (node) => {
|
|
903
940
|
if (ts.isConstructorDeclaration(node)) {
|
|
904
941
|
const funcType = {
|
|
@@ -923,7 +960,7 @@ export class TypeAnalyzer {
|
|
|
923
960
|
this.scopeManager.exitScope();
|
|
924
961
|
},
|
|
925
962
|
},
|
|
926
|
-
VariableDeclaration: {
|
|
963
|
+
[ts.SyntaxKind.VariableDeclaration]: {
|
|
927
964
|
enter: (node) => {
|
|
928
965
|
if (ts.isVariableDeclaration(node)) {
|
|
929
966
|
// Check if it is an ambient declaration (declare var/let/const ...)
|
|
@@ -990,8 +1027,8 @@ export class TypeAnalyzer {
|
|
|
990
1027
|
}
|
|
991
1028
|
},
|
|
992
1029
|
},
|
|
993
|
-
Identifier: {
|
|
994
|
-
enter: (node
|
|
1030
|
+
[ts.SyntaxKind.Identifier]: {
|
|
1031
|
+
enter: (node) => {
|
|
995
1032
|
if (ts.isIdentifier(node)) {
|
|
996
1033
|
if (isBuiltinObject.call(this, node))
|
|
997
1034
|
return;
|
|
@@ -1027,7 +1064,7 @@ export class TypeAnalyzer {
|
|
|
1027
1064
|
}
|
|
1028
1065
|
},
|
|
1029
1066
|
},
|
|
1030
|
-
BinaryExpression: {
|
|
1067
|
+
[ts.SyntaxKind.BinaryExpression]: {
|
|
1031
1068
|
enter: (node) => {
|
|
1032
1069
|
if (ts.isBinaryExpression(node)) {
|
|
1033
1070
|
const isAssignment = node.operatorToken.kind >=
|
|
@@ -1050,7 +1087,7 @@ export class TypeAnalyzer {
|
|
|
1050
1087
|
}
|
|
1051
1088
|
},
|
|
1052
1089
|
},
|
|
1053
|
-
CallExpression: {
|
|
1090
|
+
[ts.SyntaxKind.CallExpression]: {
|
|
1054
1091
|
enter: (node) => {
|
|
1055
1092
|
if (ts.isCallExpression(node)) {
|
|
1056
1093
|
const callee = node.expression;
|
|
@@ -1070,7 +1107,7 @@ export class TypeAnalyzer {
|
|
|
1070
1107
|
}
|
|
1071
1108
|
},
|
|
1072
1109
|
},
|
|
1073
|
-
ReturnStatement: {
|
|
1110
|
+
[ts.SyntaxKind.ReturnStatement]: {
|
|
1074
1111
|
enter: (node) => {
|
|
1075
1112
|
if (ts.isReturnStatement(node) && node.expression) {
|
|
1076
1113
|
const currentFuncNode = this.functionStack[this.functionStack.length - 1];
|
|
@@ -1086,14 +1123,14 @@ export class TypeAnalyzer {
|
|
|
1086
1123
|
}
|
|
1087
1124
|
},
|
|
1088
1125
|
},
|
|
1089
|
-
PostfixUnaryExpression: {
|
|
1126
|
+
[ts.SyntaxKind.PostfixUnaryExpression]: {
|
|
1090
1127
|
enter: (node) => {
|
|
1091
1128
|
if (ts.isPostfixUnaryExpression(node)) {
|
|
1092
1129
|
crossScopeModificationVisitor(node.operand);
|
|
1093
1130
|
}
|
|
1094
1131
|
},
|
|
1095
1132
|
},
|
|
1096
|
-
PrefixUnaryExpression: {
|
|
1133
|
+
[ts.SyntaxKind.PrefixUnaryExpression]: {
|
|
1097
1134
|
enter: (node) => {
|
|
1098
1135
|
if (ts.isPrefixUnaryExpression(node)) {
|
|
1099
1136
|
const op = node.operator;
|
|
@@ -153,16 +153,19 @@ export function visitForInStatement(node, context) {
|
|
|
153
153
|
derefExpr = this.getDerefCode(exprText, this.getJsVarName(expr), context, typeInfo);
|
|
154
154
|
}
|
|
155
155
|
const keysVar = this.generateUniqueName("__keys_", new Set([varName]));
|
|
156
|
+
const visitContext = {
|
|
157
|
+
...context,
|
|
158
|
+
globalScopeSymbols: this.prepareScopeSymbolsForVisit(context.globalScopeSymbols, context.localScopeSymbols),
|
|
159
|
+
localScopeSymbols: new DeclaredSymbols(),
|
|
160
|
+
currentLabel: undefined,
|
|
161
|
+
isFunctionBody: false,
|
|
162
|
+
};
|
|
156
163
|
code +=
|
|
157
164
|
`${this.indent()}std::vector<jspp::AnyValue> ${keysVar} = jspp::Access::get_object_keys(${derefExpr});\n`;
|
|
158
165
|
code += `${this.indent()}for (const auto& ${varName}_val : ${keysVar}) {\n`;
|
|
159
166
|
this.indentationLevel++;
|
|
160
167
|
code += `${this.indent()}${assignmentTarget} = ${varName}_val;\n`;
|
|
161
|
-
code += this.visit(forIn.statement,
|
|
162
|
-
...context,
|
|
163
|
-
currentLabel: undefined,
|
|
164
|
-
isFunctionBody: false,
|
|
165
|
-
});
|
|
168
|
+
code += this.visit(forIn.statement, visitContext);
|
|
166
169
|
this.indentationLevel--;
|
|
167
170
|
if (context.currentLabel) {
|
|
168
171
|
code += `${this.indent()}${context.currentLabel}_continue:;\n`;
|
|
@@ -188,6 +191,7 @@ export function visitForOfStatement(node, context) {
|
|
|
188
191
|
this.indentationLevel++; // Enter a new scope for the for-of loop
|
|
189
192
|
let elemName = "";
|
|
190
193
|
let assignmentTarget = "";
|
|
194
|
+
let declarationType = DeclarationType.const;
|
|
191
195
|
code += `${this.indent()}{\n`;
|
|
192
196
|
if (ts.isVariableDeclarationList(forOf.initializer)) {
|
|
193
197
|
const decl = forOf.initializer.declarations[0];
|
|
@@ -205,6 +209,11 @@ export function visitForOfStatement(node, context) {
|
|
|
205
209
|
`${this.indent()}jspp::AnyValue ${elemName} = jspp::Constants::UNDEFINED;\n`;
|
|
206
210
|
assignmentTarget = elemName;
|
|
207
211
|
}
|
|
212
|
+
declarationType = (decl.parent.flags & (ts.NodeFlags.Let)) !== 0
|
|
213
|
+
? DeclarationType.let
|
|
214
|
+
: (decl.parent.flags & (ts.NodeFlags.Const)) !== 0
|
|
215
|
+
? DeclarationType.const
|
|
216
|
+
: DeclarationType.var;
|
|
208
217
|
}
|
|
209
218
|
}
|
|
210
219
|
else if (ts.isIdentifier(forOf.initializer)) {
|
|
@@ -214,6 +223,12 @@ export function visitForOfStatement(node, context) {
|
|
|
214
223
|
assignmentTarget = typeInfo?.needsHeapAllocation
|
|
215
224
|
? `*${elemName}`
|
|
216
225
|
: elemName;
|
|
226
|
+
declarationType =
|
|
227
|
+
(forOf.initializer.parent.flags & (ts.NodeFlags.Let)) !== 0
|
|
228
|
+
? DeclarationType.let
|
|
229
|
+
: (forOf.initializer.parent.flags & (ts.NodeFlags.Const)) !== 0
|
|
230
|
+
? DeclarationType.const
|
|
231
|
+
: DeclarationType.var;
|
|
217
232
|
}
|
|
218
233
|
const iterableExpr = this.visit(forOf.expression, context);
|
|
219
234
|
let derefIterable = iterableExpr;
|
|
@@ -230,6 +245,19 @@ export function visitForOfStatement(node, context) {
|
|
|
230
245
|
const nextRes = this.generateUniqueName("__next_res", declaredSymbols);
|
|
231
246
|
const isAwait = forOf.awaitModifier !== undefined;
|
|
232
247
|
const varName = this.getJsVarName(forOf.expression);
|
|
248
|
+
const visitContext = {
|
|
249
|
+
...context,
|
|
250
|
+
globalScopeSymbols: this.prepareScopeSymbolsForVisit(context.globalScopeSymbols, context.localScopeSymbols),
|
|
251
|
+
localScopeSymbols: new DeclaredSymbols(),
|
|
252
|
+
currentLabel: undefined,
|
|
253
|
+
isFunctionBody: false,
|
|
254
|
+
};
|
|
255
|
+
if (elemName) {
|
|
256
|
+
visitContext.localScopeSymbols.add(elemName, {
|
|
257
|
+
type: declarationType,
|
|
258
|
+
checks: { initialized: true },
|
|
259
|
+
});
|
|
260
|
+
}
|
|
233
261
|
code += `${this.indent()}auto ${iterableRef} = ${derefIterable};\n`;
|
|
234
262
|
if (isAwait) {
|
|
235
263
|
code +=
|
|
@@ -254,11 +282,7 @@ export function visitForOfStatement(node, context) {
|
|
|
254
282
|
this.indentationLevel++;
|
|
255
283
|
code +=
|
|
256
284
|
`${this.indent()}${assignmentTarget} = ${nextRes}.get_own_property("value");\n`;
|
|
257
|
-
code += this.visit(forOf.statement,
|
|
258
|
-
...context,
|
|
259
|
-
currentLabel: undefined,
|
|
260
|
-
isFunctionBody: false,
|
|
261
|
-
});
|
|
285
|
+
code += this.visit(forOf.statement, visitContext);
|
|
262
286
|
if (context.currentLabel) {
|
|
263
287
|
code += `${this.indent()}${context.currentLabel}_continue:;\n`;
|
|
264
288
|
}
|
|
@@ -123,7 +123,7 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
123
123
|
}
|
|
124
124
|
});
|
|
125
125
|
// Extract lambda parameters from arguments span/vector
|
|
126
|
-
const
|
|
126
|
+
const wrappedFuncParamsBuilder = () => {
|
|
127
127
|
let paramsCode = "";
|
|
128
128
|
this.validateFunctionParams(node.parameters).forEach((p, i) => {
|
|
129
129
|
if (ts.isIdentifier(p.name)) {
|
|
@@ -152,14 +152,19 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
152
152
|
return;
|
|
153
153
|
}
|
|
154
154
|
// Normal parameter
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
155
|
+
const isUsedInFuncBody = !!p.initializer ||
|
|
156
|
+
this.isDeclarationUsedAsValue(p, node) ||
|
|
157
|
+
this.isDeclarationCalledAsFunction(p, node);
|
|
158
|
+
if (isUsedInFuncBody) {
|
|
159
|
+
const initValue = `${argsName}.size() > ${i} ? ${argsName}[${i}] : ${defaultValue}`;
|
|
160
|
+
if (typeInfo?.needsHeapAllocation) {
|
|
161
|
+
paramsCode +=
|
|
162
|
+
`${this.indent()}auto ${name} = std::make_shared<jspp::AnyValue>(${initValue});\n`;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
paramsCode +=
|
|
166
|
+
`${this.indent()}jspp::AnyValue ${name} = ${initValue};\n`;
|
|
167
|
+
}
|
|
163
168
|
}
|
|
164
169
|
}
|
|
165
170
|
else {
|
|
@@ -225,7 +230,7 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
225
230
|
}
|
|
226
231
|
});
|
|
227
232
|
this.indentationLevel++;
|
|
228
|
-
paramsContent +=
|
|
233
|
+
paramsContent += wrappedFuncParamsBuilder();
|
|
229
234
|
this.indentationLevel--;
|
|
230
235
|
// The block visitor already adds braces, so we need to remove the opening brace to inject the preamble and param extraction.
|
|
231
236
|
const properIndentationLevel = this.indentationLevel;
|
|
@@ -250,7 +255,7 @@ export function generateLambdaComponents(node, context, options) {
|
|
|
250
255
|
}
|
|
251
256
|
else {
|
|
252
257
|
this.indentationLevel++;
|
|
253
|
-
paramsContent +=
|
|
258
|
+
paramsContent += wrappedFuncParamsBuilder();
|
|
254
259
|
const properIndentationLevel = this.indentationLevel;
|
|
255
260
|
const nodeBody = node.body;
|
|
256
261
|
getBlockContentWithoutOpeningBrace = (isInsideNativeLambda) => {
|
|
@@ -799,7 +799,11 @@ export function findEnclosingFunctionDeclarationFromReturnStatement(node) {
|
|
|
799
799
|
let current = node;
|
|
800
800
|
let foundReturn = false;
|
|
801
801
|
while (current) {
|
|
802
|
-
if (ts.isFunctionDeclaration(current)
|
|
802
|
+
if (ts.isFunctionDeclaration(current) ||
|
|
803
|
+
ts.isFunctionExpression(current) ||
|
|
804
|
+
ts.isArrowFunction(current) ||
|
|
805
|
+
ts.isMethodDeclaration(current) ||
|
|
806
|
+
ts.isConstructorDeclaration(current)) {
|
|
803
807
|
if (foundReturn) {
|
|
804
808
|
return current;
|
|
805
809
|
}
|
|
@@ -106,7 +106,7 @@ export class CodeGenerator {
|
|
|
106
106
|
wasmWrappers +=
|
|
107
107
|
` auto res = ${pointerName}(global${callArgs});\n`;
|
|
108
108
|
wasmWrappers +=
|
|
109
|
-
` return jspp::
|
|
109
|
+
` return jspp::NumberOperators::ToDouble(res);\n`;
|
|
110
110
|
wasmWrappers += `}\n\n`;
|
|
111
111
|
}
|
|
112
112
|
}
|
|
@@ -819,22 +819,26 @@ export function visitReturnStatement(node, context) {
|
|
|
819
819
|
return `${this.indent()}jspp::Exception::throw_unresolved_reference(${this.getJsVarName(expr)});\n`; // THROWS, not returns
|
|
820
820
|
}
|
|
821
821
|
if (typeInfo &&
|
|
822
|
-
!typeInfo.isParameter &&
|
|
823
822
|
!typeInfo.isBuiltin) {
|
|
824
823
|
finalExpr = this.getDerefCode(exprText, this.getJsVarName(expr), context, typeInfo);
|
|
825
824
|
}
|
|
826
|
-
const
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
825
|
+
const funcDecl = this
|
|
826
|
+
.findEnclosingFunctionDeclarationFromReturnStatement(expr);
|
|
827
|
+
if (funcDecl) {
|
|
828
|
+
const funcReturnType = this.typeAnalyzer
|
|
829
|
+
.inferFunctionReturnType(funcDecl);
|
|
830
|
+
if (funcReturnType === "number" &&
|
|
831
|
+
context.isInsideNativeLambda &&
|
|
832
|
+
context.isInsideFunction) {
|
|
833
|
+
const exprReturnType = this.typeAnalyzer
|
|
834
|
+
.inferNodeReturnType(expr);
|
|
835
|
+
if (exprReturnType === "number") {
|
|
836
836
|
finalExpr = `${finalExpr}.as_double()`;
|
|
837
837
|
}
|
|
838
|
+
else {
|
|
839
|
+
finalExpr =
|
|
840
|
+
`jspp::NumberOperators::ToDouble(${finalExpr})`;
|
|
841
|
+
}
|
|
838
842
|
}
|
|
839
843
|
}
|
|
840
844
|
}
|
|
@@ -4,8 +4,7 @@ export class Traverser {
|
|
|
4
4
|
this.traverseNode(node, null, visitor);
|
|
5
5
|
}
|
|
6
6
|
traverseNode(node, parent, visitor) {
|
|
7
|
-
const
|
|
8
|
-
const visitorActions = visitor[nodeKind];
|
|
7
|
+
const visitorActions = visitor[node.kind];
|
|
9
8
|
if (visitorActions && visitorActions.enter) {
|
|
10
9
|
visitorActions.enter(node, parent);
|
|
11
10
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ugo-studio/jspp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "A modern transpiler that converts JavaScript code into high-performance, standard C++23.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "src/index.ts",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"scripts"
|
|
15
15
|
],
|
|
16
16
|
"scripts": {
|
|
17
|
-
"postinstall": "bun run scripts/setup-compiler.ts && bun run scripts/setup-emsdk.ts
|
|
17
|
+
"postinstall": "bun run scripts/setup-compiler.ts && bun run scripts/setup-emsdk.ts",
|
|
18
18
|
"dev": "bun run src/cli/index.ts",
|
|
19
19
|
"typecheck": "tsc --noEmit",
|
|
20
20
|
"test": "bun test",
|
|
@@ -78,7 +78,7 @@ namespace jspp {
|
|
|
78
78
|
}
|
|
79
79
|
} else {
|
|
80
80
|
auto lenVal = items.get_property_with_receiver("length", items);
|
|
81
|
-
size_t len = static_cast<size_t>(jspp::
|
|
81
|
+
size_t len = static_cast<size_t>(jspp::NumberOperators::ToUint32(lenVal));
|
|
82
82
|
|
|
83
83
|
for (size_t k = 0; k < len; ++k) {
|
|
84
84
|
auto kVal = items.get_property_with_receiver(std::to_string(k), items);
|
|
@@ -149,7 +149,7 @@ namespace jspp {
|
|
|
149
149
|
}
|
|
150
150
|
} else {
|
|
151
151
|
auto lenVal = items.get_property_with_receiver("length", items);
|
|
152
|
-
size_t len = static_cast<size_t>(jspp::
|
|
152
|
+
size_t len = static_cast<size_t>(jspp::NumberOperators::ToUint32(lenVal));
|
|
153
153
|
for (size_t k = 0; k < len; ++k) {
|
|
154
154
|
auto kVal = items.get_property_with_receiver(std::to_string(k), items);
|
|
155
155
|
if (kVal.is_promise()) kVal = co_await kVal;
|
|
@@ -11,7 +11,7 @@ namespace jspp {
|
|
|
11
11
|
|
|
12
12
|
double GetArgAsDouble(std::span<const jspp::AnyValue> args, size_t index) {
|
|
13
13
|
if (index >= args.size()) return std::numeric_limits<double>::quiet_NaN();
|
|
14
|
-
return
|
|
14
|
+
return NumberOperators::ToDouble(args[index]);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
jspp::AnyValue MathFunc1(std::span<const jspp::AnyValue> args, double (*func)(double)) {
|
|
@@ -86,7 +86,7 @@ namespace jspp {
|
|
|
86
86
|
}, "ceil"));
|
|
87
87
|
|
|
88
88
|
defMutable("clz32", AnyValue::make_function([](AnyValue, std::span<const AnyValue> args) -> AnyValue {
|
|
89
|
-
uint32_t val =
|
|
89
|
+
uint32_t val = NumberOperators::ToInt32(args.empty() ? Constants::UNDEFINED : args[0]);
|
|
90
90
|
if (val == 0) return AnyValue::make_number(32);
|
|
91
91
|
return AnyValue::make_number(std::countl_zero(val));
|
|
92
92
|
}, "clz32"));
|
|
@@ -119,7 +119,7 @@ namespace jspp {
|
|
|
119
119
|
defMutable("hypot", AnyValue::make_function([](AnyValue, std::span<const AnyValue> args) -> AnyValue {
|
|
120
120
|
double result = 0;
|
|
121
121
|
for (const auto& arg : args) {
|
|
122
|
-
double val =
|
|
122
|
+
double val = NumberOperators::ToDouble(arg);
|
|
123
123
|
if (std::isinf(val)) return AnyValue::make_number(std::numeric_limits<double>::infinity());
|
|
124
124
|
result = std::hypot(result, val);
|
|
125
125
|
}
|
|
@@ -127,8 +127,8 @@ namespace jspp {
|
|
|
127
127
|
}, "hypot"));
|
|
128
128
|
|
|
129
129
|
defMutable("imul", AnyValue::make_function([](AnyValue, std::span<const AnyValue> args) -> AnyValue {
|
|
130
|
-
int32_t a =
|
|
131
|
-
int32_t b =
|
|
130
|
+
int32_t a = NumberOperators::ToInt32(args.empty() ? Constants::UNDEFINED : args[0]);
|
|
131
|
+
int32_t b = NumberOperators::ToInt32(args.size() < 2 ? Constants::UNDEFINED : args[1]);
|
|
132
132
|
return AnyValue::make_number(a * b);
|
|
133
133
|
}, "imul"));
|
|
134
134
|
|
|
@@ -151,7 +151,7 @@ namespace jspp {
|
|
|
151
151
|
defMutable("max", AnyValue::make_function([](AnyValue, std::span<const AnyValue> args) -> AnyValue {
|
|
152
152
|
double maxVal = -std::numeric_limits<double>::infinity();
|
|
153
153
|
for (const auto& arg : args) {
|
|
154
|
-
double val =
|
|
154
|
+
double val = NumberOperators::ToDouble(arg);
|
|
155
155
|
if (std::isnan(val)) return AnyValue::make_nan();
|
|
156
156
|
if (val > maxVal) maxVal = val;
|
|
157
157
|
}
|
|
@@ -161,7 +161,7 @@ namespace jspp {
|
|
|
161
161
|
defMutable("min", AnyValue::make_function([](AnyValue, std::span<const AnyValue> args) -> AnyValue {
|
|
162
162
|
double minVal = std::numeric_limits<double>::infinity();
|
|
163
163
|
for (const auto& arg : args) {
|
|
164
|
-
double val =
|
|
164
|
+
double val = NumberOperators::ToDouble(arg);
|
|
165
165
|
if (std::isnan(val)) return AnyValue::make_nan();
|
|
166
166
|
if (val < minVal) minVal = val;
|
|
167
167
|
}
|
|
@@ -238,7 +238,7 @@ namespace jspp {
|
|
|
238
238
|
auto nextRes = nextFunc.call(iterObj, std::span<const jspp::AnyValue>{}, "next");
|
|
239
239
|
if (is_truthy(nextRes.get_own_property("done"))) break;
|
|
240
240
|
|
|
241
|
-
double val =
|
|
241
|
+
double val = NumberOperators::ToDouble(nextRes.get_own_property("value"));
|
|
242
242
|
if (std::isnan(val)) {
|
|
243
243
|
sum = std::numeric_limits<double>::quiet_NaN();
|
|
244
244
|
break;
|
|
@@ -192,15 +192,15 @@ namespace jspp
|
|
|
192
192
|
// --- UNARY OPERATORS ---
|
|
193
193
|
inline AnyValue plus(const AnyValue &val)
|
|
194
194
|
{
|
|
195
|
-
return AnyValue::make_number(
|
|
195
|
+
return AnyValue::make_number(NumberOperators::ToDouble(val));
|
|
196
196
|
}
|
|
197
197
|
inline AnyValue negate(const AnyValue &val)
|
|
198
198
|
{
|
|
199
|
-
return AnyValue::make_number(-
|
|
199
|
+
return AnyValue::make_number(-NumberOperators::ToDouble(val));
|
|
200
200
|
}
|
|
201
201
|
inline AnyValue bitwise_not(const AnyValue &val)
|
|
202
202
|
{
|
|
203
|
-
return AnyValue::make_number(~
|
|
203
|
+
return AnyValue::make_number(~NumberOperators::ToInt32(val));
|
|
204
204
|
}
|
|
205
205
|
inline AnyValue logical_not(const AnyValue &val)
|
|
206
206
|
{
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
namespace jspp
|
|
13
13
|
{
|
|
14
14
|
// Private namespace for helper functions that implement JS type conversions.
|
|
15
|
-
namespace
|
|
15
|
+
namespace NumberOperators
|
|
16
16
|
{
|
|
17
|
-
// Implements the
|
|
18
|
-
inline double
|
|
17
|
+
// Implements the ToDouble abstract operation from ECMA-262.
|
|
18
|
+
inline double ToDouble(const AnyValue &val)
|
|
19
19
|
{
|
|
20
20
|
if (val.is_number())
|
|
21
21
|
return val.as_double();
|
|
@@ -57,7 +57,7 @@ namespace jspp
|
|
|
57
57
|
// Implements the ToInt32 abstract operation from ECMA-262.
|
|
58
58
|
inline int32_t ToInt32(const AnyValue &val)
|
|
59
59
|
{
|
|
60
|
-
double num =
|
|
60
|
+
double num = ToDouble(val);
|
|
61
61
|
|
|
62
62
|
if (std::isnan(num) || std::isinf(num) || num == 0)
|
|
63
63
|
return 0;
|
|
@@ -73,7 +73,7 @@ namespace jspp
|
|
|
73
73
|
// Implements the ToUint32 abstract operation from ECMA-262.
|
|
74
74
|
inline uint32_t ToUint32(const AnyValue &val)
|
|
75
75
|
{
|
|
76
|
-
double num =
|
|
76
|
+
double num = ToDouble(val);
|
|
77
77
|
if (std::isnan(num) || std::isinf(num) || num == 0)
|
|
78
78
|
return 0;
|
|
79
79
|
double posInt = std::signbit(num) ? -std::floor(std::abs(num)) : std::floor(std::abs(num));
|
|
@@ -111,11 +111,11 @@ namespace jspp
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
// --- UNARY NATIVE ---
|
|
114
|
-
inline double plus_native(const AnyValue &val) { return
|
|
114
|
+
inline double plus_native(const AnyValue &val) { return NumberOperators::ToDouble(val); }
|
|
115
115
|
inline double plus_native(double val) { return val; }
|
|
116
|
-
inline double negate_native(const AnyValue &val) { return -
|
|
116
|
+
inline double negate_native(const AnyValue &val) { return -NumberOperators::ToDouble(val); }
|
|
117
117
|
inline double negate_native(double val) { return -val; }
|
|
118
|
-
inline double bitwise_not_native(const AnyValue &val) { return static_cast<double>(~
|
|
118
|
+
inline double bitwise_not_native(const AnyValue &val) { return static_cast<double>(~NumberOperators::ToInt32(val)); }
|
|
119
119
|
inline double bitwise_not_native(double val) { return static_cast<double>(~static_cast<int32_t>(val)); }
|
|
120
120
|
inline bool logical_not_native(const AnyValue &val) { return !is_truthy(val); }
|
|
121
121
|
inline bool logical_not_native(double val) { return !is_truthy(val); }
|
|
@@ -202,11 +202,11 @@ namespace jspp
|
|
|
202
202
|
}
|
|
203
203
|
if (lhs_type == JsType::Number && rhs_type == JsType::String)
|
|
204
204
|
{
|
|
205
|
-
return lhs.as_double() ==
|
|
205
|
+
return lhs.as_double() == NumberOperators::ToDouble(rhs);
|
|
206
206
|
}
|
|
207
207
|
if (lhs_type == JsType::String && rhs_type == JsType::Number)
|
|
208
208
|
{
|
|
209
|
-
return
|
|
209
|
+
return NumberOperators::ToDouble(lhs) == rhs.as_double();
|
|
210
210
|
}
|
|
211
211
|
if (lhs_type == JsType::Boolean)
|
|
212
212
|
{
|
|
@@ -247,114 +247,114 @@ namespace jspp
|
|
|
247
247
|
|
|
248
248
|
// --- PRIMITIVE ARITHMETIC OPERATORS ---
|
|
249
249
|
inline double add_native(const double &lhs, const double &rhs) { return lhs + rhs; }
|
|
250
|
-
inline double add_native(const AnyValue &lhs, const AnyValue &rhs) { return
|
|
251
|
-
inline double add_native(const AnyValue &lhs, const double &rhs) { return
|
|
252
|
-
inline double add_native(const double &lhs, const AnyValue &rhs) { return lhs +
|
|
250
|
+
inline double add_native(const AnyValue &lhs, const AnyValue &rhs) { return NumberOperators::ToDouble(lhs) + NumberOperators::ToDouble(rhs); }
|
|
251
|
+
inline double add_native(const AnyValue &lhs, const double &rhs) { return NumberOperators::ToDouble(lhs) + rhs; }
|
|
252
|
+
inline double add_native(const double &lhs, const AnyValue &rhs) { return lhs + NumberOperators::ToDouble(rhs); }
|
|
253
253
|
|
|
254
254
|
inline double sub_native(const double &lhs, const double &rhs) { return lhs - rhs; }
|
|
255
|
-
inline double sub_native(const AnyValue &lhs, const AnyValue &rhs) { return
|
|
256
|
-
inline double sub_native(const AnyValue &lhs, const double &rhs) { return
|
|
257
|
-
inline double sub_native(const double &lhs, const AnyValue &rhs) { return lhs -
|
|
255
|
+
inline double sub_native(const AnyValue &lhs, const AnyValue &rhs) { return NumberOperators::ToDouble(lhs) - NumberOperators::ToDouble(rhs); }
|
|
256
|
+
inline double sub_native(const AnyValue &lhs, const double &rhs) { return NumberOperators::ToDouble(lhs) - rhs; }
|
|
257
|
+
inline double sub_native(const double &lhs, const AnyValue &rhs) { return lhs - NumberOperators::ToDouble(rhs); }
|
|
258
258
|
|
|
259
259
|
inline double mul_native(const double &lhs, const double &rhs) { return lhs * rhs; }
|
|
260
|
-
inline double mul_native(const AnyValue &lhs, const AnyValue &rhs) { return
|
|
261
|
-
inline double mul_native(const AnyValue &lhs, const double &rhs) { return
|
|
262
|
-
inline double mul_native(const double &lhs, const AnyValue &rhs) { return lhs *
|
|
260
|
+
inline double mul_native(const AnyValue &lhs, const AnyValue &rhs) { return NumberOperators::ToDouble(lhs) * NumberOperators::ToDouble(rhs); }
|
|
261
|
+
inline double mul_native(const AnyValue &lhs, const double &rhs) { return NumberOperators::ToDouble(lhs) * rhs; }
|
|
262
|
+
inline double mul_native(const double &lhs, const AnyValue &rhs) { return lhs * NumberOperators::ToDouble(rhs); }
|
|
263
263
|
|
|
264
264
|
inline double div_native(const double &lhs, const double &rhs) { return lhs / rhs; }
|
|
265
|
-
inline double div_native(const AnyValue &lhs, const AnyValue &rhs) { return
|
|
266
|
-
inline double div_native(const AnyValue &lhs, const double &rhs) { return
|
|
267
|
-
inline double div_native(const double &lhs, const AnyValue &rhs) { return lhs /
|
|
265
|
+
inline double div_native(const AnyValue &lhs, const AnyValue &rhs) { return NumberOperators::ToDouble(lhs) / NumberOperators::ToDouble(rhs); }
|
|
266
|
+
inline double div_native(const AnyValue &lhs, const double &rhs) { return NumberOperators::ToDouble(lhs) / rhs; }
|
|
267
|
+
inline double div_native(const double &lhs, const AnyValue &rhs) { return lhs / NumberOperators::ToDouble(rhs); }
|
|
268
268
|
|
|
269
269
|
inline double mod_native(const double &lhs, const double &rhs) { return std::fmod(lhs, rhs); }
|
|
270
|
-
inline double mod_native(const AnyValue &lhs, const AnyValue &rhs) { return std::fmod(
|
|
271
|
-
inline double mod_native(const AnyValue &lhs, const double &rhs) { return std::fmod(
|
|
272
|
-
inline double mod_native(const double &lhs, const AnyValue &rhs) { return std::fmod(lhs,
|
|
270
|
+
inline double mod_native(const AnyValue &lhs, const AnyValue &rhs) { return std::fmod(NumberOperators::ToDouble(lhs), NumberOperators::ToDouble(rhs)); }
|
|
271
|
+
inline double mod_native(const AnyValue &lhs, const double &rhs) { return std::fmod(NumberOperators::ToDouble(lhs), rhs); }
|
|
272
|
+
inline double mod_native(const double &lhs, const AnyValue &rhs) { return std::fmod(lhs, NumberOperators::ToDouble(rhs)); }
|
|
273
273
|
|
|
274
274
|
inline double pow_native(const double &lhs, const double &rhs) { return std::pow(lhs, rhs); }
|
|
275
|
-
inline double pow_native(const AnyValue &lhs, const AnyValue &rhs) { return std::pow(
|
|
276
|
-
inline double pow_native(const AnyValue &lhs, const double &rhs) { return std::pow(
|
|
277
|
-
inline double pow_native(const double &lhs, const AnyValue &rhs) { return std::pow(lhs,
|
|
275
|
+
inline double pow_native(const AnyValue &lhs, const AnyValue &rhs) { return std::pow(NumberOperators::ToDouble(lhs), NumberOperators::ToDouble(rhs)); }
|
|
276
|
+
inline double pow_native(const AnyValue &lhs, const double &rhs) { return std::pow(NumberOperators::ToDouble(lhs), rhs); }
|
|
277
|
+
inline double pow_native(const double &lhs, const AnyValue &rhs) { return std::pow(lhs, NumberOperators::ToDouble(rhs)); }
|
|
278
278
|
|
|
279
279
|
// --- PRIMITIVE COMPARISON OPERATORS ---
|
|
280
280
|
inline bool less_than_native(const double &lhs, const double &rhs) { return lhs < rhs; }
|
|
281
|
-
inline bool less_than_native(const AnyValue &lhs, const AnyValue &rhs) { return less_than_native(
|
|
282
|
-
inline bool less_than_native(const AnyValue &lhs, const double &rhs) { return less_than_native(
|
|
283
|
-
inline bool less_than_native(const double &lhs, const AnyValue &rhs) { return less_than_native(lhs,
|
|
281
|
+
inline bool less_than_native(const AnyValue &lhs, const AnyValue &rhs) { return less_than_native(NumberOperators::ToDouble(lhs), NumberOperators::ToDouble(rhs)); }
|
|
282
|
+
inline bool less_than_native(const AnyValue &lhs, const double &rhs) { return less_than_native(NumberOperators::ToDouble(lhs), rhs); }
|
|
283
|
+
inline bool less_than_native(const double &lhs, const AnyValue &rhs) { return less_than_native(lhs, NumberOperators::ToDouble(rhs)); }
|
|
284
284
|
|
|
285
285
|
inline bool greater_than_native(const double &lhs, const double &rhs) { return lhs > rhs; }
|
|
286
|
-
inline bool greater_than_native(const AnyValue &lhs, const AnyValue &rhs) { return greater_than_native(
|
|
287
|
-
inline bool greater_than_native(const AnyValue &lhs, const double &rhs) { return greater_than_native(
|
|
288
|
-
inline bool greater_than_native(const double &lhs, const AnyValue &rhs) { return greater_than_native(lhs,
|
|
286
|
+
inline bool greater_than_native(const AnyValue &lhs, const AnyValue &rhs) { return greater_than_native(NumberOperators::ToDouble(lhs), NumberOperators::ToDouble(rhs)); }
|
|
287
|
+
inline bool greater_than_native(const AnyValue &lhs, const double &rhs) { return greater_than_native(NumberOperators::ToDouble(lhs), rhs); }
|
|
288
|
+
inline bool greater_than_native(const double &lhs, const AnyValue &rhs) { return greater_than_native(lhs, NumberOperators::ToDouble(rhs)); }
|
|
289
289
|
|
|
290
290
|
inline bool less_than_or_equal_native(const double &lhs, const double &rhs) { return lhs <= rhs; }
|
|
291
|
-
inline bool less_than_or_equal_native(const AnyValue &lhs, const AnyValue &rhs) { return less_than_or_equal_native(
|
|
292
|
-
inline bool less_than_or_equal_native(const AnyValue &lhs, const double &rhs) { return less_than_or_equal_native(
|
|
293
|
-
inline bool less_than_or_equal_native(const double &lhs, const AnyValue &rhs) { return less_than_or_equal_native(lhs,
|
|
291
|
+
inline bool less_than_or_equal_native(const AnyValue &lhs, const AnyValue &rhs) { return less_than_or_equal_native(NumberOperators::ToDouble(lhs), NumberOperators::ToDouble(rhs)); }
|
|
292
|
+
inline bool less_than_or_equal_native(const AnyValue &lhs, const double &rhs) { return less_than_or_equal_native(NumberOperators::ToDouble(lhs), rhs); }
|
|
293
|
+
inline bool less_than_or_equal_native(const double &lhs, const AnyValue &rhs) { return less_than_or_equal_native(lhs, NumberOperators::ToDouble(rhs)); }
|
|
294
294
|
|
|
295
295
|
inline bool greater_than_or_equal_native(const double &lhs, const double &rhs) { return lhs >= rhs; }
|
|
296
|
-
inline bool greater_than_or_equal_native(const AnyValue &lhs, const AnyValue &rhs) { return greater_than_or_equal_native(
|
|
297
|
-
inline bool greater_than_or_equal_native(const AnyValue &lhs, const double &rhs) { return greater_than_or_equal_native(
|
|
298
|
-
inline bool greater_than_or_equal_native(const double &lhs, const AnyValue &rhs) { return greater_than_or_equal_native(lhs,
|
|
296
|
+
inline bool greater_than_or_equal_native(const AnyValue &lhs, const AnyValue &rhs) { return greater_than_or_equal_native(NumberOperators::ToDouble(lhs), NumberOperators::ToDouble(rhs)); }
|
|
297
|
+
inline bool greater_than_or_equal_native(const AnyValue &lhs, const double &rhs) { return greater_than_or_equal_native(NumberOperators::ToDouble(lhs), rhs); }
|
|
298
|
+
inline bool greater_than_or_equal_native(const double &lhs, const AnyValue &rhs) { return greater_than_or_equal_native(lhs, NumberOperators::ToDouble(rhs)); }
|
|
299
299
|
|
|
300
300
|
inline bool equal_native(const double &lhs, const double &rhs) { return lhs == rhs; }
|
|
301
|
-
inline bool equal_native(const AnyValue &lhs, const AnyValue &rhs) { return equal_native(
|
|
302
|
-
inline bool equal_native(const AnyValue &lhs, const double &rhs) { return equal_native(
|
|
303
|
-
inline bool equal_native(const double &lhs, const AnyValue &rhs) { return equal_native(lhs,
|
|
301
|
+
inline bool equal_native(const AnyValue &lhs, const AnyValue &rhs) { return equal_native(NumberOperators::ToDouble(lhs), NumberOperators::ToDouble(rhs)); }
|
|
302
|
+
inline bool equal_native(const AnyValue &lhs, const double &rhs) { return equal_native(NumberOperators::ToDouble(lhs), rhs); }
|
|
303
|
+
inline bool equal_native(const double &lhs, const AnyValue &rhs) { return equal_native(lhs, NumberOperators::ToDouble(rhs)); }
|
|
304
304
|
|
|
305
305
|
inline bool not_equal_native(const double &lhs, const double &rhs) { return lhs != rhs; }
|
|
306
|
-
inline bool not_equal_native(const AnyValue &lhs, const AnyValue &rhs) { return not_equal_native(
|
|
307
|
-
inline bool not_equal_native(const AnyValue &lhs, const double &rhs) { return not_equal_native(
|
|
308
|
-
inline bool not_equal_native(const double &lhs, const AnyValue &rhs) { return not_equal_native(lhs,
|
|
306
|
+
inline bool not_equal_native(const AnyValue &lhs, const AnyValue &rhs) { return not_equal_native(NumberOperators::ToDouble(lhs), NumberOperators::ToDouble(rhs)); }
|
|
307
|
+
inline bool not_equal_native(const AnyValue &lhs, const double &rhs) { return not_equal_native(NumberOperators::ToDouble(lhs), rhs); }
|
|
308
|
+
inline bool not_equal_native(const double &lhs, const AnyValue &rhs) { return not_equal_native(lhs, NumberOperators::ToDouble(rhs)); }
|
|
309
309
|
|
|
310
310
|
// --- PRIMITIVE BITWISE OPERATORS ---
|
|
311
311
|
inline double bitwise_and_native(const double &lhs, const double &rhs)
|
|
312
312
|
{
|
|
313
313
|
return static_cast<double>(static_cast<int32_t>(lhs) & static_cast<int32_t>(rhs));
|
|
314
314
|
}
|
|
315
|
-
inline double bitwise_and_native(const AnyValue &lhs, const AnyValue &rhs) { return bitwise_and_native(
|
|
316
|
-
inline double bitwise_and_native(const AnyValue &lhs, const double &rhs) { return bitwise_and_native(
|
|
317
|
-
inline double bitwise_and_native(const double &lhs, const AnyValue &rhs) { return bitwise_and_native(lhs,
|
|
315
|
+
inline double bitwise_and_native(const AnyValue &lhs, const AnyValue &rhs) { return bitwise_and_native(NumberOperators::ToInt32(lhs), NumberOperators::ToInt32(rhs)); }
|
|
316
|
+
inline double bitwise_and_native(const AnyValue &lhs, const double &rhs) { return bitwise_and_native(NumberOperators::ToInt32(lhs), rhs); }
|
|
317
|
+
inline double bitwise_and_native(const double &lhs, const AnyValue &rhs) { return bitwise_and_native(lhs, NumberOperators::ToInt32(rhs)); }
|
|
318
318
|
|
|
319
319
|
inline double bitwise_or_native(const double &lhs, const double &rhs)
|
|
320
320
|
{
|
|
321
321
|
return static_cast<double>(static_cast<int32_t>(lhs) | static_cast<int32_t>(rhs));
|
|
322
322
|
}
|
|
323
|
-
inline double bitwise_or_native(const AnyValue &lhs, const AnyValue &rhs) { return bitwise_or_native(
|
|
324
|
-
inline double bitwise_or_native(const AnyValue &lhs, const double &rhs) { return bitwise_or_native(
|
|
325
|
-
inline double bitwise_or_native(const double &lhs, const AnyValue &rhs) { return bitwise_or_native(lhs,
|
|
323
|
+
inline double bitwise_or_native(const AnyValue &lhs, const AnyValue &rhs) { return bitwise_or_native(NumberOperators::ToInt32(lhs), NumberOperators::ToInt32(rhs)); }
|
|
324
|
+
inline double bitwise_or_native(const AnyValue &lhs, const double &rhs) { return bitwise_or_native(NumberOperators::ToInt32(lhs), rhs); }
|
|
325
|
+
inline double bitwise_or_native(const double &lhs, const AnyValue &rhs) { return bitwise_or_native(lhs, NumberOperators::ToInt32(rhs)); }
|
|
326
326
|
|
|
327
327
|
inline double bitwise_xor_native(const double &lhs, const double &rhs)
|
|
328
328
|
{
|
|
329
329
|
return static_cast<double>(static_cast<int32_t>(lhs) ^ static_cast<int32_t>(rhs));
|
|
330
330
|
}
|
|
331
|
-
inline double bitwise_xor_native(const AnyValue &lhs, const AnyValue &rhs) { return bitwise_xor_native(
|
|
332
|
-
inline double bitwise_xor_native(const AnyValue &lhs, const double &rhs) { return bitwise_xor_native(
|
|
333
|
-
inline double bitwise_xor_native(const double &lhs, const AnyValue &rhs) { return bitwise_xor_native(lhs,
|
|
331
|
+
inline double bitwise_xor_native(const AnyValue &lhs, const AnyValue &rhs) { return bitwise_xor_native(NumberOperators::ToInt32(lhs), NumberOperators::ToInt32(rhs)); }
|
|
332
|
+
inline double bitwise_xor_native(const AnyValue &lhs, const double &rhs) { return bitwise_xor_native(NumberOperators::ToInt32(lhs), rhs); }
|
|
333
|
+
inline double bitwise_xor_native(const double &lhs, const AnyValue &rhs) { return bitwise_xor_native(lhs, NumberOperators::ToInt32(rhs)); }
|
|
334
334
|
|
|
335
335
|
inline double left_shift_native(const double &lhs, const double &rhs)
|
|
336
336
|
{
|
|
337
337
|
return static_cast<double>(static_cast<int32_t>(lhs) << (static_cast<int32_t>(rhs) & 0x1F));
|
|
338
338
|
}
|
|
339
|
-
inline double left_shift_native(const AnyValue &lhs, const AnyValue &rhs) { return left_shift_native(
|
|
340
|
-
inline double left_shift_native(const AnyValue &lhs, const double &rhs) { return left_shift_native(
|
|
341
|
-
inline double left_shift_native(const double &lhs, const AnyValue &rhs) { return left_shift_native(lhs,
|
|
339
|
+
inline double left_shift_native(const AnyValue &lhs, const AnyValue &rhs) { return left_shift_native(NumberOperators::ToInt32(lhs), NumberOperators::ToInt32(rhs)); }
|
|
340
|
+
inline double left_shift_native(const AnyValue &lhs, const double &rhs) { return left_shift_native(NumberOperators::ToInt32(lhs), rhs); }
|
|
341
|
+
inline double left_shift_native(const double &lhs, const AnyValue &rhs) { return left_shift_native(lhs, NumberOperators::ToInt32(rhs)); }
|
|
342
342
|
|
|
343
343
|
inline double right_shift_native(const double &lhs, const double &rhs)
|
|
344
344
|
{
|
|
345
345
|
return static_cast<double>(static_cast<int32_t>(lhs) >> (static_cast<int32_t>(rhs) & 0x1F));
|
|
346
346
|
}
|
|
347
|
-
inline double right_shift_native(const AnyValue &lhs, const AnyValue &rhs) { return right_shift_native(
|
|
348
|
-
inline double right_shift_native(const AnyValue &lhs, const double &rhs) { return right_shift_native(
|
|
349
|
-
inline double right_shift_native(const double &lhs, const AnyValue &rhs) { return right_shift_native(lhs,
|
|
347
|
+
inline double right_shift_native(const AnyValue &lhs, const AnyValue &rhs) { return right_shift_native(NumberOperators::ToInt32(lhs), NumberOperators::ToInt32(rhs)); }
|
|
348
|
+
inline double right_shift_native(const AnyValue &lhs, const double &rhs) { return right_shift_native(NumberOperators::ToInt32(lhs), rhs); }
|
|
349
|
+
inline double right_shift_native(const double &lhs, const AnyValue &rhs) { return right_shift_native(lhs, NumberOperators::ToInt32(rhs)); }
|
|
350
350
|
|
|
351
351
|
inline double unsigned_right_shift_native(const double &lhs, const double &rhs)
|
|
352
352
|
{
|
|
353
353
|
uint32_t l = static_cast<uint32_t>(fmod(lhs, 4294967296.0));
|
|
354
354
|
return static_cast<double>(l >> (static_cast<int32_t>(rhs) & 0x1F));
|
|
355
355
|
}
|
|
356
|
-
inline double unsigned_right_shift_native(const AnyValue &lhs, const AnyValue &rhs) { return unsigned_right_shift_native(
|
|
357
|
-
inline double unsigned_right_shift_native(const AnyValue &lhs, const double &rhs) { return unsigned_right_shift_native(
|
|
358
|
-
inline double unsigned_right_shift_native(const double &lhs, const AnyValue &rhs) { return unsigned_right_shift_native(lhs,
|
|
356
|
+
inline double unsigned_right_shift_native(const AnyValue &lhs, const AnyValue &rhs) { return unsigned_right_shift_native(NumberOperators::ToUint32(lhs), NumberOperators::ToInt32(rhs)); }
|
|
357
|
+
inline double unsigned_right_shift_native(const AnyValue &lhs, const double &rhs) { return unsigned_right_shift_native(NumberOperators::ToUint32(lhs), rhs); }
|
|
358
|
+
inline double unsigned_right_shift_native(const double &lhs, const AnyValue &rhs) { return unsigned_right_shift_native(lhs, NumberOperators::ToInt32(rhs)); }
|
|
359
359
|
|
|
360
360
|
}
|
|
@@ -286,7 +286,7 @@ AnyValue &get_length_desc()
|
|
|
286
286
|
|
|
287
287
|
auto self = thisVal.as_array();
|
|
288
288
|
const auto &new_len_val = args[0];
|
|
289
|
-
double new_len_double =
|
|
289
|
+
double new_len_double = NumberOperators::ToDouble(new_len_val);
|
|
290
290
|
|
|
291
291
|
if (new_len_double < 0 || std::isnan(new_len_double) || std::isinf(new_len_double) || new_len_double != static_cast<uint64_t>(new_len_double))
|
|
292
292
|
{
|
|
@@ -484,7 +484,7 @@ AnyValue &get_at_fn()
|
|
|
484
484
|
{
|
|
485
485
|
auto self = thisVal.as_array();
|
|
486
486
|
double len = static_cast<double>(self->length);
|
|
487
|
-
double relativeIndex = args.empty() ? 0 :
|
|
487
|
+
double relativeIndex = args.empty() ? 0 : NumberOperators::ToDouble(args[0]);
|
|
488
488
|
double k;
|
|
489
489
|
if (relativeIndex >= 0) k = relativeIndex;
|
|
490
490
|
else k = len + relativeIndex;
|
|
@@ -502,7 +502,7 @@ AnyValue &get_includes_fn()
|
|
|
502
502
|
AnyValue searchElement = args.empty() ? Constants::UNDEFINED : args[0];
|
|
503
503
|
double len = static_cast<double>(self->length);
|
|
504
504
|
if (len == 0) return Constants::FALSE;
|
|
505
|
-
double n = (args.size() > 1) ?
|
|
505
|
+
double n = (args.size() > 1) ? NumberOperators::ToDouble(args[1]) : 0;
|
|
506
506
|
double k;
|
|
507
507
|
if (n >= 0) k = n;
|
|
508
508
|
else k = len + n;
|
|
@@ -528,7 +528,7 @@ AnyValue &get_indexOf_fn()
|
|
|
528
528
|
AnyValue searchElement = args.empty() ? Constants::UNDEFINED : args[0];
|
|
529
529
|
double len = static_cast<double>(self->length);
|
|
530
530
|
if (len == 0) return AnyValue::make_number(-1);
|
|
531
|
-
double n = (args.size() > 1) ?
|
|
531
|
+
double n = (args.size() > 1) ? NumberOperators::ToDouble(args[1]) : 0;
|
|
532
532
|
double k;
|
|
533
533
|
if (n >= 0) k = n;
|
|
534
534
|
else k = len + n;
|
|
@@ -554,7 +554,7 @@ AnyValue &get_lastIndexOf_fn()
|
|
|
554
554
|
AnyValue searchElement = args.empty() ? Constants::UNDEFINED : args[0];
|
|
555
555
|
double len = static_cast<double>(self->length);
|
|
556
556
|
if (len == 0) return AnyValue::make_number(-1);
|
|
557
|
-
double n = (args.size() > 1) ?
|
|
557
|
+
double n = (args.size() > 1) ? NumberOperators::ToDouble(args[1]) : len - 1;
|
|
558
558
|
double k;
|
|
559
559
|
if (n >= 0) k = std::min(n, len - 1);
|
|
560
560
|
else k = len + n;
|
|
@@ -897,7 +897,7 @@ AnyValue &get_flat_fn()
|
|
|
897
897
|
static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
898
898
|
{
|
|
899
899
|
auto self = thisVal.as_array();
|
|
900
|
-
double depthVal = (args.size() > 0 && !args[0].is_undefined()) ?
|
|
900
|
+
double depthVal = (args.size() > 0 && !args[0].is_undefined()) ? NumberOperators::ToDouble(args[0]) : 1;
|
|
901
901
|
int depth = static_cast<int>(depthVal);
|
|
902
902
|
if (depth < 0) depth = 0;
|
|
903
903
|
|
|
@@ -968,8 +968,8 @@ AnyValue &get_fill_fn()
|
|
|
968
968
|
auto self = thisVal.as_array();
|
|
969
969
|
AnyValue value = args.empty() ? Constants::UNDEFINED : args[0];
|
|
970
970
|
double len = static_cast<double>(self->length);
|
|
971
|
-
double start = (args.size() > 1) ?
|
|
972
|
-
double end = (args.size() > 2 && !args[2].is_undefined()) ?
|
|
971
|
+
double start = (args.size() > 1) ? NumberOperators::ToDouble(args[1]) : 0;
|
|
972
|
+
double end = (args.size() > 2 && !args[2].is_undefined()) ? NumberOperators::ToDouble(args[2]) : len;
|
|
973
973
|
|
|
974
974
|
double k;
|
|
975
975
|
if (start >= 0) k = start; else k = len + start;
|
|
@@ -1041,7 +1041,7 @@ AnyValue &get_sort_fn()
|
|
|
1041
1041
|
|
|
1042
1042
|
if (compareFn.is_function()) {
|
|
1043
1043
|
const AnyValue cmpArgs[] = {a, b};
|
|
1044
|
-
double res =
|
|
1044
|
+
double res = NumberOperators::ToDouble(compareFn.call(Constants::UNDEFINED, std::span<const AnyValue>(cmpArgs, 2)));
|
|
1045
1045
|
return res < 0;
|
|
1046
1046
|
} else {
|
|
1047
1047
|
std::string sA = a.to_std_string();
|
|
@@ -1069,13 +1069,13 @@ AnyValue &get_splice_fn()
|
|
|
1069
1069
|
{
|
|
1070
1070
|
auto self = thisVal.as_array();
|
|
1071
1071
|
double len = static_cast<double>(self->length);
|
|
1072
|
-
double start = args.empty() ? 0 :
|
|
1072
|
+
double start = args.empty() ? 0 : NumberOperators::ToDouble(args[0]);
|
|
1073
1073
|
double actualStart = (start < 0) ? std::max(len + start, 0.0) : std::min(start, len);
|
|
1074
1074
|
|
|
1075
1075
|
uint64_t startIdx = static_cast<uint64_t>(actualStart);
|
|
1076
1076
|
uint64_t deleteCount = 0;
|
|
1077
1077
|
if (args.size() >= 2) {
|
|
1078
|
-
double dc =
|
|
1078
|
+
double dc = NumberOperators::ToDouble(args[1]);
|
|
1079
1079
|
deleteCount = static_cast<uint64_t>(std::max(0.0, std::min(dc, len - startIdx)));
|
|
1080
1080
|
} else if (args.size() == 1) {
|
|
1081
1081
|
deleteCount = len - startIdx;
|
|
@@ -1141,9 +1141,9 @@ AnyValue &get_copyWithin_fn()
|
|
|
1141
1141
|
{
|
|
1142
1142
|
auto self = thisVal.as_array();
|
|
1143
1143
|
double len = static_cast<double>(self->length);
|
|
1144
|
-
double target = args.empty() ? 0 :
|
|
1145
|
-
double start = (args.size() > 1) ?
|
|
1146
|
-
double end = (args.size() > 2 && !args[2].is_undefined()) ?
|
|
1144
|
+
double target = args.empty() ? 0 : NumberOperators::ToDouble(args[0]);
|
|
1145
|
+
double start = (args.size() > 1) ? NumberOperators::ToDouble(args[1]) : 0;
|
|
1146
|
+
double end = (args.size() > 2 && !args[2].is_undefined()) ? NumberOperators::ToDouble(args[2]) : len;
|
|
1147
1147
|
|
|
1148
1148
|
double to;
|
|
1149
1149
|
if (target >= 0) to = target; else to = len + target;
|
|
@@ -1239,9 +1239,9 @@ AnyValue &get_slice_fn()
|
|
|
1239
1239
|
{
|
|
1240
1240
|
auto self = thisVal.as_array();
|
|
1241
1241
|
double len = static_cast<double>(self->length);
|
|
1242
|
-
double start = args.empty() ? 0 :
|
|
1242
|
+
double start = args.empty() ? 0 : NumberOperators::ToDouble(args[0]);
|
|
1243
1243
|
double actualStart = (start < 0) ? std::max(len + start, 0.0) : std::min(start, len);
|
|
1244
|
-
double end = (args.size() < 2 || args[1].is_undefined()) ? len :
|
|
1244
|
+
double end = (args.size() < 2 || args[1].is_undefined()) ? len : NumberOperators::ToDouble(args[1]);
|
|
1245
1245
|
double actualEnd = (end < 0) ? std::max(len + end, 0.0) : std::min(end, len);
|
|
1246
1246
|
|
|
1247
1247
|
std::vector<AnyValue> result;
|
|
@@ -1298,7 +1298,7 @@ AnyValue &get_with_fn()
|
|
|
1298
1298
|
auto copy = thisVal.get_property_with_receiver("slice", thisVal).call(thisVal, {});
|
|
1299
1299
|
|
|
1300
1300
|
double len = static_cast<double>(self->length);
|
|
1301
|
-
double idx = args.empty() ? 0 :
|
|
1301
|
+
double idx = args.empty() ? 0 : NumberOperators::ToDouble(args[0]);
|
|
1302
1302
|
double k;
|
|
1303
1303
|
if (idx >= 0) k = idx; else k = len + idx;
|
|
1304
1304
|
|
|
@@ -87,7 +87,7 @@ namespace jspp
|
|
|
87
87
|
int digits = -1;
|
|
88
88
|
if (!args.empty() && !args[0].is_undefined())
|
|
89
89
|
{
|
|
90
|
-
digits =
|
|
90
|
+
digits = NumberOperators::ToInt32(args[0]);
|
|
91
91
|
if (digits < 0 || digits > 100)
|
|
92
92
|
{
|
|
93
93
|
throw Exception::make_exception("toExponential() digits argument must be between 0 and 100", "RangeError");
|
|
@@ -118,7 +118,7 @@ namespace jspp
|
|
|
118
118
|
int digits = 0;
|
|
119
119
|
if (!args.empty() && !args[0].is_undefined())
|
|
120
120
|
{
|
|
121
|
-
digits =
|
|
121
|
+
digits = NumberOperators::ToInt32(args[0]);
|
|
122
122
|
}
|
|
123
123
|
if (digits < 0 || digits > 100)
|
|
124
124
|
{
|
|
@@ -141,7 +141,7 @@ namespace jspp
|
|
|
141
141
|
{
|
|
142
142
|
return AnyValue::make_number(self).get_own_property("toString").call(AnyValue::make_number(self), {}, "toString");
|
|
143
143
|
}
|
|
144
|
-
int precision =
|
|
144
|
+
int precision = NumberOperators::ToInt32(args[0]);
|
|
145
145
|
if (precision < 1 || precision > 100)
|
|
146
146
|
{
|
|
147
147
|
throw Exception::make_exception("toPrecision() precision argument must be between 1 and 100", "RangeError");
|
|
@@ -162,7 +162,7 @@ namespace jspp
|
|
|
162
162
|
int radix = 10;
|
|
163
163
|
if (!args.empty() && !args[0].is_undefined())
|
|
164
164
|
{
|
|
165
|
-
radix =
|
|
165
|
+
radix = NumberOperators::ToInt32(args[0]);
|
|
166
166
|
}
|
|
167
167
|
if (radix < 2 || radix > 36)
|
|
168
168
|
{
|
|
@@ -92,7 +92,7 @@ AnyValue &get_charAt_fn()
|
|
|
92
92
|
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
93
93
|
{
|
|
94
94
|
auto self = thisVal.as_string();
|
|
95
|
-
double pos = args.empty() ? 0 :
|
|
95
|
+
double pos = args.empty() ? 0 : NumberOperators::ToDouble(args[0]);
|
|
96
96
|
int index = static_cast<int>(pos);
|
|
97
97
|
if (index < 0 || index >= self->value.length())
|
|
98
98
|
{
|
|
@@ -125,7 +125,7 @@ AnyValue &get_endsWith_fn()
|
|
|
125
125
|
if (args.empty())
|
|
126
126
|
return Constants::FALSE;
|
|
127
127
|
std::string search = args[0].to_std_string();
|
|
128
|
-
size_t end_pos = (args.size() > 1 && !args[1].is_undefined()) ? static_cast<size_t>(
|
|
128
|
+
size_t end_pos = (args.size() > 1 && !args[1].is_undefined()) ? static_cast<size_t>(NumberOperators::ToDouble(args[1])) : self->value.length();
|
|
129
129
|
|
|
130
130
|
if (end_pos > self->value.length())
|
|
131
131
|
end_pos = self->value.length();
|
|
@@ -145,7 +145,7 @@ AnyValue &get_includes_fn()
|
|
|
145
145
|
if (args.empty())
|
|
146
146
|
return Constants::FALSE;
|
|
147
147
|
std::string search = args[0].to_std_string();
|
|
148
|
-
size_t pos = (args.size() > 1) ? static_cast<size_t>(
|
|
148
|
+
size_t pos = (args.size() > 1) ? static_cast<size_t>(NumberOperators::ToDouble(args[1])) : 0;
|
|
149
149
|
|
|
150
150
|
return AnyValue::make_boolean(self->value.find(search, pos) != std::string::npos); },
|
|
151
151
|
"includes");
|
|
@@ -160,7 +160,7 @@ AnyValue &get_indexOf_fn()
|
|
|
160
160
|
if (args.empty())
|
|
161
161
|
return AnyValue::make_number(-1);
|
|
162
162
|
std::string search = args[0].to_std_string();
|
|
163
|
-
size_t pos = (args.size() > 1) ? static_cast<size_t>(
|
|
163
|
+
size_t pos = (args.size() > 1) ? static_cast<size_t>(NumberOperators::ToDouble(args[1])) : 0;
|
|
164
164
|
size_t result = self->value.find(search, pos);
|
|
165
165
|
return result == std::string::npos ? AnyValue::make_number(-1) : AnyValue::make_number(result); },
|
|
166
166
|
"indexOf");
|
|
@@ -175,7 +175,7 @@ AnyValue &get_lastIndexOf_fn()
|
|
|
175
175
|
if (args.empty())
|
|
176
176
|
return AnyValue::make_number(-1);
|
|
177
177
|
std::string search = args[0].to_std_string();
|
|
178
|
-
size_t pos = (args.size() > 1 && !args[1].is_undefined()) ? static_cast<size_t>(
|
|
178
|
+
size_t pos = (args.size() > 1 && !args[1].is_undefined()) ? static_cast<size_t>(NumberOperators::ToDouble(args[1])) : std::string::npos;
|
|
179
179
|
size_t result = self->value.rfind(search, pos);
|
|
180
180
|
return result == std::string::npos ? AnyValue::make_number(-1) : AnyValue::make_number(result); },
|
|
181
181
|
"lastIndexOf");
|
|
@@ -187,7 +187,7 @@ AnyValue &get_padEnd_fn()
|
|
|
187
187
|
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
188
188
|
{
|
|
189
189
|
auto self = thisVal.as_string();
|
|
190
|
-
size_t target_length = args.empty() ? 0 : static_cast<size_t>(
|
|
190
|
+
size_t target_length = args.empty() ? 0 : static_cast<size_t>(NumberOperators::ToDouble(args[0]));
|
|
191
191
|
if (self->value.length() >= target_length)
|
|
192
192
|
return AnyValue::make_string(self->value);
|
|
193
193
|
std::string pad_string = (args.size() > 1 && !args[1].is_undefined() && !args[1].to_std_string().empty()) ? args[1].to_std_string() : " ";
|
|
@@ -206,7 +206,7 @@ AnyValue &get_padStart_fn()
|
|
|
206
206
|
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
207
207
|
{
|
|
208
208
|
auto self = thisVal.as_string();
|
|
209
|
-
size_t target_length = args.empty() ? 0 : static_cast<size_t>(
|
|
209
|
+
size_t target_length = args.empty() ? 0 : static_cast<size_t>(NumberOperators::ToDouble(args[0]));
|
|
210
210
|
if (self->value.length() >= target_length)
|
|
211
211
|
return AnyValue::make_string(self->value);
|
|
212
212
|
std::string pad_string = (args.size() > 1 && !args[1].is_undefined() && !args[1].to_std_string().empty()) ? args[1].to_std_string() : " ";
|
|
@@ -225,7 +225,7 @@ AnyValue &get_repeat_fn()
|
|
|
225
225
|
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
226
226
|
{
|
|
227
227
|
auto self = thisVal.as_string();
|
|
228
|
-
double count = args.empty() ? 0 :
|
|
228
|
+
double count = args.empty() ? 0 : NumberOperators::ToDouble(args[0]);
|
|
229
229
|
if (count < 0)
|
|
230
230
|
{
|
|
231
231
|
// In a real implementation, this should throw a RangeError.
|
|
@@ -290,8 +290,8 @@ AnyValue &get_slice_fn()
|
|
|
290
290
|
{
|
|
291
291
|
auto self = thisVal.as_string();
|
|
292
292
|
int len = self->value.length();
|
|
293
|
-
int start = args.empty() ? 0 :
|
|
294
|
-
int end = (args.size() < 2 || args[1].is_undefined()) ? len :
|
|
293
|
+
int start = args.empty() ? 0 : NumberOperators::ToInt32(args[0]);
|
|
294
|
+
int end = (args.size() < 2 || args[1].is_undefined()) ? len : NumberOperators::ToInt32(args[1]);
|
|
295
295
|
|
|
296
296
|
if (start < 0)
|
|
297
297
|
start += len;
|
|
@@ -347,7 +347,7 @@ AnyValue &get_startsWith_fn()
|
|
|
347
347
|
if (args.empty())
|
|
348
348
|
return Constants::FALSE;
|
|
349
349
|
std::string search = args[0].to_std_string();
|
|
350
|
-
size_t pos = (args.size() > 1) ? static_cast<size_t>(
|
|
350
|
+
size_t pos = (args.size() > 1) ? static_cast<size_t>(NumberOperators::ToDouble(args[1])) : 0;
|
|
351
351
|
if (pos > self->value.length())
|
|
352
352
|
pos = self->value.length();
|
|
353
353
|
|
|
@@ -362,8 +362,8 @@ AnyValue &get_substring_fn()
|
|
|
362
362
|
{
|
|
363
363
|
auto self = thisVal.as_string();
|
|
364
364
|
int len = self->value.length();
|
|
365
|
-
int start = args.empty() ? 0 :
|
|
366
|
-
int end = (args.size() < 2 || args[1].is_undefined()) ? len :
|
|
365
|
+
int start = args.empty() ? 0 : NumberOperators::ToInt32(args[0]);
|
|
366
|
+
int end = (args.size() < 2 || args[1].is_undefined()) ? len : NumberOperators::ToInt32(args[1]);
|
|
367
367
|
|
|
368
368
|
start = std::max(0, start);
|
|
369
369
|
end = std::max(0, end);
|