ES6: Add binary and octal literal support
authormsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 14 Mar 2015 16:29:20 +0000 (16:29 +0000)
committermsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 14 Mar 2015 16:29:20 +0000 (16:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142681

Reviewed by Ryosuke Niwa.

Source/JavaScriptCore:

Added a binary literal parser function, parseBinary(), to Lexer patterned after the octal parser.
Refactored the parseBinary, parseOctal and parseDecimal to use a constant size for the number of
characters to try and handle directly. Factored out the shifting past any prefix to be handled by
the caller. Added binary and octal parsing to toDouble() via helper functions.

* parser/Lexer.cpp:
(JSC::Lexer<T>::parseHex):
(JSC::Lexer<T>::parseBinary):
(JSC::Lexer<T>::parseOctal):
(JSC::Lexer<T>::parseDecimal):
(JSC::Lexer<T>::lex):
* parser/Lexer.h:
* parser/ParserTokens.h:
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::jsBinaryIntegerLiteral):
(JSC::jsOctalIntegerLiteral):
(JSC::toDouble):

Source/WTF:

* wtf/ASCIICType.h:
(WTF::isASCIIBinaryDigit): New support function.
(WTF::isASCIIOctalDigit): Updated to use logical and (&&) instead of binary and (&).

LayoutTests:

New tests.

* js/binary-literals-expected.txt: Added.
* js/binary-literals.html: Added.
* js/octal-literals-expected.txt: Added.
* js/octal-literals.html: Added.
* js/script-tests/binary-literals.js: Added.
* js/script-tests/octal-literals.js: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@181497 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
LayoutTests/ChangeLog
LayoutTests/js/binary-literals-expected.txt [new file with mode: 0644]
LayoutTests/js/binary-literals.html [new file with mode: 0644]
LayoutTests/js/octal-literals-expected.txt [new file with mode: 0644]
LayoutTests/js/octal-literals.html [new file with mode: 0644]
LayoutTests/js/script-tests/binary-literals.js [new file with mode: 0644]
LayoutTests/js/script-tests/octal-literals.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/parser/Lexer.cpp
Source/JavaScriptCore/parser/Lexer.h
Source/JavaScriptCore/parser/ParserTokens.h
Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
Source/WTF/ChangeLog
Source/WTF/wtf/ASCIICType.h

index 6aecbc1..434ef8f 100644 (file)
@@ -1,3 +1,19 @@
+2015-03-14  Michael Saboff  <msaboff@apple.com>
+
+        ES6: Add binary and octal literal support
+        https://bugs.webkit.org/show_bug.cgi?id=142681
+
+        Reviewed by Ryosuke Niwa.
+
+        New tests.
+
+        * js/binary-literals-expected.txt: Added.
+        * js/binary-literals.html: Added.
+        * js/octal-literals-expected.txt: Added.
+        * js/octal-literals.html: Added.
+        * js/script-tests/binary-literals.js: Added.
+        * js/script-tests/octal-literals.js: Added.
+
 2015-03-13  Ryosuke Niwa  <rniwa@webkit.org>
 
         Class constructor should throw TypeError when "called"
diff --git a/LayoutTests/js/binary-literals-expected.txt b/LayoutTests/js/binary-literals-expected.txt
new file mode 100644 (file)
index 0000000..f59bfb8
--- /dev/null
@@ -0,0 +1,43 @@
+Make sure that we correctly handle binary literals
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS 0b0 is 0
+PASS 0b1 is 1
+PASS 0B1 is 1
+PASS 0b00000000000000000000000000000000 is 0
+PASS 0B2 threw exception SyntaxError: No binary digits after '0b'.
+PASS 0ba threw exception SyntaxError: No binary digits after '0b'.
+PASS 0b0.0 threw exception SyntaxError: Unexpected number '.0'. Parse error..
+PASS x=0b1y=42 threw exception SyntaxError: No space between binary literal and identifier.
+PASS 0b1010 is 0xa
+PASS 0b00000001001000110100010101100111 is 0x01234567
+PASS 0b10001001101010111100110111101111 is 0x89abcdef
+PASS 0o100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 is 3.00300673152188e+256
+PASS 0b11111111111111111111111111111111111111111111111111110 is 9007199254740990
+PASS 0b11111111111111111111111111111111111111111111111111111 is 9007199254740991
+PASS 0b111111111111111111111111111111111111111111111111111110 is 18014398509481982
+PASS 0b111111111111111111111111111111111111111111111111111111 is 18014398509481984
+PASS !!0b1 is true
+PASS !!0b0 is false
+PASS Number('0b0') is 0
+PASS Number('0b1') is 1
+PASS Number('0B1') is 1
+PASS Number('0b00000000000000000000000000000000') is 0
+PASS Number('0B2') is NaN
+PASS Number('0ba') is NaN
+PASS Number('0b0.0') is NaN
+PASS Number('0b1010') is 0xa
+PASS Number('0b00000001001000110100010101100111') is 0x01234567
+PASS Number('0b10001001101010111100110111101111') is 0x89abcdef
+PASS Number('0b11111111111111111111111111111111111111111111111111110') is 9007199254740990
+PASS Number('0b11111111111111111111111111111111111111111111111111111') is 9007199254740991
+PASS Number('0b111111111111111111111111111111111111111111111111111110') is 18014398509481982
+PASS Number('0b111111111111111111111111111111111111111111111111111111') is 18014398509481984
+PASS !!Number('0b1') is true
+PASS !!Number('0b0') is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/binary-literals.html b/LayoutTests/js/binary-literals.html
new file mode 100644 (file)
index 0000000..7857c4d
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/binary-literals.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/octal-literals-expected.txt b/LayoutTests/js/octal-literals-expected.txt
new file mode 100644 (file)
index 0000000..5b86d1d
--- /dev/null
@@ -0,0 +1,43 @@
+Make sure that we correctly handle octal literals
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS 0o0 is 0
+PASS 0o1 is 1
+PASS 0O1 is 1
+PASS 0o000000000000 is 0
+PASS 0O8 threw exception SyntaxError: No octal digits after '0o'.
+PASS 0oa threw exception SyntaxError: No octal digits after '0o'.
+PASS 0o0.0 threw exception SyntaxError: Unexpected number '.0'. Parse error..
+PASS x=0o1y=42 threw exception SyntaxError: No space between octal literal and identifier.
+PASS 0o12 is 0xa
+PASS 0o110642547 is 0x01234567
+PASS 0o21152746757 is 0x89abcdef
+FAIL 0o70000000000000000000000000000000000000000000000000000000 should be 3.00300673152188e+256. Was 3.2737636676212225e+50.
+PASS 0o377777777777777776 is 9007199254740990
+PASS 0o377777777777777777 is 9007199254740991
+PASS 0o777777777777777776 is 18014398509481982
+PASS 0o777777777777777777 is 18014398509481984
+PASS !!0o1 is true
+PASS !!0o0 is false
+PASS Number('0o0') is 0
+PASS Number('0o1') is 1
+PASS Number('0O1') is 1
+PASS Number('0o00000000000000000') is 0
+PASS Number('0O8') is NaN
+PASS Number('0oa') is NaN
+PASS Number('0o0.0') is NaN
+PASS Number('0o77') is 0x3f
+PASS Number('0o110642547') is 0x01234567
+PASS Number('0o21152746757') is 0x89abcdef
+PASS Number('0o377777777777777776') is 9007199254740990
+PASS Number('0o377777777777777777') is 9007199254740991
+PASS Number('0o777777777777777776') is 18014398509481982
+PASS Number('0o777777777777777777') is 18014398509481984
+PASS !!Number('0o1') is true
+PASS !!Number('0o0') is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/octal-literals.html b/LayoutTests/js/octal-literals.html
new file mode 100644 (file)
index 0000000..60c78e1
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/octal-literals.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/script-tests/binary-literals.js b/LayoutTests/js/script-tests/binary-literals.js
new file mode 100644 (file)
index 0000000..484e307
--- /dev/null
@@ -0,0 +1,47 @@
+description("Make sure that we correctly handle binary literals");
+
+shouldBe("0b0", "0");
+shouldBe("0b1", "1");
+shouldBe("0B1", "1");
+shouldBe("0b00000000000000000000000000000000", "0");
+shouldThrow("0B2");
+shouldThrow("0ba");
+shouldThrow("0b0.0");
+shouldThrow("x=0b1y=42");
+shouldBe("0b1010", "0xa");
+shouldBe("0b00000001001000110100010101100111", "0x01234567");
+shouldBe("0b10001001101010111100110111101111", "0x89abcdef");
+shouldBe("0o100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "3.00300673152188e+256");
+
+// Try 53 bits
+shouldBe("0b11111111111111111111111111111111111111111111111111110", "9007199254740990");
+shouldBe("0b11111111111111111111111111111111111111111111111111111", "9007199254740991");
+
+// 54 bits and above should add zeroes
+shouldBe("0b111111111111111111111111111111111111111111111111111110", "18014398509481982");
+shouldBe("0b111111111111111111111111111111111111111111111111111111", "18014398509481984");
+
+shouldBeTrue("!!0b1");
+shouldBeFalse("!!0b0");
+
+shouldBe("Number('0b0')", "0");
+shouldBe("Number('0b1')", "1");
+shouldBe("Number('0B1')", "1");
+shouldBe("Number('0b00000000000000000000000000000000')", "0");
+shouldBeNaN("Number('0B2')");
+shouldBeNaN("Number('0ba')");
+shouldBeNaN("Number('0b0.0')");
+shouldBe("Number('0b1010')", "0xa");
+shouldBe("Number('0b00000001001000110100010101100111')", "0x01234567");
+shouldBe("Number('0b10001001101010111100110111101111')", "0x89abcdef");
+
+// Try 53 bits
+shouldBe("Number('0b11111111111111111111111111111111111111111111111111110')", "9007199254740990");
+shouldBe("Number('0b11111111111111111111111111111111111111111111111111111')", "9007199254740991");
+
+// 54 bits and above should add zeroes
+shouldBe("Number('0b111111111111111111111111111111111111111111111111111110')", "18014398509481982");
+shouldBe("Number('0b111111111111111111111111111111111111111111111111111111')", "18014398509481984");
+
+shouldBeTrue("!!Number('0b1')");
+shouldBeFalse("!!Number('0b0')");
diff --git a/LayoutTests/js/script-tests/octal-literals.js b/LayoutTests/js/script-tests/octal-literals.js
new file mode 100644 (file)
index 0000000..c4814f5
--- /dev/null
@@ -0,0 +1,47 @@
+description("Make sure that we correctly handle octal literals");
+
+shouldBe("0o0", "0");
+shouldBe("0o1", "1");
+shouldBe("0O1", "1");
+shouldBe("0o000000000000", "0");
+shouldThrow("0O8");
+shouldThrow("0oa");
+shouldThrow("0o0.0");
+shouldThrow("x=0o1y=42");
+shouldBe("0o12", "0xa");
+shouldBe("0o110642547", "0x01234567");
+shouldBe("0o21152746757", "0x89abcdef");
+shouldBe("0o70000000000000000000000000000000000000000000000000000000", "3.00300673152188e+256");
+
+// Try 53 bits
+shouldBe("0o377777777777777776", "9007199254740990");
+shouldBe("0o377777777777777777", "9007199254740991");
+
+// 54 bits and above should add zeroes
+shouldBe("0o777777777777777776", "18014398509481982");
+shouldBe("0o777777777777777777", "18014398509481984");
+
+shouldBeTrue("!!0o1");
+shouldBeFalse("!!0o0");
+
+shouldBe("Number('0o0')", "0");
+shouldBe("Number('0o1')", "1");
+shouldBe("Number('0O1')", "1");
+shouldBe("Number('0o00000000000000000')", "0");
+shouldBeNaN("Number('0O8')");
+shouldBeNaN("Number('0oa')");
+shouldBeNaN("Number('0o0.0')");
+shouldBe("Number('0o77')", "0x3f");
+shouldBe("Number('0o110642547')", "0x01234567");
+shouldBe("Number('0o21152746757')", "0x89abcdef");
+
+// Try 53 bits
+shouldBe("Number('0o377777777777777776')", "9007199254740990");
+shouldBe("Number('0o377777777777777777')", "9007199254740991");
+
+// 54 bits and above should add zeroes
+shouldBe("Number('0o777777777777777776')", "18014398509481982");
+shouldBe("Number('0o777777777777777777')", "18014398509481984");
+
+shouldBeTrue("!!Number('0o1')");
+shouldBeFalse("!!Number('0o0')");
index 5c35f3c..7edcaf0 100644 (file)
@@ -1,3 +1,28 @@
+2015-03-14  Michael Saboff  <msaboff@apple.com>
+
+        ES6: Add binary and octal literal support
+        https://bugs.webkit.org/show_bug.cgi?id=142681
+
+        Reviewed by Ryosuke Niwa.
+
+        Added a binary literal parser function, parseBinary(), to Lexer patterned after the octal parser.
+        Refactored the parseBinary, parseOctal and parseDecimal to use a constant size for the number of
+        characters to try and handle directly. Factored out the shifting past any prefix to be handled by
+        the caller. Added binary and octal parsing to toDouble() via helper functions.
+
+        * parser/Lexer.cpp:
+        (JSC::Lexer<T>::parseHex):
+        (JSC::Lexer<T>::parseBinary):
+        (JSC::Lexer<T>::parseOctal):
+        (JSC::Lexer<T>::parseDecimal):
+        (JSC::Lexer<T>::lex):
+        * parser/Lexer.h:
+        * parser/ParserTokens.h:
+        * runtime/JSGlobalObjectFunctions.cpp:
+        (JSC::jsBinaryIntegerLiteral):
+        (JSC::jsOctalIntegerLiteral):
+        (JSC::toDouble):
+
 2015-03-13  Alex Christensen  <achristensen@webkit.org>
 
         Progress towards CMake on Mac.
index 1ec67df..c835e1f 100644 (file)
@@ -1222,9 +1222,6 @@ ALWAYS_INLINE void Lexer<T>::parseHex(double& returnValue)
     uint32_t hexValue = 0;
     int maximumDigits = 7;
 
-    // Shift out the 'x' prefix.
-    shift();
-
     do {
         hexValue = (hexValue << 4) + toASCIIHexValue(m_current);
         shift();
@@ -1256,28 +1253,67 @@ ALWAYS_INLINE void Lexer<T>::parseHex(double& returnValue)
 }
 
 template <typename T>
+ALWAYS_INLINE bool Lexer<T>::parseBinary(double& returnValue)
+{
+    // Optimization: most binary values fit into 4 bytes.
+    uint32_t binaryValue = 0;
+    const unsigned maximumDigits = 32;
+    int digit = maximumDigits - 1;
+    // Temporary buffer for the digits. Makes easier
+    // to reconstruct the input characters when needed.
+    LChar digits[maximumDigits];
+
+    do {
+        binaryValue = (binaryValue << 1) + (m_current - '0');
+        digits[digit] = m_current;
+        shift();
+        --digit;
+    } while (isASCIIBinaryDigit(m_current) && digit >= 0);
+
+    if (!isASCIIDigit(m_current) && digit >= 0) {
+        returnValue = binaryValue;
+        return true;
+    }
+
+    for (int i = maximumDigits - 1; i > digit; --i)
+        record8(digits[i]);
+
+    while (isASCIIBinaryDigit(m_current)) {
+        record8(m_current);
+        shift();
+    }
+
+    if (isASCIIDigit(m_current))
+        return false;
+
+    returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 2);
+    return true;
+}
+
+template <typename T>
 ALWAYS_INLINE bool Lexer<T>::parseOctal(double& returnValue)
 {
     // Optimization: most octal values fit into 4 bytes.
     uint32_t octalValue = 0;
-    int maximumDigits = 9;
+    const unsigned maximumDigits = 10;
+    int digit = maximumDigits - 1;
     // Temporary buffer for the digits. Makes easier
     // to reconstruct the input characters when needed.
-    LChar digits[10];
+    LChar digits[maximumDigits];
 
     do {
         octalValue = octalValue * 8 + (m_current - '0');
-        digits[maximumDigits] = m_current;
+        digits[digit] = m_current;
         shift();
-        --maximumDigits;
-    } while (isASCIIOctalDigit(m_current) && maximumDigits >= 0);
+        --digit;
+    } while (isASCIIOctalDigit(m_current) && digit >= 0);
 
-    if (!isASCIIDigit(m_current) && maximumDigits >= 0) {
+    if (!isASCIIDigit(m_current) && digit >= 0) {
         returnValue = octalValue;
         return true;
     }
 
-    for (int i = 9; i > maximumDigits; --i)
+    for (int i = maximumDigits - 1; i > digit; --i)
          record8(digits[i]);
 
     while (isASCIIOctalDigit(m_current)) {
@@ -1301,24 +1337,25 @@ ALWAYS_INLINE bool Lexer<T>::parseDecimal(double& returnValue)
     // Since parseOctal may be executed before parseDecimal,
     // the m_buffer8 may hold ascii digits.
     if (!m_buffer8.size()) {
-        int maximumDigits = 9;
+        const unsigned maximumDigits = 10;
+        int digit = maximumDigits - 1;
         // Temporary buffer for the digits. Makes easier
         // to reconstruct the input characters when needed.
-        LChar digits[10];
+        LChar digits[maximumDigits];
 
         do {
             decimalValue = decimalValue * 10 + (m_current - '0');
-            digits[maximumDigits] = m_current;
+            digits[digit] = m_current;
             shift();
-            --maximumDigits;
-        } while (isASCIIDigit(m_current) && maximumDigits >= 0);
+            --digit;
+        } while (isASCIIDigit(m_current) && digit >= 0);
 
-        if (maximumDigits >= 0 && m_current != '.' && (m_current | 0x20) != 'e') {
+        if (digit >= 0 && m_current != '.' && (m_current | 0x20) != 'e') {
             returnValue = decimalValue;
             return true;
         }
 
-        for (int i = 9; i > maximumDigits; --i)
+        for (int i = maximumDigits - 1; i > digit; --i)
             record8(digits[i]);
     }
 
@@ -1688,6 +1725,10 @@ start:
                 token = INVALID_HEX_NUMBER_ERRORTOK;
                 goto returnError;
             }
+
+            // Shift out the 'x' prefix.
+            shift();
+
             parseHex(tokenData->doubleValue);
             if (isIdentStart(m_current)) {
                 m_lexErrorMessage = ASCIILiteral("No space between hexadecimal literal and identifier");
@@ -1698,6 +1739,47 @@ start:
             m_buffer8.resize(0);
             break;
         }
+        if ((m_current | 0x20) == 'b') {
+            if (!isASCIIBinaryDigit(peek(1))) {
+                m_lexErrorMessage = ASCIILiteral("No binary digits after '0b'");
+                token = INVALID_BINARY_NUMBER_ERRORTOK;
+                goto returnError;
+            }
+
+            // Shift out the 'b' prefix.
+            shift();
+
+            parseBinary(tokenData->doubleValue);
+            if (isIdentStart(m_current)) {
+                m_lexErrorMessage = ASCIILiteral("No space between binary literal and identifier");
+                token = INVALID_BINARY_NUMBER_ERRORTOK;
+                goto returnError;
+            }
+            token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
+            m_buffer8.resize(0);
+            break;
+        }
+
+        if ((m_current | 0x20) == 'o') {
+            if (!isASCIIOctalDigit(peek(1))) {
+                m_lexErrorMessage = ASCIILiteral("No octal digits after '0o'");
+                token = INVALID_OCTAL_NUMBER_ERRORTOK;
+                goto returnError;
+            }
+
+            // Shift out the 'o' prefix.
+            shift();
+
+            parseOctal(tokenData->doubleValue);
+            if (isIdentStart(m_current)) {
+                m_lexErrorMessage = ASCIILiteral("No space between octal literal and identifier");
+                token = INVALID_OCTAL_NUMBER_ERRORTOK;
+                goto returnError;
+            }
+            token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
+            m_buffer8.resize(0);
+            break;
+        }
 
         record8('0');
         if (strictMode && isASCIIDigit(m_current)) {
index 81b4334..6fdf1f9 100644 (file)
@@ -203,6 +203,7 @@ private:
     template <bool shouldBuildStrings> ALWAYS_INLINE StringParseResult parseString(JSTokenData*, bool strictMode);
     template <bool shouldBuildStrings> NEVER_INLINE StringParseResult parseStringSlowCase(JSTokenData*, bool strictMode);
     ALWAYS_INLINE void parseHex(double& returnValue);
+    ALWAYS_INLINE bool parseBinary(double& returnValue);
     ALWAYS_INLINE bool parseOctal(double& returnValue);
     ALWAYS_INLINE bool parseDecimal(double& returnValue);
     ALWAYS_INLINE void parseNumberAfterDecimalPoint();
index 0574b72..8329f82 100644 (file)
@@ -160,7 +160,8 @@ enum JSTokenType {
     UNTERMINATED_STRING_LITERAL_ERRORTOK = 8 | ErrorTokenFlag | UnterminatedErrorTokenFlag,
     INVALID_STRING_LITERAL_ERRORTOK = 9 | ErrorTokenFlag,
     INVALID_PRIVATE_NAME_ERRORTOK = 10 | ErrorTokenFlag,
-    INVALID_HEX_NUMBER_ERRORTOK = 11 | ErrorTokenFlag
+    INVALID_HEX_NUMBER_ERRORTOK = 11 | ErrorTokenFlag,
+    INVALID_BINARY_NUMBER_ERRORTOK = 12 | ErrorTokenFlag
 };
 
 struct JSTextPosition {
index 9800f58..ad976cc 100644 (file)
@@ -343,7 +343,51 @@ static bool isInfinity(const CharType* data, const CharType* end)
         && data[7] == 'y';
 }
 
-// See ecma-262 9.3.1
+// See ecma-262 6th 11.8.3
+template <typename CharType>
+static double jsBinaryIntegerLiteral(const CharType*& data, const CharType* end)
+{
+    // Binary number.
+    data += 2;
+    const CharType* firstDigitPosition = data;
+    double number = 0;
+    while (true) {
+        number = number * 2 + (*data - '0');
+        ++data;
+        if (data == end)
+            break;
+        if (!isASCIIBinaryDigit(*data))
+            break;
+    }
+    if (number >= mantissaOverflowLowerBound)
+        number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 2);
+
+    return number;
+}
+
+// See ecma-262 6th 11.8.3
+template <typename CharType>
+static double jsOctalIntegerLiteral(const CharType*& data, const CharType* end)
+{
+    // Octal number.
+    data += 2;
+    const CharType* firstDigitPosition = data;
+    double number = 0;
+    while (true) {
+        number = number * 8 + (*data - '0');
+        ++data;
+        if (data == end)
+            break;
+        if (!isASCIIOctalDigit(*data))
+            break;
+    }
+    if (number >= mantissaOverflowLowerBound)
+        number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 8);
+    
+    return number;
+}
+
+// See ecma-262 6th 11.8.3
 template <typename CharType>
 static double jsHexIntegerLiteral(const CharType*& data, const CharType* end)
 {
@@ -365,7 +409,7 @@ static double jsHexIntegerLiteral(const CharType*& data, const CharType* end)
     return number;
 }
 
-// See ecma-262 9.3.1
+// See ecma-262 6th 11.8.3
 template <typename CharType>
 static double jsStrDecimalLiteral(const CharType*& data, const CharType* end)
 {
@@ -422,9 +466,16 @@ static double toDouble(const CharType* characters, unsigned size)
         return 0.0;
     
     double number;
-    if (characters[0] == '0' && characters + 2 < endCharacters && (characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2]))
-        number = jsHexIntegerLiteral(characters, endCharacters);
-    else
+    if (characters[0] == '0' && characters + 2 < endCharacters) {
+        if ((characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2]))
+            number = jsHexIntegerLiteral(characters, endCharacters);
+        else if ((characters[1] | 0x20) == 'o' && isASCIIOctalDigit(characters[2]))
+            number = jsOctalIntegerLiteral(characters, endCharacters);
+        else if ((characters[1] | 0x20) == 'b' && isASCIIBinaryDigit(characters[2]))
+            number = jsBinaryIntegerLiteral(characters, endCharacters);
+        else
+            number = jsStrDecimalLiteral(characters, endCharacters);
+    } else
         number = jsStrDecimalLiteral(characters, endCharacters);
     
     // Allow trailing white space.
@@ -438,7 +489,7 @@ static double toDouble(const CharType* characters, unsigned size)
     return number;
 }
 
-// See ecma-262 9.3.1
+// See ecma-262 6th 11.8.3
 double jsToNumber(const String& s)
 {
     unsigned size = s.length();
index 61b06fa..85cf7fb 100644 (file)
@@ -1,3 +1,14 @@
+2015-03-14  Michael Saboff  <msaboff@apple.com>
+
+        ES6: Add binary and octal literal support
+        https://bugs.webkit.org/show_bug.cgi?id=142681
+
+        Reviewed by Ryosuke Niwa.
+
+        * wtf/ASCIICType.h:
+        (WTF::isASCIIBinaryDigit): New support function.
+        (WTF::isASCIIOctalDigit): Updated to use logical and (&&) instead of binary and (&).
+
 2015-03-13  Mark Lam  <mark.lam@apple.com>
 
         Replace TCSpinLock with a new WTF::SpinLock based on WTF::Atomic.
index 3445d2b..20ed3ea 100644 (file)
@@ -73,9 +73,14 @@ template<typename CharType> inline bool isASCIILower(CharType c)
     return c >= 'a' && c <= 'z';
 }
 
+template<typename CharType> inline bool isASCIIBinaryDigit(CharType c)
+{
+    return (c == '0') || (c == '1');
+}
+
 template<typename CharType> inline bool isASCIIOctalDigit(CharType c)
 {
-    return (c >= '0') & (c <= '7');
+    return (c >= '0') && (c <= '7');
 }
 
 template<typename CharType> inline bool isASCIIPrintable(CharType c)
@@ -166,6 +171,7 @@ using WTF::isASCIIAlphanumeric;
 using WTF::isASCIIDigit;
 using WTF::isASCIIHexDigit;
 using WTF::isASCIILower;
+using WTF::isASCIIBinaryDigit;
 using WTF::isASCIIOctalDigit;
 using WTF::isASCIIPrintable;
 using WTF::isASCIISpace;