+ // Skip leading white space.
+ for (; characters < endCharacters; ++characters) {
+ if (!isStrWhiteSpace(*characters))
+ break;
+ }
+
+ // Empty string.
+ if (characters == endCharacters)
+ return 0.0;
+
+ double number;
+ if (characters[0] == '0' && characters + 2 < endCharacters && (characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2]))
+ number = jsHexIntegerLiteral(characters, endCharacters);
+ else
+ number = jsStrDecimalLiteral(characters, endCharacters);
+
+ // Allow trailing white space.
+ for (; characters < endCharacters; ++characters) {
+ if (!isStrWhiteSpace(*characters))
+ break;
+ }
+ if (characters != endCharacters)
+ return QNaN;
+
+ return number;
+}
+
+// See ecma-262 9.3.1
+double jsToNumber(const String& s)
+{
+ unsigned size = s.length();
+
+ if (size == 1) {
+ UChar c = s[0];
+ if (isASCIIDigit(c))
+ return c - '0';
+ if (isStrWhiteSpace(c))
+ return 0;
+ return QNaN;
+ }
+
+ if (s.is8Bit())
+ return toDouble(s.characters8(), size);
+ return toDouble(s.characters16(), size);
+}
+
+static double parseFloat(const String& s)
+{
+ unsigned size = s.length();
+
+ if (size == 1) {
+ UChar c = s[0];
+ if (isASCIIDigit(c))
+ return c - '0';
+ return QNaN;
+ }
+
+ if (s.is8Bit()) {
+ const LChar* data = s.characters8();
+ const LChar* end = data + size;
+
+ // Skip leading white space.
+ for (; data < end; ++data) {
+ if (!isStrWhiteSpace(*data))
+ break;
+ }
+
+ // Empty string.
+ if (data == end)
+ return QNaN;
+
+ return jsStrDecimalLiteral(data, end);
+ }
+
+ const UChar* data = s.characters16();
+ const UChar* end = data + size;
+
+ // Skip leading white space.
+ for (; data < end; ++data) {
+ if (!isStrWhiteSpace(*data))
+ break;
+ }
+
+ // Empty string.
+ if (data == end)
+ return QNaN;
+
+ return jsStrDecimalLiteral(data, end);
+}