docs: public static double toNumber(String s) {
          final int len = s.length();
  
          // Skip whitespace at the start
          int start = 0;
          char startChar;
          for (;;) {
              if (start == len) {
                  // empty or contains only whitespace
                  return +0.0;
              }
              startChar = s.charAt(start);
              if (!ScriptRuntime.isStrWhiteSpaceChar(startChar)) {
                  // found first non-whitespace character
                  break;
              }
              start++;
          }
  
          // Skip whitespace at the end
          int end = len - 1;
          char endChar;
          while (ScriptRuntime.isStrWhiteSpaceChar(endChar = s.charAt(end))) {
              end--;
          }
  
          // Do not break scripts relying on old non-compliant conversion
          // (see bug #368)
          // 1. makes ToNumber parse only a valid prefix in hex literals (similar to 'parseInt()')
          //    ToNumber('0x10 something') => 16
          // 2. allows plus and minus signs for hexadecimal numbers
          //    ToNumber('-0x10') => -16
          // 3. disables support for binary ('0b10') and octal ('0o13') literals
          //    ToNumber('0b1') => NaN
          //    ToNumber('0o5') => NaN
          final Context cx = Context.getCurrentContext();
          final boolean oldParsingMode =
                  cx == null || cx.getLanguageVersion() < Context.VERSION_ES6;
  
          // Handle non-base10 numbers
          if (startChar == '0') {
              if (start + 2 <= end) {
                  final char radixC = s.charAt(start + 1);
                  int radix = -1;
                  if (radixC == 'x' || radixC == 'X') {
                      radix = 16;
                  } else if (!oldParsingMode && (radixC == 'o' || radixC == 'O')) {
                      radix = 8;
                  } else if (!oldParsingMode && (radixC == 'b' || radixC == 'B')) {
                      radix = 2;
                  }
                  if (radix != -1) {
                      if (oldParsingMode) {
                          return stringPrefixToNumber(s, start + 2, radix);
                      }
                      return stringToNumber(s, start + 2, end, radix);
                  }
              }
          } else if (oldParsingMode && (startChar == '+' || startChar == '-')) {
              // If in old parsing mode, check for a signed hexadecimal number
              if (start + 3 <= end && s.charAt(start + 1) == '0') {
                  final char radixC = s.charAt(start + 2);
                  if (radixC == 'x' || radixC == 'X') {
                      double val = stringPrefixToNumber(s, start + 3, 16);
                      return startChar == '-' ? -val : val;
                  }
              }
          }
  
          if (endChar == 'y') {
              // check for "Infinity"
              if (startChar == '+' || startChar == '-') {
                  start++;
              }
              if (start + 7 == end && s.regionMatches(start, "Infinity", 0, 8)) {
                  return startChar == '-'
                          ? Double.NEGATIVE_INFINITY
                          : Double.POSITIVE_INFINITY;
              }
              return NaN;
          }
          // A base10, non-infinity number:
          // just try a normal floating point conversion
          String sub = s.substring(start, end+1);
          // Quick test to check string contains only valid characters because
          // Double.parseDouble() can be slow and accept input we want to reject
          for (int i = sub.length() - 1; i >= 0; i--) {
              char c = sub.charAt(i);
              if (('0' <= c && c <= '9') || c == '.' ||
                      c == 'e' || c == 'E'  ||
                      c == '+' || c == '-')
                  continue;
              return NaN;
          }
          try {
              return Double.parseDouble(sub);
          } catch (NumberFormatException ex) {
              return NaN;
          }
      }