diff options
author | Linus Groh <mail@linusgroh.de> | 2021-11-19 20:43:52 +0000 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-11-20 23:10:09 +0000 |
commit | 98b876ad3f3d59dd83c91f8db0ea052ecde1d908 (patch) | |
tree | 6e664c891bf6c12d1fd276a2b1494f79e185df7a /Userland/Libraries/LibJS | |
parent | 3b1de431cc35c8886dd498ade0c9a90b268a95a1 (diff) | |
download | serenity-98b876ad3f3d59dd83c91f8db0ea052ecde1d908.zip |
LibJS: Implement parsing of TemporalZonedDateTimeString
Diffstat (limited to 'Userland/Libraries/LibJS')
5 files changed, 62 insertions, 19 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h index 68da54a227..35e166c18b 100644 --- a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h +++ b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h @@ -230,6 +230,7 @@ M(TemporalInvalidUnitRange, "Invalid unit range, {} is larger than {}") \ M(TemporalInvalidYearMonthString, "Invalid year month string '{}'") \ M(TemporalInvalidZonedDateTimeOffset, "Invalid offset for the provided date and time in the current time zone") \ + M(TemporalInvalidZonedDateTimeString, "Invalid zoned date time string '{}'") \ M(TemporalMissingOptionsObject, "Required options object is missing or undefined") \ M(TemporalMissingStartingPoint, "A starting point is required for balancing {}") \ M(TemporalObjectMustHaveOneOf, "Object must have at least one of the following properties: {}") \ diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp index 638569debd..f64442255d 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp @@ -1192,14 +1192,19 @@ ThrowCompletionOr<TemporalInstant> parse_temporal_instant_string(GlobalObject& g // 13.36 ParseTemporalZonedDateTimeString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalzoneddatetimestring ThrowCompletionOr<TemporalZonedDateTime> parse_temporal_zoned_date_time_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 TemporalZonedDateTimeString (see 13.33), then - // a. Throw a RangeError exception. - // TODO + auto parse_result = parse_iso8601(Production::TemporalZonedDateTimeString, iso_string); + if (!parse_result.has_value()) { + // a. Throw a RangeError exception. + return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidZonedDateTimeString, iso_string); + } // 3. Let result be ! ParseISODateTime(isoString). - auto result = MUST(parse_iso_date_time(global_object, {})); + auto result = MUST(parse_iso_date_time(global_object, *parse_result)); // 4. Let timeZoneResult be ? ParseTemporalTimeZoneString(isoString). auto time_zone_result = TRY(parse_temporal_time_zone_string(global_object, iso_string)); @@ -1335,18 +1340,30 @@ ThrowCompletionOr<TemporalZonedDateTime> parse_temporal_relative_to_string(Globa Optional<String> offset; Optional<String> time_zone; - // TODO: 4. If isoString satisfies the syntax of a TemporalZonedDateTimeString (see 13.33), then - // a. Let timeZoneResult be ! ParseTemporalTimeZoneString(isoString). - // b. Let z be timeZoneResult.[[Z]]. - // c. Let offset be timeZoneResult.[[Offset]]. - // d. Let timeZone be timeZoneResult.[[Name]]. + // 4. If isoString satisfies the syntax of a TemporalZonedDateTimeString (see 13.33), then + auto parse_result = parse_iso8601(Production::TemporalZonedDateTimeString, iso_string); + if (parse_result.has_value()) { + // a. Let timeZoneResult be ! ParseTemporalTimeZoneString(isoString). + // TODO: TRY() instead of MUST() as parse_temporal_time_zone_string() still throws more than it parses :^) + auto time_zone_result = TRY(parse_temporal_time_zone_string(global_object, iso_string)); + + // b. Let z be timeZoneResult.[[Z]]. + z = time_zone_result.z; + + // c. Let offset be timeZoneResult.[[Offset]]. + offset = time_zone_result.offset; - // TODO: 5. Else, - // a. Let z be false. - z = false; + // d. Let timeZone be timeZoneResult.[[Name]]. + time_zone = time_zone_result.name; + } + // 5. Else, + else { + // a. Let z be false. + z = false; - // b. Let offset be undefined. (NOTE: It already is) - // c. Let timeZone be undefined. (NOTE: It already is) + // b. Let offset be undefined. + // c. Let timeZone be undefined. + } // 6. Return the Record { [[Year]]: result.[[Year]], [[Month]]: result.[[Month]], [[Day]]: result.[[Day]], [[Hour]]: result.[[Hour]], [[Minute]]: result.[[Minute]], [[Second]]: result.[[Second]], [[Millisecond]]: result.[[Millisecond]], [[Microsecond]]: result.[[Microsecond]], [[Nanosecond]]: result.[[Nanosecond]], [[Calendar]]: result.[[Calendar]], [[TimeZoneZ]]: z, [[TimeZoneOffset]]: offset, [[TimeZoneIANAName]]: timeZone }. return TemporalZonedDateTime { .date_time = move(result), .time_zone = { .z = z, .offset = move(offset), .name = move(time_zone) } }; diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp index 4a680640c3..75300b083e 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp @@ -555,14 +555,31 @@ bool ISO8601Parser::parse_temporal_year_month_string() || parse_date_spec_year_month(); } +// https://tc39.es/proposal-temporal/#prod-TemporalZonedDateTimeString +bool ISO8601Parser::parse_temporal_zoned_date_time_string() +{ + // TemporalZonedDateTimeString : + // Date TimeSpecSeparator[opt] TimeZoneNameRequired Calendar[opt] + StateTransaction transaction { *this }; + if (!parse_date()) + return false; + (void)parse_time_spec_separator(); + if (!parse_time_zone_name_required()) + return false; + (void)parse_calendar(); + transaction.commit(); + return true; +} + } -#define JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS \ - __JS_ENUMERATE(TemporalDateString, parse_temporal_date_string) \ - __JS_ENUMERATE(TemporalDateTimeString, parse_temporal_date_time_string) \ - __JS_ENUMERATE(TemporalMonthDayString, parse_temporal_month_day_string) \ - __JS_ENUMERATE(TemporalTimeString, parse_temporal_time_string) \ - __JS_ENUMERATE(TemporalYearMonthString, parse_temporal_year_month_string) +#define JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS \ + __JS_ENUMERATE(TemporalDateString, parse_temporal_date_string) \ + __JS_ENUMERATE(TemporalDateTimeString, parse_temporal_date_time_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) Optional<ParseResult> 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 911f71e0d6..92a894edec 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h @@ -31,6 +31,7 @@ enum class Production { TemporalMonthDayString, TemporalTimeString, TemporalYearMonthString, + TemporalZonedDateTimeString, }; Optional<ParseResult> parse_iso8601(Production, StringView); @@ -87,6 +88,7 @@ public: [[nodiscard]] bool parse_temporal_month_day_string(); [[nodiscard]] bool parse_temporal_time_string(); [[nodiscard]] bool parse_temporal_year_month_string(); + [[nodiscard]] bool parse_temporal_zoned_date_time_string(); private: struct State { diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.from.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.from.js index 7e9f9f9538..b662e9ce9b 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.from.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.from.js @@ -148,4 +148,10 @@ describe("errors", () => { }); }).toThrowWithMessage(TypeError, "Required property day is missing or undefined"); }); + + test("invalid zoned date time string", () => { + expect(() => { + Temporal.ZonedDateTime.from("foo"); + }).toThrowWithMessage(RangeError, "Invalid zoned date time string 'foo'"); + }); }); |