From 79a18b058f53a788279c21d31f1f6c529508e110 Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Sat, 20 Nov 2021 01:28:46 +0000 Subject: [PATCH] LibJS: Implement parsing of TemporalCalendarString --- Userland/Libraries/LibJS/Runtime/ErrorTypes.h | 1 + .../Runtime/Temporal/AbstractOperations.cpp | 12 ++++++++---- .../LibJS/Runtime/Temporal/ISO8601.cpp | 19 +++++++++++++++++++ .../LibJS/Runtime/Temporal/ISO8601.h | 2 ++ .../Temporal/Calendar/Calendar.from.js | 2 +- .../ZonedDateTime.prototype.withCalendar.js | 6 ++---- 6 files changed, 33 insertions(+), 9 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h index e6094a7e5f..8f2929293a 100644 --- a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h +++ b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h @@ -207,6 +207,7 @@ M(TemporalInvalidCalendarFieldValue, "Invalid calendar field {}, expected a string") \ M(TemporalInvalidCalendarFunctionResult, "Invalid calendar, {}() function returned {}") \ M(TemporalInvalidCalendarIdentifier, "Invalid calendar identifier '{}'") \ + M(TemporalInvalidCalendarString, "Invalid calendar string '{}'") \ M(TemporalInvalidDateString, "Invalid date string '{}'") \ M(TemporalInvalidDateTimeString, "Invalid date time string '{}'") \ M(TemporalInvalidDuration, "Invalid duration") \ diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp index fe0a56ab34..482718ec3b 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp @@ -1216,17 +1216,21 @@ ThrowCompletionOr parse_temporal_zoned_date_time_string(G } // 13.37 ParseTemporalCalendarString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalcalendarstring -ThrowCompletionOr parse_temporal_calendar_string(GlobalObject& global_object, [[maybe_unused]] String const& iso_string) +ThrowCompletionOr parse_temporal_calendar_string(GlobalObject& global_object, String const& iso_string) { auto& vm = global_object.vm(); // 1. Assert: Type(isoString) is String. // 2. If isoString does not satisfy the syntax of a TemporalCalendarString (see 13.33), then - // a. Throw a RangeError exception. + auto parse_result = parse_iso8601(Production::TemporalCalendarString, iso_string); + if (!parse_result.has_value()) { + // a. Throw a RangeError exception. + return vm.throw_completion(global_object, ErrorType::TemporalInvalidCalendarString, iso_string); + } + // 3. Let id be the part of isoString produced by the CalendarName production, or undefined if not present. - Optional id_part; - return vm.throw_completion(global_object, ErrorType::NotImplemented, "ParseTemporalCalendarString"); + auto id_part = parse_result->calendar_name; // 4. If id is undefined, then if (!id_part.has_value()) { diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp index 4efc2e0e74..697174f727 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp @@ -843,6 +843,24 @@ 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 + // Time + // DateSpecYearMonth + // DateSpecMonthDay + return parse_calendar_name() + // TODO: || parse_temporal_instant_string() + || parse_calendar_date_time() + || parse_date_spec_year_month() + || parse_date_spec_month_day() + || parse_time(); +} + // https://tc39.es/proposal-temporal/#prod-TemporalRelativeToString bool ISO8601Parser::parse_temporal_relative_to_string() { @@ -863,6 +881,7 @@ bool ISO8601Parser::parse_temporal_relative_to_string() __JS_ENUMERATE(TemporalTimeZoneString, parse_temporal_time_zone_string) \ __JS_ENUMERATE(TemporalYearMonthString, parse_temporal_year_month_string) \ __JS_ENUMERATE(TemporalZonedDateTimeString, parse_temporal_zoned_date_time_string) \ + __JS_ENUMERATE(TemporalCalendarString, parse_temporal_calendar_string) \ __JS_ENUMERATE(TemporalRelativeToString, parse_temporal_relative_to_string) Optional 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 b584aeaa07..bb019f168c 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h @@ -40,6 +40,7 @@ enum class Production { TemporalTimeZoneString, TemporalYearMonthString, TemporalZonedDateTimeString, + TemporalCalendarString, TemporalRelativeToString, }; @@ -113,6 +114,7 @@ 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(); [[nodiscard]] bool parse_temporal_relative_to_string(); private: diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.from.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.from.js index d4ded7f953..db30ad140e 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.from.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.from.js @@ -22,6 +22,6 @@ describe("normal behavior", () => { expect(Temporal.Calendar.from(calendarLike)).toBe(calendarLike); expect(Temporal.Calendar.from(withCalendarLike)).toBe(withCalendarLike.calendar); expect(Temporal.Calendar.from("iso8601").id).toBe("iso8601"); - // TODO: test Temporal.Calendar.from("TemporalCalendarString") once ParseTemporalCalendarString is working + expect(Temporal.Calendar.from("2021-07-06[u-ca=iso8601]").id).toBe("iso8601"); }); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.withCalendar.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.withCalendar.js index 3361e0e15c..0282d07fae 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.withCalendar.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.withCalendar.js @@ -31,13 +31,11 @@ describe("errors", () => { }).toThrowWithMessage(TypeError, "Not an object of type Temporal.ZonedDateTime"); }); - // FIXME: Enable this when calendar string parsing is implemented. - test.skip("from invalid calendar string", () => { + test("from invalid calendar string", () => { const zonedDateTime = new Temporal.ZonedDateTime(1n, {}, {}); - // FIXME: Use "toThrowWithMessage" once this has an error message. expect(() => { zonedDateTime.withCalendar("iso8602foobar"); - }).toThrow(RangeError); + }).toThrowWithMessage(RangeError, "Invalid calendar string 'iso8602foobar'"); }); });