%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/temporal/
Upload File :
Create Path :
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/temporal/temporal-parser.cc

// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/temporal/temporal-parser.h"

#include "src/base/bounds.h"
#include "src/base/optional.h"
#include "src/objects/string-inl.h"
#include "src/strings/char-predicates-inl.h"

namespace v8 {
namespace internal {

namespace {

// Temporal #prod-TZLeadingChar
inline constexpr bool IsTZLeadingChar(base::uc32 c) {
  return base::IsInRange(AsciiAlphaToLower(c), 'a', 'z') || c == '.' ||
         c == '_';
}

// Temporal #prod-TZChar
inline constexpr bool IsTZChar(base::uc32 c) {
  return IsTZLeadingChar(c) || c == '-';
}

// Temporal #prod-DecimalSeparator
inline constexpr bool IsDecimalSeparator(base::uc32 c) {
  return c == '.' || c == ',';
}

// Temporal #prod-DateTimeSeparator
inline constexpr bool IsDateTimeSeparator(base::uc32 c) {
  return c == ' ' || AsciiAlphaToLower(c) == 't';
}

// Temporal #prod-ASCIISign
inline constexpr bool IsAsciiSign(base::uc32 c) { return c == '-' || c == '+'; }

// Temporal #prod-Sign
inline constexpr bool IsSign(base::uc32 c) {
  return c == 0x2212 || IsAsciiSign(c);
}

// Temporal #prod-TimeZoneUTCOffsetSign
inline constexpr bool IsTimeZoneUTCOffsetSign(base::uc32 c) {
  return IsSign(c);
}

inline constexpr base::uc32 CanonicalSign(base::uc32 c) {
  return c == 0x2212 ? '-' : c;
}

inline constexpr int32_t ToInt(base::uc32 c) { return c - '0'; }

// A helper template to make the scanning of production w/ two digits simpler.
template <typename Char>
bool HasTwoDigits(base::Vector<Char> str, int32_t s, int32_t* out) {
  if (str.length() >= (s + 2) && IsDecimalDigit(str[s]) &&
      IsDecimalDigit(str[s + 1])) {
    *out = ToInt(str[s]) * 10 + ToInt(str[s + 1]);
    return true;
  }
  return false;
}

// A helper template to make the scanning of production w/ a single two digits
// value simpler.
template <typename Char>
int32_t ScanTwoDigitsExpectValue(base::Vector<Char> str, int32_t s,
                                 int32_t expected, int32_t* out) {
  return HasTwoDigits<Char>(str, s, out) && (*out == expected) ? 2 : 0;
}

// A helper template to make the scanning of production w/ two digits value in a
// range simpler.
template <typename Char>
int32_t ScanTwoDigitsExpectRange(base::Vector<Char> str, int32_t s, int32_t min,
                                 int32_t max, int32_t* out) {
  return HasTwoDigits<Char>(str, s, out) && base::IsInRange(*out, min, max) ? 2
                                                                            : 0;
}

// A helper template to make the scanning of production w/ two digits value as 0
// or in a range simpler.
template <typename Char>
int32_t ScanTwoDigitsExpectZeroOrRange(base::Vector<Char> str, int32_t s,
                                       int32_t min, int32_t max, int32_t* out) {
  return HasTwoDigits<Char>(str, s, out) &&
                 (*out == 0 || base::IsInRange(*out, min, max))
             ? 2
             : 0;
}

/**
 * The TemporalParser use two types of internal routine:
 * - Scan routines: Follow the function signature below:
 *   template <typename Char> int32_t Scan$ProductionName(
 *   base::Vector<Char> str, int32_t s, R* out)
 *
 *   These routine scan the next item from position s in str and store the
 *   parsed result into out if the expected string is successfully scanned.
 *   It return the length of matched text from s or 0 to indicate no
 *   expected item matched.
 *
 * - Satisfy routines: Follow the function sigature below:
 *   template <typename Char>
 *   bool Satisfy$ProductionName(base::Vector<Char> str, R* r);
 *   It scan from the beginning of the str by calling Scan routines to put
 *   parsed result into r and return true if the entire str satisfy the
 *   production. It internally use Scan routines.
 *
 * TODO(ftang) investigate refactoring to class before shipping
 * Reference to RegExpParserImpl by encapsulating the cursor position and
 * only manipulating the current character and position with Next(),
 * Advance(), current(), etc
 */

// For Hour Production
// Hour:
//   [0 1] Digit
//   2 [0 1 2 3]
template <typename Char>
int32_t ScanHour(base::Vector<Char> str, int32_t s, int32_t* out) {
  return ScanTwoDigitsExpectRange<Char>(str, s, 0, 23, out);
}

// UnpaddedHour :
//   DecimalDigit
//   1 DecimalDigit
//   20
//   21
//   22
//   23
template <typename Char>
int32_t ScanUnpaddedHour(base::Vector<Char> str, int32_t s) {
  int32_t dummy;
  int32_t len = ScanTwoDigitsExpectRange<Char>(str, s, 10, 23, &dummy);
  if (len > 0) return len;
  if (str.length() >= (s + 1) && IsDecimalDigit(str[s])) return 1;
  return 0;
}

// MinuteSecond:
//   [0 1 2 3 4 5] Digit
template <typename Char>
int32_t ScanMinuteSecond(base::Vector<Char> str, int32_t s, int32_t* out) {
  return ScanTwoDigitsExpectRange<Char>(str, s, 0, 59, out);
}

// For the forward production in the grammar such as
// ProductionB:
//   ProductionT
#define SCAN_FORWARD(B, T, R)                                \
  template <typename Char>                                   \
  int32_t Scan##B(base::Vector<Char> str, int32_t s, R* r) { \
    return Scan##T(str, s, r);                               \
  }

// Same as above but store the result into a particular field in R

// For the forward production in the grammar such as
// ProductionB:
//   ProductionT1
//   ProductionT2
#define SCAN_EITHER_FORWARD(B, T1, T2, R)                    \
  template <typename Char>                                   \
  int32_t Scan##B(base::Vector<Char> str, int32_t s, R* r) { \
    int32_t len;                                             \
    if ((len = Scan##T1(str, s, r)) > 0) return len;         \
    return Scan##T2(str, s, r);                              \
  }

// TimeHour: Hour
SCAN_FORWARD(TimeHour, Hour, int32_t)

// TimeMinute: MinuteSecond
SCAN_FORWARD(TimeMinute, MinuteSecond, int32_t)

// TimeSecond:
//   MinuteSecond
//   60
template <typename Char>
int32_t ScanTimeSecond(base::Vector<Char> str, int32_t s, int32_t* out) {
  return ScanTwoDigitsExpectRange<Char>(str, s, 0, 60, out);
}

constexpr int kPowerOfTen[] = {1,      10,      100,      1000,     10000,
                               100000, 1000000, 10000000, 100000000};

// FractionalPart : Digit{1,9}
template <typename Char>
int32_t ScanFractionalPart(base::Vector<Char> str, int32_t s, int32_t* out) {
  int32_t cur = s;
  if ((str.length() < (cur + 1)) || !IsDecimalDigit(str[cur])) return 0;
  *out = ToInt(str[cur++]);
  while ((cur < str.length()) && ((cur - s) < 9) && IsDecimalDigit(str[cur])) {
    *out = 10 * (*out) + ToInt(str[cur++]);
  }
  *out *= kPowerOfTen[9 - (cur - s)];
  return cur - s;
}

// TimeFraction: FractionalPart
SCAN_FORWARD(TimeFractionalPart, FractionalPart, int32_t)

// Fraction: DecimalSeparator FractionalPart
// DecimalSeparator: one of , .
template <typename Char>
int32_t ScanFraction(base::Vector<Char> str, int32_t s, int32_t* out) {
  if ((str.length() < (s + 2)) || (!IsDecimalSeparator(str[s]))) return 0;
  int32_t len;
  if ((len = ScanFractionalPart(str, s + 1, out)) == 0) return 0;
  return len + 1;
}

// TimeFraction: DecimalSeparator TimeFractionalPart
// DecimalSeparator: one of , .
template <typename Char>
int32_t ScanTimeFraction(base::Vector<Char> str, int32_t s, int32_t* out) {
  if ((str.length() < (s + 2)) || (!IsDecimalSeparator(str[s]))) return 0;
  int32_t len;
  if ((len = ScanTimeFractionalPart(str, s + 1, out)) == 0) return 0;
  return len + 1;
}

template <typename Char>
int32_t ScanTimeFraction(base::Vector<Char> str, int32_t s,
                         ParsedISO8601Result* r) {
  return ScanTimeFraction(str, s, &(r->time_nanosecond));
}

// TimeSpec:
//  TimeHour
//  TimeHour : TimeMinute
//  TimeHour : TimeMinute : TimeSecond [TimeFraction]
//  TimeHour TimeMinute
//  TimeHour TimeMinute TimeSecond [TimeFraction]
template <typename Char>
int32_t ScanTimeSpec(base::Vector<Char> str, int32_t s,
                     ParsedISO8601Result* r) {
  int32_t time_hour, time_minute, time_second;
  int32_t len;
  int32_t cur = s;
  if ((len = ScanTimeHour(str, cur, &time_hour)) == 0) return 0;
  cur += len;
  if ((cur + 1) > str.length()) {
    // TimeHour
    r->time_hour = time_hour;
    return cur - s;
  }
  if (str[cur] == ':') {
    cur++;
    if ((len = ScanTimeMinute(str, cur, &time_minute)) == 0) return 0;
    cur += len;
    if ((cur + 1) > str.length() || (str[cur] != ':')) {
      // TimeHour : TimeMinute
      r->time_hour = time_hour;
      r->time_minute = time_minute;
      return cur - s;
    }
    cur++;
    if ((len = ScanTimeSecond(str, cur, &time_second)) == 0) return 0;
  } else {
    if ((len = ScanTimeMinute(str, cur, &time_minute)) == 0) {
      // TimeHour
      r->time_hour = time_hour;
      return cur - s;
    }
    cur += len;
    if ((len = ScanTimeSecond(str, cur, &time_second)) == 0) {
      // TimeHour TimeMinute
      r->time_hour = time_hour;
      r->time_minute = time_minute;
      return cur - s;
    }
  }
  cur += len;
  len = ScanTimeFraction(str, cur, r);
  r->time_hour = time_hour;
  r->time_minute = time_minute;
  r->time_second = time_second;
  cur += len;
  return cur - s;
}

// TimeSpecSeparator: DateTimeSeparator TimeSpec
// DateTimeSeparator: SPACE, 't', or 'T'
template <typename Char>
int32_t ScanTimeSpecSeparator(base::Vector<Char> str, int32_t s,
                              ParsedISO8601Result* r) {
  if (!(((s + 1) < str.length()) && IsDateTimeSeparator(str[s]))) return 0;
  int32_t len = ScanTimeSpec(str, s + 1, r);
  return (len == 0) ? 0 : len + 1;
}

// DateExtendedYear: Sign Digit Digit Digit Digit Digit Digit
template <typename Char>
int32_t ScanDateExtendedYear(base::Vector<Char> str, int32_t s, int32_t* out) {
  if (str.length() < (s + 7)) return 0;
  if (IsSign(str[s]) && IsDecimalDigit(str[s + 1]) &&
      IsDecimalDigit(str[s + 2]) && IsDecimalDigit(str[s + 3]) &&
      IsDecimalDigit(str[s + 4]) && IsDecimalDigit(str[s + 5]) &&
      IsDecimalDigit(str[s + 6])) {
    int32_t sign = (CanonicalSign(str[s]) == '-') ? -1 : 1;
    *out = sign * (ToInt(str[s + 1]) * 100000 + ToInt(str[s + 2]) * 10000 +
                   ToInt(str[s + 3]) * 1000 + ToInt(str[s + 4]) * 100 +
                   ToInt(str[s + 5]) * 10 + ToInt(str[s + 6]));
    // In the end of #sec-temporal-iso8601grammar
    // It is a Syntax Error if DateExtendedYear is "-000000" or "−000000"
    // (U+2212 MINUS SIGN followed by 000000).
    if (sign == -1 && *out == 0) return 0;
    return 7;
  }
  return 0;
}

// DateFourDigitYear: Digit Digit Digit Digit
template <typename Char>
int32_t ScanDateFourDigitYear(base::Vector<Char> str, int32_t s, int32_t* out) {
  if (str.length() < (s + 4)) return 0;
  if (IsDecimalDigit(str[s]) && IsDecimalDigit(str[s + 1]) &&
      IsDecimalDigit(str[s + 2]) && IsDecimalDigit(str[s + 3])) {
    *out = ToInt(str[s]) * 1000 + ToInt(str[s + 1]) * 100 +
           ToInt(str[s + 2]) * 10 + ToInt(str[s + 3]);
    return 4;
  }
  return 0;
}

// DateYear:
//   DateFourDigitYear
//   DateExtendedYear
// The lookahead is at most 1 char.
SCAN_EITHER_FORWARD(DateYear, DateFourDigitYear, DateExtendedYear, int32_t)

// DateMonth:
//   0 NonzeroDigit
//   10
//   11
//   12
template <typename Char>
int32_t ScanDateMonth(base::Vector<Char> str, int32_t s, int32_t* out) {
  return ScanTwoDigitsExpectRange<Char>(str, s, 1, 12, out);
}

// DateDay:
//   0 NonzeroDigit
//   1 Digit
//   2 Digit
//   30
//   31
template <typename Char>
int32_t ScanDateDay(base::Vector<Char> str, int32_t s, int32_t* out) {
  return ScanTwoDigitsExpectRange<Char>(str, s, 1, 31, out);
}

// Date:
//   DateYear - DateMonth - DateDay
//   DateYear DateMonth DateDay
template <typename Char>
int32_t ScanDate(base::Vector<Char> str, int32_t s, ParsedISO8601Result* r) {
  int32_t date_year, date_month, date_day;
  int32_t cur = s;
  int32_t len;
  if ((len = ScanDateYear(str, cur, &date_year)) == 0) return 0;
  if (((cur += len) + 1) > str.length()) return 0;
  if (str[cur] == '-') {
    cur++;
    if ((len = ScanDateMonth(str, cur, &date_month)) == 0) return 0;
    cur += len;
    if (((cur + 1) > str.length()) || (str[cur++] != '-')) return 0;
  } else {
    if ((len = ScanDateMonth(str, cur, &date_month)) == 0) return 0;
    cur += len;
  }
  if ((len = ScanDateDay(str, cur, &date_day)) == 0) return 0;
  r->date_year = date_year;
  r->date_month = date_month;
  r->date_day = date_day;
  return cur + len - s;
}

// DateMonthWithThirtyOneDays : one of
//    01 03 05 07 08 10 12
template <typename Char>
int32_t ScanDateMonthWithThirtyOneDays(base::Vector<Char> str, int32_t s) {
  int32_t value;
  if (!HasTwoDigits(str, s, &value)) return false;
  return value == 1 || value == 3 || value == 5 || value == 7 || value == 8 ||
         value == 10 || value == 12;
}

// TimeZoneUTCOffsetHour: Hour
SCAN_FORWARD(TimeZoneUTCOffsetHour, Hour, int32_t)

// TimeZoneUTCOffsetMinute
SCAN_FORWARD(TimeZoneUTCOffsetMinute, MinuteSecond, int32_t)

// TimeZoneUTCOffsetSecond
SCAN_FORWARD(TimeZoneUTCOffsetSecond, MinuteSecond, int32_t)

// TimeZoneUTCOffsetFractionalPart: FractionalPart
// See PR1796
SCAN_FORWARD(TimeZoneUTCOffsetFractionalPart, FractionalPart, int32_t)

// TimeZoneUTCOffsetFraction: DecimalSeparator TimeZoneUTCOffsetFractionalPart
// See PR1796
template <typename Char>
int32_t ScanTimeZoneUTCOffsetFraction(base::Vector<Char> str, int32_t s,
                                      int32_t* out) {
  if ((str.length() < (s + 2)) || (!IsDecimalSeparator(str[s]))) return 0;
  int32_t len;
  if ((len = ScanTimeZoneUTCOffsetFractionalPart(str, s + 1, out)) > 0) {
    return len + 1;
  }
  return 0;
}

// TimeZoneNumericUTCOffset:
//   TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour
//   TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute
//   TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute
//   TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute :
//   TimeZoneUTCOffsetSecond [TimeZoneUTCOffsetFraction] TimeZoneUTCOffsetSign
//   TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute TimeZoneUTCOffsetSecond
//   [TimeZoneUTCOffsetFraction]

template <typename Char>
int32_t ScanTimeZoneNumericUTCOffset(base::Vector<Char> str, int32_t s,
                                     ParsedISO8601Result* r) {
  int32_t len, hour, minute, second, nanosecond;
  int32_t cur = s;
  if ((str.length() < (cur + 1)) || (!IsTimeZoneUTCOffsetSign(str[cur]))) {
    return 0;
  }
  int32_t sign = (CanonicalSign(str[cur++]) == '-') ? -1 : 1;
  if ((len = ScanTimeZoneUTCOffsetHour(str, cur, &hour)) == 0) return 0;
  cur += len;
  if ((cur + 1) > str.length()) {
    //   TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour
    r->tzuo_sign = sign;
    r->tzuo_hour = hour;
    r->offset_string_start = s;
    r->offset_string_length = cur - s;
    return cur - s;
  }
  if (str[cur] == ':') {
    cur++;
    if ((len = ScanTimeZoneUTCOffsetMinute(str, cur, &minute)) == 0) return 0;
    cur += len;
    if ((cur + 1) > str.length() || str[cur] != ':') {
      //   TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute
      r->tzuo_sign = sign;
      r->tzuo_hour = hour;
      r->tzuo_minute = minute;
      r->offset_string_start = s;
      r->offset_string_length = cur - s;
      return cur - s;
    }
    cur++;
    if ((len = ScanTimeZoneUTCOffsetSecond(str, cur, &second)) == 0) return 0;
  } else {
    if ((len = ScanTimeZoneUTCOffsetMinute(str, cur, &minute)) == 0) {
      //   TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour
      r->tzuo_sign = sign;
      r->tzuo_hour = hour;
      r->offset_string_start = s;
      r->offset_string_length = cur - s;
      return cur - s;
    }
    cur += len;
    if ((len = ScanTimeZoneUTCOffsetSecond(str, cur, &second)) == 0) {
      //   TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute
      r->tzuo_sign = sign;
      r->tzuo_hour = hour;
      r->tzuo_minute = minute;
      r->offset_string_start = s;
      r->offset_string_length = cur - s;
      return cur - s;
    }
  }
  cur += len;
  len = ScanTimeZoneUTCOffsetFraction(str, cur, &nanosecond);
  r->tzuo_sign = sign;
  r->tzuo_hour = hour;
  r->tzuo_minute = minute;
  r->tzuo_second = second;
  if (len > 0) r->tzuo_nanosecond = nanosecond;
  r->offset_string_start = s;
  r->offset_string_length = cur + len - s;
  cur += len;
  return cur - s;
}

// TimeZoneUTCOffset:
//   TimeZoneNumericUTCOffset
//   UTCDesignator
template <typename Char>
int32_t ScanTimeZoneUTCOffset(base::Vector<Char> str, int32_t s,
                              ParsedISO8601Result* r) {
  if (str.length() < (s + 1)) return 0;
  if (AsciiAlphaToLower(str[s]) == 'z') {
    // UTCDesignator
    r->utc_designator = true;
    return 1;
  }
  // TimeZoneNumericUTCOffset
  return ScanTimeZoneNumericUTCOffset(str, s, r);
}

// TimeZoneIANANameComponent :
//   TZLeadingChar TZChar{0,13} but not one of . or ..
template <typename Char>
int32_t ScanTimeZoneIANANameComponent(base::Vector<Char> str, int32_t s) {
  int32_t cur = s;
  if (str.length() < (cur + 1) || !IsTZLeadingChar(str[cur++])) return 0;
  while (((cur) < str.length()) && ((cur - s) < 14) && IsTZChar(str[cur])) {
    cur++;
  }
  if ((cur - s) == 1 && str[s] == '.') return 0;
  if ((cur - s) == 2 && str[s] == '.' && str[s + 1] == '.') return 0;
  return cur - s;
}
// TimeZoneIANALegacyName :
//   Etc/GMT0
//   GMT0
//   GMT-0
//   GMT+0
//   EST5EDT
//   CST6CDT
//   MST7MDT
//   PST8PDT

template <typename Char>
int32_t ScanTimeZoneIANALegacyName(base::Vector<Char> str, int32_t s) {
  int32_t cur = s;
  {
    constexpr int32_t len = 4;
    if (str.length() < cur + len) return 0;
    if (CompareCharsEqual(str.begin() + cur, "GMT0", len)) return len;
  }

  {
    constexpr int32_t len = 5;
    if (str.length() < cur + len) return 0;
    if (CompareCharsEqual(str.begin() + cur, "GMT+0", len) ||
        CompareCharsEqual(str.begin() + cur, "GMT-0", len)) {
      return len;
    }
  }

  {
    constexpr int32_t len = 7;
    if (str.length() < cur + len) return 0;
    if (CompareCharsEqual(str.begin() + cur, "EST5EDT", len) ||
        CompareCharsEqual(str.begin() + cur, "CST6CDT", len) ||
        CompareCharsEqual(str.begin() + cur, "MST7MDT", len) ||
        CompareCharsEqual(str.begin() + cur, "PST8PDT", len)) {
      return len;
    }
  }

  {
    constexpr int32_t len = 8;
    if (str.length() < cur + len) return 0;
    if (CompareCharsEqual(str.begin() + cur, "Etc/GMT0", len)) return len;
  }

  return 0;
}

// Etc/GMT ASCIISign UnpaddedHour
template <typename Char>
int32_t ScanEtcGMTASCIISignUnpaddedHour(base::Vector<Char> str, int32_t s) {
  if ((s + 9) > str.length()) return 0;
  int32_t cur = s;
  int32_t len = arraysize("Etc/GMT") - 1;
  if (!CompareCharsEqual(str.begin() + cur, "Etc/GMT", len)) return 0;
  cur += len;
  Char sign = str[cur++];
  if (!IsAsciiSign(sign)) return 0;
  len = ScanUnpaddedHour(str, cur);
  if (len == 0) return 0;
  cur += len;
  return cur - s;
}

// TimeZoneIANANameTail :
//   TimeZoneIANANameComponent
//   TimeZoneIANANameComponent / TimeZoneIANANameTail
// TimeZoneIANAName :
//   Etc/GMT ASCIISign UnpaddedHour
//   TimeZoneIANANameTail
//   TimeZoneIANALegacyName
// The spec text use tail recusion with TimeZoneIANANameComponent and
// TimeZoneIANANameTail. In our implementation, we use an iteration loop
// instead.
template <typename Char>
int32_t ScanTimeZoneIANAName(base::Vector<Char> str, int32_t s) {
  int32_t len;
  if ((len = ScanEtcGMTASCIISignUnpaddedHour(str, s)) > 0 ||
      (len = ScanTimeZoneIANALegacyName(str, s)) > 0) {
    return len;
  }
  int32_t cur = s;
  if ((len = ScanTimeZoneIANANameComponent(str, cur)) == 0) return 0;
  cur += len;
  while ((str.length() > (cur + 1)) && (str[cur] == '/')) {
    cur++;
    if ((len = ScanTimeZoneIANANameComponent(str, cur)) == 0) {
      return 0;
    }
    // TimeZoneIANANameComponent / TimeZoneIANAName
    cur += len;
  }
  return cur - s;
}

// TimeZoneUTCOffsetName
//   Sign Hour
//   Sign Hour : MinuteSecond
//   Sign Hour MinuteSecond
//   Sign Hour : MinuteSecond : MinuteSecond [Fraction]
//   Sign Hour MinuteSecond MinuteSecond [Fraction]
//
template <typename Char>
int32_t ScanTimeZoneUTCOffsetName(base::Vector<Char> str, int32_t s) {
  int32_t cur = s;
  int32_t len;
  if ((str.length() < (s + 3)) || !IsSign(str[cur++])) return 0;
  int32_t hour, minute, second, fraction;
  if ((len = ScanHour(str, cur, &hour)) == 0) return 0;
  cur += len;
  if ((cur + 1) > str.length()) {
    // Sign Hour
    return cur - s;
  }
  if (str[cur] == ':') {
    // Sign Hour :
    cur++;
    if ((len = ScanMinuteSecond(str, cur, &minute)) == 0) return 0;
    cur += len;
    if ((cur + 1) > str.length() || (str[cur] != ':')) {
      // Sign Hour : MinuteSecond
      return cur - s;
    }
    cur++;
    // Sign Hour : MinuteSecond :
    if ((len = ScanMinuteSecond(str, cur, &second)) == 0) return 0;
    cur += len;
    len = ScanFraction(str, cur, &fraction);
    return cur + len - s;
  } else {
    if ((len = ScanMinuteSecond(str, cur, &minute)) == 0) {
      // Sign Hour
      return cur - s;
    }
    cur += len;
    if ((len = ScanMinuteSecond(str, cur, &second)) == 0) {
      // Sign Hour MinuteSecond
      return cur - s;
    }
    cur += len;
    len = ScanFraction(str, cur, &fraction);
    //  Sign Hour MinuteSecond MinuteSecond [Fraction]
    cur += len;
    return cur - s;
  }
}

// TimeZoneBracketedName
//   TimeZoneIANAName
//   "Etc/GMT" ASCIISign Hour
//   TimeZoneUTCOffsetName
// Since "Etc/GMT" also fit TimeZoneIANAName so we need to try
// "Etc/GMT" ASCIISign Hour first.
template <typename Char>
int32_t ScanEtcGMTAsciiSignHour(base::Vector<Char> str, int32_t s) {
  if ((s + 10) > str.length()) return 0;
  int32_t cur = s;
  if ((str[cur++] != 'E') || (str[cur++] != 't') || (str[cur++] != 'c') ||
      (str[cur++] != '/') || (str[cur++] != 'G') || (str[cur++] != 'M') ||
      (str[cur++] != 'T')) {
    return 0;
  }
  Char sign = str[cur++];
  if (!IsAsciiSign(sign)) return 0;
  int32_t hour;
  int32_t len = ScanHour(str, cur, &hour);
  if (len == 0) return 0;
  //   "Etc/GMT" ASCIISign Hour
  return 10;
}

template <typename Char>
int32_t ScanTimeZoneIdentifier(base::Vector<Char> str, int32_t s,
                               ParsedISO8601Result* r);
// TimeZoneBracketedAnnotation :
// [ TimeZoneIdentifier ]
template <typename Char>
int32_t ScanTimeZoneBracketedAnnotation(base::Vector<Char> str, int32_t s,
                                        ParsedISO8601Result* r) {
  if ((str.length() < (s + 3)) || (str[s] != '[')) return 0;
  int32_t cur = s + 1;
  int32_t len = ScanTimeZoneIdentifier(str, cur, r);
  cur += len;
  if (len == 0 || str.length() < (cur + 1) || (str[cur] != ']')) {
    // Only ScanTimeZoneBracketedAnnotation know the post condition of
    // TimeZoneIdentifier is not matched so we need to reset here.
    r->tzi_name_start = 0;
    r->tzi_name_length = 0;
    return 0;
  }
  cur++;
  return cur - s;
}

// TimeZoneOffsetRequired:
//   TimeZoneUTCOffset [TimeZoneBracketedAnnotation]
template <typename Char>
int32_t ScanTimeZoneOffsetRequired(base::Vector<Char> str, int32_t s,
                                   ParsedISO8601Result* r) {
  int32_t cur = s;
  cur += ScanTimeZoneUTCOffset(str, cur, r);
  if (cur == s) return 0;
  cur += ScanTimeZoneBracketedAnnotation(str, cur, r);
  return cur - s;
}

//   TimeZoneNameRequired:
//   [TimeZoneUTCOffset] TimeZoneBracketedAnnotation
template <typename Char>
int32_t ScanTimeZoneNameRequired(base::Vector<Char> str, int32_t s,
                                 ParsedISO8601Result* r) {
  int32_t cur = s;
  cur += ScanTimeZoneUTCOffset(str, cur, r);
  int32_t len = ScanTimeZoneBracketedAnnotation(str, cur, r);
  if (len == 0) return 0;
  cur += len;
  return cur - s;
}

// TimeZone:
//   TimeZoneUTCOffset [TimeZoneBracketedAnnotation]
//   TimeZoneBracketedAnnotation
template <typename Char>
int32_t ScanTimeZone(base::Vector<Char> str, int32_t s,
                     ParsedISO8601Result* r) {
  int32_t cur = s;
  int32_t len;
  // TimeZoneUTCOffset [TimeZoneBracketedAnnotation]
  if ((len = ScanTimeZoneUTCOffset(str, cur, r)) > 0) {
    cur += len;
    // [TimeZoneBracketedAnnotation]
    len = ScanTimeZoneBracketedAnnotation(str, cur, r);
    cur += len;
    return cur - s;
  }
  // TimeZoneBracketedAnnotation
  return ScanTimeZoneBracketedAnnotation(str, cur, r);
}

// ValidMonthDay :
//   DateMonth [-] 0 NonZeroDigit
//   DateMonth [-] 1 DecimalDigit
//   DateMonth [-] 2 DecimalDigit
//   DateMonth [-] 30 but not one of 0230 or 02-30
//   DateMonthWithThirtyOneDays [-] 31
template <typename Char>
int32_t ScanValidMonthDay(base::Vector<Char> str, int32_t s) {
  int32_t len;
  int32_t cur = s;
  int32_t date_month;
  if ((len = ScanDateMonth(str, cur, &date_month)) > 0) {
    cur += len;
    if (str.length() >= (cur + 1)) {
      if (str[cur] == '-') cur++;
      int32_t day_of_month;
      if ((len = ScanTwoDigitsExpectRange(str, cur, 1, 30, &day_of_month)) >
          0) {
        cur += len;
        // 0 NonZeroDigit
        // 1 DecimalDigit
        // 2 DecimalDigit
        // 30 but not one of 0230 or 02-30
        if (date_month != 2 || day_of_month != 30) {
          return cur - s;
        }
      }
    }
  }
  // Reset cur
  cur = s;
  //   DateMonthWithThirtyOneDays [-] 31
  if ((len = ScanDateMonthWithThirtyOneDays(str, cur)) > 0) {
    cur += len;
    if (str.length() >= (cur + 1)) {
      if (str[cur] == '-') cur++;
      int32_t dummy;
      if ((len = ScanTwoDigitsExpectValue(str, cur, 31, &dummy)) > 0) {
        cur += len;
        return cur - s;
      }
    }
  }
  return 0;
}

template <typename Char>
int32_t ScanDateSpecYearMonth(base::Vector<Char> str, int32_t s,
                              ParsedISO8601Result* r);

// TimeSpecWithOptionalTimeZoneNotAmbiguous :
//   TimeSpec [TimeZone] but not one of ValidMonthDay or DateSpecYearMonth
template <typename Char>
int32_t ScanTimeSpecWithOptionalTimeZoneNotAmbiguous(base::Vector<Char> str,
                                                     int32_t s,
                                                     ParsedISO8601Result* r) {
  int32_t cur = s;
  int32_t len;
  if ((len = ScanTimeSpec(str, cur, r)) == 0) return 0;
  cur += len;
  // [TimeZone]
  len = ScanTimeZone(str, cur, r);
  cur += len;
  len = cur - s;
  // If it match ValidMonthDay, consider invalid.
  if (ScanValidMonthDay(str, s) == len) return 0;
  // If it match DateSpecYearMonth, consider invalid.
  ParsedISO8601Result tmp;
  if (ScanDateSpecYearMonth(str, s, &tmp) == len) return 0;
  return len;
}

// CalendarNameComponent:
//   CalChar {3,8}
template <typename Char>
int32_t ScanCalendarNameComponent(base::Vector<Char> str, int32_t s) {
  int32_t cur = s;
  while ((cur < str.length()) && IsAlphaNumeric(str[cur])) cur++;
  if ((cur - s) < 3 || (cur - s) > 8) return 0;
  return cur - s;
}

// CalendarNameTail :
//   CalendarNameComponent
//   CalendarNameComponent - CalendarNameTail
// CalendarName :
//   CalendarNameTail
// The spec text use tail recusion with CalendarNameComponent and
// CalendarNameTail. In our implementation, we use an iteration loop instead.
template <typename Char>
int32_t ScanCalendarName(base::Vector<Char> str, int32_t s,
                         ParsedISO8601Result* r) {
  int32_t cur = s;
  int32_t len;
  if ((len = ScanCalendarNameComponent(str, cur)) == 0) return 0;
  cur += len;
  while ((str.length() > (cur + 1)) && (str[cur++] == '-')) {
    if ((len = ScanCalendarNameComponent(str, cur)) == 0) return 0;
    // CalendarNameComponent - CalendarName
    cur += len;
  }
  r->calendar_name_start = s;
  r->calendar_name_length = cur - s;
  return cur - s;
}

// Calendar: '[u-ca=' CalendarName ']'
template <typename Char>
int32_t ScanCalendar(base::Vector<Char> str, int32_t s,
                     ParsedISO8601Result* r) {
  if (str.length() < (s + 7)) return 0;
  int32_t cur = s;
  // "[u-ca="
  if ((str[cur++] != '[') || (str[cur++] != 'u') || (str[cur++] != '-') ||
      (str[cur++] != 'c') || (str[cur++] != 'a') || (str[cur++] != '=')) {
    return 0;
  }
  int32_t len = ScanCalendarName(str, cur, r);
  if (len == 0) return 0;
  if ((str.length() < (cur + len + 1)) || (str[cur + len] != ']')) {
    // Only ScanCalendar know the post condition of CalendarName is not met and
    // need to reset here.
    r->calendar_name_start = 0;
    r->calendar_name_length = 0;
    return 0;
  }
  return 6 + len + 1;
}

// CalendarTime_L1:
//  TimeDesignator TimeSpec [TimeZone] [Calendar]
template <typename Char>
int32_t ScanCalendarTime_L1(base::Vector<Char> str, int32_t s,
                            ParsedISO8601Result* r) {
  int32_t cur = s;
  if (str.length() < (s + 1)) return 0;
  // TimeDesignator
  if (AsciiAlphaToLower(str[cur++]) != 't') return 0;
  int32_t len = ScanTimeSpec(str, cur, r);
  if (len == 0) return 0;
  cur += len;
  // [TimeZone]
  cur += ScanTimeZone(str, cur, r);
  // [Calendar]
  cur += ScanCalendar(str, cur, r);
  return cur - s;
}

// CalendarTime_L2 :
//  TimeSpecWithOptionalTimeZoneNotAmbiguous [Calendar]
template <typename Char>
int32_t ScanCalendarTime_L2(base::Vector<Char> str, int32_t s,
                            ParsedISO8601Result* r) {
  int32_t cur = s;
  int32_t len = ScanTimeSpecWithOptionalTimeZoneNotAmbiguous(str, cur, r);
  if (len == 0) return 0;
  cur += len;
  // [Calendar]
  cur += ScanCalendar(str, cur, r);
  return cur - s;
}

// DateTime: Date [TimeSpecSeparator][TimeZone]
template <typename Char>
int32_t ScanDateTime(base::Vector<Char> str, int32_t s,
                     ParsedISO8601Result* r) {
  int32_t cur = s;
  int32_t len = ScanDate(str, cur, r);
  if (len == 0) return 0;
  cur += len;
  cur += ScanTimeSpecSeparator(str, cur, r);
  cur += ScanTimeZone(str, cur, r);
  return cur - s;
}

// DateSpecYearMonth: DateYear ['-'] DateMonth
template <typename Char>
int32_t ScanDateSpecYearMonth(base::Vector<Char> str, int32_t s,
                              ParsedISO8601Result* r) {
  int32_t date_year, date_month;
  int32_t cur = s;
  int32_t len = ScanDateYear(str, cur, &date_year);
  if (len == 0) return 0;
  cur += len;
  if (str.length() < (cur + 1)) return 0;
  if (str[cur] == '-') cur++;
  len = ScanDateMonth(str, cur, &date_month);
  if (len == 0) return 0;
  r->date_year = date_year;
  r->date_month = date_month;
  cur += len;
  return cur - s;
}

// DateSpecMonthDay:
//   [TwoDash] DateMonth [-] DateDay
template <typename Char>
int32_t ScanDateSpecMonthDay(base::Vector<Char> str, int32_t s,
                             ParsedISO8601Result* r) {
  if (str.length() < (s + 4)) return 0;
  int32_t cur = s;
  if (str[cur] == '-') {
    // The first two dash are optional together
    if (str[++cur] != '-') return 0;
    // TwoDash
    cur++;
  }
  int32_t date_month, date_day;
  int32_t len = ScanDateMonth(str, cur, &date_month);
  if (len == 0) return 0;
  cur += len;
  if (str.length() < (cur + 1)) return 0;
  // '-'
  if (str[cur] == '-') cur++;
  len = ScanDateDay(str, cur, &date_day);
  if (len == 0) return 0;
  r->date_month = date_month;
  r->date_day = date_day;
  cur += len;
  return cur - s;
}

// TimeZoneIdentifier :
//   TimeZoneIANAName
//   TimeZoneUTCOffsetName
template <typename Char>
int32_t ScanTimeZoneIdentifier(base::Vector<Char> str, int32_t s,
                               ParsedISO8601Result* r) {
  int32_t len;
  int32_t cur = s;
  if ((len = ScanTimeZoneIANAName(str, cur)) > 0 ||
      (len = ScanTimeZoneUTCOffsetName(str, cur)) > 0) {
    cur += len;
    r->tzi_name_start = s;
    r->tzi_name_length = len;
    return cur - s;
  }
  return 0;
}

// CalendarDateTime: DateTime [Calendar]
template <typename Char>
int32_t ScanCalendarDateTime(base::Vector<Char> str, int32_t s,
                             ParsedISO8601Result* r) {
  int32_t len = ScanDateTime(str, s, r);
  if (len == 0) return 0;
  return len + ScanCalendar(str, len, r);
}

// CalendarDateTimeTimeRequired: Date TimeSpecSeparator [TimeZone] [Calendar]
template <typename Char>
int32_t ScanCalendarDateTimeTimeRequired(base::Vector<Char> str, int32_t s,
                                         ParsedISO8601Result* r) {
  int32_t cur = s;
  int32_t len = ScanDate(str, cur, r);
  if (len == 0) return 0;
  cur += len;
  len = ScanTimeSpecSeparator(str, cur, r);
  if (len == 0) return 0;
  cur += len;
  // [TimeZone]
  cur += ScanTimeZone(str, cur, r);
  // [Calendar]
  cur += ScanCalendar(str, cur, r);
  return cur - s;
}

// TemporalZonedDateTimeString:
//   Date [TimeSpecSeparator] TimeZoneNameRequired [Calendar]
template <typename Char>
int32_t ScanTemporalZonedDateTimeString(base::Vector<Char> str, int32_t s,
                                        ParsedISO8601Result* r) {
  // Date
  int32_t cur = s;
  int32_t len = ScanDate(str, cur, r);
  if (len == 0) return 0;
  cur += len;

  // TimeSpecSeparator
  cur += ScanTimeSpecSeparator(str, cur, r);

  // TimeZoneNameRequired
  len = ScanTimeZoneNameRequired(str, cur, r);
  if (len == 0) return 0;
  cur += len;

  // Calendar
  cur += ScanCalendar(str, cur, r);
  return cur - s;
}

SCAN_FORWARD(TemporalDateTimeString, CalendarDateTime, ParsedISO8601Result)

// TemporalMonthDayString
//   DateSpecMonthDay
//   CalendarDateTime
// The lookahead is at most 5 chars.
SCAN_EITHER_FORWARD(TemporalMonthDayString, DateSpecMonthDay, CalendarDateTime,
                    ParsedISO8601Result)

// TemporalInstantString
//   Date [TimeSpecSeparator] TimeZoneOffsetRequired [Calendar]
template <typename Char>
int32_t ScanTemporalInstantString(base::Vector<Char> str, int32_t s,
                                  ParsedISO8601Result* r) {
  // Date
  int32_t cur = s;
  int32_t len = ScanDate(str, cur, r);
  if (len == 0) return 0;
  cur += len;

  // [TimeSpecSeparator]
  cur += ScanTimeSpecSeparator(str, cur, r);

  // TimeZoneOffsetRequired
  len = ScanTimeZoneOffsetRequired(str, cur, r);
  if (len == 0) return 0;
  cur += len;
  // [Calendar]
  cur += ScanCalendar(str, cur, r);
  return cur - s;
}

// ==============================================================================
#define SATISIFY(T, R)                            \
  template <typename Char>                        \
  bool Satisfy##T(base::Vector<Char> str, R* r) { \
    R ret;                                        \
    int32_t len = Scan##T(str, 0, &ret);          \
    if ((len > 0) && (len == str.length())) {     \
      *r = ret;                                   \
      return true;                                \
    }                                             \
    return false;                                 \
  }

#define IF_SATISFY_RETURN(T)             \
  {                                      \
    if (Satisfy##T(str, r)) return true; \
  }

#define SATISIFY_EITHER(T1, T2, T3, R)             \
  template <typename Char>                         \
  bool Satisfy##T1(base::Vector<Char> str, R* r) { \
    IF_SATISFY_RETURN(T2)                          \
    IF_SATISFY_RETURN(T3)                          \
    return false;                                  \
  }

SATISIFY(TemporalDateTimeString, ParsedISO8601Result)
SATISIFY(DateTime, ParsedISO8601Result)
SATISIFY(DateSpecYearMonth, ParsedISO8601Result)
SATISIFY(DateSpecMonthDay, ParsedISO8601Result)
SATISIFY(CalendarDateTime, ParsedISO8601Result)
SATISIFY(CalendarTime_L1, ParsedISO8601Result)
SATISIFY(CalendarTime_L2, ParsedISO8601Result)

template <typename Char>
bool SatisfyCalendarTime(base::Vector<Char> str, ParsedISO8601Result* r) {
  IF_SATISFY_RETURN(CalendarTime_L1)
  IF_SATISFY_RETURN(CalendarTime_L2)
  return false;
}
SATISIFY(CalendarDateTimeTimeRequired, ParsedISO8601Result)
SATISIFY_EITHER(TemporalTimeString, CalendarTime, CalendarDateTimeTimeRequired,
                ParsedISO8601Result)
SATISIFY_EITHER(TemporalYearMonthString, DateSpecYearMonth, CalendarDateTime,
                ParsedISO8601Result)
SATISIFY_EITHER(TemporalMonthDayString, DateSpecMonthDay, CalendarDateTime,
                ParsedISO8601Result)
SATISIFY(TimeZoneNumericUTCOffset, ParsedISO8601Result)
SATISIFY(TimeZoneIdentifier, ParsedISO8601Result)
SATISIFY(TemporalInstantString, ParsedISO8601Result)
SATISIFY(TemporalZonedDateTimeString, ParsedISO8601Result)

SATISIFY(CalendarName, ParsedISO8601Result)

// Duration

// Digits : Digit [Digits]

template <typename Char>
int32_t ScanDigits(base::Vector<Char> str, int32_t s, double* out) {
  if (str.length() < (s + 1) || !IsDecimalDigit(str[s])) return 0;
  *out = ToInt(str[s]);
  int32_t len = 1;
  while (s + len + 1 <= str.length() && IsDecimalDigit(str[s + len])) {
    *out = 10 * (*out) + ToInt(str[s + len]);
    len++;
  }
  return len;
}

SCAN_FORWARD(DurationYears, Digits, double)
SCAN_FORWARD(DurationMonths, Digits, double)
SCAN_FORWARD(DurationWeeks, Digits, double)
SCAN_FORWARD(DurationDays, Digits, double)

// DurationWholeHours : Digits
SCAN_FORWARD(DurationWholeHours, Digits, double)

// DurationWholeMinutes : Digits
SCAN_FORWARD(DurationWholeMinutes, Digits, double)

// DurationWholeSeconds : Digits
SCAN_FORWARD(DurationWholeSeconds, Digits, double)

// DurationHoursFraction : TimeFraction
SCAN_FORWARD(DurationHoursFraction, TimeFraction, int32_t)

// DurationMinutesFraction : TimeFraction
SCAN_FORWARD(DurationMinutesFraction, TimeFraction, int32_t)

// DurationSecondsFraction : TimeFraction
SCAN_FORWARD(DurationSecondsFraction, TimeFraction, int32_t)

#define DURATION_WHOLE_FRACTION_DESIGNATOR(Name, name, d)                 \
  template <typename Char>                                                \
  int32_t ScanDurationWhole##Name##FractionDesignator(                    \
      base::Vector<Char> str, int32_t s, ParsedISO8601Duration* r) {      \
    int32_t cur = s;                                                      \
    double whole = ParsedISO8601Duration::kEmpty;                         \
    cur += ScanDurationWhole##Name(str, cur, &whole);                     \
    if (cur == s) return 0;                                               \
    int32_t fraction = ParsedISO8601Duration::kEmpty;                     \
    int32_t len = ScanDuration##Name##Fraction(str, cur, &fraction);      \
    cur += len;                                                           \
    if (str.length() < (cur + 1) || AsciiAlphaToLower(str[cur++]) != (d)) \
      return 0;                                                           \
    r->whole_##name = whole;                                              \
    r->name##_fraction = fraction;                                        \
    return cur - s;                                                       \
  }

DURATION_WHOLE_FRACTION_DESIGNATOR(Seconds, seconds, 's')
DURATION_WHOLE_FRACTION_DESIGNATOR(Minutes, minutes, 'm')
DURATION_WHOLE_FRACTION_DESIGNATOR(Hours, hours, 'h')

// DurationSecondsPart :
//   DurationWholeSeconds DurationSecondsFractionopt SecondsDesignator
SCAN_FORWARD(DurationSecondsPart, DurationWholeSecondsFractionDesignator,
             ParsedISO8601Duration)

// DurationMinutesPart :
//   DurationWholeMinutes DurationMinutesFractionopt MinutesDesignator
//   [DurationSecondsPart]
template <typename Char>
int32_t ScanDurationMinutesPart(base::Vector<Char> str, int32_t s,
                                ParsedISO8601Duration* r) {
  int32_t cur = s;
  int32_t len = ScanDurationWholeMinutesFractionDesignator(str, s, r);
  if (len == 0) return 0;
  cur += len;
  cur += ScanDurationSecondsPart(str, cur, r);
  return cur - s;
}

// DurationHoursPart :
//   DurationWholeHours DurationHoursFractionopt HoursDesignator
//   DurationMinutesPart
//
//   DurationWholeHours DurationHoursFractionopt HoursDesignator
//   [DurationSecondsPart]
template <typename Char>
int32_t ScanDurationHoursPart(base::Vector<Char> str, int32_t s,
                              ParsedISO8601Duration* r) {
  int32_t cur = s;
  int32_t len = ScanDurationWholeHoursFractionDesignator(str, s, r);
  if (len == 0) return 0;
  cur += len;
  len = ScanDurationMinutesPart(str, cur, r);
  if (len > 0) {
    cur += len;
  } else {
    cur += ScanDurationSecondsPart(str, cur, r);
  }
  return cur - s;
}

// DurationTime :
//   TimeDesignator DurationHoursPart
//   TimeDesignator DurationMinutesPart
//   TimeDesignator DurationSecondsPart
template <typename Char>
int32_t ScanDurationTime(base::Vector<Char> str, int32_t s,
                         ParsedISO8601Duration* r) {
  int32_t cur = s;
  if (str.length() < (s + 1)) return 0;
  if (AsciiAlphaToLower(str[cur++]) != 't') return 0;
  if ((cur += ScanDurationHoursPart(str, cur, r)) - s > 1) return cur - s;
  if ((cur += ScanDurationMinutesPart(str, cur, r)) - s > 1) return cur - s;
  if ((cur += ScanDurationSecondsPart(str, cur, r)) - s > 1) return cur - s;
  return 0;
}

#define DURATION_AND_DESIGNATOR(Name, name, d)                              \
  template <typename Char>                                                  \
  int32_t ScanDuration##Name##Designator(base::Vector<Char> str, int32_t s, \
                                         ParsedISO8601Duration* r) {        \
    int32_t cur = s;                                                        \
    double name;                                                            \
    if ((cur += ScanDuration##Name(str, cur, &name)) == s) return 0;        \
    if (str.length() < (cur + 1) || AsciiAlphaToLower(str[cur++]) != (d)) { \
      return 0;                                                             \
    }                                                                       \
    r->name = name;                                                         \
    return cur - s;                                                         \
  }

DURATION_AND_DESIGNATOR(Days, days, 'd')
DURATION_AND_DESIGNATOR(Weeks, weeks, 'w')
DURATION_AND_DESIGNATOR(Months, months, 'm')
DURATION_AND_DESIGNATOR(Years, years, 'y')

// DurationDaysPart : DurationDays DaysDesignator
SCAN_FORWARD(DurationDaysPart, DurationDaysDesignator, ParsedISO8601Duration)

// DurationWeeksPart : DurationWeeks WeeksDesignator [DurationDaysPart]
template <typename Char>
int32_t ScanDurationWeeksPart(base::Vector<Char> str, int32_t s,
                              ParsedISO8601Duration* r) {
  int32_t cur = s;
  if ((cur += ScanDurationWeeksDesignator(str, cur, r)) == s) return 0;
  cur += ScanDurationDaysPart(str, cur, r);
  return cur - s;
}

// DurationMonthsPart :
//   DurationMonths MonthsDesignator DurationWeeksPart
//   DurationMonths MonthsDesignator [DurationDaysPart]
template <typename Char>
int32_t ScanDurationMonthsPart(base::Vector<Char> str, int32_t s,
                               ParsedISO8601Duration* r) {
  int32_t cur = s;
  int32_t len = ScanDurationMonthsDesignator(str, cur, r);
  if (len == 0) return 0;
  cur += len;
  if ((len = ScanDurationWeeksPart(str, cur, r)) > 0) {
    cur += len;
  } else {
    cur += ScanDurationDaysPart(str, cur, r);
  }
  return cur - s;
}

// DurationYearsPart :
//   DurationYears YearsDesignator DurationMonthsPart
//   DurationYears YearsDesignator DurationWeeksPart
//   DurationYears YearsDesignator [DurationDaysPart]
template <typename Char>
int32_t ScanDurationYearsPart(base::Vector<Char> str, int32_t s,
                              ParsedISO8601Duration* r) {
  int32_t cur = s;
  int32_t len = ScanDurationYearsDesignator(str, cur, r);
  if (len == 0) return 0;
  cur += len;
  if ((len = ScanDurationMonthsPart(str, cur, r)) > 0) {
    cur += len;
  } else if ((len = ScanDurationWeeksPart(str, cur, r)) > 0) {
    cur += len;
  } else {
    len = ScanDurationDaysPart(str, cur, r);
    cur += len;
  }
  return cur - s;
}

// DurationDate :
//   DurationYearsPart [DurationTime]
//   DurationMonthsPart [DurationTime]
//   DurationWeeksPart [DurationTime]
//   DurationDaysPart [DurationTime]
template <typename Char>
int32_t ScanDurationDate(base::Vector<Char> str, int32_t s,
                         ParsedISO8601Duration* r) {
  int32_t cur = s;
  do {
    if ((cur += ScanDurationYearsPart(str, cur, r)) > s) break;
    if ((cur += ScanDurationMonthsPart(str, cur, r)) > s) break;
    if ((cur += ScanDurationWeeksPart(str, cur, r)) > s) break;
    if ((cur += ScanDurationDaysPart(str, cur, r)) > s) break;
    return 0;
  } while (false);
  cur += ScanDurationTime(str, cur, r);
  return cur - s;
}

// Duration :
//   Signopt DurationDesignator DurationDate
//   Signopt DurationDesignator DurationTime
template <typename Char>
int32_t ScanDuration(base::Vector<Char> str, int32_t s,
                     ParsedISO8601Duration* r) {
  if (str.length() < (s + 2)) return 0;
  int32_t cur = s;
  int32_t sign =
      (IsSign(str[cur]) && CanonicalSign(str[cur++]) == '-') ? -1 : 1;
  if (AsciiAlphaToLower(str[cur++]) != 'p') return 0;
  int32_t len = ScanDurationDate(str, cur, r);
  if (len == 0) len = ScanDurationTime(str, cur, r);
  if (len == 0) return 0;
  r->sign = sign;
  cur += len;
  return cur - s;
}
SCAN_FORWARD(TemporalDurationString, Duration, ParsedISO8601Duration)

SATISIFY(TemporalDurationString, ParsedISO8601Duration)

}  // namespace

#define IMPL_PARSE_METHOD(R, NAME)                                           \
  base::Optional<R> TemporalParser::Parse##NAME(Isolate* isolate,            \
                                                Handle<String> iso_string) { \
    bool valid;                                                              \
    R parsed;                                                                \
    iso_string = String::Flatten(isolate, iso_string);                       \
    {                                                                        \
      DisallowGarbageCollection no_gc;                                       \
      String::FlatContent str_content = iso_string->GetFlatContent(no_gc);   \
      if (str_content.IsOneByte()) {                                         \
        valid = Satisfy##NAME(str_content.ToOneByteVector(), &parsed);       \
      } else {                                                               \
        valid = Satisfy##NAME(str_content.ToUC16Vector(), &parsed);          \
      }                                                                      \
    }                                                                        \
    if (valid) return parsed;                                                \
    return base::nullopt;                                                    \
  }

IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalDateTimeString)
IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalYearMonthString)
IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalMonthDayString)
IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalTimeString)
IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalInstantString)
IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalZonedDateTimeString)
IMPL_PARSE_METHOD(ParsedISO8601Result, TimeZoneIdentifier)
IMPL_PARSE_METHOD(ParsedISO8601Result, CalendarName)
IMPL_PARSE_METHOD(ParsedISO8601Result, TimeZoneNumericUTCOffset)
IMPL_PARSE_METHOD(ParsedISO8601Duration, TemporalDurationString)

}  // namespace internal
}  // namespace v8

Zerion Mini Shell 1.0