Преглед на файлове

LibJS: Implement parsing of TemporalCalendarString

Linus Groh преди 3 години
родител
ревизия
79a18b058f

+ 1 - 0
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")                                                                                      \

+ 8 - 4
Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp

@@ -1216,17 +1216,21 @@ ThrowCompletionOr<TemporalZonedDateTime> parse_temporal_zoned_date_time_string(G
 }
 
 // 13.37 ParseTemporalCalendarString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalcalendarstring
-ThrowCompletionOr<String> parse_temporal_calendar_string(GlobalObject& global_object, [[maybe_unused]] String const& iso_string)
+ThrowCompletionOr<String> 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<RangeError>(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<StringView> id_part;
-    return vm.throw_completion<InternalError>(global_object, ErrorType::NotImplemented, "ParseTemporalCalendarString");
+    auto id_part = parse_result->calendar_name;
 
     // 4. If id is undefined, then
     if (!id_part.has_value()) {

+ 19 - 0
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<ParseResult> parse_iso8601(Production production, StringView input)

+ 2 - 0
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:

+ 1 - 1
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");
     });
 });

+ 2 - 4
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'");
     });
 });