mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:37:45 +00:00
LibJS: Fix TemporalCalendarString ambiguity
This is a normative change in the Temporal spec. See: -278d238
-b73aea7
This commit is contained in:
parent
484c66125d
commit
b6f101f1c0
6 changed files with 63 additions and 50 deletions
|
@ -243,6 +243,7 @@
|
||||||
M(TemporalInvalidEpochNanoseconds, "Invalid epoch nanoseconds value, must be in range -86400 * 10^17 to 86400 * 10^17") \
|
M(TemporalInvalidEpochNanoseconds, "Invalid epoch nanoseconds value, must be in range -86400 * 10^17 to 86400 * 10^17") \
|
||||||
M(TemporalInvalidInstantString, "Invalid instant string '{}'") \
|
M(TemporalInvalidInstantString, "Invalid instant string '{}'") \
|
||||||
M(TemporalInvalidISODate, "Invalid ISO date") \
|
M(TemporalInvalidISODate, "Invalid ISO date") \
|
||||||
|
M(TemporalInvalidISODateTime, "Invalid ISO date time") \
|
||||||
M(TemporalInvalidMonthCode, "Invalid month code") \
|
M(TemporalInvalidMonthCode, "Invalid month code") \
|
||||||
M(TemporalInvalidMonthDayString, "Invalid month day string '{}'") \
|
M(TemporalInvalidMonthDayString, "Invalid month day string '{}'") \
|
||||||
M(TemporalInvalidMonthDayStringUTCDesignator, "Invalid month day string '{}': must not contain a UTC designator") \
|
M(TemporalInvalidMonthDayStringUTCDesignator, "Invalid month day string '{}': must not contain a UTC designator") \
|
||||||
|
|
|
@ -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
|
// 13.28 ParseISODateTime ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parseisodatetime
|
||||||
ThrowCompletionOr<ISODateTime> parse_iso_date_time(VM& vm, ParseResult const& parse_result)
|
ThrowCompletionOr<ISODateTime> parse_iso_date_time(VM& vm, StringView iso_string)
|
||||||
{
|
{
|
||||||
// 1. Let parseResult be empty.
|
// 1. Let parseResult be empty.
|
||||||
// 2. For each nonterminal goal of « TemporalDateTimeString, TemporalInstantString, TemporalMonthDayString, TemporalTimeString, TemporalYearMonthString, TemporalZonedDateTimeString », do
|
Optional<ParseResult> parse_result;
|
||||||
// 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).
|
|
||||||
|
|
||||||
|
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<RangeError>(ErrorType::TemporalInvalidISODateTime);
|
||||||
|
|
||||||
|
return parse_iso_date_time(vm, *parse_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 13.28 ParseISODateTime ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parseisodatetime
|
||||||
|
ThrowCompletionOr<ISODateTime> 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.
|
// 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 year = parse_result.date_year;
|
||||||
auto month = parse_result.date_month;
|
auto month = parse_result.date_month;
|
||||||
|
@ -1357,24 +1381,33 @@ ThrowCompletionOr<ISODateTime> parse_temporal_zoned_date_time_string(VM& vm, Str
|
||||||
// 13.31 ParseTemporalCalendarString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalcalendarstring
|
// 13.31 ParseTemporalCalendarString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalcalendarstring
|
||||||
ThrowCompletionOr<String> parse_temporal_calendar_string(VM& vm, String const& iso_string)
|
ThrowCompletionOr<String> parse_temporal_calendar_string(VM& vm, String const& iso_string)
|
||||||
{
|
{
|
||||||
// 1. Let parseResult be ParseText(StringToCodePoints(isoString), TemporalCalendarString).
|
// 1. Let parseResult be Completion(ParseISODateTime(isoString)).
|
||||||
auto parse_result = parse_iso8601(Production::TemporalCalendarString, iso_string);
|
auto parse_result_completion = parse_iso_date_time(vm, iso_string);
|
||||||
|
|
||||||
// 2. If parseResult is a List of errors, throw a RangeError exception.
|
// 2. If parseResult is a normal completion, then
|
||||||
if (!parse_result.has_value())
|
if (!parse_result_completion.is_error()) {
|
||||||
return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidCalendarString, iso_string);
|
// 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.
|
// b. If calendar is undefined, return "iso8601".
|
||||||
auto id = parse_result->calendar_name;
|
if (!calendar.has_value())
|
||||||
|
return "iso8601"sv;
|
||||||
// 4. If id is empty, then
|
// c. Else, return calendar.
|
||||||
if (!id.has_value()) {
|
else
|
||||||
// a. Return "iso8601".
|
return calendar.release_value();
|
||||||
return "iso8601"sv;
|
|
||||||
}
|
}
|
||||||
|
// 3. Else,
|
||||||
|
else {
|
||||||
|
// a. Set parseResult to ParseText(StringToCodePoints(isoString), CalendarName).
|
||||||
|
auto parse_result = parse_iso8601(Production::CalendarName, iso_string);
|
||||||
|
|
||||||
// 5. Return CodePointsToString(id).
|
// b. If parseResult is a List of errors, throw a RangeError exception.
|
||||||
return id.value();
|
if (!parse_result.has_value())
|
||||||
|
return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidCalendarString, iso_string);
|
||||||
|
// c. Else, return isoString.
|
||||||
|
else
|
||||||
|
return iso_string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 13.32 ParseTemporalDateString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaldatestring
|
// 13.32 ParseTemporalDateString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaldatestring
|
||||||
|
|
|
@ -161,6 +161,7 @@ Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedDivisionResu
|
||||||
double round_number_to_increment(double, u64 increment, StringView rounding_mode);
|
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(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);
|
Crypto::SignedBigInteger round_number_to_increment_as_if_positive(Crypto::SignedBigInteger const&, u64 increment, StringView rounding_mode);
|
||||||
|
ThrowCompletionOr<ISODateTime> parse_iso_date_time(VM&, StringView iso_string);
|
||||||
ThrowCompletionOr<ISODateTime> parse_iso_date_time(VM&, ParseResult const& parse_result);
|
ThrowCompletionOr<ISODateTime> parse_iso_date_time(VM&, ParseResult const& parse_result);
|
||||||
ThrowCompletionOr<TemporalInstant> parse_temporal_instant_string(VM&, String const& iso_string);
|
ThrowCompletionOr<TemporalInstant> parse_temporal_instant_string(VM&, String const& iso_string);
|
||||||
ThrowCompletionOr<ISODateTime> parse_temporal_zoned_date_time_string(VM&, String const& iso_string);
|
ThrowCompletionOr<ISODateTime> parse_temporal_zoned_date_time_string(VM&, String const& iso_string);
|
||||||
|
|
|
@ -406,17 +406,14 @@ ThrowCompletionOr<Object*> to_temporal_calendar(VM& vm, Value temporal_calendar_
|
||||||
// 2. Let identifier be ? ToString(temporalCalendarLike).
|
// 2. Let identifier be ? ToString(temporalCalendarLike).
|
||||||
auto identifier = TRY(temporal_calendar_like.to_string(vm));
|
auto identifier = TRY(temporal_calendar_like.to_string(vm));
|
||||||
|
|
||||||
// 3. If IsBuiltinCalendar(identifier) is false, then
|
// 3. Set identifier to ? ParseTemporalCalendarString(identifier).
|
||||||
if (!is_builtin_calendar(identifier)) {
|
identifier = TRY(parse_temporal_calendar_string(vm, identifier));
|
||||||
// a. Set identifier to ? ParseTemporalCalendarString(identifier).
|
|
||||||
identifier = TRY(parse_temporal_calendar_string(vm, identifier));
|
|
||||||
|
|
||||||
// b. If IsBuiltinCalendar(identifier) is false, throw a RangeError exception.
|
// 4. If IsBuiltinCalendar(identifier) is false, throw a RangeError exception.
|
||||||
if (!is_builtin_calendar(identifier))
|
if (!is_builtin_calendar(identifier))
|
||||||
return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidCalendarIdentifier, identifier);
|
return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidCalendarIdentifier, identifier);
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Return ! CreateTemporalCalendar(identifier).
|
// 5. Return ! CreateTemporalCalendar(identifier).
|
||||||
return MUST(create_temporal_calendar(vm, identifier));
|
return MUST(create_temporal_calendar(vm, identifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1446,24 +1446,6 @@ bool ISO8601Parser::parse_temporal_zoned_date_time_string()
|
||||||
return true;
|
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 \
|
#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(TemporalTimeZoneString, parse_temporal_time_zone_string) \
|
||||||
__JS_ENUMERATE(TemporalYearMonthString, parse_temporal_year_month_string) \
|
__JS_ENUMERATE(TemporalYearMonthString, parse_temporal_year_month_string) \
|
||||||
__JS_ENUMERATE(TemporalZonedDateTimeString, parse_temporal_zoned_date_time_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<ParseResult> parse_iso8601(Production production, StringView input)
|
Optional<ParseResult> parse_iso8601(Production production, StringView input)
|
||||||
{
|
{
|
||||||
|
|
|
@ -52,8 +52,8 @@ enum class Production {
|
||||||
TemporalTimeZoneString,
|
TemporalTimeZoneString,
|
||||||
TemporalYearMonthString,
|
TemporalYearMonthString,
|
||||||
TemporalZonedDateTimeString,
|
TemporalZonedDateTimeString,
|
||||||
TemporalCalendarString,
|
|
||||||
TimeZoneNumericUTCOffset,
|
TimeZoneNumericUTCOffset,
|
||||||
|
CalendarName,
|
||||||
};
|
};
|
||||||
|
|
||||||
Optional<ParseResult> parse_iso8601(Production, StringView);
|
Optional<ParseResult> parse_iso8601(Production, StringView);
|
||||||
|
@ -166,7 +166,6 @@ public:
|
||||||
[[nodiscard]] bool parse_temporal_time_zone_string();
|
[[nodiscard]] bool parse_temporal_time_zone_string();
|
||||||
[[nodiscard]] bool parse_temporal_year_month_string();
|
[[nodiscard]] bool parse_temporal_year_month_string();
|
||||||
[[nodiscard]] bool parse_temporal_zoned_date_time_string();
|
[[nodiscard]] bool parse_temporal_zoned_date_time_string();
|
||||||
[[nodiscard]] bool parse_temporal_calendar_string();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct State {
|
struct State {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue