123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335 |
- /*
- * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <AK/CharacterTypes.h>
- #include <LibJS/Runtime/Temporal/ISO8601.h>
- namespace JS::Temporal {
- namespace Detail {
- // https://tc39.es/proposal-temporal/#prod-DecimalDigits
- bool ISO8601Parser::parse_decimal_digits()
- {
- // DecimalDigits[Sep] ::
- // DecimalDigit
- // DecimalDigits[?Sep] DecimalDigit
- // [+Sep] DecimalDigits[+Sep] NumericLiteralSeparator DecimalDigit
- // NOTE: Temporal exclusively uses the variant without a separator ([~Sep])
- if (!parse_decimal_digit())
- return false;
- while (parse_decimal_digit())
- ;
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DecimalDigit
- bool ISO8601Parser::parse_decimal_digit()
- {
- // DecimalDigit : one of
- // 0 1 2 3 4 5 6 7 8 9
- if (m_state.lexer.next_is(is_ascii_digit)) {
- m_state.lexer.consume();
- return true;
- }
- return false;
- }
- // https://tc39.es/proposal-temporal/#prod-NonZeroDigit
- bool ISO8601Parser::parse_non_zero_digit()
- {
- // NonZeroDigit : one of
- // 1 2 3 4 5 6 7 8 9
- if (m_state.lexer.next_is(is_ascii_digit) && !m_state.lexer.next_is('0')) {
- m_state.lexer.consume();
- return true;
- }
- return false;
- }
- // https://tc39.es/proposal-temporal/#prod-ASCIISign
- bool ISO8601Parser::parse_ascii_sign()
- {
- // ASCIISign : one of
- // + -
- return m_state.lexer.consume_specific('+')
- || m_state.lexer.consume_specific('-');
- }
- // https://tc39.es/proposal-temporal/#prod-Sign
- bool ISO8601Parser::parse_sign()
- {
- // Sign :
- // ASCIISign
- // U+2212
- StateTransaction transaction { *this };
- auto success = parse_ascii_sign()
- || m_state.lexer.consume_specific("\xE2\x88\x92"sv);
- if (!success)
- return false;
- m_state.parse_result.sign = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-Hour
- bool ISO8601Parser::parse_hour()
- {
- // Hour :
- // 0 DecimalDigit
- // 1 DecimalDigit
- // 20
- // 21
- // 22
- // 23
- StateTransaction transaction { *this };
- if (m_state.lexer.consume_specific('0') || m_state.lexer.consume_specific('1')) {
- if (!parse_decimal_digit())
- return false;
- } else {
- auto success = m_state.lexer.consume_specific("20"sv)
- || m_state.lexer.consume_specific("21"sv)
- || m_state.lexer.consume_specific("22"sv)
- || m_state.lexer.consume_specific("23"sv);
- if (!success)
- return false;
- }
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-MinuteSecond
- bool ISO8601Parser::parse_minute_second()
- {
- // MinuteSecond :
- // 0 DecimalDigit
- // 1 DecimalDigit
- // 2 DecimalDigit
- // 3 DecimalDigit
- // 4 DecimalDigit
- // 5 DecimalDigit
- StateTransaction transaction { *this };
- auto success = m_state.lexer.consume_specific('0')
- || m_state.lexer.consume_specific('1')
- || m_state.lexer.consume_specific('2')
- || m_state.lexer.consume_specific('3')
- || m_state.lexer.consume_specific('4')
- || m_state.lexer.consume_specific('5');
- if (!success)
- return false;
- if (!parse_decimal_digit())
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DecimalSeparator
- bool ISO8601Parser::parse_decimal_separator()
- {
- // DecimalSeparator : one of
- // . ,
- return m_state.lexer.consume_specific('.')
- || m_state.lexer.consume_specific(',');
- }
- // https://tc39.es/proposal-temporal/#prod-DaysDesignator
- bool ISO8601Parser::parse_days_designator()
- {
- // DaysDesignator : one of
- // D d
- return m_state.lexer.consume_specific('D')
- || m_state.lexer.consume_specific('d');
- }
- // https://tc39.es/proposal-temporal/#prod-HoursDesignator
- bool ISO8601Parser::parse_hours_designator()
- {
- // HoursDesignator : one of
- // H h
- return m_state.lexer.consume_specific('H')
- || m_state.lexer.consume_specific('h');
- }
- // https://tc39.es/proposal-temporal/#prod-MinutesDesignator
- bool ISO8601Parser::parse_minutes_designator()
- {
- // MinutesDesignator : one of
- // M m
- return m_state.lexer.consume_specific('M')
- || m_state.lexer.consume_specific('m');
- }
- // https://tc39.es/proposal-temporal/#prod-MonthsDesignator
- bool ISO8601Parser::parse_months_designator()
- {
- // MonthsDesignator : one of
- // M m
- return m_state.lexer.consume_specific('M')
- || m_state.lexer.consume_specific('m');
- }
- // https://tc39.es/proposal-temporal/#prod-DurationDesignator
- bool ISO8601Parser::parse_duration_designator()
- {
- // DurationDesignator : one of
- // P p
- return m_state.lexer.consume_specific('P')
- || m_state.lexer.consume_specific('p');
- }
- // https://tc39.es/proposal-temporal/#prod-SecondsDesignator
- bool ISO8601Parser::parse_seconds_designator()
- {
- // SecondsDesignator : one of
- // S s
- return m_state.lexer.consume_specific('S')
- || m_state.lexer.consume_specific('s');
- }
- // https://tc39.es/proposal-temporal/#prod-DateTimeSeparator
- bool ISO8601Parser::parse_date_time_separator()
- {
- // DateTimeSeparator :
- // <SP>
- // T
- // t
- return m_state.lexer.consume_specific(' ')
- || m_state.lexer.consume_specific('T')
- || m_state.lexer.consume_specific('t');
- }
- // https://tc39.es/proposal-temporal/#prod-TimeDesignator
- bool ISO8601Parser::parse_time_designator()
- {
- // TimeDesignator : one of
- // T t
- return m_state.lexer.consume_specific('T')
- || m_state.lexer.consume_specific('t');
- }
- // https://tc39.es/proposal-temporal/#prod-WeeksDesignator
- bool ISO8601Parser::parse_weeks_designator()
- {
- // WeeksDesignator : one of
- // W w
- return m_state.lexer.consume_specific('W')
- || m_state.lexer.consume_specific('w');
- }
- // https://tc39.es/proposal-temporal/#prod-YearsDesignator
- bool ISO8601Parser::parse_years_designator()
- {
- // YearsDesignator : one of
- // Y y
- return m_state.lexer.consume_specific('Y')
- || m_state.lexer.consume_specific('y');
- }
- // https://tc39.es/proposal-temporal/#prod-UTCDesignator
- bool ISO8601Parser::parse_utc_designator()
- {
- // UTCDesignator : one of
- // Z z
- StateTransaction transaction { *this };
- auto success = m_state.lexer.consume_specific('Z')
- || m_state.lexer.consume_specific('z');
- if (!success)
- return false;
- m_state.parse_result.utc_designator = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DateYear
- bool ISO8601Parser::parse_date_year()
- {
- // DateFourDigitYear :
- // DecimalDigit DecimalDigit DecimalDigit DecimalDigit
- // DateExtendedYear :
- // Sign DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
- // DateYear :
- // DateFourDigitYear
- // DateExtendedYear
- StateTransaction transaction { *this };
- if (parse_sign()) {
- for (size_t i = 0; i < 6; ++i) {
- if (!parse_decimal_digit())
- return false;
- }
- } else {
- for (size_t i = 0; i < 4; ++i) {
- if (!parse_decimal_digit())
- return false;
- }
- }
- m_state.parse_result.date_year = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DateMonth
- bool ISO8601Parser::parse_date_month()
- {
- // DateMonth :
- // 0 NonZeroDigit
- // 10
- // 11
- // 12
- StateTransaction transaction { *this };
- if (m_state.lexer.consume_specific('0')) {
- if (!parse_non_zero_digit())
- return false;
- } else {
- auto success = m_state.lexer.consume_specific("10"sv)
- || m_state.lexer.consume_specific("11"sv)
- || m_state.lexer.consume_specific("12"sv);
- if (!success)
- return false;
- }
- m_state.parse_result.date_month = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DateDay
- bool ISO8601Parser::parse_date_day()
- {
- // DateDay :
- // 0 NonZeroDigit
- // 1 DecimalDigit
- // 2 DecimalDigit
- // 30
- // 31
- StateTransaction transaction { *this };
- if (m_state.lexer.consume_specific('0')) {
- if (!parse_non_zero_digit())
- return false;
- } else if (m_state.lexer.consume_specific('1') || m_state.lexer.consume_specific('2')) {
- if (!parse_decimal_digit())
- return false;
- } else {
- auto success = m_state.lexer.consume_specific("30"sv)
- || m_state.lexer.consume_specific("31"sv);
- if (!success)
- return false;
- }
- m_state.parse_result.date_day = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DateSpecYearMonth
- bool ISO8601Parser::parse_date_spec_year_month()
- {
- // DateSpecYearMonth :
- // DateYear -[opt] DateMonth
- StateTransaction transaction { *this };
- if (!parse_date_year())
- return false;
- m_state.lexer.consume_specific('-');
- if (!parse_date_month())
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DateSpecMonthDay
- bool ISO8601Parser::parse_date_spec_month_day()
- {
- // TwoDashes :
- // --
- // DateSpecMonthDay :
- // TwoDashes[opt] DateMonth -[opt] DateDay
- StateTransaction transaction { *this };
- m_state.lexer.consume_specific("--"sv);
- if (!parse_date_month())
- return false;
- m_state.lexer.consume_specific('-');
- if (!parse_date_day())
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-Date
- bool ISO8601Parser::parse_date()
- {
- // Date :
- // DateYear - DateMonth - DateDay
- // DateYear DateMonth DateDay
- StateTransaction transaction { *this };
- if (!parse_date_year())
- return false;
- auto with_dashes = m_state.lexer.consume_specific('-');
- if (!parse_date_month())
- return false;
- if (with_dashes && !m_state.lexer.consume_specific('-'))
- return false;
- if (!parse_date_day())
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeHour
- bool ISO8601Parser::parse_time_hour()
- {
- // TimeHour :
- // Hour
- StateTransaction transaction { *this };
- if (!parse_hour())
- return false;
- m_state.parse_result.time_hour = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeMinute
- bool ISO8601Parser::parse_time_minute()
- {
- // TimeMinute :
- // MinuteSecond
- StateTransaction transaction { *this };
- if (!parse_minute_second())
- return false;
- m_state.parse_result.time_minute = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeSecond
- bool ISO8601Parser::parse_time_second()
- {
- // TimeSecond :
- // MinuteSecond
- // 60
- StateTransaction transaction { *this };
- auto success = parse_minute_second()
- || m_state.lexer.consume_specific("60"sv);
- if (!success)
- return false;
- m_state.parse_result.time_second = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-FractionalPart
- bool ISO8601Parser::parse_fractional_part()
- {
- // FractionalPart :
- // DecimalDigit DecimalDigit[opt] DecimalDigit[opt] DecimalDigit[opt] DecimalDigit[opt] DecimalDigit[opt] DecimalDigit[opt] DecimalDigit[opt] DecimalDigit[opt]
- if (!parse_decimal_digit())
- return false;
- for (size_t i = 0; i < 8; ++i) {
- if (!parse_decimal_digit())
- break;
- }
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-Fraction
- bool ISO8601Parser::parse_fraction()
- {
- // Fraction :
- // DecimalSeparator FractionalPart
- StateTransaction transaction { *this };
- if (!parse_decimal_separator())
- return false;
- if (!parse_fractional_part())
- return false;
- m_state.parse_result.fractional_part = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeFraction
- bool ISO8601Parser::parse_time_fraction()
- {
- // TimeFraction :
- // Fraction
- return parse_fraction();
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetSign
- bool ISO8601Parser::parse_time_zone_utc_offset_sign()
- {
- // TimeZoneUTCOffsetSign :
- // Sign
- StateTransaction transaction { *this };
- if (!parse_sign())
- return false;
- m_state.parse_result.time_zone_utc_offset_sign = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetHour
- bool ISO8601Parser::parse_time_zone_utc_offset_hour()
- {
- // TimeZoneUTCOffsetHour :
- // Hour
- StateTransaction transaction { *this };
- if (!parse_hour())
- return false;
- m_state.parse_result.time_zone_utc_offset_hour = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetMinute
- bool ISO8601Parser::parse_time_zone_utc_offset_minute()
- {
- // TimeZoneUTCOffsetMinute :
- // MinuteSecond
- StateTransaction transaction { *this };
- if (!parse_minute_second())
- return false;
- m_state.parse_result.time_zone_utc_offset_minute = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetSecond
- bool ISO8601Parser::parse_time_zone_utc_offset_second()
- {
- // TimeZoneUTCOffsetSecond :
- // MinuteSecond
- StateTransaction transaction { *this };
- if (!parse_minute_second())
- return false;
- m_state.parse_result.time_zone_utc_offset_second = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetFractionalPart
- bool ISO8601Parser::parse_time_zone_utc_offset_fractional_part()
- {
- // TimeZoneUTCOffsetFractionalPart :
- // FractionalPart
- StateTransaction transaction { *this };
- if (!parse_fractional_part())
- return false;
- m_state.parse_result.time_zone_utc_offset_fractional_part = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetFraction
- bool ISO8601Parser::parse_time_zone_utc_offset_fraction()
- {
- // TimeZoneUTCOffsetFraction :
- // DecimalSeparator TimeZoneUTCOffsetFractionalPart
- StateTransaction transaction { *this };
- if (!parse_decimal_separator())
- return false;
- if (!parse_time_zone_utc_offset_fractional_part())
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneNumericUTCOffset
- bool ISO8601Parser::parse_time_zone_numeric_utc_offset()
- {
- // TimeZoneNumericUTCOffset :
- // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour
- // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute
- // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute
- // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute : TimeZoneUTCOffsetSecond TimeZoneUTCOffsetFraction[opt]
- // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute TimeZoneUTCOffsetSecond TimeZoneUTCOffsetFraction[opt]
- StateTransaction transaction { *this };
- if (!parse_time_zone_utc_offset_sign())
- return false;
- if (!parse_time_zone_utc_offset_hour())
- return false;
- if (m_state.lexer.consume_specific(':')) {
- if (!parse_time_zone_utc_offset_minute())
- return false;
- if (m_state.lexer.consume_specific(':')) {
- if (!parse_time_zone_utc_offset_second())
- return false;
- (void)parse_time_zone_utc_offset_fraction();
- }
- } else if (parse_time_zone_utc_offset_minute()) {
- if (parse_time_zone_utc_offset_second())
- (void)parse_time_zone_utc_offset_fraction();
- }
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffset
- bool ISO8601Parser::parse_time_zone_utc_offset()
- {
- // TimeZoneUTCOffset :
- // TimeZoneNumericUTCOffset
- // UTCDesignator
- return parse_time_zone_numeric_utc_offset()
- || parse_utc_designator();
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetName
- bool ISO8601Parser::parse_time_zone_utc_offset_name()
- {
- // TimeZoneUTCOffsetName :
- // Sign Hour
- // Sign Hour : MinuteSecond
- // Sign Hour MinuteSecond
- // Sign Hour : MinuteSecond : MinuteSecond Fraction[opt]
- // Sign Hour MinuteSecond MinuteSecond Fraction[opt]
- StateTransaction transaction { *this };
- if (!parse_sign())
- return false;
- if (!parse_hour())
- return false;
- if (m_state.lexer.consume_specific(':')) {
- if (!parse_minute_second())
- return false;
- if (m_state.lexer.consume_specific(':')) {
- if (!parse_minute_second())
- return false;
- (void)parse_fraction();
- }
- } else if (parse_minute_second()) {
- if (parse_minute_second())
- (void)parse_fraction();
- }
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneIANAName
- bool ISO8601Parser::parse_time_zone_iana_name()
- {
- // TZLeadingChar :
- // Alpha
- // .
- // _
- // TZChar :
- // Alpha
- // .
- // -
- // _
- // TimeZoneIANANameComponent :
- // TZLeadingChar TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] but not one of . or ..
- // TimeZoneIANANameTail :
- // TimeZoneIANANameComponent
- // TimeZoneIANANameComponent / TimeZoneIANANameTail
- // TimeZoneIANAName :
- // TimeZoneIANANameTail
- StateTransaction transaction { *this };
- // TODO: Implement the full production. Currently, anything other than "UTC" would get rejected as unknown anyway.
- auto success = (m_state.lexer.consume_specific('U') || m_state.lexer.consume_specific('u'))
- && (m_state.lexer.consume_specific('T') || m_state.lexer.consume_specific('t'))
- && (m_state.lexer.consume_specific('C') || m_state.lexer.consume_specific('c'));
- if (!success)
- return false;
- m_state.parse_result.time_zone_iana_name = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedName
- bool ISO8601Parser::parse_time_zone_bracketed_name()
- {
- // TimeZoneBracketedName :
- // TimeZoneIANAName
- // Etc/GMT ASCIISign Hour
- // TimeZoneUTCOffsetName
- StateTransaction transaction { *this };
- if (parse_time_zone_iana_name()) {
- // no-op.
- } else if (m_state.lexer.consume_specific("Etc/GMT"sv)) {
- if (!parse_ascii_sign())
- return false;
- if (!parse_hour())
- return false;
- } else if (!parse_time_zone_utc_offset_name()) {
- return false;
- }
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedAnnotation
- bool ISO8601Parser::parse_time_zone_bracketed_annotation()
- {
- // TimeZoneBracketedAnnotation :
- // [ TimeZoneBracketedName ]
- StateTransaction transaction { *this };
- if (!m_state.lexer.consume_specific('['))
- return false;
- if (!parse_time_zone_bracketed_name())
- return false;
- if (!m_state.lexer.consume_specific(']'))
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneOffsetRequired
- bool ISO8601Parser::parse_time_zone_offset_required()
- {
- // TimeZoneOffsetRequired :
- // TimeZoneUTCOffset TimeZoneBracketedAnnotation[opt]
- StateTransaction transaction { *this };
- if (!parse_time_zone_utc_offset())
- return false;
- (void)parse_time_zone_bracketed_annotation();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZoneNameRequired
- bool ISO8601Parser::parse_time_zone_name_required()
- {
- // TimeZoneNameRequired :
- // TimeZoneUTCOffset[opt] TimeZoneBracketedAnnotation
- StateTransaction transaction { *this };
- (void)parse_time_zone_utc_offset();
- if (!parse_time_zone_bracketed_annotation())
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeZone
- bool ISO8601Parser::parse_time_zone()
- {
- // TimeZone :
- // TimeZoneOffsetRequired
- // TimeZoneNameRequired
- return parse_time_zone_offset_required()
- || parse_time_zone_name_required();
- }
- // https://tc39.es/proposal-temporal/#prod-CalendarName
- bool ISO8601Parser::parse_calendar_name()
- {
- // CalChar :
- // Alpha
- // DecimalDigit
- // CalendarNameComponent :
- // CalChar CalChar CalChar CalChar[opt] CalChar[opt] CalChar[opt] CalChar[opt] CalChar[opt]
- // CalendarNameTail :
- // CalendarNameComponent
- // CalendarNameComponent - CalendarNameTail
- // CalendarName :
- // CalendarNameTail
- auto parse_calendar_name_component = [&] {
- for (size_t i = 0; i < 8; ++i) {
- if (!m_state.lexer.next_is(is_ascii_alphanumeric))
- return i > 2;
- m_state.lexer.consume();
- }
- return true;
- };
- StateTransaction transaction { *this };
- do {
- if (!parse_calendar_name_component())
- return false;
- } while (m_state.lexer.consume_specific('-'));
- m_state.parse_result.calendar_name = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-Calendar
- bool ISO8601Parser::parse_calendar()
- {
- // Calendar :
- // [u-ca= CalendarName ]
- StateTransaction transaction { *this };
- if (!m_state.lexer.consume_specific("[u-ca="sv))
- return false;
- if (!parse_calendar_name())
- return false;
- if (!m_state.lexer.consume_specific(']'))
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeSpec
- bool ISO8601Parser::parse_time_spec()
- {
- // TimeSpec :
- // TimeHour
- // TimeHour : TimeMinute
- // TimeHour TimeMinute
- // TimeHour : TimeMinute : TimeSecond TimeFraction[opt]
- // TimeHour TimeMinute TimeSecond TimeFraction[opt]
- StateTransaction transaction { *this };
- if (!parse_time_hour())
- return false;
- if (m_state.lexer.consume_specific(':')) {
- if (!parse_time_minute())
- return false;
- if (m_state.lexer.consume_specific(':')) {
- if (!parse_time_second())
- return false;
- (void)parse_time_fraction();
- }
- } else if (parse_time_minute()) {
- if (parse_time_second())
- (void)parse_time_fraction();
- }
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TimeSpecSeparator
- bool ISO8601Parser::parse_time_spec_separator()
- {
- // TimeSpecSeparator :
- // DateTimeSeparator TimeSpec
- StateTransaction transaction { *this };
- if (!parse_date_time_separator())
- return false;
- if (!parse_time_spec())
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DateTime
- bool ISO8601Parser::parse_date_time()
- {
- // DateTime :
- // Date TimeSpecSeparator[opt] TimeZone[opt]
- if (!parse_date())
- return false;
- (void)parse_time_spec_separator();
- (void)parse_time_zone();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-CalendarTime
- bool ISO8601Parser::parse_calendar_time()
- {
- // CalendarTime :
- // TimeDesignator[opt] TimeSpec TimeZone[opt] Calendar[opt]
- StateTransaction transaction { *this };
- (void)parse_time_designator();
- if (!parse_time_spec())
- return false;
- (void)parse_time_zone();
- (void)parse_calendar();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-CalendarDateTime
- bool ISO8601Parser::parse_calendar_date_time()
- {
- // CalendarDateTime :
- // DateTime Calendar[opt]
- if (!parse_date_time())
- return false;
- (void)parse_calendar();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-CalendarDateTimeTimeRequired
- bool ISO8601Parser::parse_calendar_date_time_time_required()
- {
- // CalendarDateTimeTimeRequired :
- // Date TimeSpecSeparator TimeZone[opt] Calendar[opt]
- StateTransaction transaction { *this };
- if (!parse_date())
- return false;
- if (!parse_time_spec_separator())
- return false;
- (void)parse_time_zone();
- (void)parse_calendar();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationWholeSeconds
- bool ISO8601Parser::parse_duration_whole_seconds()
- {
- // DurationWholeSeconds :
- // DecimalDigits[~Sep]
- StateTransaction transaction { *this };
- if (!parse_decimal_digits())
- return false;
- m_state.parse_result.duration_whole_seconds = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationSecondsFraction
- bool ISO8601Parser::parse_duration_seconds_fraction()
- {
- // DurationSecondsFraction :
- // TimeFraction
- StateTransaction transaction { *this };
- if (!parse_time_fraction())
- return false;
- m_state.parse_result.duration_seconds_fraction = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationSecondsPart
- bool ISO8601Parser::parse_duration_seconds_part()
- {
- // DurationSecondsPart :
- // DurationWholeSeconds DurationSecondsFraction[opt] SecondsDesignator
- StateTransaction transaction { *this };
- if (!parse_duration_whole_seconds())
- return false;
- (void)parse_duration_seconds_fraction();
- if (!parse_seconds_designator())
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationWholeMinutes
- bool ISO8601Parser::parse_duration_whole_minutes()
- {
- // DurationWholeMinutes :
- // DecimalDigits[~Sep]
- StateTransaction transaction { *this };
- if (!parse_decimal_digits())
- return false;
- m_state.parse_result.duration_whole_minutes = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationMinutesFraction
- bool ISO8601Parser::parse_duration_minutes_fraction()
- {
- // DurationMinutesFraction :
- // TimeFraction
- StateTransaction transaction { *this };
- if (!parse_time_fraction())
- return false;
- m_state.parse_result.duration_minutes_fraction = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationMinutesPart
- bool ISO8601Parser::parse_duration_minutes_part()
- {
- // DurationMinutesPart :
- // DurationWholeMinutes DurationMinutesFraction[opt] MinutesDesignator DurationSecondsPart[opt]
- StateTransaction transaction { *this };
- if (!parse_duration_whole_minutes())
- return false;
- (void)parse_duration_minutes_fraction();
- if (!parse_minutes_designator())
- return false;
- (void)parse_duration_seconds_part();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationWholeHours
- bool ISO8601Parser::parse_duration_whole_hours()
- {
- // DurationWholeHours :
- // DecimalDigits[~Sep]
- StateTransaction transaction { *this };
- if (!parse_decimal_digits())
- return false;
- m_state.parse_result.duration_whole_hours = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationHoursFraction
- bool ISO8601Parser::parse_duration_hours_fraction()
- {
- // DurationHoursFraction :
- // TimeFraction
- StateTransaction transaction { *this };
- if (!parse_time_fraction())
- return false;
- m_state.parse_result.duration_hours_fraction = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationHoursPart
- bool ISO8601Parser::parse_duration_hours_part()
- {
- // DurationHoursPart :
- // DurationWholeHours DurationHoursFraction[opt] HoursDesignator DurationMinutesPart
- // DurationWholeHours DurationHoursFraction[opt] HoursDesignator DurationSecondsPart[opt]
- StateTransaction transaction { *this };
- if (!parse_duration_whole_hours())
- return false;
- (void)parse_duration_hours_fraction();
- if (!parse_hours_designator())
- return false;
- (void)(parse_duration_minutes_part()
- || parse_duration_seconds_part());
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationTime
- bool ISO8601Parser::parse_duration_time()
- {
- // DurationTime :
- // TimeDesignator DurationHoursPart
- // TimeDesignator DurationMinutesPart
- // TimeDesignator DurationSecondsPart
- StateTransaction transaction { *this };
- if (!parse_time_designator())
- return false;
- auto success = parse_duration_hours_part()
- || parse_duration_minutes_part()
- || parse_duration_seconds_part();
- if (!success)
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationDays
- bool ISO8601Parser::parse_duration_days()
- {
- // DurationDays :
- // DecimalDigits[~Sep]
- StateTransaction transaction { *this };
- if (!parse_decimal_digits())
- return false;
- m_state.parse_result.duration_days = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationDaysPart
- bool ISO8601Parser::parse_duration_days_part()
- {
- // DurationDaysPart :
- // DurationDays DaysDesignator
- StateTransaction transaction { *this };
- if (!parse_duration_days())
- return false;
- if (!parse_days_designator())
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationWeeks
- bool ISO8601Parser::parse_duration_weeks()
- {
- // DurationWeeks :
- // DecimalDigits[~Sep]
- StateTransaction transaction { *this };
- if (!parse_decimal_digits())
- return false;
- m_state.parse_result.duration_weeks = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationWeeksPart
- bool ISO8601Parser::parse_duration_weeks_part()
- {
- // DurationWeeksPart :
- // DurationWeeks WeeksDesignator DurationDaysPart[opt]
- StateTransaction transaction { *this };
- if (!parse_duration_weeks())
- return false;
- if (!parse_weeks_designator())
- return false;
- (void)parse_duration_days_part();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationMonths
- bool ISO8601Parser::parse_duration_months()
- {
- // DurationMonths :
- // DecimalDigits[~Sep]
- StateTransaction transaction { *this };
- if (!parse_decimal_digits())
- return false;
- m_state.parse_result.duration_months = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationMonthsPart
- bool ISO8601Parser::parse_duration_months_part()
- {
- // DurationMonthsPart :
- // DurationMonths MonthsDesignator DurationWeeksPart
- // DurationMonths MonthsDesignator DurationDaysPart[opt]
- StateTransaction transaction { *this };
- if (!parse_duration_months())
- return false;
- if (!parse_months_designator())
- return false;
- (void)(parse_duration_weeks_part()
- || parse_duration_days_part());
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationYears
- bool ISO8601Parser::parse_duration_years()
- {
- // DurationYears :
- // DecimalDigits[~Sep]
- StateTransaction transaction { *this };
- if (!parse_decimal_digits())
- return false;
- m_state.parse_result.duration_years = transaction.parsed_string_view();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationYearsPart
- bool ISO8601Parser::parse_duration_years_part()
- {
- // DurationYearsPart :
- // DurationYears YearsDesignator DurationMonthsPart
- // DurationYears YearsDesignator DurationWeeksPart
- // DurationYears YearsDesignator DurationDaysPart[opt]
- StateTransaction transaction { *this };
- if (!parse_duration_years())
- return false;
- if (!parse_years_designator())
- return false;
- (void)(parse_duration_months_part()
- || parse_duration_weeks_part()
- || parse_duration_days_part());
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-DurationDate
- bool ISO8601Parser::parse_duration_date()
- {
- // DurationDate :
- // DurationYearsPart DurationTime[opt]
- // DurationMonthsPart DurationTime[opt]
- // DurationWeeksPart DurationTime[opt]
- // DurationDaysPart DurationTime[opt]
- auto success = parse_duration_years_part()
- || parse_duration_months_part()
- || parse_duration_weeks_part()
- || parse_duration_days_part();
- if (!success)
- return false;
- (void)parse_duration_time();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-Duration
- bool ISO8601Parser::parse_duration()
- {
- // Duration :
- // Sign[opt] DurationDesignator DurationDate
- // Sign[opt] DurationDesignator DurationTime
- StateTransaction transaction { *this };
- (void)parse_sign();
- if (!parse_duration_designator())
- return false;
- auto success = parse_duration_date()
- || parse_duration_time();
- if (!success)
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TemporalInstantString
- bool ISO8601Parser::parse_temporal_instant_string()
- {
- // TemporalInstantString :
- // Date TimeSpecSeparator[opt] TimeZoneOffsetRequired
- StateTransaction transaction { *this };
- if (!parse_date())
- return false;
- (void)parse_time_spec_separator();
- if (!parse_time_zone_offset_required())
- return false;
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TemporalDateString
- bool ISO8601Parser::parse_temporal_date_string()
- {
- // TemporalDateString :
- // CalendarDateTime
- return parse_calendar_date_time();
- }
- // https://tc39.es/proposal-temporal/#prod-TemporalDateTimeString
- bool ISO8601Parser::parse_temporal_date_time_string()
- {
- // TemporalDateTimeString :
- // CalendarDateTime
- return parse_calendar_date_time();
- }
- // https://tc39.es/proposal-temporal/#prod-TemporalDurationString
- bool ISO8601Parser::parse_temporal_duration_string()
- {
- // TemporalDurationString :
- // Duration
- return parse_duration();
- }
- // https://tc39.es/proposal-temporal/#prod-TemporalMonthDayString
- bool ISO8601Parser::parse_temporal_month_day_string()
- {
- // TemporalMonthDayString :
- // DateSpecMonthDay
- // CalendarDateTime
- // NOTE: Reverse order here because `DateSpecMonthDay` can be a subset of `CalendarDateTime`,
- // so we'd not attempt to parse that but may not exhaust the input string.
- return parse_calendar_date_time()
- || parse_date_spec_month_day();
- }
- // https://tc39.es/proposal-temporal/#prod-TemporalTimeString
- bool ISO8601Parser::parse_temporal_time_string()
- {
- // TemporalTimeString :
- // CalendarTime
- // CalendarDateTimeTimeRequired
- // NOTE: Reverse order here because `Time` can be a subset of `CalendarDateTimeTimeRequired`,
- // so we'd not attempt to parse that but may not exhaust the input string.
- return parse_calendar_date_time_time_required()
- || parse_calendar_time();
- }
- // https://tc39.es/proposal-temporal/#prod-TemporalTimeZoneIdentifier
- bool ISO8601Parser::parse_temporal_time_zone_identifier()
- {
- // TemporalTimeZoneIdentifier :
- // TimeZoneNumericUTCOffset
- // TimeZoneIANAName
- return parse_time_zone_numeric_utc_offset()
- || parse_time_zone_iana_name();
- }
- // https://tc39.es/proposal-temporal/#prod-TemporalTimeZoneString
- bool ISO8601Parser::parse_temporal_time_zone_string()
- {
- // TemporalTimeZoneString :
- // TemporalTimeZoneIdentifier
- // Date TimeSpecSeparator[opt] TimeZone Calendar[opt]
- StateTransaction transaction { *this };
- if (!parse_temporal_time_zone_identifier()) {
- if (!parse_date())
- return false;
- (void)parse_time_spec_separator();
- if (!parse_time_zone())
- return false;
- (void)parse_calendar();
- }
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TemporalYearMonthString
- bool ISO8601Parser::parse_temporal_year_month_string()
- {
- // TemporalYearMonthString :
- // DateSpecYearMonth
- // CalendarDateTime
- // NOTE: Reverse order here because `DateSpecYearMonth` can be a subset of `CalendarDateTime`,
- // so we'd not attempt to parse that but may not exhaust the input string.
- return parse_calendar_date_time()
- || parse_date_spec_year_month();
- }
- // https://tc39.es/proposal-temporal/#prod-TemporalZonedDateTimeString
- bool ISO8601Parser::parse_temporal_zoned_date_time_string()
- {
- // TemporalZonedDateTimeString :
- // Date TimeSpecSeparator[opt] TimeZoneNameRequired Calendar[opt]
- StateTransaction transaction { *this };
- if (!parse_date())
- return false;
- (void)parse_time_spec_separator();
- if (!parse_time_zone_name_required())
- return false;
- (void)parse_calendar();
- transaction.commit();
- return true;
- }
- // https://tc39.es/proposal-temporal/#prod-TemporalCalendarString
- bool ISO8601Parser::parse_temporal_calendar_string()
- {
- // TemporalCalendarString :
- // CalendarName
- // TemporalInstantString
- // CalendarDateTime
- // CalendarTime
- // DateSpecYearMonth
- // DateSpecMonthDay
- return parse_calendar_name()
- || parse_temporal_instant_string()
- || parse_calendar_date_time()
- || parse_date_spec_year_month()
- || parse_date_spec_month_day()
- || parse_calendar_time();
- }
- // https://tc39.es/proposal-temporal/#prod-TemporalRelativeToString
- bool ISO8601Parser::parse_temporal_relative_to_string()
- {
- // TemporalRelativeToString :
- // TemporalDateTimeString
- return parse_temporal_date_time_string();
- }
- }
- #define JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS \
- __JS_ENUMERATE(TemporalInstantString, parse_temporal_instant_string) \
- __JS_ENUMERATE(TemporalDateString, parse_temporal_date_string) \
- __JS_ENUMERATE(TemporalDateTimeString, parse_temporal_date_time_string) \
- __JS_ENUMERATE(TemporalDurationString, parse_temporal_duration_string) \
- __JS_ENUMERATE(TemporalMonthDayString, parse_temporal_month_day_string) \
- __JS_ENUMERATE(TemporalTimeString, parse_temporal_time_string) \
- __JS_ENUMERATE(TemporalTimeZoneString, parse_temporal_time_zone_string) \
- __JS_ENUMERATE(TemporalYearMonthString, parse_temporal_year_month_string) \
- __JS_ENUMERATE(TemporalZonedDateTimeString, parse_temporal_zoned_date_time_string) \
- __JS_ENUMERATE(TemporalCalendarString, parse_temporal_calendar_string) \
- __JS_ENUMERATE(TemporalRelativeToString, parse_temporal_relative_to_string)
- Optional<ParseResult> parse_iso8601(Production production, StringView input)
- {
- auto parser = Detail::ISO8601Parser { input };
- switch (production) {
- #define __JS_ENUMERATE(ProductionName, parse_production) \
- case Production::ProductionName: \
- if (!parser.parse_production()) \
- return {}; \
- break;
- JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS
- #undef __JS_ENUMERATE
- default:
- VERIFY_NOT_REACHED();
- }
- // If we parsed successfully but didn't reach the end, the string doesn't match the given production.
- if (!parser.lexer().is_eof())
- return {};
- return parser.parse_result();
- }
- }
|