12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319 |
- /*
- * 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-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
- // CalendarDateTime
- // NOTE: Reverse order here because `Time` can be a subset of `DateTime`,
- // so we'd not attempt to parse that but may not exhaust the input string.
- return parse_calendar_date_time()
- || 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();
- }
- }
|