Changeset 245655 in webkit
- Timestamp:
- May 22, 2019 3:43:25 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r245652 r245655 1 2019-05-22 Ross Kirsling <ross.kirsling@sony.com> 2 3 [ESNext] Implement support for Numeric Separators 4 https://bugs.webkit.org/show_bug.cgi?id=196351 5 6 Reviewed by Keith Miller. 7 8 * stress/numeric-literal-separators.js: Added. 9 Add tests for feature. 10 11 * test262/expectations.yaml: 12 Mark 60 test cases as passing. 13 1 14 2019-05-22 Tadeu Zagallo <tzagallo@apple.com> 2 15 -
trunk/JSTests/test262/expectations.yaml
r245648 r245655 2601 2601 default: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all' 2602 2602 strict mode: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all' 2603 test/language/literals/numeric/numeric-separator-literal-bil-bd-nsl-bd.js:2604 default: 'SyntaxError: No space between binary literal and identifier'2605 strict mode: 'SyntaxError: No space between binary literal and identifier'2606 test/language/literals/numeric/numeric-separator-literal-bil-bd-nsl-bds.js:2607 default: 'SyntaxError: No space between binary literal and identifier'2608 strict mode: 'SyntaxError: No space between binary literal and identifier'2609 test/language/literals/numeric/numeric-separator-literal-bil-bds-nsl-bd.js:2610 default: 'SyntaxError: No space between binary literal and identifier'2611 strict mode: 'SyntaxError: No space between binary literal and identifier'2612 test/language/literals/numeric/numeric-separator-literal-bil-bds-nsl-bds.js:2613 default: 'SyntaxError: No space between binary literal and identifier'2614 strict mode: 'SyntaxError: No space between binary literal and identifier'2615 test/language/literals/numeric/numeric-separator-literal-dd-dot-dd-ep-sign-minus-dd-nsl-dd.js:2616 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2617 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2618 test/language/literals/numeric/numeric-separator-literal-dd-dot-dd-ep-sign-minus-dds-nsl-dd.js:2619 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2620 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2621 test/language/literals/numeric/numeric-separator-literal-dd-dot-dd-ep-sign-plus-dd-nsl-dd.js:2622 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2623 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2624 test/language/literals/numeric/numeric-separator-literal-dd-dot-dd-ep-sign-plus-dds-nsl-dd.js:2625 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2626 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2627 test/language/literals/numeric/numeric-separator-literal-dd-nsl-dd-one-of.js:2628 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2629 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2630 test/language/literals/numeric/numeric-separator-literal-dds-dot-dd-nsl-dd-ep-dd.js:2631 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2632 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2633 test/language/literals/numeric/numeric-separator-literal-dds-nsl-dd.js:2634 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2635 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2636 test/language/literals/numeric/numeric-separator-literal-dot-dd-nsl-dd-ep.js:2637 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2638 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2639 test/language/literals/numeric/numeric-separator-literal-dot-dd-nsl-dds-ep.js:2640 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2641 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2642 test/language/literals/numeric/numeric-separator-literal-dot-dds-nsl-dd-ep.js:2643 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2644 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2645 test/language/literals/numeric/numeric-separator-literal-dot-dds-nsl-dds-ep.js:2646 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2647 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2648 test/language/literals/numeric/numeric-separator-literal-hil-hd-nsl-hd.js:2649 default: 'SyntaxError: No space between hexadecimal literal and identifier'2650 strict mode: 'SyntaxError: No space between hexadecimal literal and identifier'2651 test/language/literals/numeric/numeric-separator-literal-hil-hd-nsl-hds.js:2652 default: 'SyntaxError: No space between hexadecimal literal and identifier'2653 strict mode: 'SyntaxError: No space between hexadecimal literal and identifier'2654 test/language/literals/numeric/numeric-separator-literal-hil-hds-nsl-hd.js:2655 default: 'SyntaxError: No space between hexadecimal literal and identifier'2656 strict mode: 'SyntaxError: No space between hexadecimal literal and identifier'2657 test/language/literals/numeric/numeric-separator-literal-hil-hds-nsl-hds.js:2658 default: 'SyntaxError: No space between hexadecimal literal and identifier'2659 strict mode: 'SyntaxError: No space between hexadecimal literal and identifier'2660 test/language/literals/numeric/numeric-separator-literal-hil-od-nsl-od-one-of.js:2661 default: 'SyntaxError: No space between hexadecimal literal and identifier'2662 strict mode: 'SyntaxError: No space between hexadecimal literal and identifier'2663 test/language/literals/numeric/numeric-separator-literal-nzd-nsl-dd-one-of.js:2664 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2665 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2666 test/language/literals/numeric/numeric-separator-literal-nzd-nsl-dd.js:2667 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2668 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2669 test/language/literals/numeric/numeric-separator-literal-nzd-nsl-dds.js:2670 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2671 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2672 test/language/literals/numeric/numeric-separator-literal-oil-od-nsl-od-one-of.js:2673 default: 'SyntaxError: No space between octal literal and identifier'2674 strict mode: 'SyntaxError: No space between octal literal and identifier'2675 test/language/literals/numeric/numeric-separator-literal-oil-od-nsl-od.js:2676 default: 'SyntaxError: No space between octal literal and identifier'2677 strict mode: 'SyntaxError: No space between octal literal and identifier'2678 test/language/literals/numeric/numeric-separator-literal-oil-od-nsl-ods.js:2679 default: 'SyntaxError: No space between octal literal and identifier'2680 strict mode: 'SyntaxError: No space between octal literal and identifier'2681 test/language/literals/numeric/numeric-separator-literal-oil-ods-nsl-od.js:2682 default: 'SyntaxError: No space between octal literal and identifier'2683 strict mode: 'SyntaxError: No space between octal literal and identifier'2684 test/language/literals/numeric/numeric-separator-literal-oil-ods-nsl-ods.js:2685 default: 'SyntaxError: No space between octal literal and identifier'2686 strict mode: 'SyntaxError: No space between octal literal and identifier'2687 test/language/literals/numeric/numeric-separator-literal-sign-minus-dds-nsl-dd.js:2688 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2689 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2690 test/language/literals/numeric/numeric-separator-literal-sign-plus-dds-nsl-dd.js:2691 default: 'SyntaxError: No identifiers allowed directly after numeric literal'2692 strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'2693 2603 test/language/literals/regexp/named-groups/invalid-dangling-groupname-2-u.js: 2694 2604 default: 'Test262: This statement should not be evaluated.' -
trunk/Source/JavaScriptCore/ChangeLog
r245652 r245655 1 2019-05-22 Ross Kirsling <ross.kirsling@sony.com> 2 3 [ESNext] Implement support for Numeric Separators 4 https://bugs.webkit.org/show_bug.cgi?id=196351 5 6 Reviewed by Keith Miller. 7 8 Implement the following proposal, which is now Stage 3: 9 https://github.com/tc39/proposal-numeric-separator 10 11 Specifically, this allows `_` to be used as a separator in numeric literals. 12 It may be inserted arbitrarily without semantic effect, but it may not occur: 13 - multiple times in a row 14 - at the beginning or end of the literal 15 - adjacent to `0x`, `0b`, `0o`, `.`, `e`, or `n` 16 - after a leading zero (e.g. `0_123`), even in sloppy mode 17 18 * parser/Lexer.cpp: 19 (JSC::isASCIIDigitOrSeparator): Added. 20 (JSC::isASCIIHexDigitOrSeparator): Added. 21 (JSC::isASCIIBinaryDigitOrSeparator): Added. 22 (JSC::isASCIIOctalDigitOrSeparator): Added. 23 (JSC::Lexer<T>::parseHex): 24 (JSC::Lexer<T>::parseBinary): 25 (JSC::Lexer<T>::parseOctal): 26 (JSC::Lexer<T>::parseDecimal): 27 (JSC::Lexer<T>::parseNumberAfterDecimalPoint): 28 (JSC::Lexer<T>::parseNumberAfterExponentIndicator): 29 (JSC::Lexer<T>::lexWithoutClearingLineTerminator): 30 * parser/Lexer.h: 31 1 32 2019-05-22 Tadeu Zagallo <tzagallo@apple.com> 2 33 -
trunk/Source/JavaScriptCore/parser/Lexer.cpp
r245648 r245655 814 814 } 815 815 816 template<typename CharacterType> 817 static inline bool isASCIIDigitOrSeparator(CharacterType character) 818 { 819 return isASCIIDigit(character) || character == '_'; 820 } 821 822 template<typename CharacterType> 823 static inline bool isASCIIHexDigitOrSeparator(CharacterType character) 824 { 825 return isASCIIHexDigit(character) || character == '_'; 826 } 827 828 template<typename CharacterType> 829 static inline bool isASCIIBinaryDigitOrSeparator(CharacterType character) 830 { 831 return isASCIIBinaryDigit(character) || character == '_'; 832 } 833 834 template<typename CharacterType> 835 static inline bool isASCIIOctalDigitOrSeparator(CharacterType character) 836 { 837 return isASCIIOctalDigit(character) || character == '_'; 838 } 839 816 840 static inline LChar singleEscape(int c) 817 841 { … … 1491 1515 1492 1516 template <typename T> 1493 ALWAYS_INLINE auto Lexer<T>::parseHex() -> NumberParseResult 1494 { 1517 ALWAYS_INLINE auto Lexer<T>::parseHex() -> Optional<NumberParseResult> 1518 { 1519 ASSERT(isASCIIHexDigit(m_current)); 1520 1495 1521 // Optimization: most hexadecimal values fit into 4 bytes. 1496 1522 uint32_t hexValue = 0; … … 1498 1524 1499 1525 do { 1526 if (m_current == '_') { 1527 if (UNLIKELY(!isASCIIHexDigit(peek(1)))) 1528 return WTF::nullopt; 1529 1530 shift(); 1531 } 1532 1500 1533 hexValue = (hexValue << 4) + toASCIIHexValue(m_current); 1501 1534 shift(); 1502 1535 --maximumDigits; 1503 } while (isASCIIHexDigit (m_current) && maximumDigits >= 0);1536 } while (isASCIIHexDigitOrSeparator(m_current) && maximumDigits >= 0); 1504 1537 1505 1538 if (LIKELY(maximumDigits >= 0 && m_current != 'n')) 1506 return hexValue;1539 return NumberParseResult { hexValue }; 1507 1540 1508 1541 // No more place in the hexValue buffer. … … 1517 1550 } 1518 1551 1519 while (isASCIIHexDigit(m_current)) { 1552 while (isASCIIHexDigitOrSeparator(m_current)) { 1553 if (m_current == '_') { 1554 if (UNLIKELY(!isASCIIHexDigit(peek(1)))) 1555 return WTF::nullopt; 1556 1557 shift(); 1558 } 1559 1520 1560 record8(m_current); 1521 1561 shift(); … … 1523 1563 1524 1564 if (UNLIKELY(Options::useBigInt() && m_current == 'n')) 1525 return makeIdentifier(m_buffer8.data(), m_buffer8.size());1565 return NumberParseResult { makeIdentifier(m_buffer8.data(), m_buffer8.size()) }; 1526 1566 1527 return parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 16);1567 return NumberParseResult { parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 16) }; 1528 1568 } 1529 1569 … … 1531 1571 ALWAYS_INLINE auto Lexer<T>::parseBinary() -> Optional<NumberParseResult> 1532 1572 { 1573 ASSERT(isASCIIBinaryDigit(m_current)); 1574 1533 1575 // Optimization: most binary values fit into 4 bytes. 1534 1576 uint32_t binaryValue = 0; … … 1540 1582 1541 1583 do { 1584 if (m_current == '_') { 1585 if (UNLIKELY(!isASCIIBinaryDigit(peek(1)))) 1586 return WTF::nullopt; 1587 1588 shift(); 1589 } 1590 1542 1591 binaryValue = (binaryValue << 1) + (m_current - '0'); 1543 1592 digits[digit] = m_current; 1544 1593 shift(); 1545 1594 --digit; 1546 } while (isASCIIBinaryDigit (m_current) && digit >= 0);1547 1548 if (LIKELY(!isASCIIDigit (m_current) && digit >= 0 && m_current != 'n'))1549 return Variant<double, const Identifier*>{ binaryValue };1595 } while (isASCIIBinaryDigitOrSeparator(m_current) && digit >= 0); 1596 1597 if (LIKELY(!isASCIIDigitOrSeparator(m_current) && digit >= 0 && m_current != 'n')) 1598 return NumberParseResult { binaryValue }; 1550 1599 1551 1600 for (int i = maximumDigits - 1; i > digit; --i) 1552 1601 record8(digits[i]); 1553 1602 1554 while (isASCIIBinaryDigit(m_current)) { 1603 while (isASCIIBinaryDigitOrSeparator(m_current)) { 1604 if (m_current == '_') { 1605 if (UNLIKELY(!isASCIIBinaryDigit(peek(1)))) 1606 return WTF::nullopt; 1607 1608 shift(); 1609 } 1610 1555 1611 record8(m_current); 1556 1612 shift(); … … 1558 1614 1559 1615 if (UNLIKELY(Options::useBigInt() && m_current == 'n')) 1560 return Variant<double, const Identifier*>{ makeIdentifier(m_buffer8.data(), m_buffer8.size()) };1616 return NumberParseResult { makeIdentifier(m_buffer8.data(), m_buffer8.size()) }; 1561 1617 1562 1618 if (isASCIIDigit(m_current)) 1563 1619 return WTF::nullopt; 1564 1620 1565 return Variant<double, const Identifier*>{ parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 2) };1621 return NumberParseResult { parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 2) }; 1566 1622 } 1567 1623 … … 1569 1625 ALWAYS_INLINE auto Lexer<T>::parseOctal() -> Optional<NumberParseResult> 1570 1626 { 1627 ASSERT(isASCIIOctalDigit(m_current)); 1628 1571 1629 // Optimization: most octal values fit into 4 bytes. 1572 1630 uint32_t octalValue = 0; … … 1578 1636 1579 1637 do { 1638 if (m_current == '_') { 1639 if (UNLIKELY(!isASCIIOctalDigit(peek(1)))) 1640 return WTF::nullopt; 1641 1642 shift(); 1643 } 1644 1580 1645 octalValue = octalValue * 8 + (m_current - '0'); 1581 1646 digits[digit] = m_current; 1582 1647 shift(); 1583 1648 --digit; 1584 } while (isASCIIOctalDigit(m_current) && digit >= 0); 1585 1586 if (LIKELY(!isASCIIDigit(m_current) && digit >= 0 && m_current != 'n')) 1587 return Variant<double, const Identifier*> { octalValue }; 1588 1649 } while (isASCIIOctalDigitOrSeparator(m_current) && digit >= 0); 1650 1651 if (LIKELY(!isASCIIDigitOrSeparator(m_current) && digit >= 0 && m_current != 'n')) 1652 return NumberParseResult { octalValue }; 1589 1653 1590 1654 for (int i = maximumDigits - 1; i > digit; --i) 1591 1655 record8(digits[i]); 1592 1656 1593 while (isASCIIOctalDigit(m_current)) { 1657 while (isASCIIOctalDigitOrSeparator(m_current)) { 1658 if (m_current == '_') { 1659 if (UNLIKELY(!isASCIIOctalDigit(peek(1)))) 1660 return WTF::nullopt; 1661 1662 shift(); 1663 } 1664 1594 1665 record8(m_current); 1595 1666 shift(); … … 1597 1668 1598 1669 if (UNLIKELY(Options::useBigInt() && m_current == 'n')) 1599 return Variant<double, const Identifier*>{ makeIdentifier(m_buffer8.data(), m_buffer8.size()) };1670 return NumberParseResult { makeIdentifier(m_buffer8.data(), m_buffer8.size()) }; 1600 1671 1601 1672 if (isASCIIDigit(m_current)) 1602 1673 return WTF::nullopt; 1603 1674 1604 return Variant<double, const Identifier*>{ parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 8) };1675 return NumberParseResult { parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 8) }; 1605 1676 } 1606 1677 … … 1621 1692 1622 1693 do { 1694 if (m_current == '_') { 1695 if (UNLIKELY(!isASCIIDigit(peek(1)))) 1696 return WTF::nullopt; 1697 1698 shift(); 1699 } 1700 1623 1701 decimalValue = decimalValue * 10 + (m_current - '0'); 1624 1702 digits[digit] = m_current; 1625 1703 shift(); 1626 1704 --digit; 1627 } while (isASCIIDigit (m_current) && digit >= 0);1705 } while (isASCIIDigitOrSeparator(m_current) && digit >= 0); 1628 1706 1629 1707 if (digit >= 0 && m_current != '.' && !isASCIIAlphaCaselessEqual(m_current, 'e') && m_current != 'n') 1630 return Variant<double, const Identifier*>{ decimalValue };1708 return NumberParseResult { decimalValue }; 1631 1709 1632 1710 for (int i = maximumDigits - 1; i > digit; --i) … … 1634 1712 } 1635 1713 1636 while (isASCIIDigit(m_current)) { 1714 while (isASCIIDigitOrSeparator(m_current)) { 1715 if (m_current == '_') { 1716 if (UNLIKELY(!isASCIIDigit(peek(1)))) 1717 return WTF::nullopt; 1718 1719 shift(); 1720 } 1721 1637 1722 record8(m_current); 1638 1723 shift(); … … 1640 1725 1641 1726 if (UNLIKELY(Options::useBigInt() && m_current == 'n')) 1642 return Variant<double, const Identifier*>{ makeIdentifier(m_buffer8.data(), m_buffer8.size()) };1727 return NumberParseResult { makeIdentifier(m_buffer8.data(), m_buffer8.size()) }; 1643 1728 1644 1729 return WTF::nullopt; … … 1646 1731 1647 1732 template <typename T> 1648 ALWAYS_INLINE void Lexer<T>::parseNumberAfterDecimalPoint() 1649 { 1733 ALWAYS_INLINE bool Lexer<T>::parseNumberAfterDecimalPoint() 1734 { 1735 ASSERT(isASCIIDigit(m_current)); 1650 1736 record8('.'); 1651 while (isASCIIDigit(m_current)) { 1737 1738 do { 1739 if (m_current == '_') { 1740 if (UNLIKELY(!isASCIIDigit(peek(1)))) 1741 return false; 1742 1743 shift(); 1744 } 1745 1652 1746 record8(m_current); 1653 1747 shift(); 1654 } 1748 } while (isASCIIDigitOrSeparator(m_current)); 1749 1750 return true; 1655 1751 } 1656 1752 … … 1669 1765 1670 1766 do { 1767 if (m_current == '_') { 1768 if (UNLIKELY(!isASCIIDigit(peek(1)))) 1769 return false; 1770 1771 shift(); 1772 } 1773 1671 1774 record8(m_current); 1672 1775 shift(); 1673 } while (isASCIIDigit(m_current)); 1776 } while (isASCIIDigitOrSeparator(m_current)); 1777 1674 1778 return true; 1675 1779 } … … 2091 2195 break; 2092 2196 } 2093 parseNumberAfterDecimalPoint(); 2197 if (UNLIKELY(!parseNumberAfterDecimalPoint())) { 2198 m_lexErrorMessage = "Non-number found after decimal point"_s; 2199 token = INVALID_NUMERIC_LITERAL_ERRORTOK; 2200 goto returnError; 2201 } 2094 2202 token = DOUBLE; 2095 2203 if (isASCIIAlphaCaselessEqual(m_current, 'e')) { … … 2125 2233 2126 2234 auto parseNumberResult = parseHex(); 2127 if (WTF::holds_alternative<double>(parseNumberResult)) 2128 tokenData->doubleValue = WTF::get<double>(parseNumberResult); 2235 if (!parseNumberResult) 2236 tokenData->doubleValue = 0; 2237 else if (WTF::holds_alternative<double>(*parseNumberResult)) 2238 tokenData->doubleValue = WTF::get<double>(*parseNumberResult); 2129 2239 else { 2130 2240 token = BIGINT; 2131 2241 shift(); 2132 tokenData->bigIntString = WTF::get<const Identifier*>( parseNumberResult);2242 tokenData->bigIntString = WTF::get<const Identifier*>(*parseNumberResult); 2133 2243 tokenData->radix = 16; 2134 2244 } … … 2208 2318 m_buffer8.shrink(0); 2209 2319 break; 2320 } 2321 2322 if (UNLIKELY(m_current == '_')) { 2323 m_lexErrorMessage = "Numeric literals may not begin with 0_"_s; 2324 token = UNTERMINATED_OCTAL_NUMBER_ERRORTOK; 2325 goto returnError; 2210 2326 } 2211 2327 … … 2241 2357 if (m_current == '.') { 2242 2358 shift(); 2243 parseNumberAfterDecimalPoint(); 2359 if (UNLIKELY(isASCIIDigit(m_current) && !parseNumberAfterDecimalPoint())) { 2360 m_lexErrorMessage = "Non-number found after decimal point"_s; 2361 token = INVALID_NUMERIC_LITERAL_ERRORTOK; 2362 goto returnError; 2363 } 2244 2364 token = DOUBLE; 2245 2365 } -
trunk/Source/JavaScriptCore/parser/Lexer.h
r245648 r245655 180 180 181 181 using NumberParseResult = Variant<double, const Identifier*>; 182 ALWAYS_INLINE NumberParseResultparseHex();182 ALWAYS_INLINE Optional<NumberParseResult> parseHex(); 183 183 ALWAYS_INLINE Optional<NumberParseResult> parseBinary(); 184 184 ALWAYS_INLINE Optional<NumberParseResult> parseOctal(); 185 185 ALWAYS_INLINE Optional<NumberParseResult> parseDecimal(); 186 ALWAYS_INLINE voidparseNumberAfterDecimalPoint();186 ALWAYS_INLINE bool parseNumberAfterDecimalPoint(); 187 187 ALWAYS_INLINE bool parseNumberAfterExponentIndicator(); 188 188 ALWAYS_INLINE bool parseMultilineComment();
Note: See TracChangeset
for help on using the changeset viewer.