+static double parseInt(const UString& s, int radix)
+{
+ if (s.is8Bit())
+ return parseInt(s, s.characters8(), radix);
+ return parseInt(s, s.characters16(), radix);
+}
+
+static const int SizeOfInfinity = 8;
+
+template <typename CharType>
+static bool isInfinity(const CharType* data, const CharType* end)
+{
+ return (end - data) >= SizeOfInfinity
+ && data[0] == 'I'
+ && data[1] == 'n'
+ && data[2] == 'f'
+ && data[3] == 'i'
+ && data[4] == 'n'
+ && data[5] == 'i'
+ && data[6] == 't'
+ && data[7] == 'y';
+}
+
+// See ecma-262 9.3.1
+template <typename CharType>
+static double jsHexIntegerLiteral(const CharType*& data, const CharType* end)
+{
+ // Hex number.
+ data += 2;
+ const CharType* firstDigitPosition = data;
+ double number = 0;
+ while (true) {
+ number = number * 16 + toASCIIHexValue(*data);
+ ++data;
+ if (data == end)
+ break;
+ if (!isASCIIHexDigit(*data))
+ break;
+ }
+ if (number >= mantissaOverflowLowerBound)
+ number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 16);
+
+ return number;
+}
+
+// See ecma-262 9.3.1
+template <typename CharType>
+static double jsStrDecimalLiteral(const CharType*& data, const CharType* end)
+{
+ ASSERT(data < end);
+
+ size_t parsedLength;
+ double number = parseDouble(data, end - data, parsedLength);
+ if (parsedLength) {
+ data += parsedLength;
+ return number;
+ }
+
+ // Check for [+-]?Infinity
+ switch (*data) {
+ case 'I':
+ if (isInfinity(data, end)) {
+ data += SizeOfInfinity;
+ return std::numeric_limits<double>::infinity();
+ }
+ break;
+
+ case '+':
+ if (isInfinity(data + 1, end)) {
+ data += SizeOfInfinity + 1;
+ return std::numeric_limits<double>::infinity();
+ }
+ break;
+
+ case '-':
+ if (isInfinity(data + 1, end)) {
+ data += SizeOfInfinity + 1;
+ return -std::numeric_limits<double>::infinity();
+ }
+ break;
+ }
+
+ // Not a number.
+ return std::numeric_limits<double>::quiet_NaN();
+}
+
+template <typename CharType>
+static double toDouble(const CharType* characters, unsigned size)
+{
+ const CharType* endCharacters = characters + size;
+
+ // 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 std::numeric_limits<double>::quiet_NaN();
+
+ return number;
+}
+
+// See ecma-262 9.3.1
+double jsToNumber(const UString& s)
+{
+ unsigned size = s.length();
+
+ if (size == 1) {
+ UChar c = s[0];
+ if (isASCIIDigit(c))
+ return c - '0';
+ if (isStrWhiteSpace(c))
+ return 0;
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+
+ if (s.is8Bit())
+ return toDouble(s.characters8(), size);
+ return toDouble(s.characters16(), size);
+}
+