%PDF- %PDF-
| Direktori : /home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/temporal/ |
| Current File : //home2/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