diff --git a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h index cdf19cee9f..b2190caf7a 100644 --- a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h +++ b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h @@ -243,6 +243,7 @@ M(TemporalInvalidEpochNanoseconds, "Invalid epoch nanoseconds value, must be in range -86400 * 10^17 to 86400 * 10^17") \ M(TemporalInvalidInstantString, "Invalid instant string '{}'") \ M(TemporalInvalidISODate, "Invalid ISO date") \ + M(TemporalInvalidISODateTime, "Invalid ISO date time") \ M(TemporalInvalidMonthCode, "Invalid month code") \ M(TemporalInvalidMonthDayString, "Invalid month day string '{}'") \ M(TemporalInvalidMonthDayStringUTCDesignator, "Invalid month day string '{}': must not contain a UTC designator") \ diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp index 535be421fd..5e9d4b524f 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp @@ -1162,14 +1162,38 @@ Crypto::SignedBigInteger round_number_to_increment_as_if_positive(Crypto::Signed } // 13.28 ParseISODateTime ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parseisodatetime -ThrowCompletionOr parse_iso_date_time(VM& vm, ParseResult const& parse_result) +ThrowCompletionOr parse_iso_date_time(VM& vm, StringView iso_string) { // 1. Let parseResult be empty. - // 2. For each nonterminal goal of « TemporalDateTimeString, TemporalInstantString, TemporalMonthDayString, TemporalTimeString, TemporalYearMonthString, TemporalZonedDateTimeString », do - // a. If parseResult is not a Parse Node, set parseResult to ParseText(StringToCodePoints(isoString), goal). - // 3. Assert: parseResult is a Parse Node. - // NOTE: All of this is done by receiving an already parsed ISO string (ParseResult). + Optional parse_result; + static constexpr auto productions = AK::Array { + Production::TemporalDateTimeString, + Production::TemporalInstantString, + Production::TemporalMonthDayString, + Production::TemporalTimeString, + Production::TemporalYearMonthString, + Production::TemporalZonedDateTimeString, + }; + + // 2. For each nonterminal goal of « TemporalDateTimeString, TemporalInstantString, TemporalMonthDayString, TemporalTimeString, TemporalYearMonthString, TemporalZonedDateTimeString », do + for (auto goal : productions) { + // a. If parseResult is not a Parse Node, set parseResult to ParseText(StringToCodePoints(isoString), goal). + parse_result = parse_iso8601(goal, iso_string); + if (parse_result.has_value()) + break; + } + + // 3. If parseResult is not a Parse Node, throw a RangeError exception. + if (!parse_result.has_value()) + return vm.throw_completion(ErrorType::TemporalInvalidISODateTime); + + return parse_iso_date_time(vm, *parse_result); +} + +// 13.28 ParseISODateTime ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parseisodatetime +ThrowCompletionOr parse_iso_date_time(VM& vm, ParseResult const& parse_result) +{ // 4. Let each of year, month, day, hour, minute, second, fSeconds, and calendar be the source text matched by the respective DateYear, DateMonth, DateDay, TimeHour, TimeMinute, TimeSecond, TimeFraction, and CalendarName Parse Node contained within parseResult, or an empty sequence of code points if not present. auto year = parse_result.date_year; auto month = parse_result.date_month; @@ -1357,24 +1381,33 @@ ThrowCompletionOr parse_temporal_zoned_date_time_string(VM& vm, Str // 13.31 ParseTemporalCalendarString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalcalendarstring ThrowCompletionOr parse_temporal_calendar_string(VM& vm, String const& iso_string) { - // 1. Let parseResult be ParseText(StringToCodePoints(isoString), TemporalCalendarString). - auto parse_result = parse_iso8601(Production::TemporalCalendarString, iso_string); + // 1. Let parseResult be Completion(ParseISODateTime(isoString)). + auto parse_result_completion = parse_iso_date_time(vm, iso_string); - // 2. If parseResult is a List of errors, throw a RangeError exception. - if (!parse_result.has_value()) - return vm.throw_completion(ErrorType::TemporalInvalidCalendarString, iso_string); + // 2. If parseResult is a normal completion, then + if (!parse_result_completion.is_error()) { + // a. Let calendar be parseResult.[[Value]].[[Calendar]]. + auto calendar = parse_result_completion.value().calendar; - // 3. Let id be the source text matched by the CalendarName Parse Node contained within parseResult, or an empty sequence of code points if not present. - auto id = parse_result->calendar_name; - - // 4. If id is empty, then - if (!id.has_value()) { - // a. Return "iso8601". - return "iso8601"sv; + // b. If calendar is undefined, return "iso8601". + if (!calendar.has_value()) + return "iso8601"sv; + // c. Else, return calendar. + else + return calendar.release_value(); } + // 3. Else, + else { + // a. Set parseResult to ParseText(StringToCodePoints(isoString), CalendarName). + auto parse_result = parse_iso8601(Production::CalendarName, iso_string); - // 5. Return CodePointsToString(id). - return id.value(); + // b. If parseResult is a List of errors, throw a RangeError exception. + if (!parse_result.has_value()) + return vm.throw_completion(ErrorType::TemporalInvalidCalendarString, iso_string); + // c. Else, return isoString. + else + return iso_string; + } } // 13.32 ParseTemporalDateString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaldatestring diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h index 2a94ca8e2f..18066792be 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h @@ -161,6 +161,7 @@ Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedDivisionResu double round_number_to_increment(double, u64 increment, StringView rounding_mode); Crypto::SignedBigInteger round_number_to_increment(Crypto::SignedBigInteger const&, u64 increment, StringView rounding_mode); Crypto::SignedBigInteger round_number_to_increment_as_if_positive(Crypto::SignedBigInteger const&, u64 increment, StringView rounding_mode); +ThrowCompletionOr parse_iso_date_time(VM&, StringView iso_string); ThrowCompletionOr parse_iso_date_time(VM&, ParseResult const& parse_result); ThrowCompletionOr parse_temporal_instant_string(VM&, String const& iso_string); ThrowCompletionOr parse_temporal_zoned_date_time_string(VM&, String const& iso_string); diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp index 6419eadef5..22247048f5 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp @@ -406,17 +406,14 @@ ThrowCompletionOr to_temporal_calendar(VM& vm, Value temporal_calendar_ // 2. Let identifier be ? ToString(temporalCalendarLike). auto identifier = TRY(temporal_calendar_like.to_string(vm)); - // 3. If IsBuiltinCalendar(identifier) is false, then - if (!is_builtin_calendar(identifier)) { - // a. Set identifier to ? ParseTemporalCalendarString(identifier). - identifier = TRY(parse_temporal_calendar_string(vm, identifier)); + // 3. Set identifier to ? ParseTemporalCalendarString(identifier). + identifier = TRY(parse_temporal_calendar_string(vm, identifier)); - // b. If IsBuiltinCalendar(identifier) is false, throw a RangeError exception. - if (!is_builtin_calendar(identifier)) - return vm.throw_completion(ErrorType::TemporalInvalidCalendarIdentifier, identifier); - } + // 4. If IsBuiltinCalendar(identifier) is false, throw a RangeError exception. + if (!is_builtin_calendar(identifier)) + return vm.throw_completion(ErrorType::TemporalInvalidCalendarIdentifier, identifier); - // 4. Return ! CreateTemporalCalendar(identifier). + // 5. Return ! CreateTemporalCalendar(identifier). return MUST(create_temporal_calendar(vm, identifier)); } diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp index dcff49afc3..ad66f79837 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp @@ -1446,24 +1446,6 @@ bool ISO8601Parser::parse_temporal_zoned_date_time_string() return true; } -// https://tc39.es/proposal-temporal/#prod-TemporalCalendarString -bool ISO8601Parser::parse_temporal_calendar_string() -{ - // TemporalCalendarString : - // CalendarName - // TemporalInstantString - // CalendarDateTime - // CalendarTime - // DateSpecYearMonth - // DateSpecMonthDay - return parse_calendar_name() - || parse_temporal_instant_string() - || parse_calendar_date_time() - || parse_date_spec_year_month() - || parse_date_spec_month_day() - || parse_calendar_time(); -} - } #define JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS \ @@ -1475,8 +1457,8 @@ bool ISO8601Parser::parse_temporal_calendar_string() __JS_ENUMERATE(TemporalTimeZoneString, parse_temporal_time_zone_string) \ __JS_ENUMERATE(TemporalYearMonthString, parse_temporal_year_month_string) \ __JS_ENUMERATE(TemporalZonedDateTimeString, parse_temporal_zoned_date_time_string) \ - __JS_ENUMERATE(TemporalCalendarString, parse_temporal_calendar_string) \ - __JS_ENUMERATE(TimeZoneNumericUTCOffset, parse_time_zone_numeric_utc_offset) + __JS_ENUMERATE(TimeZoneNumericUTCOffset, parse_time_zone_numeric_utc_offset) \ + __JS_ENUMERATE(CalendarName, parse_calendar_name) Optional parse_iso8601(Production production, StringView input) { diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h index 25506e865d..4e5bd70c2e 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h @@ -52,8 +52,8 @@ enum class Production { TemporalTimeZoneString, TemporalYearMonthString, TemporalZonedDateTimeString, - TemporalCalendarString, TimeZoneNumericUTCOffset, + CalendarName, }; Optional parse_iso8601(Production, StringView); @@ -166,7 +166,6 @@ public: [[nodiscard]] bool parse_temporal_time_zone_string(); [[nodiscard]] bool parse_temporal_year_month_string(); [[nodiscard]] bool parse_temporal_zoned_date_time_string(); - [[nodiscard]] bool parse_temporal_calendar_string(); private: struct State {