@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 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 precompile the runtime headers and library.*
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,
@@ -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}${path.basename(exeFilePath)}${COLORS.reset} ${COLORS.dim}[${compileTime}]${COLORS.reset}`);
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
- await runOutput(exeFilePath, scriptArgs, isWasm);
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
- ClassDeclaration: {
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, parent) => {
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 generateParamsBuilder = () => {
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 initValue = `${argsName}.size() > ${i} ? ${argsName}[${i}] : ${defaultValue}`;
156
- if (typeInfo?.needsHeapAllocation) {
157
- paramsCode +=
158
- `${this.indent()}auto ${name} = std::make_shared<jspp::AnyValue>(${initValue});\n`;
159
- }
160
- else {
161
- paramsCode +=
162
- `${this.indent()}jspp::AnyValue ${name} = ${initValue};\n`;
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 += generateParamsBuilder();
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 += generateParamsBuilder();
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::Operators_Private::ToNumber(res);\n`;
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 exprReturnType = this.typeAnalyzer.inferNodeReturnType(expr);
827
- if (exprReturnType === "number" &&
828
- context.isInsideNativeLambda &&
829
- context.isInsideFunction) {
830
- const funcDecl = this
831
- .findEnclosingFunctionDeclarationFromReturnStatement(expr);
832
- if (funcDecl) {
833
- const funcReturnType = this.typeAnalyzer
834
- .inferFunctionReturnType(funcDecl);
835
- if (funcReturnType === "number") {
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 nodeKind = ts.SyntaxKind[node.kind];
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",
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 && bun run scripts/precompile-headers.ts --mode debug",
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::Operators_Private::ToUint32(lenVal));
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::Operators_Private::ToUint32(lenVal));
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 Operators_Private::ToNumber(args[index]);
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 = Operators_Private::ToInt32(args.empty() ? Constants::UNDEFINED : args[0]);
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 = Operators_Private::ToNumber(arg);
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 = Operators_Private::ToInt32(args.empty() ? Constants::UNDEFINED : args[0]);
131
- int32_t b = Operators_Private::ToInt32(args.size() < 2 ? Constants::UNDEFINED : args[1]);
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 = Operators_Private::ToNumber(arg);
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 = Operators_Private::ToNumber(arg);
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 = Operators_Private::ToNumber(nextRes.get_own_property("value"));
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(Operators_Private::ToNumber(val));
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(-Operators_Private::ToNumber(val));
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(~Operators_Private::ToInt32(val));
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 Operators_Private
15
+ namespace NumberOperators
16
16
  {
17
- // Implements the ToNumber abstract operation from ECMA-262.
18
- inline double ToNumber(const AnyValue &val)
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 = ToNumber(val);
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 = ToNumber(val);
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 Operators_Private::ToNumber(val); }
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 -Operators_Private::ToNumber(val); }
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>(~Operators_Private::ToInt32(val)); }
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() == Operators_Private::ToNumber(rhs);
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 Operators_Private::ToNumber(lhs) == rhs.as_double();
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 Operators_Private::ToNumber(lhs) + Operators_Private::ToNumber(rhs); }
251
- inline double add_native(const AnyValue &lhs, const double &rhs) { return Operators_Private::ToNumber(lhs) + rhs; }
252
- inline double add_native(const double &lhs, const AnyValue &rhs) { return lhs + Operators_Private::ToNumber(rhs); }
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 Operators_Private::ToNumber(lhs) - Operators_Private::ToNumber(rhs); }
256
- inline double sub_native(const AnyValue &lhs, const double &rhs) { return Operators_Private::ToNumber(lhs) - rhs; }
257
- inline double sub_native(const double &lhs, const AnyValue &rhs) { return lhs - Operators_Private::ToNumber(rhs); }
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 Operators_Private::ToNumber(lhs) * Operators_Private::ToNumber(rhs); }
261
- inline double mul_native(const AnyValue &lhs, const double &rhs) { return Operators_Private::ToNumber(lhs) * rhs; }
262
- inline double mul_native(const double &lhs, const AnyValue &rhs) { return lhs * Operators_Private::ToNumber(rhs); }
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 Operators_Private::ToNumber(lhs) / Operators_Private::ToNumber(rhs); }
266
- inline double div_native(const AnyValue &lhs, const double &rhs) { return Operators_Private::ToNumber(lhs) / rhs; }
267
- inline double div_native(const double &lhs, const AnyValue &rhs) { return lhs / Operators_Private::ToNumber(rhs); }
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(Operators_Private::ToNumber(lhs), Operators_Private::ToNumber(rhs)); }
271
- inline double mod_native(const AnyValue &lhs, const double &rhs) { return std::fmod(Operators_Private::ToNumber(lhs), rhs); }
272
- inline double mod_native(const double &lhs, const AnyValue &rhs) { return std::fmod(lhs, Operators_Private::ToNumber(rhs)); }
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(Operators_Private::ToNumber(lhs), Operators_Private::ToNumber(rhs)); }
276
- inline double pow_native(const AnyValue &lhs, const double &rhs) { return std::pow(Operators_Private::ToNumber(lhs), rhs); }
277
- inline double pow_native(const double &lhs, const AnyValue &rhs) { return std::pow(lhs, Operators_Private::ToNumber(rhs)); }
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(Operators_Private::ToNumber(lhs), Operators_Private::ToNumber(rhs)); }
282
- inline bool less_than_native(const AnyValue &lhs, const double &rhs) { return less_than_native(Operators_Private::ToNumber(lhs), rhs); }
283
- inline bool less_than_native(const double &lhs, const AnyValue &rhs) { return less_than_native(lhs, Operators_Private::ToNumber(rhs)); }
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(Operators_Private::ToNumber(lhs), Operators_Private::ToNumber(rhs)); }
287
- inline bool greater_than_native(const AnyValue &lhs, const double &rhs) { return greater_than_native(Operators_Private::ToNumber(lhs), rhs); }
288
- inline bool greater_than_native(const double &lhs, const AnyValue &rhs) { return greater_than_native(lhs, Operators_Private::ToNumber(rhs)); }
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(Operators_Private::ToNumber(lhs), Operators_Private::ToNumber(rhs)); }
292
- inline bool less_than_or_equal_native(const AnyValue &lhs, const double &rhs) { return less_than_or_equal_native(Operators_Private::ToNumber(lhs), rhs); }
293
- inline bool less_than_or_equal_native(const double &lhs, const AnyValue &rhs) { return less_than_or_equal_native(lhs, Operators_Private::ToNumber(rhs)); }
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(Operators_Private::ToNumber(lhs), Operators_Private::ToNumber(rhs)); }
297
- inline bool greater_than_or_equal_native(const AnyValue &lhs, const double &rhs) { return greater_than_or_equal_native(Operators_Private::ToNumber(lhs), rhs); }
298
- inline bool greater_than_or_equal_native(const double &lhs, const AnyValue &rhs) { return greater_than_or_equal_native(lhs, Operators_Private::ToNumber(rhs)); }
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(Operators_Private::ToNumber(lhs), Operators_Private::ToNumber(rhs)); }
302
- inline bool equal_native(const AnyValue &lhs, const double &rhs) { return equal_native(Operators_Private::ToNumber(lhs), rhs); }
303
- inline bool equal_native(const double &lhs, const AnyValue &rhs) { return equal_native(lhs, Operators_Private::ToNumber(rhs)); }
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(Operators_Private::ToNumber(lhs), Operators_Private::ToNumber(rhs)); }
307
- inline bool not_equal_native(const AnyValue &lhs, const double &rhs) { return not_equal_native(Operators_Private::ToNumber(lhs), rhs); }
308
- inline bool not_equal_native(const double &lhs, const AnyValue &rhs) { return not_equal_native(lhs, Operators_Private::ToNumber(rhs)); }
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(Operators_Private::ToInt32(lhs), Operators_Private::ToInt32(rhs)); }
316
- inline double bitwise_and_native(const AnyValue &lhs, const double &rhs) { return bitwise_and_native(Operators_Private::ToInt32(lhs), rhs); }
317
- inline double bitwise_and_native(const double &lhs, const AnyValue &rhs) { return bitwise_and_native(lhs, Operators_Private::ToInt32(rhs)); }
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(Operators_Private::ToInt32(lhs), Operators_Private::ToInt32(rhs)); }
324
- inline double bitwise_or_native(const AnyValue &lhs, const double &rhs) { return bitwise_or_native(Operators_Private::ToInt32(lhs), rhs); }
325
- inline double bitwise_or_native(const double &lhs, const AnyValue &rhs) { return bitwise_or_native(lhs, Operators_Private::ToInt32(rhs)); }
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(Operators_Private::ToInt32(lhs), Operators_Private::ToInt32(rhs)); }
332
- inline double bitwise_xor_native(const AnyValue &lhs, const double &rhs) { return bitwise_xor_native(Operators_Private::ToInt32(lhs), rhs); }
333
- inline double bitwise_xor_native(const double &lhs, const AnyValue &rhs) { return bitwise_xor_native(lhs, Operators_Private::ToInt32(rhs)); }
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(Operators_Private::ToInt32(lhs), Operators_Private::ToInt32(rhs)); }
340
- inline double left_shift_native(const AnyValue &lhs, const double &rhs) { return left_shift_native(Operators_Private::ToInt32(lhs), rhs); }
341
- inline double left_shift_native(const double &lhs, const AnyValue &rhs) { return left_shift_native(lhs, Operators_Private::ToInt32(rhs)); }
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(Operators_Private::ToInt32(lhs), Operators_Private::ToInt32(rhs)); }
348
- inline double right_shift_native(const AnyValue &lhs, const double &rhs) { return right_shift_native(Operators_Private::ToInt32(lhs), rhs); }
349
- inline double right_shift_native(const double &lhs, const AnyValue &rhs) { return right_shift_native(lhs, Operators_Private::ToInt32(rhs)); }
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(Operators_Private::ToUint32(lhs), Operators_Private::ToInt32(rhs)); }
357
- inline double unsigned_right_shift_native(const AnyValue &lhs, const double &rhs) { return unsigned_right_shift_native(Operators_Private::ToUint32(lhs), rhs); }
358
- inline double unsigned_right_shift_native(const double &lhs, const AnyValue &rhs) { return unsigned_right_shift_native(lhs, Operators_Private::ToInt32(rhs)); }
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 = Operators_Private::ToNumber(new_len_val);
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 : Operators_Private::ToNumber(args[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) ? Operators_Private::ToNumber(args[1]) : 0;
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) ? Operators_Private::ToNumber(args[1]) : 0;
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) ? Operators_Private::ToNumber(args[1]) : len - 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()) ? Operators_Private::ToNumber(args[0]) : 1;
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) ? Operators_Private::ToNumber(args[1]) : 0;
972
- double end = (args.size() > 2 && !args[2].is_undefined()) ? Operators_Private::ToNumber(args[2]) : len;
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 = Operators_Private::ToNumber(compareFn.call(Constants::UNDEFINED, std::span<const AnyValue>(cmpArgs, 2)));
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 : Operators_Private::ToNumber(args[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 = Operators_Private::ToNumber(args[1]);
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 : Operators_Private::ToNumber(args[0]);
1145
- double start = (args.size() > 1) ? Operators_Private::ToNumber(args[1]) : 0;
1146
- double end = (args.size() > 2 && !args[2].is_undefined()) ? Operators_Private::ToNumber(args[2]) : len;
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 : Operators_Private::ToNumber(args[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 : Operators_Private::ToNumber(args[1]);
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 : Operators_Private::ToNumber(args[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 = Operators_Private::ToInt32(args[0]);
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 = Operators_Private::ToInt32(args[0]);
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 = Operators_Private::ToInt32(args[0]);
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 = Operators_Private::ToInt32(args[0]);
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 : Operators_Private::ToNumber(args[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>(Operators_Private::ToNumber(args[1])) : self->value.length();
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>(Operators_Private::ToNumber(args[1])) : 0;
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>(Operators_Private::ToNumber(args[1])) : 0;
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>(Operators_Private::ToNumber(args[1])) : std::string::npos;
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>(Operators_Private::ToNumber(args[0]));
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>(Operators_Private::ToNumber(args[0]));
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 : Operators_Private::ToNumber(args[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 : Operators_Private::ToInt32(args[0]);
294
- int end = (args.size() < 2 || args[1].is_undefined()) ? len : Operators_Private::ToInt32(args[1]);
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>(Operators_Private::ToNumber(args[1])) : 0;
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 : Operators_Private::ToInt32(args[0]);
366
- int end = (args.size() < 2 || args[1].is_undefined()) ? len : Operators_Private::ToInt32(args[1]);
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);