Bug 1421400 - Part 1: Add TokenStream::matchInteger to parse an integer string. r=jorendorff
authorAndré Bargull <andre.bargull@gmail.com>
Sun, 05 May 2019 09:55:48 +0000
changeset 472689 dae98f84b3f415d10c31cbe7d88778de8ebfe74c
parent 472688 801ff1a58ffc0cbfa6641b31b7a030b53d5bc6d5
child 472690 11d3fdc18c479945ef0f229cd2a6ce0fd83aa64a
push id35976
push useropoprus@mozilla.com
push dateMon, 06 May 2019 21:44:12 +0000
treeherdermozilla-central@e9f5f01d8b8e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1421400
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1421400 - Part 1: Add TokenStream::matchInteger to parse an integer string. r=jorendorff Part 3 will add the numeric separator parsing to this function. Differential Revision: https://phabricator.services.mozilla.com/D28529
js/src/frontend/TokenStream.cpp
js/src/frontend/TokenStream.h
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -161,16 +161,23 @@ static uint32_t GetSingleCodePoint(const
   }
 
   codePoint = **p;
   (*p)++;
   return codePoint;
 }
 
 template <typename CharT>
+static constexpr bool IsAsciiBinary(CharT c) {
+  using UnsignedCharT = std::make_unsigned_t<CharT>;
+  auto uc = static_cast<UnsignedCharT>(c);
+  return uc == '0' || uc == '1';
+}
+
+template <typename CharT>
 static constexpr bool IsAsciiOctal(CharT c) {
   using UnsignedCharT = std::make_unsigned_t<CharT>;
   auto uc = static_cast<UnsignedCharT>(c);
   return '0' <= uc && uc <= '7';
 }
 
 template <typename CharT>
 static constexpr uint8_t AsciiOctalToNumber(CharT c) {
@@ -2160,26 +2167,45 @@ void SourceUnits<Utf8Unit>::consumeRestO
       return;
     }
 
     consumeKnownCodePoint(peeked);
   }
 }
 
 template <typename Unit, class AnyCharsAccess>
+MOZ_MUST_USE MOZ_ALWAYS_INLINE bool
+TokenStreamSpecific<Unit, AnyCharsAccess>::matchInteger(
+    IsIntegerUnit isIntegerUnit, int32_t* nextUnit) {
+  int32_t unit;
+  while (true) {
+    unit = getCodeUnit();
+    if (isIntegerUnit(unit)) {
+      continue;
+    }
+    break;
+  }
+
+  *nextUnit = unit;
+  return true;
+}
+
+template <typename Unit, class AnyCharsAccess>
 MOZ_MUST_USE bool TokenStreamSpecific<Unit, AnyCharsAccess>::decimalNumber(
     int32_t unit, TokenStart start, const Unit* numStart, Modifier modifier,
     TokenKind* out) {
   // Run the bad-token code for every path out of this function except the
   // one success-case.
   auto noteBadToken = MakeScopeExit([this]() { this->badToken(); });
 
   // Consume integral component digits.
-  while (IsAsciiDigit(unit)) {
-    unit = getCodeUnit();
+  if (IsAsciiDigit(unit)) {
+    if (!matchInteger(IsAsciiDigit, &unit)) {
+      return false;
+    }
   }
 
   // Numbers contain no escapes, so we can read directly from |sourceUnits|.
   double dval;
   bool isBigInt = false;
   DecimalPoint decimalPoint = NoDecimal;
   if (unit != '.' && unit != 'e' && unit != 'E' && unit != 'n') {
     // NOTE: |unit| may be EOF here.
@@ -2193,19 +2219,19 @@ MOZ_MUST_USE bool TokenStreamSpecific<Un
     }
   } else if (unit == 'n' && anyCharsAccess().options().bigIntEnabledOption) {
     isBigInt = true;
     unit = peekCodeUnit();
   } else {
     // Consume any decimal dot and fractional component.
     if (unit == '.') {
       decimalPoint = HasDecimal;
-      do {
-        unit = getCodeUnit();
-      } while (IsAsciiDigit(unit));
+      if (!matchInteger(IsAsciiDigit, &unit)) {
+        return false;
+      }
     }
 
     // Consume any exponential notation.
     if (unit == 'e' || unit == 'E') {
       unit = getCodeUnit();
       if (unit == '+' || unit == '-') {
         unit = getCodeUnit();
       }
@@ -2213,19 +2239,19 @@ MOZ_MUST_USE bool TokenStreamSpecific<Un
       // Exponential notation must contain at least one digit.
       if (!IsAsciiDigit(unit)) {
         ungetCodeUnit(unit);
         error(JSMSG_MISSING_EXPONENT);
         return false;
       }
 
       // Consume exponential digits.
-      do {
-        unit = getCodeUnit();
-      } while (IsAsciiDigit(unit));
+      if (!matchInteger(IsAsciiDigit, &unit)) {
+        return false;
+      }
     }
 
     ungetCodeUnit(unit);
 
     // "0." and "0e..." numbers parse "." or "e..." here.  Neither range
     // contains a number, so we can't use |FullStringToDouble|.  (Parse
     // failures return 0.0, so we'll still get the right result.)
     if (!StringToDouble(anyCharsAccess().cx, numStart,
@@ -2612,50 +2638,50 @@ MOZ_MUST_USE bool TokenStreamSpecific<Un
           ungetCodeUnit(unit);
           error(JSMSG_MISSING_HEXDIGITS);
           return badToken();
         }
 
         // one past the '0x'
         numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
 
-        while (IsAsciiHexDigit(unit)) {
-          unit = getCodeUnit();
+        if (!matchInteger(IsAsciiHexDigit, &unit)) {
+          return badToken();
         }
       } else if (unit == 'b' || unit == 'B') {
         radix = 2;
         unit = getCodeUnit();
-        if (unit != '0' && unit != '1') {
+        if (!IsAsciiBinary(unit)) {
           // NOTE: |unit| may be EOF here.
           ungetCodeUnit(unit);
           error(JSMSG_MISSING_BINARY_DIGITS);
           return badToken();
         }
 
         // one past the '0b'
         numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
 
-        while (unit == '0' || unit == '1') {
-          unit = getCodeUnit();
+        if (!matchInteger(IsAsciiBinary, &unit)) {
+          return badToken();
         }
       } else if (unit == 'o' || unit == 'O') {
         radix = 8;
         unit = getCodeUnit();
         if (!IsAsciiOctal(unit)) {
           // NOTE: |unit| may be EOF here.
           ungetCodeUnit(unit);
           error(JSMSG_MISSING_OCTAL_DIGITS);
           return badToken();
         }
 
         // one past the '0o'
         numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
 
-        while (IsAsciiOctal(unit)) {
-          unit = getCodeUnit();
+        if (!matchInteger(IsAsciiOctal, &unit)) {
+          return badToken();
         }
       } else if (IsAsciiDigit(unit)) {
         radix = 8;
         isLegacyOctalOrNoctal = true;
         // one past the '0'
         numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
 
         do {
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -2505,16 +2505,20 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
       case InvalidEscapeType::Octal:
         errorAt(offset, JSMSG_DEPRECATED_OCTAL);
         return;
     }
   }
 
   MOZ_MUST_USE bool putIdentInCharBuffer(const Unit* identStart);
 
+  using IsIntegerUnit = bool (*)(int32_t);
+  MOZ_MUST_USE MOZ_ALWAYS_INLINE bool matchInteger(IsIntegerUnit isIntegerUnit,
+                                                   int32_t* nextUnit);
+
   /**
    * Tokenize a decimal number that begins at |numStart| into the provided
    * token.
    *
    * |unit| must be one of these values:
    *
    *   1. The first decimal digit in the integral part of a decimal number
    *      not starting with '0' or '.', e.g. '1' for "17", '3' for "3.14", or