mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 09:30:24 +00:00
LibJS: Implement parsing of TemporalRelativeToString
This commit is contained in:
parent
98b876ad3f
commit
1583c7257c
Notes:
sideshowbarker
2024-07-18 00:56:15 +09:00
Author: https://github.com/linusg Commit: https://github.com/SerenityOS/serenity/commit/1583c7257c3 Pull-request: https://github.com/SerenityOS/serenity/pull/10971 Reviewed-by: https://github.com/IdanHo ✅ Reviewed-by: https://github.com/alimpfard
12 changed files with 370 additions and 61 deletions
|
@ -224,9 +224,11 @@
|
|||
M(TemporalInvalidPlainTime, "Invalid plain time") \
|
||||
M(TemporalInvalidPlainTimeLikeObject, "Invalid plain time-like object") \
|
||||
M(TemporalInvalidPlainYearMonth, "Invalid plain year month") \
|
||||
M(TemporalInvalidRelativeToString, "Invalid relative to string '{}'") \
|
||||
M(TemporalInvalidTime, "Invalid time") \
|
||||
M(TemporalInvalidTimeString, "Invalid time string '{}'") \
|
||||
M(TemporalInvalidTimeZoneName, "Invalid time zone name") \
|
||||
M(TemporalInvalidTimeZoneString, "Invalid time zone string '{}'") \
|
||||
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") \
|
||||
|
|
|
@ -1325,27 +1325,31 @@ ThrowCompletionOr<TemporalMonthDay> parse_temporal_month_day_string(GlobalObject
|
|||
}
|
||||
|
||||
// 13.42 ParseTemporalRelativeToString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalrelativetostring
|
||||
ThrowCompletionOr<TemporalZonedDateTime> parse_temporal_relative_to_string(GlobalObject& global_object, [[maybe_unused]] String const& iso_string)
|
||||
ThrowCompletionOr<TemporalZonedDateTime> parse_temporal_relative_to_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 TemporalRelativeToString (see 13.33), then
|
||||
// a. Throw a RangeError exception.
|
||||
// TODO
|
||||
auto parse_result = parse_iso8601(Production::TemporalRelativeToString, iso_string);
|
||||
if (!parse_result.has_value()) {
|
||||
// a. Throw a RangeError exception.
|
||||
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidRelativeToString, 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));
|
||||
|
||||
bool z;
|
||||
Optional<String> offset;
|
||||
Optional<String> time_zone;
|
||||
|
||||
// 4. If isoString satisfies the syntax of a TemporalZonedDateTimeString (see 13.33), then
|
||||
auto parse_result = parse_iso8601(Production::TemporalZonedDateTimeString, iso_string);
|
||||
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));
|
||||
auto time_zone_result = MUST(parse_temporal_time_zone_string(global_object, iso_string));
|
||||
|
||||
// b. Let z be timeZoneResult.[[Z]].
|
||||
z = time_zone_result.z;
|
||||
|
@ -1391,23 +1395,27 @@ ThrowCompletionOr<TemporalTime> parse_temporal_time_string(GlobalObject& global_
|
|||
}
|
||||
|
||||
// 13.44 ParseTemporalTimeZoneString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaltimezonestring
|
||||
ThrowCompletionOr<TemporalTimeZone> parse_temporal_time_zone_string(GlobalObject& global_object, [[maybe_unused]] String const& iso_string)
|
||||
ThrowCompletionOr<TemporalTimeZone> parse_temporal_time_zone_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 TemporalTimeZoneString (see 13.33), then
|
||||
// a. Throw a RangeError exception.
|
||||
auto parse_result = parse_iso8601(Production::TemporalTimeZoneString, iso_string);
|
||||
if (!parse_result.has_value()) {
|
||||
// a. Throw a RangeError exception.
|
||||
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidTimeZoneString, iso_string);
|
||||
}
|
||||
|
||||
// 3. Let z, sign, hours, minutes, seconds, fraction and name be the parts of isoString produced respectively by the UTCDesignator, TimeZoneUTCOffsetSign, TimeZoneUTCOffsetHour, TimeZoneUTCOffsetMinute, TimeZoneUTCOffsetSecond, TimeZoneUTCOffsetFractionalPart, and TimeZoneIANAName productions, or undefined if not present.
|
||||
Optional<StringView> z_part;
|
||||
Optional<StringView> sign_part;
|
||||
Optional<StringView> hours_part;
|
||||
Optional<StringView> minutes_part;
|
||||
Optional<StringView> seconds_part;
|
||||
Optional<StringView> fraction_part;
|
||||
Optional<StringView> name_part;
|
||||
return vm.throw_completion<InternalError>(global_object, ErrorType::NotImplemented, "ParseTemporalTimeZoneString");
|
||||
auto z_part = parse_result->utc_designator;
|
||||
auto sign_part = parse_result->time_zone_utc_offset_sign;
|
||||
auto hours_part = parse_result->time_zone_utc_offset_hour;
|
||||
auto minutes_part = parse_result->time_zone_utc_offset_minute;
|
||||
auto seconds_part = parse_result->time_zone_utc_offset_second;
|
||||
auto fraction_part = parse_result->time_zone_utc_offset_fractional_part;
|
||||
auto name_part = parse_result->time_zone_iana_name;
|
||||
|
||||
// 4. If z is not undefined, then
|
||||
if (z_part.has_value()) {
|
||||
|
@ -1427,7 +1435,7 @@ ThrowCompletionOr<TemporalTimeZone> parse_temporal_time_zone_string(GlobalObject
|
|||
VERIFY(sign_part.has_value());
|
||||
|
||||
// b. Set hours to ! ToIntegerOrInfinity(hours).
|
||||
u8 hours = MUST(Value(js_string(vm, *hours_part)).to_integer_or_infinity(global_object));
|
||||
u8 hours = *hours_part->to_uint<u8>();
|
||||
|
||||
u8 sign;
|
||||
// c. If sign is the code unit 0x002D (HYPHEN-MINUS) or the code unit 0x2212 (MINUS SIGN), then
|
||||
|
@ -1442,10 +1450,10 @@ ThrowCompletionOr<TemporalTimeZone> parse_temporal_time_zone_string(GlobalObject
|
|||
}
|
||||
|
||||
// e. Set minutes to ! ToIntegerOrInfinity(minutes).
|
||||
u8 minutes = MUST(Value(js_string(vm, minutes_part.value_or(""sv))).to_integer_or_infinity(global_object));
|
||||
u8 minutes = *minutes_part.value_or("0"sv).to_uint<u8>();
|
||||
|
||||
// f. Set seconds to ! ToIntegerOrInfinity(seconds).
|
||||
u8 seconds = MUST(Value(js_string(vm, seconds_part.value_or(""sv))).to_integer_or_infinity(global_object));
|
||||
u8 seconds = *seconds_part.value_or("0"sv).to_uint<u8>();
|
||||
|
||||
i32 nanoseconds;
|
||||
// g. If fraction is not undefined, then
|
||||
|
@ -1454,7 +1462,7 @@ ThrowCompletionOr<TemporalTimeZone> parse_temporal_time_zone_string(GlobalObject
|
|||
auto fraction = String::formatted("{}000000000", *fraction_part);
|
||||
// ii. Let nanoseconds be the String value equal to the substring of fraction from 1 to 10.
|
||||
// iii. Set nanoseconds to ! ToIntegerOrInfinity(nanoseconds).
|
||||
nanoseconds = MUST(Value(js_string(vm, fraction.substring(1, 10))).to_integer_or_infinity(global_object));
|
||||
nanoseconds = *fraction.substring(1, 10).to_int<i32>();
|
||||
}
|
||||
// h. Else,
|
||||
else {
|
||||
|
|
|
@ -132,6 +132,21 @@ bool ISO8601Parser::parse_date_time_separator()
|
|||
|| m_state.lexer.consume_specific('t');
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-UTCDesignator
|
||||
bool ISO8601Parser::parse_utc_designator()
|
||||
{
|
||||
// UTCDesignator : one of
|
||||
// Z z
|
||||
StateTransaction transaction { *this };
|
||||
auto success = m_state.lexer.consume_specific('Z')
|
||||
|| m_state.lexer.consume_specific('z');
|
||||
if (!success)
|
||||
return false;
|
||||
m_state.parse_result.utc_designator = transaction.parsed_string_view();
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-DateYear
|
||||
bool ISO8601Parser::parse_date_year()
|
||||
{
|
||||
|
@ -354,12 +369,235 @@ bool ISO8601Parser::parse_time_fraction()
|
|||
return parse_fraction();
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetSign
|
||||
bool ISO8601Parser::parse_time_zone_utc_offset_sign()
|
||||
{
|
||||
// TimeZoneUTCOffsetSign :
|
||||
// Sign
|
||||
StateTransaction transaction { *this };
|
||||
if (!parse_sign())
|
||||
return false;
|
||||
m_state.parse_result.time_zone_utc_offset_sign = transaction.parsed_string_view();
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetHour
|
||||
bool ISO8601Parser::parse_time_zone_utc_offset_hour()
|
||||
{
|
||||
// TimeZoneUTCOffsetHour :
|
||||
// Hour
|
||||
StateTransaction transaction { *this };
|
||||
if (!parse_hour())
|
||||
return false;
|
||||
m_state.parse_result.time_zone_utc_offset_hour = transaction.parsed_string_view();
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetMinute
|
||||
bool ISO8601Parser::parse_time_zone_utc_offset_minute()
|
||||
{
|
||||
// TimeZoneUTCOffsetMinute :
|
||||
// MinuteSecond
|
||||
StateTransaction transaction { *this };
|
||||
if (!parse_minute_second())
|
||||
return false;
|
||||
m_state.parse_result.time_zone_utc_offset_minute = transaction.parsed_string_view();
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetSecond
|
||||
bool ISO8601Parser::parse_time_zone_utc_offset_second()
|
||||
{
|
||||
// TimeZoneUTCOffsetSecond :
|
||||
// MinuteSecond
|
||||
StateTransaction transaction { *this };
|
||||
if (!parse_minute_second())
|
||||
return false;
|
||||
m_state.parse_result.time_zone_utc_offset_second = transaction.parsed_string_view();
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetFractionalPart
|
||||
bool ISO8601Parser::parse_time_zone_utc_offset_fractional_part()
|
||||
{
|
||||
// TimeZoneUTCOffsetFractionalPart :
|
||||
// FractionalPart
|
||||
StateTransaction transaction { *this };
|
||||
if (!parse_fractional_part())
|
||||
return false;
|
||||
m_state.parse_result.time_zone_utc_offset_fractional_part = transaction.parsed_string_view();
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetFraction
|
||||
bool ISO8601Parser::parse_time_zone_utc_offset_fraction()
|
||||
{
|
||||
// TimeZoneUTCOffsetFraction :
|
||||
// DecimalSeparator TimeZoneUTCOffsetFractionalPart
|
||||
StateTransaction transaction { *this };
|
||||
if (!parse_decimal_separator())
|
||||
return false;
|
||||
if (!parse_time_zone_utc_offset_fractional_part())
|
||||
return false;
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneNumericUTCOffset
|
||||
bool ISO8601Parser::parse_time_zone_numeric_utc_offset()
|
||||
{
|
||||
// TimeZoneNumericUTCOffset :
|
||||
// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour
|
||||
// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute
|
||||
// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute
|
||||
// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute : TimeZoneUTCOffsetSecond TimeZoneUTCOffsetFraction[opt]
|
||||
// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute TimeZoneUTCOffsetSecond TimeZoneUTCOffsetFraction[opt]
|
||||
StateTransaction transaction { *this };
|
||||
if (!parse_time_zone_utc_offset_sign())
|
||||
return false;
|
||||
if (!parse_time_zone_utc_offset_hour())
|
||||
return false;
|
||||
if (m_state.lexer.consume_specific(':')) {
|
||||
if (!parse_time_zone_utc_offset_minute())
|
||||
return false;
|
||||
if (m_state.lexer.consume_specific(':')) {
|
||||
if (!parse_time_zone_utc_offset_second())
|
||||
return false;
|
||||
(void)parse_time_zone_utc_offset_fraction();
|
||||
}
|
||||
} else if (parse_time_zone_utc_offset_minute()) {
|
||||
if (parse_time_zone_utc_offset_second())
|
||||
(void)parse_time_zone_utc_offset_fraction();
|
||||
}
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffset
|
||||
bool ISO8601Parser::parse_time_zone_utc_offset()
|
||||
{
|
||||
// TimeZoneUTCOffset :
|
||||
// TimeZoneNumericUTCOffset
|
||||
// UTCDesignator
|
||||
return parse_time_zone_numeric_utc_offset()
|
||||
|| parse_utc_designator();
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetName
|
||||
bool ISO8601Parser::parse_time_zone_utc_offset_name()
|
||||
{
|
||||
// TimeZoneUTCOffsetName :
|
||||
// Sign Hour
|
||||
// Sign Hour : MinuteSecond
|
||||
// Sign Hour MinuteSecond
|
||||
// Sign Hour : MinuteSecond : MinuteSecond Fraction[opt]
|
||||
// Sign Hour MinuteSecond MinuteSecond Fraction[opt]
|
||||
StateTransaction transaction { *this };
|
||||
if (!parse_sign())
|
||||
return false;
|
||||
if (!parse_hour())
|
||||
return false;
|
||||
if (m_state.lexer.consume_specific(':')) {
|
||||
if (!parse_minute_second())
|
||||
return false;
|
||||
if (m_state.lexer.consume_specific(':')) {
|
||||
if (!parse_minute_second())
|
||||
return false;
|
||||
(void)parse_fraction();
|
||||
}
|
||||
} else if (parse_minute_second()) {
|
||||
if (parse_minute_second())
|
||||
(void)parse_fraction();
|
||||
}
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneIANAName
|
||||
bool ISO8601Parser::parse_time_zone_iana_name()
|
||||
{
|
||||
// TZLeadingChar :
|
||||
// Alpha
|
||||
// .
|
||||
// _
|
||||
// TZChar :
|
||||
// Alpha
|
||||
// .
|
||||
// -
|
||||
// _
|
||||
// TimeZoneIANANameComponent :
|
||||
// TZLeadingChar TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] but not one of . or ..
|
||||
// TimeZoneIANANameTail :
|
||||
// TimeZoneIANANameComponent
|
||||
// TimeZoneIANANameComponent / TimeZoneIANANameTail
|
||||
// TimeZoneIANAName :
|
||||
// TimeZoneIANANameTail
|
||||
StateTransaction transaction { *this };
|
||||
// TODO: Implement the full production. Currently, anything other than "UTC" would get rejected as unknown anyway.
|
||||
auto success = (m_state.lexer.consume_specific('U') || m_state.lexer.consume_specific('u'))
|
||||
&& (m_state.lexer.consume_specific('T') || m_state.lexer.consume_specific('t'))
|
||||
&& (m_state.lexer.consume_specific('C') || m_state.lexer.consume_specific('c'));
|
||||
if (!success)
|
||||
return false;
|
||||
m_state.parse_result.time_zone_iana_name = transaction.parsed_string_view();
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedName
|
||||
bool ISO8601Parser::parse_time_zone_bracketed_name()
|
||||
{
|
||||
// TimeZoneBracketedName :
|
||||
// TimeZoneIANAName
|
||||
// Etc/GMT ASCIISign Hour
|
||||
// TimeZoneUTCOffsetName
|
||||
StateTransaction transaction { *this };
|
||||
if (parse_time_zone_iana_name()) {
|
||||
// no-op.
|
||||
} else if (m_state.lexer.consume_specific("Etc/GMT"sv)) {
|
||||
if (!parse_ascii_sign())
|
||||
return false;
|
||||
if (!parse_hour())
|
||||
return false;
|
||||
} else if (!parse_time_zone_utc_offset_name()) {
|
||||
return false;
|
||||
}
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedAnnotation
|
||||
bool ISO8601Parser::parse_time_zone_bracketed_annotation()
|
||||
{
|
||||
// TimeZoneBracketedAnnotation :
|
||||
// [ TimeZoneBracketedName ]
|
||||
StateTransaction transaction { *this };
|
||||
if (!m_state.lexer.consume_specific('['))
|
||||
return false;
|
||||
if (!parse_time_zone_bracketed_name())
|
||||
return false;
|
||||
if (!m_state.lexer.consume_specific(']'))
|
||||
return false;
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneOffsetRequired
|
||||
bool ISO8601Parser::parse_time_zone_offset_required()
|
||||
{
|
||||
// TimeZoneOffsetRequired :
|
||||
// TimeZoneUTCOffset TimeZoneBracketedAnnotation[opt]
|
||||
return false;
|
||||
StateTransaction transaction { *this };
|
||||
if (!parse_time_zone_utc_offset())
|
||||
return false;
|
||||
(void)parse_time_zone_bracketed_annotation();
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZoneNameRequired
|
||||
|
@ -367,7 +605,12 @@ bool ISO8601Parser::parse_time_zone_name_required()
|
|||
{
|
||||
// TimeZoneNameRequired :
|
||||
// TimeZoneUTCOffset[opt] TimeZoneBracketedAnnotation
|
||||
return false;
|
||||
StateTransaction transaction { *this };
|
||||
(void)parse_time_zone_utc_offset();
|
||||
if (!parse_time_zone_bracketed_annotation())
|
||||
return false;
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TimeZone
|
||||
|
@ -543,6 +786,35 @@ bool ISO8601Parser::parse_temporal_time_string()
|
|||
|| parse_time();
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TemporalTimeZoneIdentifier
|
||||
bool ISO8601Parser::parse_temporal_time_zone_identifier()
|
||||
{
|
||||
// TemporalTimeZoneIdentifier :
|
||||
// TimeZoneNumericUTCOffset
|
||||
// TimeZoneIANAName
|
||||
return parse_time_zone_numeric_utc_offset()
|
||||
|| parse_time_zone_iana_name();
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TemporalTimeZoneString
|
||||
bool ISO8601Parser::parse_temporal_time_zone_string()
|
||||
{
|
||||
// TemporalTimeZoneString :
|
||||
// TemporalTimeZoneIdentifier
|
||||
// Date TimeSpecSeparator[opt] TimeZone Calendar[opt]
|
||||
StateTransaction transaction { *this };
|
||||
if (!parse_temporal_time_zone_identifier()) {
|
||||
if (!parse_date())
|
||||
return false;
|
||||
(void)parse_time_spec_separator();
|
||||
if (!parse_time_zone())
|
||||
return false;
|
||||
(void)parse_calendar();
|
||||
}
|
||||
transaction.commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TemporalYearMonthString
|
||||
bool ISO8601Parser::parse_temporal_year_month_string()
|
||||
{
|
||||
|
@ -571,15 +843,27 @@ bool ISO8601Parser::parse_temporal_zoned_date_time_string()
|
|||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#prod-TemporalRelativeToString
|
||||
bool ISO8601Parser::parse_temporal_relative_to_string()
|
||||
{
|
||||
// TemporalRelativeToString :
|
||||
// TemporalDateTimeString
|
||||
// TemporalZonedDateTimeString
|
||||
return parse_temporal_date_time_string()
|
||||
|| parse_temporal_zoned_date_time_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)
|
||||
}
|
||||
|
||||
#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(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(TemporalRelativeToString, parse_temporal_relative_to_string)
|
||||
|
||||
Optional<ParseResult> parse_iso8601(Production production, StringView input)
|
||||
{
|
||||
|
@ -603,5 +887,4 @@ Optional<ParseResult> parse_iso8601(Production production, StringView input)
|
|||
|
||||
return parser.parse_result();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,13 @@ struct ParseResult {
|
|||
Optional<StringView> time_second;
|
||||
Optional<StringView> time_fractional_part;
|
||||
Optional<StringView> calendar_name;
|
||||
Optional<StringView> utc_designator;
|
||||
Optional<StringView> time_zone_utc_offset_sign;
|
||||
Optional<StringView> time_zone_utc_offset_hour;
|
||||
Optional<StringView> time_zone_utc_offset_minute;
|
||||
Optional<StringView> time_zone_utc_offset_second;
|
||||
Optional<StringView> time_zone_utc_offset_fractional_part;
|
||||
Optional<StringView> time_zone_iana_name;
|
||||
};
|
||||
|
||||
enum class Production {
|
||||
|
@ -30,8 +37,10 @@ enum class Production {
|
|||
TemporalDateTimeString,
|
||||
TemporalMonthDayString,
|
||||
TemporalTimeString,
|
||||
TemporalTimeZoneString,
|
||||
TemporalYearMonthString,
|
||||
TemporalZonedDateTimeString,
|
||||
TemporalRelativeToString,
|
||||
};
|
||||
|
||||
Optional<ParseResult> parse_iso8601(Production, StringView);
|
||||
|
@ -60,6 +69,7 @@ public:
|
|||
[[nodiscard]] bool parse_minute_second();
|
||||
[[nodiscard]] bool parse_decimal_separator();
|
||||
[[nodiscard]] bool parse_date_time_separator();
|
||||
[[nodiscard]] bool parse_utc_designator();
|
||||
[[nodiscard]] bool parse_date_year();
|
||||
[[nodiscard]] bool parse_date_month();
|
||||
[[nodiscard]] bool parse_date_day();
|
||||
|
@ -73,6 +83,18 @@ public:
|
|||
[[nodiscard]] bool parse_time_fractional_part();
|
||||
[[nodiscard]] bool parse_fraction();
|
||||
[[nodiscard]] bool parse_time_fraction();
|
||||
[[nodiscard]] bool parse_time_zone_utc_offset_sign();
|
||||
[[nodiscard]] bool parse_time_zone_utc_offset_hour();
|
||||
[[nodiscard]] bool parse_time_zone_utc_offset_minute();
|
||||
[[nodiscard]] bool parse_time_zone_utc_offset_second();
|
||||
[[nodiscard]] bool parse_time_zone_utc_offset_fractional_part();
|
||||
[[nodiscard]] bool parse_time_zone_utc_offset_fraction();
|
||||
[[nodiscard]] bool parse_time_zone_numeric_utc_offset();
|
||||
[[nodiscard]] bool parse_time_zone_utc_offset();
|
||||
[[nodiscard]] bool parse_time_zone_utc_offset_name();
|
||||
[[nodiscard]] bool parse_time_zone_iana_name();
|
||||
[[nodiscard]] bool parse_time_zone_bracketed_name();
|
||||
[[nodiscard]] bool parse_time_zone_bracketed_annotation();
|
||||
[[nodiscard]] bool parse_time_zone_offset_required();
|
||||
[[nodiscard]] bool parse_time_zone_name_required();
|
||||
[[nodiscard]] bool parse_time_zone();
|
||||
|
@ -87,8 +109,11 @@ public:
|
|||
[[nodiscard]] bool parse_temporal_date_time_string();
|
||||
[[nodiscard]] bool parse_temporal_month_day_string();
|
||||
[[nodiscard]] bool parse_temporal_time_string();
|
||||
[[nodiscard]] bool parse_temporal_time_zone_identifier();
|
||||
[[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_relative_to_string();
|
||||
|
||||
private:
|
||||
struct State {
|
||||
|
|
|
@ -3,8 +3,7 @@ describe("correct behavior", () => {
|
|||
expect(Temporal.Instant.prototype.toZonedDateTimeISO).toHaveLength(1);
|
||||
});
|
||||
|
||||
// TODO: Un-skip when ParseTemporalTimeZoneString is fully implemented
|
||||
test.skip("basic functionality", () => {
|
||||
test("basic functionality", () => {
|
||||
const instant = new Temporal.Instant(1625614921123456789n);
|
||||
const zonedDateTime = instant.toZonedDateTimeISO("UTC");
|
||||
expect(zonedDateTime.year).toBe(2021);
|
||||
|
|
|
@ -58,8 +58,7 @@ describe("correct behavior", () => {
|
|||
expect(zonedDateTime.timeZone).toBe(timeZone);
|
||||
});
|
||||
|
||||
// TODO: Enable when parse_temporal_time_zone_string() is fully implemented
|
||||
test.skip("basic functionality - time zone identifier", () => {
|
||||
test("basic functionality - time zone identifier", () => {
|
||||
// 4. in the spec
|
||||
const plainDate = new Temporal.PlainDate(2021, 7, 6);
|
||||
const zonedDateTime = plainDate.toZonedDateTime("UTC");
|
||||
|
|
|
@ -95,8 +95,7 @@ describe("correct behavior", () => {
|
|||
expect(plainDateTime.nanosecond).toBe(999);
|
||||
});
|
||||
|
||||
// Un-skip once ParseISODateTime & ParseTemporalDateString are implemented
|
||||
test.skip("PlainDateTime string argument", () => {
|
||||
test("PlainDateTime string argument", () => {
|
||||
const plainDateTime = Temporal.PlainDateTime.from("2021-07-06T23:42:01Z");
|
||||
expect(plainDateTime.year).toBe(2021);
|
||||
expect(plainDateTime.month).toBe(7);
|
||||
|
|
|
@ -41,8 +41,7 @@ describe("correct behavior", () => {
|
|||
expect(plainMonthDay.day).toBe(6);
|
||||
});
|
||||
|
||||
// Un-skip once ParseISODateTime, ToTemporalMonthDay & ParseTemporalMonthDayString are fully implemented
|
||||
test.skip("from date time string", () => {
|
||||
test("from date time string", () => {
|
||||
const plainMonthDay = Temporal.PlainMonthDay.from("2021-07-06T23:42:01Z");
|
||||
expect(plainMonthDay.monthCode).toBe("M07");
|
||||
expect(plainMonthDay.day).toBe(6);
|
||||
|
|
|
@ -37,8 +37,7 @@ describe("correct behavior", () => {
|
|||
expect(createdPlainTime.nanosecond).toBe(0);
|
||||
});
|
||||
|
||||
// Un-skip once ParseISODateTime & ParseTemporalTimeString are implemented
|
||||
test.skip("PlainTime string argument", () => {
|
||||
test("PlainTime string argument", () => {
|
||||
const createdPlainTime = Temporal.PlainTime.from("2021-08-27T18:44:11Z");
|
||||
expect(createdPlainTime.hour).toBe(18);
|
||||
expect(createdPlainTime.minute).toBe(44);
|
||||
|
|
|
@ -62,8 +62,7 @@ describe("correct behavior", () => {
|
|||
expect(plainYearMonth.monthCode).toBe("M07");
|
||||
});
|
||||
|
||||
// Un-skip once ParseISODateTime & ParseTemporalYearMonthString are fully implemented
|
||||
test.skip("from date time string", () => {
|
||||
test("from date time string", () => {
|
||||
const plainYearMonth = Temporal.PlainYearMonth.from("2021-07-06T23:42:01Z");
|
||||
expect(plainYearMonth.year).toBe(2021);
|
||||
expect(plainYearMonth.month).toBe(7);
|
||||
|
|
|
@ -96,7 +96,7 @@ describe("correct behavior", () => {
|
|||
});
|
||||
|
||||
// FIXME: Enable when parse_iso_date_time is implemented.
|
||||
test.skip("from string", () => {
|
||||
test("from string", () => {
|
||||
const zonedDateTime = Temporal.ZonedDateTime.from(
|
||||
"2021-11-07T00:20:05.100200300+00:00[UTC][u-ca=iso8601]"
|
||||
);
|
||||
|
@ -106,17 +106,17 @@ describe("correct behavior", () => {
|
|||
expect(zonedDateTime.timeZone.id).toBe("UTC");
|
||||
expect(zonedDateTime.calendar).toBeInstanceOf(Temporal.Calendar);
|
||||
expect(zonedDateTime.calendar.id).toBe("iso8601");
|
||||
expect(createdZoneDateTime.year).toBe(2021);
|
||||
expect(createdZoneDateTime.month).toBe(11);
|
||||
expect(createdZoneDateTime.day).toBe(7);
|
||||
expect(createdZoneDateTime.hour).toBe(0);
|
||||
expect(createdZoneDateTime.minute).toBe(20);
|
||||
expect(createdZoneDateTime.second).toBe(5);
|
||||
expect(createdZoneDateTime.millisecond).toBe(100);
|
||||
expect(createdZoneDateTime.microsecond).toBe(200);
|
||||
expect(createdZoneDateTime.nanosecond).toBe(300);
|
||||
expect(createdZoneDateTime.offset).toBe("+00:00");
|
||||
expect(createdZoneDateTime.offsetNanoseconds).toBe(0);
|
||||
expect(zonedDateTime.year).toBe(2021);
|
||||
expect(zonedDateTime.month).toBe(11);
|
||||
expect(zonedDateTime.day).toBe(7);
|
||||
expect(zonedDateTime.hour).toBe(0);
|
||||
expect(zonedDateTime.minute).toBe(20);
|
||||
expect(zonedDateTime.second).toBe(5);
|
||||
expect(zonedDateTime.millisecond).toBe(100);
|
||||
expect(zonedDateTime.microsecond).toBe(200);
|
||||
expect(zonedDateTime.nanosecond).toBe(300);
|
||||
expect(zonedDateTime.offset).toBe("+00:00");
|
||||
expect(zonedDateTime.offsetNanoseconds).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -13,8 +13,7 @@ describe("correct behavior", () => {
|
|||
expect(withTimeZoneZonedDateTime.timeZone).toBe(timeZone);
|
||||
});
|
||||
|
||||
// FIXME: Enable this when time zone string parsing is implemented.
|
||||
test.skip("from time zone string", () => {
|
||||
test("from time zone string", () => {
|
||||
const object = {};
|
||||
const zonedDateTime = new Temporal.ZonedDateTime(1n, object);
|
||||
expect(zonedDateTime.timeZone).toBe(object);
|
||||
|
@ -32,13 +31,11 @@ describe("errors", () => {
|
|||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.ZonedDateTime");
|
||||
});
|
||||
|
||||
// FIXME: Enable this when time zone string parsing is implemented.
|
||||
test.skip("from invalid time zone string", () => {
|
||||
test("from invalid time zone string", () => {
|
||||
const zonedDateTime = new Temporal.ZonedDateTime(1n, {});
|
||||
|
||||
// FIXME: Use "toThrowWithMessage" once this has an error message.
|
||||
expect(() => {
|
||||
zonedDateTime.withTimeZone("UTCfoobar");
|
||||
}).toThrow(RangeError);
|
||||
}).toThrowWithMessage(RangeError, "Invalid time zone string 'UTCfoobar'");
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue