⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 181497 in webkit


Ignore:
Timestamp:
Mar 14, 2015, 9:29:20 AM (11 years ago)
Author:
msaboff@apple.com
Message:

ES6: Add binary and octal literal support
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.
Location:
trunk
Files:
6 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r181490 r181497  
     12015-03-14  Michael Saboff  <msaboff@apple.com>
     2
     3        ES6: Add binary and octal literal support
     4        https://bugs.webkit.org/show_bug.cgi?id=142681
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        New tests.
     9
     10        * js/binary-literals-expected.txt: Added.
     11        * js/binary-literals.html: Added.
     12        * js/octal-literals-expected.txt: Added.
     13        * js/octal-literals.html: Added.
     14        * js/script-tests/binary-literals.js: Added.
     15        * js/script-tests/octal-literals.js: Added.
     16
    1172015-03-13  Ryosuke Niwa  <rniwa@webkit.org>
    218
  • trunk/Source/JavaScriptCore/ChangeLog

    r181496 r181497  
     12015-03-14  Michael Saboff  <msaboff@apple.com>
     2
     3        ES6: Add binary and octal literal support
     4        https://bugs.webkit.org/show_bug.cgi?id=142681
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        Added a binary literal parser function, parseBinary(), to Lexer patterned after the octal parser.
     9        Refactored the parseBinary, parseOctal and parseDecimal to use a constant size for the number of
     10        characters to try and handle directly. Factored out the shifting past any prefix to be handled by
     11        the caller. Added binary and octal parsing to toDouble() via helper functions.
     12
     13        * parser/Lexer.cpp:
     14        (JSC::Lexer<T>::parseHex):
     15        (JSC::Lexer<T>::parseBinary):
     16        (JSC::Lexer<T>::parseOctal):
     17        (JSC::Lexer<T>::parseDecimal):
     18        (JSC::Lexer<T>::lex):
     19        * parser/Lexer.h:
     20        * parser/ParserTokens.h:
     21        * runtime/JSGlobalObjectFunctions.cpp:
     22        (JSC::jsBinaryIntegerLiteral):
     23        (JSC::jsOctalIntegerLiteral):
     24        (JSC::toDouble):
     25
    1262015-03-13  Alex Christensen  <achristensen@webkit.org>
    227
  • trunk/Source/JavaScriptCore/parser/Lexer.cpp

    r180813 r181497  
    12231223    int maximumDigits = 7;
    12241224
    1225     // Shift out the 'x' prefix.
    1226     shift();
    1227 
    12281225    do {
    12291226        hexValue = (hexValue << 4) + toASCIIHexValue(m_current);
     
    12571254
    12581255template <typename T>
     1256ALWAYS_INLINE bool Lexer<T>::parseBinary(double& returnValue)
     1257{
     1258    // Optimization: most binary values fit into 4 bytes.
     1259    uint32_t binaryValue = 0;
     1260    const unsigned maximumDigits = 32;
     1261    int digit = maximumDigits - 1;
     1262    // Temporary buffer for the digits. Makes easier
     1263    // to reconstruct the input characters when needed.
     1264    LChar digits[maximumDigits];
     1265
     1266    do {
     1267        binaryValue = (binaryValue << 1) + (m_current - '0');
     1268        digits[digit] = m_current;
     1269        shift();
     1270        --digit;
     1271    } while (isASCIIBinaryDigit(m_current) && digit >= 0);
     1272
     1273    if (!isASCIIDigit(m_current) && digit >= 0) {
     1274        returnValue = binaryValue;
     1275        return true;
     1276    }
     1277
     1278    for (int i = maximumDigits - 1; i > digit; --i)
     1279        record8(digits[i]);
     1280
     1281    while (isASCIIBinaryDigit(m_current)) {
     1282        record8(m_current);
     1283        shift();
     1284    }
     1285
     1286    if (isASCIIDigit(m_current))
     1287        return false;
     1288
     1289    returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 2);
     1290    return true;
     1291}
     1292
     1293template <typename T>
    12591294ALWAYS_INLINE bool Lexer<T>::parseOctal(double& returnValue)
    12601295{
    12611296    // Optimization: most octal values fit into 4 bytes.
    12621297    uint32_t octalValue = 0;
    1263     int maximumDigits = 9;
     1298    const unsigned maximumDigits = 10;
     1299    int digit = maximumDigits - 1;
    12641300    // Temporary buffer for the digits. Makes easier
    12651301    // to reconstruct the input characters when needed.
    1266     LChar digits[10];
     1302    LChar digits[maximumDigits];
    12671303
    12681304    do {
    12691305        octalValue = octalValue * 8 + (m_current - '0');
    1270         digits[maximumDigits] = m_current;
    1271         shift();
    1272         --maximumDigits;
    1273     } while (isASCIIOctalDigit(m_current) && maximumDigits >= 0);
    1274 
    1275     if (!isASCIIDigit(m_current) && maximumDigits >= 0) {
     1306        digits[digit] = m_current;
     1307        shift();
     1308        --digit;
     1309    } while (isASCIIOctalDigit(m_current) && digit >= 0);
     1310
     1311    if (!isASCIIDigit(m_current) && digit >= 0) {
    12761312        returnValue = octalValue;
    12771313        return true;
    12781314    }
    12791315
    1280     for (int i = 9; i > maximumDigits; --i)
     1316    for (int i = maximumDigits - 1; i > digit; --i)
    12811317         record8(digits[i]);
    12821318
     
    13021338    // the m_buffer8 may hold ascii digits.
    13031339    if (!m_buffer8.size()) {
    1304         int maximumDigits = 9;
     1340        const unsigned maximumDigits = 10;
     1341        int digit = maximumDigits - 1;
    13051342        // Temporary buffer for the digits. Makes easier
    13061343        // to reconstruct the input characters when needed.
    1307         LChar digits[10];
     1344        LChar digits[maximumDigits];
    13081345
    13091346        do {
    13101347            decimalValue = decimalValue * 10 + (m_current - '0');
    1311             digits[maximumDigits] = m_current;
    1312             shift();
    1313             --maximumDigits;
    1314         } while (isASCIIDigit(m_current) && maximumDigits >= 0);
    1315 
    1316         if (maximumDigits >= 0 && m_current != '.' && (m_current | 0x20) != 'e') {
     1348            digits[digit] = m_current;
     1349            shift();
     1350            --digit;
     1351        } while (isASCIIDigit(m_current) && digit >= 0);
     1352
     1353        if (digit >= 0 && m_current != '.' && (m_current | 0x20) != 'e') {
    13171354            returnValue = decimalValue;
    13181355            return true;
    13191356        }
    13201357
    1321         for (int i = 9; i > maximumDigits; --i)
     1358        for (int i = maximumDigits - 1; i > digit; --i)
    13221359            record8(digits[i]);
    13231360    }
     
    16891726                goto returnError;
    16901727            }
     1728
     1729            // Shift out the 'x' prefix.
     1730            shift();
     1731
    16911732            parseHex(tokenData->doubleValue);
    16921733            if (isIdentStart(m_current)) {
    16931734                m_lexErrorMessage = ASCIILiteral("No space between hexadecimal literal and identifier");
    16941735                token = INVALID_HEX_NUMBER_ERRORTOK;
     1736                goto returnError;
     1737            }
     1738            token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
     1739            m_buffer8.resize(0);
     1740            break;
     1741        }
     1742        if ((m_current | 0x20) == 'b') {
     1743            if (!isASCIIBinaryDigit(peek(1))) {
     1744                m_lexErrorMessage = ASCIILiteral("No binary digits after '0b'");
     1745                token = INVALID_BINARY_NUMBER_ERRORTOK;
     1746                goto returnError;
     1747            }
     1748
     1749            // Shift out the 'b' prefix.
     1750            shift();
     1751
     1752            parseBinary(tokenData->doubleValue);
     1753            if (isIdentStart(m_current)) {
     1754                m_lexErrorMessage = ASCIILiteral("No space between binary literal and identifier");
     1755                token = INVALID_BINARY_NUMBER_ERRORTOK;
     1756                goto returnError;
     1757            }
     1758            token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
     1759            m_buffer8.resize(0);
     1760            break;
     1761        }
     1762
     1763        if ((m_current | 0x20) == 'o') {
     1764            if (!isASCIIOctalDigit(peek(1))) {
     1765                m_lexErrorMessage = ASCIILiteral("No octal digits after '0o'");
     1766                token = INVALID_OCTAL_NUMBER_ERRORTOK;
     1767                goto returnError;
     1768            }
     1769
     1770            // Shift out the 'o' prefix.
     1771            shift();
     1772
     1773            parseOctal(tokenData->doubleValue);
     1774            if (isIdentStart(m_current)) {
     1775                m_lexErrorMessage = ASCIILiteral("No space between octal literal and identifier");
     1776                token = INVALID_OCTAL_NUMBER_ERRORTOK;
    16951777                goto returnError;
    16961778            }
  • trunk/Source/JavaScriptCore/parser/Lexer.h

    r177222 r181497  
    204204    template <bool shouldBuildStrings> NEVER_INLINE StringParseResult parseStringSlowCase(JSTokenData*, bool strictMode);
    205205    ALWAYS_INLINE void parseHex(double& returnValue);
     206    ALWAYS_INLINE bool parseBinary(double& returnValue);
    206207    ALWAYS_INLINE bool parseOctal(double& returnValue);
    207208    ALWAYS_INLINE bool parseDecimal(double& returnValue);
  • trunk/Source/JavaScriptCore/parser/ParserTokens.h

    r181419 r181497  
    161161    INVALID_STRING_LITERAL_ERRORTOK = 9 | ErrorTokenFlag,
    162162    INVALID_PRIVATE_NAME_ERRORTOK = 10 | ErrorTokenFlag,
    163     INVALID_HEX_NUMBER_ERRORTOK = 11 | ErrorTokenFlag
     163    INVALID_HEX_NUMBER_ERRORTOK = 11 | ErrorTokenFlag,
     164    INVALID_BINARY_NUMBER_ERRORTOK = 12 | ErrorTokenFlag
    164165};
    165166
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r180370 r181497  
    344344}
    345345
    346 // See ecma-262 9.3.1
     346// See ecma-262 6th 11.8.3
     347template <typename CharType>
     348static double jsBinaryIntegerLiteral(const CharType*& data, const CharType* end)
     349{
     350    // Binary number.
     351    data += 2;
     352    const CharType* firstDigitPosition = data;
     353    double number = 0;
     354    while (true) {
     355        number = number * 2 + (*data - '0');
     356        ++data;
     357        if (data == end)
     358            break;
     359        if (!isASCIIBinaryDigit(*data))
     360            break;
     361    }
     362    if (number >= mantissaOverflowLowerBound)
     363        number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 2);
     364
     365    return number;
     366}
     367
     368// See ecma-262 6th 11.8.3
     369template <typename CharType>
     370static double jsOctalIntegerLiteral(const CharType*& data, const CharType* end)
     371{
     372    // Octal number.
     373    data += 2;
     374    const CharType* firstDigitPosition = data;
     375    double number = 0;
     376    while (true) {
     377        number = number * 8 + (*data - '0');
     378        ++data;
     379        if (data == end)
     380            break;
     381        if (!isASCIIOctalDigit(*data))
     382            break;
     383    }
     384    if (number >= mantissaOverflowLowerBound)
     385        number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 8);
     386   
     387    return number;
     388}
     389
     390// See ecma-262 6th 11.8.3
    347391template <typename CharType>
    348392static double jsHexIntegerLiteral(const CharType*& data, const CharType* end)
     
    366410}
    367411
    368 // See ecma-262 9.3.1
     412// See ecma-262 6th 11.8.3
    369413template <typename CharType>
    370414static double jsStrDecimalLiteral(const CharType*& data, const CharType* end)
     
    423467   
    424468    double number;
    425     if (characters[0] == '0' && characters + 2 < endCharacters && (characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2]))
    426         number = jsHexIntegerLiteral(characters, endCharacters);
    427     else
     469    if (characters[0] == '0' && characters + 2 < endCharacters) {
     470        if ((characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2]))
     471            number = jsHexIntegerLiteral(characters, endCharacters);
     472        else if ((characters[1] | 0x20) == 'o' && isASCIIOctalDigit(characters[2]))
     473            number = jsOctalIntegerLiteral(characters, endCharacters);
     474        else if ((characters[1] | 0x20) == 'b' && isASCIIBinaryDigit(characters[2]))
     475            number = jsBinaryIntegerLiteral(characters, endCharacters);
     476        else
     477            number = jsStrDecimalLiteral(characters, endCharacters);
     478    } else
    428479        number = jsStrDecimalLiteral(characters, endCharacters);
    429480   
     
    439490}
    440491
    441 // See ecma-262 9.3.1
     492// See ecma-262 6th 11.8.3
    442493double jsToNumber(const String& s)
    443494{
  • trunk/Source/WTF/ChangeLog

    r181485 r181497  
     12015-03-14  Michael Saboff  <msaboff@apple.com>
     2
     3        ES6: Add binary and octal literal support
     4        https://bugs.webkit.org/show_bug.cgi?id=142681
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        * wtf/ASCIICType.h:
     9        (WTF::isASCIIBinaryDigit): New support function.
     10        (WTF::isASCIIOctalDigit): Updated to use logical and (&&) instead of binary and (&).
     11
    1122015-03-13  Mark Lam  <mark.lam@apple.com>
    213
  • trunk/Source/WTF/wtf/ASCIICType.h

    r165676 r181497  
    7474}
    7575
     76template<typename CharType> inline bool isASCIIBinaryDigit(CharType c)
     77{
     78    return (c == '0') || (c == '1');
     79}
     80
    7681template<typename CharType> inline bool isASCIIOctalDigit(CharType c)
    7782{
    78     return (c >= '0') & (c <= '7');
     83    return (c >= '0') && (c <= '7');
    7984}
    8085
     
    167172using WTF::isASCIIHexDigit;
    168173using WTF::isASCIILower;
     174using WTF::isASCIIBinaryDigit;
    169175using WTF::isASCIIOctalDigit;
    170176using WTF::isASCIIPrintable;
Note: See TracChangeset for help on using the changeset viewer.