Title: [245634] trunk
Revision
245634
Author
[email protected]
Date
2019-05-22 12:06:03 -0700 (Wed, 22 May 2019)

Log Message

[ESNext] Implement support for Numeric Separators
https://bugs.webkit.org/show_bug.cgi?id=196351

Reviewed by Keith Miller.

JSTests:

* stress/numeric-literal-separators.js: Added.
Add tests for feature.

* test262/expectations.yaml:
Mark 60 test cases as passing.

Source/_javascript_Core:

Implement the following proposal, which is now Stage 3:
  https://github.com/tc39/proposal-numeric-separator

Specifically, this allows `_` to be used as a separator in numeric literals.
It may be inserted arbitrarily without semantic effect, but it may not occur:
  - multiple times in a row
  - at the beginning or end of the literal
  - adjacent to `0x`, `0b`, `0o`, `.`, `e`, or `n`
  - after a leading zero (e.g. `0_123`), even in sloppy mode

* parser/Lexer.cpp:
(JSC::isASCIIDigitOrSeparator): Added.
(JSC::isASCIIHexDigitOrSeparator): Added.
(JSC::isASCIIBinaryDigitOrSeparator): Added.
(JSC::isASCIIOctalDigitOrSeparator): Added.
(JSC::Lexer<T>::parseHex):
(JSC::Lexer<T>::parseBinary):
(JSC::Lexer<T>::parseOctal):
(JSC::Lexer<T>::parseDecimal):
(JSC::Lexer<T>::parseNumberAfterDecimalPoint):
(JSC::Lexer<T>::parseNumberAfterExponentIndicator):
(JSC::Lexer<T>::lexWithoutClearingLineTerminator):
* parser/Lexer.h:

Modified Paths

Diff

Modified: trunk/JSTests/ChangeLog (245633 => 245634)


--- trunk/JSTests/ChangeLog	2019-05-22 18:08:12 UTC (rev 245633)
+++ trunk/JSTests/ChangeLog	2019-05-22 19:06:03 UTC (rev 245634)
@@ -1,3 +1,16 @@
+2019-05-22  Ross Kirsling  <[email protected]>
+
+        [ESNext] Implement support for Numeric Separators
+        https://bugs.webkit.org/show_bug.cgi?id=196351
+
+        Reviewed by Keith Miller.
+
+        * stress/numeric-literal-separators.js: Added.
+        Add tests for feature.
+
+        * test262/expectations.yaml:
+        Mark 60 test cases as passing.
+
 2019-05-22  Yusuke Suzuki  <[email protected]>
 
         [JSC] ArrayBufferContents::tryAllocate signs the pointer with allocation size and authenticates it with sizeInBytes

Modified: trunk/JSTests/test262/expectations.yaml (245633 => 245634)


--- trunk/JSTests/test262/expectations.yaml	2019-05-22 18:08:12 UTC (rev 245633)
+++ trunk/JSTests/test262/expectations.yaml	2019-05-22 19:06:03 UTC (rev 245634)
@@ -2586,96 +2586,6 @@
 test/language/global-code/script-decl-var-err.js:
   default: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
   strict mode: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
-test/language/literals/numeric/numeric-separator-literal-bil-bd-nsl-bd.js:
-  default: 'SyntaxError: No space between binary literal and identifier'
-  strict mode: 'SyntaxError: No space between binary literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-bil-bd-nsl-bds.js:
-  default: 'SyntaxError: No space between binary literal and identifier'
-  strict mode: 'SyntaxError: No space between binary literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-bil-bds-nsl-bd.js:
-  default: 'SyntaxError: No space between binary literal and identifier'
-  strict mode: 'SyntaxError: No space between binary literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-bil-bds-nsl-bds.js:
-  default: 'SyntaxError: No space between binary literal and identifier'
-  strict mode: 'SyntaxError: No space between binary literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-dd-dot-dd-ep-sign-minus-dd-nsl-dd.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-dd-dot-dd-ep-sign-minus-dds-nsl-dd.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-dd-dot-dd-ep-sign-plus-dd-nsl-dd.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-dd-dot-dd-ep-sign-plus-dds-nsl-dd.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-dd-nsl-dd-one-of.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-dds-dot-dd-nsl-dd-ep-dd.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-dds-nsl-dd.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-dot-dd-nsl-dd-ep.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-dot-dd-nsl-dds-ep.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-dot-dds-nsl-dd-ep.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-dot-dds-nsl-dds-ep.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-hil-hd-nsl-hd.js:
-  default: 'SyntaxError: No space between hexadecimal literal and identifier'
-  strict mode: 'SyntaxError: No space between hexadecimal literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-hil-hd-nsl-hds.js:
-  default: 'SyntaxError: No space between hexadecimal literal and identifier'
-  strict mode: 'SyntaxError: No space between hexadecimal literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-hil-hds-nsl-hd.js:
-  default: 'SyntaxError: No space between hexadecimal literal and identifier'
-  strict mode: 'SyntaxError: No space between hexadecimal literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-hil-hds-nsl-hds.js:
-  default: 'SyntaxError: No space between hexadecimal literal and identifier'
-  strict mode: 'SyntaxError: No space between hexadecimal literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-hil-od-nsl-od-one-of.js:
-  default: 'SyntaxError: No space between hexadecimal literal and identifier'
-  strict mode: 'SyntaxError: No space between hexadecimal literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-nzd-nsl-dd-one-of.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-nzd-nsl-dd.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-nzd-nsl-dds.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-oil-od-nsl-od-one-of.js:
-  default: 'SyntaxError: No space between octal literal and identifier'
-  strict mode: 'SyntaxError: No space between octal literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-oil-od-nsl-od.js:
-  default: 'SyntaxError: No space between octal literal and identifier'
-  strict mode: 'SyntaxError: No space between octal literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-oil-od-nsl-ods.js:
-  default: 'SyntaxError: No space between octal literal and identifier'
-  strict mode: 'SyntaxError: No space between octal literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-oil-ods-nsl-od.js:
-  default: 'SyntaxError: No space between octal literal and identifier'
-  strict mode: 'SyntaxError: No space between octal literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-oil-ods-nsl-ods.js:
-  default: 'SyntaxError: No space between octal literal and identifier'
-  strict mode: 'SyntaxError: No space between octal literal and identifier'
-test/language/literals/numeric/numeric-separator-literal-sign-minus-dds-nsl-dd.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/numeric/numeric-separator-literal-sign-plus-dds-nsl-dd.js:
-  default: 'SyntaxError: No identifiers allowed directly after numeric literal'
-  strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
 test/language/literals/regexp/named-groups/invalid-dangling-groupname-2-u.js:
   default: 'Test262: This statement should not be evaluated.'
   strict mode: 'Test262: This statement should not be evaluated.'

Modified: trunk/Source/_javascript_Core/ChangeLog (245633 => 245634)


--- trunk/Source/_javascript_Core/ChangeLog	2019-05-22 18:08:12 UTC (rev 245633)
+++ trunk/Source/_javascript_Core/ChangeLog	2019-05-22 19:06:03 UTC (rev 245634)
@@ -1,3 +1,34 @@
+2019-05-22  Ross Kirsling  <[email protected]>
+
+        [ESNext] Implement support for Numeric Separators
+        https://bugs.webkit.org/show_bug.cgi?id=196351
+
+        Reviewed by Keith Miller.
+
+        Implement the following proposal, which is now Stage 3:
+          https://github.com/tc39/proposal-numeric-separator
+
+        Specifically, this allows `_` to be used as a separator in numeric literals.
+        It may be inserted arbitrarily without semantic effect, but it may not occur:
+          - multiple times in a row
+          - at the beginning or end of the literal
+          - adjacent to `0x`, `0b`, `0o`, `.`, `e`, or `n`
+          - after a leading zero (e.g. `0_123`), even in sloppy mode
+
+        * parser/Lexer.cpp:
+        (JSC::isASCIIDigitOrSeparator): Added.
+        (JSC::isASCIIHexDigitOrSeparator): Added.
+        (JSC::isASCIIBinaryDigitOrSeparator): Added.
+        (JSC::isASCIIOctalDigitOrSeparator): Added.
+        (JSC::Lexer<T>::parseHex):
+        (JSC::Lexer<T>::parseBinary):
+        (JSC::Lexer<T>::parseOctal):
+        (JSC::Lexer<T>::parseDecimal):
+        (JSC::Lexer<T>::parseNumberAfterDecimalPoint):
+        (JSC::Lexer<T>::parseNumberAfterExponentIndicator):
+        (JSC::Lexer<T>::lexWithoutClearingLineTerminator):
+        * parser/Lexer.h:
+
 2019-05-22  Yusuke Suzuki  <[email protected]>
 
         [JSC] ArrayBufferContents::tryAllocate signs the pointer with allocation size and authenticates it with sizeInBytes

Modified: trunk/Source/_javascript_Core/parser/Lexer.cpp (245633 => 245634)


--- trunk/Source/_javascript_Core/parser/Lexer.cpp	2019-05-22 18:08:12 UTC (rev 245633)
+++ trunk/Source/_javascript_Core/parser/Lexer.cpp	2019-05-22 19:06:03 UTC (rev 245634)
@@ -813,6 +813,30 @@
     return isIdentPartIncludingEscapeTemplate(code, codeEnd);
 }
 
+template<typename CharacterType>
+static inline bool isASCIIDigitOrSeparator(CharacterType character)
+{
+    return isASCIIDigit(character) || character == '_';
+}
+
+template<typename CharacterType>
+static inline bool isASCIIHexDigitOrSeparator(CharacterType character)
+{
+    return isASCIIHexDigit(character) || character == '_';
+}
+
+template<typename CharacterType>
+static inline bool isASCIIBinaryDigitOrSeparator(CharacterType character)
+{
+    return isASCIIBinaryDigit(character) || character == '_';
+}
+
+template<typename CharacterType>
+static inline bool isASCIIOctalDigitOrSeparator(CharacterType character)
+{
+    return isASCIIOctalDigit(character) || character == '_';
+}
+
 static inline LChar singleEscape(int c)
 {
     if (c < 128) {
@@ -1490,20 +1514,29 @@
 }
 
 template <typename T>
-ALWAYS_INLINE auto Lexer<T>::parseHex() -> NumberParseResult
+ALWAYS_INLINE auto Lexer<T>::parseHex() -> Optional<NumberParseResult>
 {
+    ASSERT(isASCIIHexDigit(m_current));
+
     // Optimization: most hexadecimal values fit into 4 bytes.
     uint32_t hexValue = 0;
     int maximumDigits = 7;
 
     do {
+        if (m_current == '_') {
+            if (UNLIKELY(!isASCIIHexDigit(peek(1))))
+                return WTF::nullopt;
+
+            shift();
+        }
+
         hexValue = (hexValue << 4) + toASCIIHexValue(m_current);
         shift();
         --maximumDigits;
-    } while (isASCIIHexDigit(m_current) && maximumDigits >= 0);
+    } while (isASCIIHexDigitOrSeparator(m_current) && maximumDigits >= 0);
 
     if (LIKELY(maximumDigits >= 0 && m_current != 'n'))
-        return hexValue;
+        return NumberParseResult { hexValue };
 
     // No more place in the hexValue buffer.
     // The values are shifted out and placed into the m_buffer8 vector.
@@ -1516,20 +1549,29 @@
          hexValue <<= 4;
     }
 
-    while (isASCIIHexDigit(m_current)) {
+    while (isASCIIHexDigitOrSeparator(m_current)) {
+        if (m_current == '_') {
+            if (UNLIKELY(!isASCIIHexDigit(peek(1))))
+                return WTF::nullopt;
+
+            shift();
+        }
+
         record8(m_current);
         shift();
     }
 
     if (UNLIKELY(Options::useBigInt() && m_current == 'n'))
-        return makeIdentifier(m_buffer8.data(), m_buffer8.size());
+        return NumberParseResult { makeIdentifier(m_buffer8.data(), m_buffer8.size()) };
     
-    return parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 16);
+    return NumberParseResult { parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 16) };
 }
 
 template <typename T>
 ALWAYS_INLINE auto Lexer<T>::parseBinary() -> Optional<NumberParseResult>
 {
+    ASSERT(isASCIIBinaryDigit(m_current));
+
     // Optimization: most binary values fit into 4 bytes.
     uint32_t binaryValue = 0;
     const unsigned maximumDigits = 32;
@@ -1539,35 +1581,51 @@
     LChar digits[maximumDigits];
 
     do {
+        if (m_current == '_') {
+            if (UNLIKELY(!isASCIIBinaryDigit(peek(1))))
+                return WTF::nullopt;
+
+            shift();
+        }
+
         binaryValue = (binaryValue << 1) + (m_current - '0');
         digits[digit] = m_current;
         shift();
         --digit;
-    } while (isASCIIBinaryDigit(m_current) && digit >= 0);
+    } while (isASCIIBinaryDigitOrSeparator(m_current) && digit >= 0);
 
-    if (LIKELY(!isASCIIDigit(m_current) && digit >= 0 && m_current != 'n'))
-        return Variant<double, const Identifier*> { binaryValue };
+    if (LIKELY(!isASCIIDigitOrSeparator(m_current) && digit >= 0 && m_current != 'n'))
+        return NumberParseResult { binaryValue };
 
     for (int i = maximumDigits - 1; i > digit; --i)
         record8(digits[i]);
 
-    while (isASCIIBinaryDigit(m_current)) {
+    while (isASCIIBinaryDigitOrSeparator(m_current)) {
+        if (m_current == '_') {
+            if (UNLIKELY(!isASCIIBinaryDigit(peek(1))))
+                return WTF::nullopt;
+
+            shift();
+        }
+
         record8(m_current);
         shift();
     }
 
     if (UNLIKELY(Options::useBigInt() && m_current == 'n'))
-        return Variant<double, const Identifier*> { makeIdentifier(m_buffer8.data(), m_buffer8.size()) };
+        return NumberParseResult { makeIdentifier(m_buffer8.data(), m_buffer8.size()) };
 
     if (isASCIIDigit(m_current))
         return WTF::nullopt;
 
-    return Variant<double, const Identifier*> { parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 2) };
+    return NumberParseResult { parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 2) };
 }
 
 template <typename T>
 ALWAYS_INLINE auto Lexer<T>::parseOctal() -> Optional<NumberParseResult>
 {
+    ASSERT(isASCIIOctalDigit(m_current));
+
     // Optimization: most octal values fit into 4 bytes.
     uint32_t octalValue = 0;
     const unsigned maximumDigits = 10;
@@ -1577,36 +1635,51 @@
     LChar digits[maximumDigits];
 
     do {
+        if (m_current == '_') {
+            if (UNLIKELY(!isASCIIOctalDigit(peek(1))))
+                return WTF::nullopt;
+
+            shift();
+        }
+
         octalValue = octalValue * 8 + (m_current - '0');
         digits[digit] = m_current;
         shift();
         --digit;
-    } while (isASCIIOctalDigit(m_current) && digit >= 0);
+    } while (isASCIIOctalDigitOrSeparator(m_current) && digit >= 0);
 
-    if (LIKELY(!isASCIIDigit(m_current) && digit >= 0 && m_current != 'n'))
-        return Variant<double, const Identifier*> { octalValue };
+    if (LIKELY(!isASCIIDigitOrSeparator(m_current) && digit >= 0 && m_current != 'n'))
+        return NumberParseResult { octalValue };
 
-
     for (int i = maximumDigits - 1; i > digit; --i)
          record8(digits[i]);
 
-    while (isASCIIOctalDigit(m_current)) {
+    while (isASCIIOctalDigitOrSeparator(m_current)) {
+        if (m_current == '_') {
+            if (UNLIKELY(!isASCIIOctalDigit(peek(1))))
+                return WTF::nullopt;
+
+            shift();
+        }
+
         record8(m_current);
         shift();
     }
 
     if (UNLIKELY(Options::useBigInt() && m_current == 'n'))
-        return Variant<double, const Identifier*> { makeIdentifier(m_buffer8.data(), m_buffer8.size()) };
+        return NumberParseResult { makeIdentifier(m_buffer8.data(), m_buffer8.size()) };
 
     if (isASCIIDigit(m_current))
         return WTF::nullopt;
 
-    return Variant<double, const Identifier*> { parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 8) };
+    return NumberParseResult { parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 8) };
 }
 
 template <typename T>
 ALWAYS_INLINE auto Lexer<T>::parseDecimal() -> Optional<NumberParseResult>
 {
+    ASSERT(isASCIIDigit(m_current));
+
     // Optimization: most decimal values fit into 4 bytes.
     uint32_t decimalValue = 0;
 
@@ -1620,38 +1693,63 @@
         LChar digits[maximumDigits];
 
         do {
+            if (m_current == '_') {
+                if (UNLIKELY(!isASCIIDigit(peek(1))))
+                    return WTF::nullopt;
+
+                shift();
+            }
+
             decimalValue = decimalValue * 10 + (m_current - '0');
             digits[digit] = m_current;
             shift();
             --digit;
-        } while (isASCIIDigit(m_current) && digit >= 0);
+        } while (isASCIIDigitOrSeparator(m_current) && digit >= 0);
 
         if (digit >= 0 && m_current != '.' && !isASCIIAlphaCaselessEqual(m_current, 'e') && m_current != 'n')
-            return Variant<double, const Identifier*> { decimalValue };
+            return NumberParseResult { decimalValue };
 
         for (int i = maximumDigits - 1; i > digit; --i)
             record8(digits[i]);
     }
 
-    while (isASCIIDigit(m_current)) {
+    while (isASCIIDigitOrSeparator(m_current)) {
+        if (m_current == '_') {
+            if (UNLIKELY(!isASCIIDigit(peek(1))))
+                return WTF::nullopt;
+
+            shift();
+        }
+
         record8(m_current);
         shift();
     }
     
     if (UNLIKELY(Options::useBigInt() && m_current == 'n'))
-        return Variant<double, const Identifier*> { makeIdentifier(m_buffer8.data(), m_buffer8.size()) };
+        return NumberParseResult { makeIdentifier(m_buffer8.data(), m_buffer8.size()) };
 
     return WTF::nullopt;
 }
 
 template <typename T>
-ALWAYS_INLINE void Lexer<T>::parseNumberAfterDecimalPoint()
+ALWAYS_INLINE bool Lexer<T>::parseNumberAfterDecimalPoint()
 {
+    ASSERT(isASCIIDigit(m_current));
     record8('.');
-    while (isASCIIDigit(m_current)) {
+
+    do {
+        if (m_current == '_') {
+            if (UNLIKELY(!isASCIIDigit(peek(1))))
+                return false;
+
+            shift();
+        }
+
         record8(m_current);
         shift();
-    }
+    } while (isASCIIDigitOrSeparator(m_current));
+
+    return true;
 }
 
 template <typename T>
@@ -1668,9 +1766,17 @@
         return false;
 
     do {
+        if (m_current == '_') {
+            if (UNLIKELY(!isASCIIDigit(peek(1))))
+                return false;
+
+            shift();
+        }
+
         record8(m_current);
         shift();
-    } while (isASCIIDigit(m_current));
+    } while (isASCIIDigitOrSeparator(m_current));
+
     return true;
 }
 
@@ -2090,7 +2196,11 @@
             token = DOT;
             break;
         }
-        parseNumberAfterDecimalPoint();
+        if (UNLIKELY(!parseNumberAfterDecimalPoint())) {
+            m_lexErrorMessage = "Non-number found after decimal point"_s;
+            token = INVALID_NUMERIC_LITERAL_ERRORTOK;
+            goto returnError;
+        }
         token = DOUBLE;
         if (isASCIIAlphaCaselessEqual(m_current, 'e')) {
             if (!parseNumberAfterExponentIndicator()) {
@@ -2124,12 +2234,14 @@
             shift();
 
             auto parseNumberResult = parseHex();
-            if (WTF::holds_alternative<double>(parseNumberResult))
-                tokenData->doubleValue = WTF::get<double>(parseNumberResult);
+            if (!parseNumberResult)
+                tokenData->doubleValue = 0;
+            else if (WTF::holds_alternative<double>(*parseNumberResult))
+                tokenData->doubleValue = WTF::get<double>(*parseNumberResult);
             else {
                 token = BIGINT;
                 shift();
-                tokenData->bigIntString = WTF::get<const Identifier*>(parseNumberResult);
+                tokenData->bigIntString = WTF::get<const Identifier*>(*parseNumberResult);
                 tokenData->radix = 16;
             }
 
@@ -2209,6 +2321,12 @@
             break;
         }
 
+        if (UNLIKELY(m_current == '_')) {
+            m_lexErrorMessage = "Numeric literals may not begin with 0_"_s;
+            token = UNTERMINATED_OCTAL_NUMBER_ERRORTOK;
+            goto returnError;
+        }
+
         record8('0');
         if (strictMode && isASCIIDigit(m_current)) {
             m_lexErrorMessage = "Decimal integer literals with a leading zero are forbidden in strict mode"_s;
@@ -2240,7 +2358,11 @@
                     token = INTEGER;
                     if (m_current == '.') {
                         shift();
-                        parseNumberAfterDecimalPoint();
+                        if (UNLIKELY(isASCIIDigit(m_current) && !parseNumberAfterDecimalPoint())) {
+                            m_lexErrorMessage = "Non-number found after decimal point"_s;
+                            token = INVALID_NUMERIC_LITERAL_ERRORTOK;
+                            goto returnError;
+                        }
                         token = DOUBLE;
                     }
                     if (isASCIIAlphaCaselessEqual(m_current, 'e')) {

Modified: trunk/Source/_javascript_Core/parser/Lexer.h (245633 => 245634)


--- trunk/Source/_javascript_Core/parser/Lexer.h	2019-05-22 18:08:12 UTC (rev 245633)
+++ trunk/Source/_javascript_Core/parser/Lexer.h	2019-05-22 19:06:03 UTC (rev 245634)
@@ -179,11 +179,11 @@
     ALWAYS_INLINE StringParseResult parseTemplateLiteral(JSTokenData*, RawStringsBuildMode);
     
     using NumberParseResult = Variant<double, const Identifier*>;
-    ALWAYS_INLINE NumberParseResult parseHex();
+    ALWAYS_INLINE Optional<NumberParseResult> parseHex();
     ALWAYS_INLINE Optional<NumberParseResult> parseBinary();
     ALWAYS_INLINE Optional<NumberParseResult> parseOctal();
     ALWAYS_INLINE Optional<NumberParseResult> parseDecimal();
-    ALWAYS_INLINE void parseNumberAfterDecimalPoint();
+    ALWAYS_INLINE bool parseNumberAfterDecimalPoint();
     ALWAYS_INLINE bool parseNumberAfterExponentIndicator();
     ALWAYS_INLINE bool parseMultilineComment();
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to