| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | /*
 | 
					
						
							|  |  |  |  |  * Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org> | 
					
						
							| 
									
										
										
										
											2025-01-16 08:05:16 -05:00
										 |  |  |  |  * Copyright (c) 2024-2025, Tim Flynn <trflynn89@ladybird.org> | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include <AK/CharacterTypes.h>
 | 
					
						
							|  |  |  |  | #include <AK/GenericLexer.h>
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  | #include <LibJS/Runtime/Temporal/DateEquations.h>
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | #include <LibJS/Runtime/Temporal/ISO8601.h>
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  | #include <LibJS/Runtime/Value.h>
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | namespace JS::Temporal { | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  | enum class Extended { | 
					
						
							|  |  |  |  |     No, | 
					
						
							|  |  |  |  |     Yes, | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | enum class Separator { | 
					
						
							|  |  |  |  |     No, | 
					
						
							|  |  |  |  |     Yes, | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | enum class TimeRequired { | 
					
						
							|  |  |  |  |     No, | 
					
						
							|  |  |  |  |     Yes, | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | enum class ZDesignator { | 
					
						
							|  |  |  |  |     No, | 
					
						
							|  |  |  |  |     Yes, | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | enum class Zoned { | 
					
						
							|  |  |  |  |     No, | 
					
						
							|  |  |  |  |     Yes, | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-20 11:57:42 -04:00
										 |  |  |  | // 13.31.1 Static Semantics: IsValidMonthDay, https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar-static-semantics-isvalidmonthday
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  | static bool is_valid_month_day(ParseResult const& result) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     // 1. If DateDay is "31" and DateMonth is "02", "04", "06", "09", "11", return false.
 | 
					
						
							|  |  |  |  |     if (result.date_day == "31"sv && result.date_month->is_one_of("02"sv, "04"sv, "06"sv, "09"sv, "11"sv)) | 
					
						
							|  |  |  |  |         return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 2. If DateMonth is "02" and DateDay is "30", return false.
 | 
					
						
							|  |  |  |  |     if (result.date_month == "02"sv && result.date_day == "30"sv) | 
					
						
							|  |  |  |  |         return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 3. Return true.
 | 
					
						
							|  |  |  |  |     return true; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-20 11:57:42 -04:00
										 |  |  |  | // 13.31.2 Static Semantics: IsValidDate, https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar-static-semantics-isvaliddate
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  | static bool is_valid_date(ParseResult const& result) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     // 1. If IsValidMonthDay of DateSpec is false, return false.
 | 
					
						
							|  |  |  |  |     if (!is_valid_month_day(result)) | 
					
						
							|  |  |  |  |         return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 2. Let year be ℝ(StringToNumber(CodePointsToString(DateYear))).
 | 
					
						
							|  |  |  |  |     auto year = string_to_number(*result.date_year); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 3. If DateMonth is "02" and DateDay is "29" and MathematicalInLeapYear(EpochTimeForYear(year)) = 0, return false.
 | 
					
						
							|  |  |  |  |     if (result.date_month == "02"sv && result.date_day == "29"sv && mathematical_in_leap_year(epoch_time_for_year(year)) == 0) | 
					
						
							|  |  |  |  |         return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 4. Return true.
 | 
					
						
							|  |  |  |  |     return true; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-20 11:57:42 -04:00
										 |  |  |  | // 13.31 RFC 9557 / ISO 8601 grammar, https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | class ISO8601Parser { | 
					
						
							|  |  |  |  | public: | 
					
						
							|  |  |  |  |     explicit ISO8601Parser(StringView input) | 
					
						
							|  |  |  |  |         : m_input(input) | 
					
						
							|  |  |  |  |         , m_state({ | 
					
						
							|  |  |  |  |               .lexer = GenericLexer { input }, | 
					
						
							|  |  |  |  |               .parse_result = {}, | 
					
						
							|  |  |  |  |           }) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     [[nodiscard]] GenericLexer const& lexer() const { return m_state.lexer; } | 
					
						
							|  |  |  |  |     [[nodiscard]] ParseResult const& parse_result() const { return m_state.parse_result; } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TemporalDateTimeString
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_temporal_date_time_string() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // TemporalDateTimeString[Zoned] :::
 | 
					
						
							|  |  |  |  |         //     AnnotatedDateTime[?Zoned, ~TimeRequired]
 | 
					
						
							|  |  |  |  |         return parse_annotated_date_time(Zoned::No, TimeRequired::No); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TemporalDateTimeString
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_temporal_zoned_date_time_string() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // TemporalDateTimeString[Zoned] :::
 | 
					
						
							|  |  |  |  |         //     AnnotatedDateTime[?Zoned, ~TimeRequired]
 | 
					
						
							|  |  |  |  |         return parse_annotated_date_time(Zoned::Yes, TimeRequired::No); | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TemporalDurationString
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_temporal_duration_string() | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // TemporalDurationString :::
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |         //     Duration
 | 
					
						
							|  |  |  |  |         return parse_duration(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TemporalInstantString
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_temporal_instant_string() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // TemporalInstantString :::
 | 
					
						
							|  |  |  |  |         //     Date DateTimeSeparator Time DateTimeUTCOffset[+Z] TimeZoneAnnotation[opt] Annotations[opt]
 | 
					
						
							|  |  |  |  |         if (!parse_date()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!parse_date_time_separator()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!parse_time()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!parse_date_time_utc_offset(ZDesignator::Yes)) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         (void)parse_time_zone_annotation(); | 
					
						
							|  |  |  |  |         (void)parse_annotations(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TemporalMonthDayString
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_temporal_month_day_string() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // TemporalMonthDayString :::
 | 
					
						
							|  |  |  |  |         //     AnnotatedMonthDay
 | 
					
						
							|  |  |  |  |         //     AnnotatedDateTime[~Zoned, ~TimeRequired]
 | 
					
						
							|  |  |  |  |         //  NOTE: Reverse order here because `AnnotatedMonthDay` can be a subset of `AnnotatedDateTime`.
 | 
					
						
							|  |  |  |  |         return parse_annotated_date_time(Zoned::No, TimeRequired::No) || parse_annotated_month_day(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TemporalTimeString
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_temporal_time_string() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // TemporalTimeString :::
 | 
					
						
							|  |  |  |  |         //     AnnotatedTime
 | 
					
						
							|  |  |  |  |         //     AnnotatedDateTime[~Zoned, +TimeRequired]
 | 
					
						
							|  |  |  |  |         // NOTE: Reverse order here because `AnnotatedTime` can be a subset of `AnnotatedDateTime`.
 | 
					
						
							|  |  |  |  |         return parse_annotated_date_time(Zoned::No, TimeRequired::Yes) || parse_annotated_time(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-20 12:52:53 -04:00
										 |  |  |  |     // https://tc39.es/proposal-temporal/#prod-AmbiguousTemporalTimeString
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_ambiguous_temporal_time_string() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // AmbiguousTemporalTimeString :::
 | 
					
						
							|  |  |  |  |         //     DateSpecMonthDay TimeZoneAnnotation[opt] Annotations[opt]
 | 
					
						
							|  |  |  |  |         //     DateSpecYearMonth TimeZoneAnnotation[opt] Annotations[opt]
 | 
					
						
							|  |  |  |  |         return parse_annotated_month_day() || parse_annotated_year_month(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TemporalYearMonthString
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_temporal_year_month_string() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // TemporalYearMonthString :::
 | 
					
						
							|  |  |  |  |         //     AnnotatedYearMonth
 | 
					
						
							|  |  |  |  |         //     AnnotatedDateTime[~Zoned, ~TimeRequired]
 | 
					
						
							|  |  |  |  |         //  NOTE: Reverse order here because `AnnotatedYearMonth` can be a subset of `AnnotatedDateTime`.
 | 
					
						
							|  |  |  |  |         return parse_annotated_date_time(Zoned::No, TimeRequired::No) || parse_annotated_year_month(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-AnnotatedDateTime
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_annotated_date_time(Zoned zoned, TimeRequired time_required) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // AnnotatedDateTime[Zoned, TimeRequired] :::
 | 
					
						
							|  |  |  |  |         //     [~Zoned] DateTime[~Z, ?TimeRequired] TimeZoneAnnotation[opt] Annotations[opt]
 | 
					
						
							|  |  |  |  |         //     [+Zoned] DateTime[+Z, ?TimeRequired] TimeZoneAnnotation Annotations[opt]
 | 
					
						
							|  |  |  |  |         if (!parse_date_time(zoned == Zoned::Yes ? ZDesignator::Yes : ZDesignator::No, time_required)) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!parse_time_zone_annotation()) { | 
					
						
							|  |  |  |  |             if (zoned == Zoned::Yes) | 
					
						
							|  |  |  |  |                 return false; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         (void)parse_annotations(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-AnnotatedMonthDay
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_annotated_month_day() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // AnnotatedMonthDay :::
 | 
					
						
							|  |  |  |  |         //     DateSpecMonthDay TimeZoneAnnotation[opt] Annotations[opt]
 | 
					
						
							|  |  |  |  |         if (!parse_date_spec_month_day()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         (void)parse_time_zone_annotation(); | 
					
						
							|  |  |  |  |         (void)parse_annotations(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-AnnotatedTime
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_annotated_time() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // AnnotatedTime :::
 | 
					
						
							|  |  |  |  |         //     TimeDesignator Time DateTimeUTCOffset[~Z][opt] TimeZoneAnnotation[opt] Annotations[opt]
 | 
					
						
							|  |  |  |  |         //     Time DateTimeUTCOffset[~Z][opt] TimeZoneAnnotation[opt] Annotations[opt]
 | 
					
						
							| 
									
										
										
										
											2025-07-20 12:52:53 -04:00
										 |  |  |  |         (void)parse_time_designator(); | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!parse_time()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         (void)parse_date_time_utc_offset(ZDesignator::No); | 
					
						
							|  |  |  |  |         (void)parse_time_zone_annotation(); | 
					
						
							|  |  |  |  |         (void)parse_annotations(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-AnnotatedYearMonth
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_annotated_year_month() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // AnnotatedYearMonth :::
 | 
					
						
							|  |  |  |  |         //     DateSpecYearMonth TimeZoneAnnotation[opt] Annotations[opt]
 | 
					
						
							|  |  |  |  |         if (!parse_date_spec_year_month()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         (void)parse_time_zone_annotation(); | 
					
						
							|  |  |  |  |         (void)parse_annotations(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-DateTime
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_date_time(ZDesignator z_designator, TimeRequired time_required) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // DateTime[Z, TimeRequired] :::
 | 
					
						
							|  |  |  |  |         //     [~TimeRequired] Date
 | 
					
						
							|  |  |  |  |         //     Date DateTimeSeparator Time DateTimeUTCOffset[?Z][opt]
 | 
					
						
							|  |  |  |  |         if (!parse_date()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (parse_date_time_separator()) { | 
					
						
							|  |  |  |  |             if (!parse_time()) | 
					
						
							|  |  |  |  |                 return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             (void)parse_date_time_utc_offset(z_designator); | 
					
						
							|  |  |  |  |         } else if (time_required == TimeRequired::Yes) { | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-Date
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_date() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // Date :::
 | 
					
						
							|  |  |  |  |         //     DateSpec[+Extended]
 | 
					
						
							|  |  |  |  |         //     DateSpec[~Extended]
 | 
					
						
							|  |  |  |  |         return parse_date_spec(Extended::Yes) || parse_date_spec(Extended::No); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-DateSpec
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_date_spec(Extended extended) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // DateSpec[Extended] :::
 | 
					
						
							|  |  |  |  |         //     DateYear DateSeparator[?Extended] DateMonth DateSeparator[?Extended] DateDay
 | 
					
						
							|  |  |  |  |         if (!parse_date_year()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!parse_date_separator(extended)) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!parse_date_month()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!parse_date_separator(extended)) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!parse_date_day()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-20 12:50:45 -04:00
										 |  |  |  |         // Note the prohibition on invalid combinations of month and day in 13.31.3.
 | 
					
						
							|  |  |  |  |         // https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar-static-semantics-early-errors
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // It is a Syntax Error if IsValidDate of DateSpec is false.
 | 
					
						
							|  |  |  |  |         if (!is_valid_date(m_state.parse_result)) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-DateSpecMonthDay
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_date_spec_month_day() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // DateSpecMonthDay :::
 | 
					
						
							|  |  |  |  |         //     --[opt] DateMonth DateSeparator[+Extended] DateDay
 | 
					
						
							|  |  |  |  |         //     --[opt] DateMonth DateSeparator[~Extended] DateDay
 | 
					
						
							|  |  |  |  |         (void)m_state.lexer.consume_specific("--"sv); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!parse_date_month()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!parse_date_separator(Extended::Yes) && !parse_date_separator(Extended::No)) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!parse_date_day()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-20 12:50:45 -04:00
										 |  |  |  |         // Note the prohibition on invalid combinations of month and day in 13.31.3.
 | 
					
						
							|  |  |  |  |         // https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar-static-semantics-early-errors
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // It is a Syntax Error if IsValidMonthDay of DateSpecMonthDay is false.
 | 
					
						
							|  |  |  |  |         if (!is_valid_month_day(m_state.parse_result)) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-DateSpecYearMonth
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_date_spec_year_month() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // DateSpecYearMonth :::
 | 
					
						
							|  |  |  |  |         //     DateYear DateSeparator[+Extended] DateMonth
 | 
					
						
							|  |  |  |  |         //     DateYear DateSeparator[~Extended] DateMonth
 | 
					
						
							|  |  |  |  |         if (!parse_date_year()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!parse_date_separator(Extended::Yes) && !parse_date_separator(Extended::No)) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!parse_date_month()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-DateYear
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_date_year() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // DateYear :::
 | 
					
						
							|  |  |  |  |         //     DecimalDigit DecimalDigit DecimalDigit DecimalDigit
 | 
					
						
							|  |  |  |  |         //     ASCIISign DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
 | 
					
						
							|  |  |  |  |         size_t digit_count = parse_ascii_sign() ? 6 : 4; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         for (size_t i = 0; i < digit_count; ++i) { | 
					
						
							|  |  |  |  |             if (!parse_decimal_digit()) | 
					
						
							|  |  |  |  |                 return false; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-20 12:50:45 -04:00
										 |  |  |  |         // Note the prohibition on negative zero in 13.31.3.
 | 
					
						
							|  |  |  |  |         // https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar-static-semantics-early-errors
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // It is a Syntax Error if DateYear is "-000000".
 | 
					
						
							|  |  |  |  |         if (transaction.parsed_string_view() == "-000000"sv) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         m_state.parse_result.date_year = transaction.parsed_string_view(); | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-DateMonth
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_date_month() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // DateMonth :::
 | 
					
						
							|  |  |  |  |         //     0 NonZeroDigit
 | 
					
						
							|  |  |  |  |         //     10
 | 
					
						
							|  |  |  |  |         //     11
 | 
					
						
							|  |  |  |  |         //     12
 | 
					
						
							|  |  |  |  |         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
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_date_day() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // DateDay :::
 | 
					
						
							|  |  |  |  |         //     0 NonZeroDigit
 | 
					
						
							|  |  |  |  |         //     1 DecimalDigit
 | 
					
						
							|  |  |  |  |         //     2 DecimalDigit
 | 
					
						
							|  |  |  |  |         //     30
 | 
					
						
							|  |  |  |  |         //     31
 | 
					
						
							|  |  |  |  |         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-DateTimeUTCOffset
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_date_time_utc_offset(ZDesignator z_designator) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // DateTimeUTCOffset[Z] :::
 | 
					
						
							|  |  |  |  |         //     [+Z] UTCDesignator
 | 
					
						
							|  |  |  |  |         //     UTCOffset[+SubMinutePrecision]
 | 
					
						
							|  |  |  |  |         if (z_designator == ZDesignator::Yes) { | 
					
						
							|  |  |  |  |             if (parse_utc_designator()) | 
					
						
							|  |  |  |  |                 return true; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return parse_utc_offset(SubMinutePrecision::Yes, m_state.parse_result.date_time_offset); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-Time
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_time() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // Time :::
 | 
					
						
							|  |  |  |  |         //     TimeSpec[+Extended]
 | 
					
						
							|  |  |  |  |         //     TimeSpec[~Extended]
 | 
					
						
							|  |  |  |  |         return parse_time_spec(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TimeSpec
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_time_spec() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         auto parse_time_hour = [&]() { | 
					
						
							|  |  |  |  |             return scoped_parse(m_state.parse_result.time_hour, [&]() { return parse_hour(); }); | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  |         auto parse_time_minute = [&]() { | 
					
						
							|  |  |  |  |             return scoped_parse(m_state.parse_result.time_minute, [&]() { return parse_minute_second(); }); | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  |         auto parse_time_fraction = [&]() { | 
					
						
							|  |  |  |  |             return scoped_parse(m_state.parse_result.time_fraction, [&]() { return parse_temporal_decimal_fraction(); }); | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // TimeSpec[Extended] :::
 | 
					
						
							|  |  |  |  |         //     Hour
 | 
					
						
							|  |  |  |  |         //     Hour TimeSeparator[?Extended] MinuteSecond
 | 
					
						
							|  |  |  |  |         //     Hour TimeSeparator[?Extended] MinuteSecond TimeSeparator[?Extended] TimeSecond TemporalDecimalFraction[opt]
 | 
					
						
							|  |  |  |  |         if (!parse_time_hour()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (parse_time_separator(Extended::Yes)) { | 
					
						
							|  |  |  |  |             if (!parse_time_minute()) | 
					
						
							|  |  |  |  |                 return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (parse_time_separator(Extended::Yes)) { | 
					
						
							|  |  |  |  |                 if (!parse_time_second()) | 
					
						
							|  |  |  |  |                     return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 (void)parse_time_fraction(); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } else if (parse_time_minute() && parse_time_second()) { | 
					
						
							|  |  |  |  |             (void)parse_time_fraction(); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TimeSecond
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_time_second() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // TimeSecond :::
 | 
					
						
							|  |  |  |  |         //     MinuteSecond
 | 
					
						
							|  |  |  |  |         //     60
 | 
					
						
							|  |  |  |  |         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-TimeZoneAnnotation
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_time_zone_annotation() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // TimeZoneAnnotation :::
 | 
					
						
							|  |  |  |  |         //    [ AnnotationCriticalFlag[opt] TimeZoneIdentifier ]
 | 
					
						
							|  |  |  |  |         if (!m_state.lexer.consume_specific('[')) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         (void)parse_annotation_critical_flag(); | 
					
						
							|  |  |  |  |         if (!parse_time_zone_identifier()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!m_state.lexer.consume_specific(']')) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TimeZoneIdentifier
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_time_zone_identifier() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // TimeZoneIdentifier :::
 | 
					
						
							|  |  |  |  |         //    UTCOffset[~SubMinutePrecision]
 | 
					
						
							|  |  |  |  |         //    TimeZoneIANAName
 | 
					
						
							|  |  |  |  |         auto success = parse_utc_offset(SubMinutePrecision::No, m_state.parse_result.time_zone_offset) || parse_time_zone_iana_name(); | 
					
						
							|  |  |  |  |         if (!success) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         m_state.parse_result.time_zone_identifier = transaction.parsed_string_view(); | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TimeZoneIANAName
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_time_zone_iana_name() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // TimeZoneIANAName :::
 | 
					
						
							|  |  |  |  |         //     TimeZoneIANANameComponent
 | 
					
						
							|  |  |  |  |         //     TimeZoneIANAName / TimeZoneIANANameComponent
 | 
					
						
							|  |  |  |  |         if (!parse_time_zone_iana_name_component()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         while (m_state.lexer.consume_specific('/')) { | 
					
						
							|  |  |  |  |             if (!parse_time_zone_iana_name_component()) | 
					
						
							|  |  |  |  |                 return false; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         m_state.parse_result.time_zone_iana_name = transaction.parsed_string_view(); | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TimeZoneIANANameComponent
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_time_zone_iana_name_component() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // TimeZoneIANANameComponent :::
 | 
					
						
							|  |  |  |  |         //     TZLeadingChar
 | 
					
						
							|  |  |  |  |         //     TimeZoneIANANameComponent TZChar
 | 
					
						
							|  |  |  |  |         if (!parse_tz_leading_char()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         while (parse_tz_leading_char()) | 
					
						
							|  |  |  |  |             ; | 
					
						
							|  |  |  |  |         while (parse_tz_char()) | 
					
						
							|  |  |  |  |             ; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TZLeadingChar
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_tz_leading_char() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // TZLeadingChar :::
 | 
					
						
							|  |  |  |  |         //     Alpha
 | 
					
						
							|  |  |  |  |         //     .
 | 
					
						
							|  |  |  |  |         //     _
 | 
					
						
							|  |  |  |  |         return parse_alpha() || m_state.lexer.consume_specific('.') || m_state.lexer.consume_specific('_'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TZChar
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_tz_char() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // TZChar :::
 | 
					
						
							|  |  |  |  |         //     TZLeadingChar
 | 
					
						
							|  |  |  |  |         //     DecimalDigit
 | 
					
						
							|  |  |  |  |         //     -
 | 
					
						
							|  |  |  |  |         //     +
 | 
					
						
							|  |  |  |  |         return parse_tz_leading_char() || parse_decimal_digit() || m_state.lexer.consume_specific('.') || m_state.lexer.consume_specific('+'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-Annotations
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_annotations() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // Annotations :::
 | 
					
						
							|  |  |  |  |         //     Annotation Annotationsopt
 | 
					
						
							|  |  |  |  |         if (!parse_annotation()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         while (parse_annotation()) | 
					
						
							|  |  |  |  |             ; | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-Annotation
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_annotation() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         Optional<StringView> key; | 
					
						
							|  |  |  |  |         Optional<StringView> value; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // Annotation :::
 | 
					
						
							|  |  |  |  |         //     [ AnnotationCriticalFlag[opt] AnnotationKey = AnnotationValue ]
 | 
					
						
							|  |  |  |  |         if (!m_state.lexer.consume_specific('[')) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         auto critical = parse_annotation_critical_flag(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!scoped_parse(key, [&]() { return parse_annotation_key(); })) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!m_state.lexer.consume_specific('=')) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!scoped_parse(value, [&]() { return parse_annotation_value(); })) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!m_state.lexer.consume_specific(']')) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         m_state.parse_result.annotations.empend(critical, *key, *value); | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-AnnotationKey
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_annotation_key() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // AnnotationKey :::
 | 
					
						
							|  |  |  |  |         //     AKeyLeadingChar
 | 
					
						
							|  |  |  |  |         //     AnnotationKey AKeyChar
 | 
					
						
							|  |  |  |  |         if (!parse_annotation_key_leading_char()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         while (parse_annotation_key_leading_char()) | 
					
						
							|  |  |  |  |             ; | 
					
						
							|  |  |  |  |         while (parse_annotation_key_char()) | 
					
						
							|  |  |  |  |             ; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-AKeyLeadingChar
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_annotation_key_leading_char() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // AKeyLeadingChar :::
 | 
					
						
							|  |  |  |  |         //     LowercaseAlpha
 | 
					
						
							|  |  |  |  |         //     _
 | 
					
						
							|  |  |  |  |         return parse_lowercase_alpha() || m_state.lexer.consume_specific('_'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-AKeyChar
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_annotation_key_char() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // AKeyChar :::
 | 
					
						
							|  |  |  |  |         //     AKeyLeadingChar
 | 
					
						
							|  |  |  |  |         //     DecimalDigit
 | 
					
						
							|  |  |  |  |         //     -
 | 
					
						
							|  |  |  |  |         return parse_annotation_key_leading_char() || parse_decimal_digit() || m_state.lexer.consume_specific('-'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-AnnotationValue
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_annotation_value() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // AnnotationValue :::
 | 
					
						
							|  |  |  |  |         //     AnnotationValueComponent
 | 
					
						
							|  |  |  |  |         //     AnnotationValueComponent - AnnotationValue
 | 
					
						
							|  |  |  |  |         if (!parse_annotation_value_component()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         while (m_state.lexer.consume_specific('-')) { | 
					
						
							|  |  |  |  |             if (!parse_annotation_value_component()) | 
					
						
							|  |  |  |  |                 return false; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-AnnotationValueComponent
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_annotation_value_component() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // AnnotationValueComponent :::
 | 
					
						
							|  |  |  |  |         //     Alpha AnnotationValueComponent[opt]
 | 
					
						
							|  |  |  |  |         //     DecimalDigit AnnotationValueComponent[opt]
 | 
					
						
							|  |  |  |  |         auto parse_component = [&]() { return parse_alpha() || parse_decimal_digit(); }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!parse_component()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         while (parse_component()) | 
					
						
							|  |  |  |  |             ; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-UTCOffset
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_utc_offset(SubMinutePrecision sub_minute_precision, Optional<TimeZoneOffset>& result) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  |         TimeZoneOffset time_zone_offset; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         auto parse_utc_sign = [&]() { | 
					
						
							|  |  |  |  |             return scoped_parse(time_zone_offset.sign, [&]() { return parse_ascii_sign(); }); | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  |         auto parse_utc_hours = [&]() { | 
					
						
							|  |  |  |  |             return scoped_parse(time_zone_offset.hours, [&]() { return parse_hour(); }); | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  |         auto parse_utc_minutes = [&]() { | 
					
						
							|  |  |  |  |             return scoped_parse(time_zone_offset.minutes, [&]() { return parse_minute_second(); }); | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  |         auto parse_utc_seconds = [&]() { | 
					
						
							|  |  |  |  |             return scoped_parse(time_zone_offset.seconds, [&]() { return parse_minute_second(); }); | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  |         auto parse_utc_fraction = [&]() { | 
					
						
							|  |  |  |  |             return scoped_parse(time_zone_offset.fraction, [&]() { return parse_temporal_decimal_fraction(); }); | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // UTCOffset[SubMinutePrecision] :::
 | 
					
						
							|  |  |  |  |         //     ASCIISign Hour
 | 
					
						
							|  |  |  |  |         //     ASCIISign Hour TimeSeparator[+Extended] MinuteSecond
 | 
					
						
							|  |  |  |  |         //     ASCIISign Hour TimeSeparator[~Extended] MinuteSecond
 | 
					
						
							|  |  |  |  |         //     [+SubMinutePrecision] ASCIISign Hour TimeSeparator[+Extended] MinuteSecond TimeSeparator[+Extended] MinuteSecond TemporalDecimalFraction[opt]
 | 
					
						
							|  |  |  |  |         //     [+SubMinutePrecision] ASCIISign Hour TimeSeparator[~Extended] MinuteSecond TimeSeparator[~Extended] MinuteSecond TemporalDecimalFraction[opt]
 | 
					
						
							|  |  |  |  |         if (!parse_utc_sign()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!parse_utc_hours()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (parse_time_separator(Extended::Yes)) { | 
					
						
							|  |  |  |  |             if (!parse_utc_minutes()) | 
					
						
							|  |  |  |  |                 return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (sub_minute_precision == SubMinutePrecision::Yes && parse_time_separator(Extended::Yes)) { | 
					
						
							|  |  |  |  |                 if (!parse_utc_seconds()) | 
					
						
							|  |  |  |  |                     return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 (void)parse_utc_fraction(); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } else if (parse_utc_minutes()) { | 
					
						
							|  |  |  |  |             if (sub_minute_precision == SubMinutePrecision::Yes && parse_utc_seconds()) | 
					
						
							|  |  |  |  |                 (void)parse_utc_fraction(); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         time_zone_offset.source_text = transaction.parsed_string_view(); | 
					
						
							|  |  |  |  |         result = move(time_zone_offset); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/ecma262/#prod-Hour
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_hour() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // Hour :::
 | 
					
						
							|  |  |  |  |         //     0 DecimalDigit
 | 
					
						
							|  |  |  |  |         //     1 DecimalDigit
 | 
					
						
							|  |  |  |  |         //     20
 | 
					
						
							|  |  |  |  |         //     21
 | 
					
						
							|  |  |  |  |         //     22
 | 
					
						
							|  |  |  |  |         //     23
 | 
					
						
							|  |  |  |  |         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; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/ecma262/#prod-MinuteSecond
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_minute_second() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // MinuteSecond :::
 | 
					
						
							|  |  |  |  |         //     0 DecimalDigit
 | 
					
						
							|  |  |  |  |         //     1 DecimalDigit
 | 
					
						
							|  |  |  |  |         //     2 DecimalDigit
 | 
					
						
							|  |  |  |  |         //     3 DecimalDigit
 | 
					
						
							|  |  |  |  |         //     4 DecimalDigit
 | 
					
						
							|  |  |  |  |         //     5 DecimalDigit
 | 
					
						
							|  |  |  |  |         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; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |     // https://tc39.es/proposal-temporal/#prod-DurationDate
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_duration_date() | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // DurationDate :::
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |         //     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
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_duration() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // Duration :::
 | 
					
						
							|  |  |  |  |         //    ASCIISign[opt] DurationDesignator DurationDate
 | 
					
						
							|  |  |  |  |         //    ASCIISign[opt] DurationDesignator DurationTime
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         (void)scoped_parse(m_state.parse_result.sign, [&]() { return parse_ascii_sign(); }); | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         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-DurationYearsPart
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_duration_years_part() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // DurationYearsPart :::
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |         //     DecimalDigits[~Sep] YearsDesignator DurationMonthsPart
 | 
					
						
							|  |  |  |  |         //     DecimalDigits[~Sep] YearsDesignator DurationWeeksPart
 | 
					
						
							|  |  |  |  |         //     DecimalDigits[~Sep] YearsDesignator DurationDaysPart[opt]
 | 
					
						
							|  |  |  |  |         if (!parse_decimal_digits(Separator::No, m_state.parse_result.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-DurationMonthsPart
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_duration_months_part() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // DurationMonthsPart :::
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |         //     DecimalDigits[~Sep] MonthsDesignator DurationWeeksPart
 | 
					
						
							|  |  |  |  |         //     DecimalDigits[~Sep] MonthsDesignator DurationDaysPart[opt]
 | 
					
						
							|  |  |  |  |         if (!parse_decimal_digits(Separator::No, m_state.parse_result.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-DurationWeeksPart
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_duration_weeks_part() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // DurationWeeksPart :::
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |         //     DecimalDigits[~Sep] WeeksDesignator DurationDaysPart[opt]
 | 
					
						
							|  |  |  |  |         if (!parse_decimal_digits(Separator::No, m_state.parse_result.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-DurationDaysPart
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_duration_days_part() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // DurationDaysPart :::
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |         //     DecimalDigits[~Sep] DaysDesignator
 | 
					
						
							|  |  |  |  |         if (!parse_decimal_digits(Separator::No, m_state.parse_result.duration_days)) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!parse_days_designator()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-DurationTime
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_duration_time() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // DurationTime :::
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |         //     TimeDesignator DurationHoursPart
 | 
					
						
							|  |  |  |  |         //     TimeDesignator DurationMinutesPart
 | 
					
						
							|  |  |  |  |         //     TimeDesignator DurationSecondsPart
 | 
					
						
							|  |  |  |  |         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-DurationHoursPart
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_duration_hours_part() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // DurationHoursPart :::
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |         //     DecimalDigits[~Sep] TemporalDecimalFraction HoursDesignator
 | 
					
						
							|  |  |  |  |         //     DecimalDigits[~Sep] HoursDesignator DurationMinutesPart
 | 
					
						
							|  |  |  |  |         //     DecimalDigits[~Sep] HoursDesignator DurationSecondsPart[opt]
 | 
					
						
							|  |  |  |  |         if (!parse_decimal_digits(Separator::No, m_state.parse_result.duration_hours)) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         auto is_fractional = scoped_parse(m_state.parse_result.duration_hours_fraction, [&]() { return parse_temporal_decimal_fraction(); }); | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!parse_hours_designator()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!is_fractional) | 
					
						
							|  |  |  |  |             (void)(parse_duration_minutes_part() || parse_duration_seconds_part()); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-DurationMinutesPart
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_duration_minutes_part() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // DurationMinutesPart :::
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |         //     DecimalDigits[~Sep] TemporalDecimalFraction MinutesDesignator
 | 
					
						
							|  |  |  |  |         //     DecimalDigits[~Sep] MinutesDesignator DurationSecondsPart[opt]
 | 
					
						
							|  |  |  |  |         if (!parse_decimal_digits(Separator::No, m_state.parse_result.duration_minutes)) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         auto is_fractional = scoped_parse(m_state.parse_result.duration_minutes_fraction, [&]() { return parse_temporal_decimal_fraction(); }); | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!parse_minutes_designator()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         if (!is_fractional) | 
					
						
							|  |  |  |  |             (void)parse_duration_seconds_part(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-DurationSecondsPart
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_duration_seconds_part() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // DurationSecondsPart :::
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |         //     DecimalDigits[~Sep] TemporalDecimalFraction[opt] SecondsDesignator
 | 
					
						
							|  |  |  |  |         if (!parse_decimal_digits(Separator::No, m_state.parse_result.duration_seconds)) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         (void)scoped_parse(m_state.parse_result.duration_seconds_fraction, [&]() { return parse_temporal_decimal_fraction(); }); | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!parse_seconds_designator()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |     // https://tc39.es/ecma262/#prod-TemporalDecimalFraction
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_temporal_decimal_fraction() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // TemporalDecimalFraction :::
 | 
					
						
							|  |  |  |  |         //     TemporalDecimalSeparator DecimalDigit
 | 
					
						
							|  |  |  |  |         //     TemporalDecimalSeparator DecimalDigit DecimalDigit
 | 
					
						
							|  |  |  |  |         //     TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit
 | 
					
						
							|  |  |  |  |         //     TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit DecimalDigit
 | 
					
						
							|  |  |  |  |         //     TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
 | 
					
						
							|  |  |  |  |         //     TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
 | 
					
						
							|  |  |  |  |         //     TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
 | 
					
						
							|  |  |  |  |         //     TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
 | 
					
						
							|  |  |  |  |         //     TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
 | 
					
						
							|  |  |  |  |         if (!parse_temporal_decimal_separator()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         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-Alpha
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_alpha() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // Alpha ::: one of
 | 
					
						
							|  |  |  |  |         //     A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z
 | 
					
						
							|  |  |  |  |         if (m_state.lexer.next_is(is_ascii_alpha)) { | 
					
						
							|  |  |  |  |             m_state.lexer.consume(); | 
					
						
							|  |  |  |  |             return true; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return false; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-LowercaseAlpha
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_lowercase_alpha() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // LowercaseAlpha ::: one of
 | 
					
						
							|  |  |  |  |         //     a b c d e f g h i j k l m n o p q r s t u v w x y z
 | 
					
						
							|  |  |  |  |         if (m_state.lexer.next_is(is_ascii_lower_alpha)) { | 
					
						
							|  |  |  |  |             m_state.lexer.consume(); | 
					
						
							|  |  |  |  |             return true; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return false; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |     // https://tc39.es/ecma262/#prod-DecimalDigit
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool 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/ecma262/#prod-DecimalDigits
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_decimal_digits(Separator separator, Optional<StringView>& result) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // FIXME: Implement [+Sep] if it's ever needed.
 | 
					
						
							|  |  |  |  |         VERIFY(separator == Separator::No); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // DecimalDigits[Sep] ::
 | 
					
						
							|  |  |  |  |         //     DecimalDigit
 | 
					
						
							|  |  |  |  |         //     DecimalDigits[?Sep] DecimalDigit
 | 
					
						
							|  |  |  |  |         //     [+Sep] DecimalDigits[+Sep] NumericLiteralSeparator DecimalDigit
 | 
					
						
							|  |  |  |  |         if (!parse_decimal_digit()) | 
					
						
							|  |  |  |  |             return {}; | 
					
						
							|  |  |  |  |         while (parse_decimal_digit()) | 
					
						
							|  |  |  |  |             ; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         result = transaction.parsed_string_view(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |     // https://tc39.es/ecma262/#prod-NonZeroDigit
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_non_zero_digit() | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         // 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; | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/ecma262/#prod-ASCIISign
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_ascii_sign() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // ASCIISign : one of
 | 
					
						
							|  |  |  |  |         //     + -
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |         return m_state.lexer.consume_specific('+') || m_state.lexer.consume_specific('-'); | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |     // https://tc39.es/proposal-temporal/#prod-DateSeparator
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_date_separator(Extended extended) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // DateSeparator[Extended] :::
 | 
					
						
							|  |  |  |  |         //     [+Extended] -
 | 
					
						
							|  |  |  |  |         //     [~Extended] [empty]
 | 
					
						
							|  |  |  |  |         if (extended == Extended::Yes) | 
					
						
							|  |  |  |  |             return m_state.lexer.consume_specific('-'); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |     // https://tc39.es/ecma262/#prod-TimeSeparator
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_time_separator(Extended extended) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // TimeSeparator[Extended] :::
 | 
					
						
							|  |  |  |  |         //     [+Extended] :
 | 
					
						
							|  |  |  |  |         //     [~Extended] [empty]
 | 
					
						
							|  |  |  |  |         if (extended == Extended::Yes) | 
					
						
							|  |  |  |  |             return m_state.lexer.consume_specific(':'); | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |     // https://tc39.es/proposal-temporal/#prod-TimeDesignator
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool 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-DateTimeSeparator
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool 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'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |     // https://tc39.es/ecma262/#prod-TemporalDecimalSeparator
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_temporal_decimal_separator() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // TemporalDecimalSeparator ::: one of
 | 
					
						
							|  |  |  |  |         //    . ,
 | 
					
						
							|  |  |  |  |         return m_state.lexer.consume_specific('.') || m_state.lexer.consume_specific(','); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // https://tc39.es/proposal-temporal/#prod-DurationDesignator
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool 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-YearsDesignator
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool 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-MonthsDesignator
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool 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-WeeksDesignator
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool 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-DaysDesignator
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool 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
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool 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
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool 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-SecondsDesignator
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_seconds_designator() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // SecondsDesignator : one of
 | 
					
						
							|  |  |  |  |         //     S s
 | 
					
						
							|  |  |  |  |         return m_state.lexer.consume_specific('S') || m_state.lexer.consume_specific('s'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |     // https://tc39.es/proposal-temporal/#prod-UTCDesignator
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_utc_designator() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // UTCDesignator : one of
 | 
					
						
							|  |  |  |  |         //     Z z
 | 
					
						
							|  |  |  |  |         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-AnnotationCriticalFlag
 | 
					
						
							|  |  |  |  |     [[nodiscard]] bool parse_annotation_critical_flag() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // AnnotationCriticalFlag :::
 | 
					
						
							|  |  |  |  |         //     !
 | 
					
						
							|  |  |  |  |         return m_state.lexer.consume_specific('!'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | private: | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |     template<typename Parser, typename T> | 
					
						
							|  |  |  |  |     [[nodiscard]] bool scoped_parse(Optional<T>& storage, Parser&& parser) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         StateTransaction transaction { *this }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!parser()) | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if constexpr (IsSame<T, char>) | 
					
						
							|  |  |  |  |             storage = transaction.parsed_string_view()[0]; | 
					
						
							|  |  |  |  |         else | 
					
						
							|  |  |  |  |             storage = transaction.parsed_string_view(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         transaction.commit(); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  |     struct State { | 
					
						
							|  |  |  |  |         GenericLexer lexer; | 
					
						
							|  |  |  |  |         ParseResult parse_result; | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     struct StateTransaction { | 
					
						
							|  |  |  |  |         explicit StateTransaction(ISO8601Parser& parser) | 
					
						
							|  |  |  |  |             : m_parser(parser) | 
					
						
							|  |  |  |  |             , m_saved_state(parser.m_state) | 
					
						
							|  |  |  |  |             , m_start_index(parser.m_state.lexer.tell()) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         ~StateTransaction() | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             if (!m_commit) | 
					
						
							|  |  |  |  |                 m_parser.m_state = move(m_saved_state); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         void commit() { m_commit = true; } | 
					
						
							|  |  |  |  |         StringView parsed_string_view() const | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             return m_parser.m_input.substring_view(m_start_index, m_parser.m_state.lexer.tell() - m_start_index); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     private: | 
					
						
							|  |  |  |  |         ISO8601Parser& m_parser; | 
					
						
							|  |  |  |  |         State m_saved_state; | 
					
						
							|  |  |  |  |         size_t m_start_index { 0 }; | 
					
						
							|  |  |  |  |         bool m_commit { false }; | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     StringView m_input; | 
					
						
							|  |  |  |  |     State m_state; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  | #define JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS                                        \
 | 
					
						
							| 
									
										
										
										
											2025-07-20 12:52:53 -04:00
										 |  |  |  |     __JS_ENUMERATE(AmbiguousTemporalTimeString, parse_ambiguous_temporal_time_string)  \ | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  |     __JS_ENUMERATE(AnnotationValue, parse_annotation_value)                            \ | 
					
						
							|  |  |  |  |     __JS_ENUMERATE(DateMonth, parse_date_month)                                        \ | 
					
						
							|  |  |  |  |     __JS_ENUMERATE(TemporalDateTimeString, parse_temporal_date_time_string)            \ | 
					
						
							|  |  |  |  |     __JS_ENUMERATE(TemporalDurationString, parse_temporal_duration_string)             \ | 
					
						
							|  |  |  |  |     __JS_ENUMERATE(TemporalInstantString, parse_temporal_instant_string)               \ | 
					
						
							|  |  |  |  |     __JS_ENUMERATE(TemporalMonthDayString, parse_temporal_month_day_string)            \ | 
					
						
							|  |  |  |  |     __JS_ENUMERATE(TemporalTimeString, parse_temporal_time_string)                     \ | 
					
						
							|  |  |  |  |     __JS_ENUMERATE(TemporalYearMonthString, parse_temporal_year_month_string)          \ | 
					
						
							|  |  |  |  |     __JS_ENUMERATE(TemporalZonedDateTimeString, parse_temporal_zoned_date_time_string) \ | 
					
						
							|  |  |  |  |     __JS_ENUMERATE(TimeZoneIdentifier, parse_time_zone_identifier) | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | Optional<ParseResult> parse_iso8601(Production production, StringView input) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     ISO8601Parser parser { 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(); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-19 15:15:13 -05:00
										 |  |  |  | Optional<TimeZoneOffset> parse_utc_offset(StringView input, SubMinutePrecision sub_minute_precision) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     ISO8601Parser parser { input }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     Optional<TimeZoneOffset> utc_offset; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (!parser.parse_utc_offset(sub_minute_precision, utc_offset)) | 
					
						
							|  |  |  |  |         return {}; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 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 utc_offset; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:58:51 -05:00
										 |  |  |  | } |