Diff
Modified: trunk/JSTests/ChangeLog (290247 => 290248)
--- trunk/JSTests/ChangeLog 2022-02-21 17:50:40 UTC (rev 290247)
+++ trunk/JSTests/ChangeLog 2022-02-21 17:56:12 UTC (rev 290248)
@@ -1,3 +1,14 @@
+2022-02-21 Yusuke Suzuki <[email protected]>
+
+ [JSC] Add CalendarDateTime parsing
+ https://bugs.webkit.org/show_bug.cgi?id=236886
+
+ Reviewed by Dean Jackson.
+
+ * stress/temporal-instant.js:
+ * stress/temporal-plaindate.js:
+ * stress/temporal-plaintime.js:
+
2022-02-19 Commit Queue <[email protected]>
Unreviewed, reverting r290194 and r290210.
Modified: trunk/JSTests/stress/temporal-instant.js (290247 => 290248)
--- trunk/JSTests/stress/temporal-instant.js 2022-02-21 17:50:40 UTC (rev 290247)
+++ trunk/JSTests/stress/temporal-instant.js 2022-02-21 17:56:12 UTC (rev 290248)
@@ -313,8 +313,7 @@
shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30+00')}`, '1976-11-18T15:23:30Z');
shouldBe(`${Temporal.Instant.from('1976-11-18T15Z')}`, '1976-11-18T15:00:00Z');
// ignores any specified calendar
-// FIXME: parse calendar
-// shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.123456789Z[u-ca=discord]')}`, '1976-11-18T15:23:30.123456789Z');
+shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.123456789Z[u-ca=discord]')}`, '1976-11-18T15:23:30.123456789Z');
// no junk at end of string
shouldThrow(() => Temporal.Instant.from('1976-11-18T15:23:30.123456789Zjunk'), RangeError);
Modified: trunk/JSTests/stress/temporal-plaindate.js (290247 => 290248)
--- trunk/JSTests/stress/temporal-plaindate.js 2022-02-21 17:50:40 UTC (rev 290247)
+++ trunk/JSTests/stress/temporal-plaindate.js 2022-02-21 17:56:12 UTC (rev 290248)
@@ -47,7 +47,6 @@
shouldBe(String(Temporal.PlainDate.from('2007-01-09T03:24:30')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09t03:24:30')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30')), `2007-01-09`);
-shouldBe(String(Temporal.PlainDate.from('2007-01-09T03:24:30Z')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09T03:24:30+20:20:59')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09T03:24:30-20:20:59')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09T03:24:30\u221220:20:59')), `2007-01-09`);
@@ -77,6 +76,9 @@
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[+01:00:00.123456789]')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[-01:00]')), `2007-01-09`);
shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[\u221201:00]')), `2007-01-09`);
+shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[u-ca=japanese]')), `2007-01-09`);
+shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[Europe/Brussels][u-ca=japanese]')), `2007-01-09`);
+shouldBe(String(Temporal.PlainDate.from('2007-01-09[u-ca=japanese]')), `2007-01-09`);
{
let date = Temporal.PlainDate.from('2007-01-09T03:24:30+01:00[Europe/Brussels]')
shouldBe(date === Temporal.PlainDate.from(date), false);
@@ -142,6 +144,9 @@
"2007-01-09 03:24:30+01:00[02:0000.123456789]",
"2007-01-09 03:24:30+01:00[0200:00.123456789]",
"2007-01-09 03:24:30+01:00[02:00:60.123456789]",
+ "2007-01-09T03:24:30Z", // UTCDesignator
+ "2007-01-09 03:24:30[u-ca=japanese][Europe/Brussels]",
+ "2007-01-09 03:24:30+01:00[u-ca=japanese][Europe/Brussels]",
];
for (let text of failures) {
Modified: trunk/JSTests/stress/temporal-plaintime.js (290247 => 290248)
--- trunk/JSTests/stress/temporal-plaintime.js 2022-02-21 17:50:40 UTC (rev 290247)
+++ trunk/JSTests/stress/temporal-plaintime.js 2022-02-21 17:56:12 UTC (rev 290248)
@@ -102,10 +102,14 @@
shouldBe(String(Temporal.PlainTime.from('03:24:30')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('2020-01')), `20:20:00`); // -01 UTC offset
shouldBe(String(Temporal.PlainTime.from('01-01')), `01:00:00`); // -01 UTC offset
+shouldBe(String(Temporal.PlainTime.from('03:24:30[u-ca=japanese]')), `03:24:30`);
+shouldBe(String(Temporal.PlainTime.from('03:24:30+01:00[Europe/Brussels][u-ca=japanese]')), `03:24:30`);
+shouldBe(String(Temporal.PlainTime.from('03:24:30+01:00[u-ca=japanese]')), `03:24:30`);
+shouldBe(String(Temporal.PlainTime.from('T03:24:30+01:00[Europe/Brussels][u-ca=japanese]')), `03:24:30`);
+shouldBe(String(Temporal.PlainTime.from('T03:24:30+01:00[u-ca=japanese]')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07T03:24:30')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07t03:24:30')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30')), `03:24:30`);
-shouldBe(String(Temporal.PlainTime.from('1995-12-07T03:24:30Z')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07T03:24:30+20:20:59')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07T03:24:30-20:20:59')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07T03:24:30\u221220:20:59')), `03:24:30`);
@@ -135,6 +139,9 @@
shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30+01:00[+01:00:00.123456789]')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30+01:00[-01:00]')), `03:24:30`);
shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30+01:00[\u221201:00]')), `03:24:30`);
+shouldBe(String(Temporal.PlainTime.from('2007-01-09 03:24:30+01:00[u-ca=japanese]')), `03:24:30`);
+shouldBe(String(Temporal.PlainTime.from('2007-01-09 03:24:30+01:00[Europe/Brussels][u-ca=japanese]')), `03:24:30`);
+shouldBe(String(Temporal.PlainTime.from('2007-01-09 03:24:30[u-ca=japanese]')), `03:24:30`);
{
let time = Temporal.PlainTime.from('1995-12-07T03:24:30+01:00[Europe/Brussels]')
shouldBe(time === Temporal.PlainTime.from(time), false);
@@ -249,6 +256,9 @@
"1995-12-07 03:24:30+01:00[02:0000.123456789]",
"1995-12-07 03:24:30+01:00[0200:00.123456789]",
"1995-12-07 03:24:30+01:00[02:00:60.123456789]",
+ "1995-12-07T03:24:30Z", // UTCDesignator
+ "2007-01-09 03:24:30[u-ca=japanese][Europe/Brussels]",
+ "2007-01-09 03:24:30+01:00[u-ca=japanese][Europe/Brussels]",
];
for (let text of failures) {
Modified: trunk/Source/_javascript_Core/ChangeLog (290247 => 290248)
--- trunk/Source/_javascript_Core/ChangeLog 2022-02-21 17:50:40 UTC (rev 290247)
+++ trunk/Source/_javascript_Core/ChangeLog 2022-02-21 17:56:12 UTC (rev 290248)
@@ -1,3 +1,30 @@
+2022-02-21 Yusuke Suzuki <[email protected]>
+
+ [JSC] Add CalendarDateTime parsing
+ https://bugs.webkit.org/show_bug.cgi?id=236886
+
+ Reviewed by Dean Jackson.
+
+ This patch adds calendar parsing code to ISO8601 so that Temporal.Instant / Temporal.PlainDate / Temporal.PlainTime
+ can parse string with calendar correctly via "from" methods. Currently, we are just ignoring these calendar values,
+ but we should create a calendar instance from that in a subsequent patch.
+
+ * runtime/ISO8601.cpp:
+ (JSC::ISO8601::canBeCalendar):
+ (JSC::ISO8601::canBeTimeZone):
+ (JSC::ISO8601::parseTimeZone):
+ (JSC::ISO8601::parseCalendar):
+ (JSC::ISO8601::parseTime):
+ (JSC::ISO8601::parseDateTime):
+ (JSC::ISO8601::parseCalendarTime):
+ (JSC::ISO8601::parseCalendarDateTime):
+ (JSC::ISO8601::parseInstant):
+ * runtime/ISO8601.h:
+ * runtime/TemporalPlainDate.cpp:
+ (JSC::TemporalPlainDate::from):
+ * runtime/TemporalPlainTime.cpp:
+ (JSC::TemporalPlainTime::from):
+
2022-02-19 Commit Queue <[email protected]>
Unreviewed, reverting r290194 and r290210.
Modified: trunk/Source/_javascript_Core/runtime/ISO8601.cpp (290247 => 290248)
--- trunk/Source/_javascript_Core/runtime/ISO8601.cpp 2022-02-21 17:50:40 UTC (rev 290247)
+++ trunk/Source/_javascript_Core/runtime/ISO8601.cpp 2022-02-21 17:56:12 UTC (rev 290248)
@@ -433,6 +433,45 @@
}
template<typename CharacterType>
+static bool canBeCalendar(const StringParsingBuffer<CharacterType>& buffer)
+{
+ // https://tc39.es/proposal-temporal/#prod-Calendar
+ // Calendar :
+ // [u-ca= CalendarName]
+ return buffer.lengthRemaining() >= 6 && buffer[0] == '[' && buffer[1] == 'u' && buffer[2] == '-' && buffer[3] == 'c' && buffer[4] == 'a' && buffer[5] == '=';
+}
+
+template<typename CharacterType>
+static bool canBeTimeZone(const StringParsingBuffer<CharacterType>& buffer, CharacterType character)
+{
+ switch (static_cast<UChar>(character)) {
+ // UTCDesignator
+ // https://tc39.es/proposal-temporal/#prod-UTCDesignator
+ case 'z':
+ case 'Z':
+ // TimeZoneUTCOffsetSign
+ // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetSign
+ case '+':
+ case '-':
+ case minusSign:
+ return true;
+ // TimeZoneBracketedAnnotation
+ // https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedAnnotation
+ case '[': {
+ // We should reject calendar extension case.
+ // https://tc39.es/proposal-temporal/#prod-Calendar
+ // Calendar :
+ // [u-ca= CalendarName]
+ if (canBeCalendar(buffer))
+ return false;
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+template<typename CharacterType>
static std::optional<std::variant<Vector<LChar>, int64_t>> parseTimeZoneBracketedAnnotation(StringParsingBuffer<CharacterType>& buffer)
{
// https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedAnnotation
@@ -585,35 +624,6 @@
}
template<typename CharacterType>
-static bool canBeTimeZone(const StringParsingBuffer<CharacterType>& buffer, CharacterType character)
-{
- switch (static_cast<UChar>(character)) {
- // UTCDesignator
- // https://tc39.es/proposal-temporal/#prod-UTCDesignator
- case 'z':
- case 'Z':
- // TimeZoneUTCOffsetSign
- // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetSign
- case '+':
- case '-':
- case minusSign:
- // TimeZoneBracketedAnnotation
- // https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedAnnotation
- case '[': {
- // We should reject calendar extension case.
- // https://tc39.es/proposal-temporal/#prod-Calendar
- // Calendar :
- // [u-ca= CalendarName]
- if (buffer.lengthRemaining() >= 6 && buffer[1] == 'u' && buffer[2] == '-' && buffer[3] == 'c' && buffer[4] == 'a' && buffer[5] == '=')
- return false;
- return true;
- }
- default:
- return false;
- }
-}
-
-template<typename CharacterType>
static std::optional<TimeZoneRecord> parseTimeZone(StringParsingBuffer<CharacterType>& buffer)
{
if (buffer.atEnd())
@@ -624,7 +634,7 @@
case 'z':
case 'Z': {
buffer.advance();
- if (!buffer.atEnd() && *buffer == '[') {
+ if (!buffer.atEnd() && *buffer == '[' && canBeTimeZone(buffer, *buffer)) {
auto timeZone = parseTimeZoneBracketedAnnotation(buffer);
if (!timeZone)
return std::nullopt;
@@ -640,7 +650,7 @@
auto offset = parseTimeZoneNumericUTCOffset(buffer);
if (!offset)
return std::nullopt;
- if (!buffer.atEnd() && *buffer == '[') {
+ if (!buffer.atEnd() && *buffer == '[' && canBeTimeZone(buffer, *buffer)) {
auto timeZone = parseTimeZoneBracketedAnnotation(buffer);
if (!timeZone)
return std::nullopt;
@@ -662,6 +672,97 @@
}
template<typename CharacterType>
+static std::optional<CalendarRecord> parseCalendar(StringParsingBuffer<CharacterType>& buffer)
+{
+ // https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedAnnotation
+ // Calendar :
+ // [u-ca= CalendarName ]
+ //
+ // CalendarName :
+ // CalendarNameComponent
+ // CalendarNameComponent - CalendarName
+ //
+ // CalendarNameComponent :
+ // CalChar CalChar CalChar CalChar[opt] CalChar[opt] CalChar[opt] CalChar[opt] CalChar[opt]
+ //
+ // CalChar :
+ // Alpha
+ // Digit
+
+ if (!canBeCalendar(buffer))
+ return std::nullopt;
+ buffer.advanceBy(6);
+
+ if (buffer.atEnd())
+ return std::nullopt;
+
+ unsigned nameLength = 0;
+ {
+ unsigned index = 0;
+ for (; index < buffer.lengthRemaining(); ++index) {
+ auto character = buffer[index];
+ if (character == ']')
+ break;
+ if (!isASCIIAlpha(character) && !isASCIIDigit(character) && character != '-')
+ return std::nullopt;
+ }
+ if (!index)
+ return std::nullopt;
+ nameLength = index;
+ }
+
+ auto isValidComponent = [&](unsigned start, unsigned end) {
+ unsigned componentLength = end - start;
+ if (componentLength < minCalendarLength)
+ return false;
+ if (componentLength > maxCalendarLength)
+ return false;
+ return true;
+ };
+
+ unsigned currentNameComponentStartIndex = 0;
+ bool isLeadingCharacterInNameComponent = true;
+ for (unsigned index = 0; index < nameLength; ++index) {
+ auto character = buffer[index];
+ if (isLeadingCharacterInNameComponent) {
+ if (!(isASCIIAlpha(character) || isASCIIDigit(character)))
+ return std::nullopt;
+
+ currentNameComponentStartIndex = index;
+ isLeadingCharacterInNameComponent = false;
+ continue;
+ }
+
+ if (character == '-') {
+ if (!isValidComponent(currentNameComponentStartIndex, index))
+ return std::nullopt;
+ isLeadingCharacterInNameComponent = true;
+ continue;
+ }
+
+ if (!(isASCIIAlpha(character) || isASCIIDigit(character)))
+ return std::nullopt;
+ }
+ if (isLeadingCharacterInNameComponent)
+ return std::nullopt;
+ if (!isValidComponent(currentNameComponentStartIndex, nameLength))
+ return std::nullopt;
+
+ Vector<LChar, maxCalendarLength> result;
+ result.reserveInitialCapacity(nameLength);
+ for (unsigned index = 0; index < nameLength; ++index)
+ result.uncheckedAppend(buffer[index]);
+ buffer.advanceBy(nameLength);
+
+ if (buffer.atEnd())
+ return std::nullopt;
+ if (*buffer != ']')
+ return std::nullopt;
+ buffer.advance();
+ return CalendarRecord { WTFMove(result) };
+}
+
+template<typename CharacterType>
static std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>>> parseTime(StringParsingBuffer<CharacterType>& buffer)
{
// https://tc39.es/proposal-temporal/#prod-Time
@@ -671,14 +772,14 @@
if (!plainTime)
return std::nullopt;
if (buffer.atEnd())
- return std::tuple { plainTime.value(), std::nullopt };
+ return std::tuple { WTFMove(plainTime.value()), std::nullopt };
if (canBeTimeZone(buffer, *buffer)) {
auto timeZone = parseTimeZone(buffer);
if (!timeZone)
return std::nullopt;
- return std::tuple { plainTime.value(), timeZone };
+ return std::tuple { WTFMove(plainTime.value()), WTFMove(timeZone) };
}
- return std::tuple { plainTime.value(), std::nullopt };
+ return std::tuple { WTFMove(plainTime.value()), std::nullopt };
}
// https://tc39.es/proposal-temporal/#sec-temporal-isodaysinmonth
@@ -839,7 +940,7 @@
if (!plainDate)
return std::nullopt;
if (buffer.atEnd())
- return std::tuple { plainDate.value(), std::nullopt, std::nullopt };
+ return std::tuple { WTFMove(plainDate.value()), std::nullopt, std::nullopt };
if (*buffer == ' ' || *buffer == 'T' || *buffer == 't') {
buffer.advance();
@@ -846,8 +947,8 @@
auto plainTimeAndTimeZone = parseTime(buffer);
if (!plainTimeAndTimeZone)
return std::nullopt;
- auto [plainTime, timeZone] = plainTimeAndTimeZone.value();
- return std::tuple { plainDate.value(), plainTime, timeZone };
+ auto [plainTime, timeZone] = WTFMove(plainTimeAndTimeZone.value());
+ return std::tuple { WTFMove(plainDate.value()), WTFMove(plainTime), WTFMove(timeZone) };
}
if (canBeTimeZone(buffer, *buffer)) {
@@ -854,12 +955,78 @@
auto timeZone = parseTimeZone(buffer);
if (!timeZone)
return std::nullopt;
- return std::tuple { plainDate.value(), std::nullopt, timeZone };
+ return std::tuple { WTFMove(plainDate.value()), std::nullopt, WTFMove(timeZone) };
}
- return std::tuple { plainDate.value(), std::nullopt, std::nullopt };
+ return std::tuple { WTFMove(plainDate.value()), std::nullopt, std::nullopt };
}
+template<typename CharacterType>
+static std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> parseCalendarTime(StringParsingBuffer<CharacterType>& buffer)
+{
+ // https://tc39.es/proposal-temporal/#prod-CalendarTime
+ // CalendarTime :
+ // TimeDesignator TimeSpec TimeZone[opt] Calendar[opt]
+ // TimeSpec TimeZone[opt] Calendar
+ // TimeSpecWithOptionalTimeZoneNotAmbiguous
+
+ if (buffer.atEnd())
+ return std::nullopt;
+
+ if (*buffer == 'T' || *buffer == 't')
+ buffer.advance();
+
+ auto plainTime = parseTimeSpec(buffer, Second60Mode::Accept);
+ if (!plainTime)
+ return std::nullopt;
+ if (buffer.atEnd())
+ return std::tuple { WTFMove(plainTime.value()), std::nullopt, std::nullopt };
+
+ std::optional<TimeZoneRecord> timeZoneOptional;
+ if (canBeTimeZone(buffer, *buffer)) {
+ auto timeZone = parseTimeZone(buffer);
+ if (!timeZone)
+ return std::nullopt;
+ timeZoneOptional = WTFMove(timeZone);
+ }
+
+ if (buffer.atEnd())
+ return std::tuple { WTFMove(plainTime.value()), WTFMove(timeZoneOptional), std::nullopt };
+
+ std::optional<CalendarRecord> calendarOptional;
+ if (canBeCalendar(buffer)) {
+ auto calendar = parseCalendar(buffer);
+ if (!calendar)
+ return std::nullopt;
+ calendarOptional = WTFMove(calendar);
+ }
+
+ return std::tuple { WTFMove(plainTime.value()), WTFMove(timeZoneOptional), WTFMove(calendarOptional) };
+}
+
+template<typename CharacterType>
+static std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> parseCalendarDateTime(StringParsingBuffer<CharacterType>& buffer)
+{
+ // https://tc39.es/proposal-temporal/#prod-DateTime
+ // CalendarDateTime :
+ // DateTime CalendarName[opt]
+ //
+ auto dateTime = parseDateTime(buffer);
+ if (!dateTime)
+ return std::nullopt;
+
+ auto [plainDate, plainTimeOptional, timeZoneOptional] = WTFMove(dateTime.value());
+
+ if (!buffer.atEnd() && canBeCalendar(buffer)) {
+ auto calendar = parseCalendar(buffer);
+ if (!calendar)
+ return std::nullopt;
+ return std::tuple { WTFMove(plainDate), WTFMove(plainTimeOptional), WTFMove(timeZoneOptional), WTFMove(calendar) };
+ }
+
+ return std::tuple { WTFMove(plainDate), WTFMove(plainTimeOptional), WTFMove(timeZoneOptional), std::nullopt };
+}
+
std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>>> parseTime(StringView string)
{
return readCharactersForParsing(string, [](auto buffer) -> std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>>> {
@@ -870,6 +1037,16 @@
});
}
+std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> parseCalendarTime(StringView string)
+{
+ return readCharactersForParsing(string, [](auto buffer) -> std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> {
+ auto result = parseCalendarTime(buffer);
+ if (!buffer.atEnd())
+ return std::nullopt;
+ return result;
+ });
+}
+
std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>>> parseDateTime(StringView string)
{
return readCharactersForParsing(string, [](auto buffer) -> std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>>> {
@@ -880,6 +1057,16 @@
});
}
+std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> parseCalendarDateTime(StringView string)
+{
+ return readCharactersForParsing(string, [](auto buffer) -> std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> {
+ auto result = parseCalendarDateTime(buffer);
+ if (!buffer.atEnd())
+ return std::nullopt;
+ return result;
+ });
+}
+
std::optional<ExactTime> parseInstant(StringView string)
{
// https://tc39.es/proposal-temporal/#prod-TemporalInstantString
@@ -892,22 +1079,19 @@
// TimeZoneUTCOffset TimeZoneBracketedAnnotation_opt
return readCharactersForParsing(string, [](auto buffer) -> std::optional<ExactTime> {
- auto datetime = parseDateTime(buffer);
+ auto datetime = parseCalendarDateTime(buffer);
if (!datetime)
return std::nullopt;
- auto [date, maybeTime, maybeTimeZone] = datetime.value();
- if (!maybeTimeZone || (!maybeTimeZone->m_z && !maybeTimeZone->m_offset))
+ auto [plainDate, plainTimeOptional, timeZoneOptional, calendarOptional] = WTFMove(datetime.value());
+ if (!timeZoneOptional || (!timeZoneOptional->m_z && !timeZoneOptional->m_offset))
return std::nullopt;
- // FIXME: parse calendar annotation
if (!buffer.atEnd())
return std::nullopt;
- PlainTime time;
- if (maybeTime)
- time = maybeTime.value();
+ PlainTime plainTime = plainTimeOptional.value_or(PlainTime());
- int64_t offset = maybeTimeZone->m_z ? 0 : *maybeTimeZone->m_offset;
- return { ExactTime::fromISOPartsAndOffset(date.year(), date.month(), date.day(), time.hour(), time.minute(), time.second(), time.millisecond(), time.microsecond(), time.nanosecond(), offset) };
+ int64_t offset = timeZoneOptional->m_z ? 0 : *timeZoneOptional->m_offset;
+ return { ExactTime::fromISOPartsAndOffset(plainDate.year(), plainDate.month(), plainDate.day(), plainTime.hour(), plainTime.minute(), plainTime.second(), plainTime.millisecond(), plainTime.microsecond(), plainTime.nanosecond(), offset) };
});
}
Modified: trunk/Source/_javascript_Core/runtime/ISO8601.h (290247 => 290248)
--- trunk/Source/_javascript_Core/runtime/ISO8601.h 2022-02-21 17:50:40 UTC (rev 290247)
+++ trunk/Source/_javascript_Core/runtime/ISO8601.h 2022-02-21 17:56:12 UTC (rev 290248)
@@ -247,7 +247,13 @@
class PlainDate {
WTF_MAKE_FAST_ALLOCATED(PlainDate);
public:
- constexpr PlainDate() = default;
+ constexpr PlainDate()
+ : m_year(0)
+ , m_month(1)
+ , m_day(1)
+ {
+ }
+
constexpr PlainDate(int32_t year, unsigned month, unsigned day)
: m_year(year)
, m_month(month)
@@ -260,10 +266,13 @@
uint8_t day() const { return m_day; }
private:
- int32_t m_year { 0 };
- uint8_t m_month { 1 };
- uint8_t m_day { 1 };
+ int32_t m_year : 21; // ECMAScript max / min date's year can be represented <= 20 bits.
+ int32_t m_month : 5;
+ int32_t m_day : 6;
};
+#if COMPILER(GCC_COMPATIBLE)
+static_assert(sizeof(PlainDate) == sizeof(int32_t));
+#endif
using TimeZone = std::variant<TimeZoneID, int64_t>;
@@ -275,6 +284,12 @@
std::variant<Vector<LChar>, int64_t> m_nameOrOffset;
};
+static constexpr unsigned minCalendarLength = 3;
+static constexpr unsigned maxCalendarLength = 8;
+struct CalendarRecord {
+ Vector<LChar, maxCalendarLength> m_name;
+};
+
// https://tc39.es/proposal-temporal/#sup-isvalidtimezonename
std::optional<TimeZoneID> parseTimeZoneName(StringView);
std::optional<Duration> parseDuration(StringView);
@@ -281,7 +296,9 @@
std::optional<int64_t> parseTimeZoneNumericUTCOffset(StringView);
enum class ValidateTimeZoneID { Yes, No };
std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>>> parseTime(StringView);
+std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> parseCalendarTime(StringView);
std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>>> parseDateTime(StringView);
+std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> parseCalendarDateTime(StringView);
String formatTimeZoneOffsetString(int64_t);
String temporalTimeToString(PlainTime, std::tuple<Precision, unsigned> precision);
String temporalDateToString(PlainDate);
Modified: trunk/Source/_javascript_Core/runtime/TemporalPlainDate.cpp (290247 => 290248)
--- trunk/Source/_javascript_Core/runtime/TemporalPlainDate.cpp 2022-02-21 17:50:40 UTC (rev 290247)
+++ trunk/Source/_javascript_Core/runtime/TemporalPlainDate.cpp 2022-02-21 17:56:12 UTC (rev 290248)
@@ -151,10 +151,14 @@
auto string = itemValue.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, { });
- auto dateTime = ISO8601::parseDateTime(string);
+ // https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaldatestring
+ // TemporalDateString :
+ // CalendarDateTime
+ auto dateTime = ISO8601::parseCalendarDateTime(string);
if (dateTime) {
- auto [plainDate, plainTimeOptional, timeZoneOptional] = dateTime.value();
- return TemporalPlainDate::create(vm, globalObject->plainDateStructure(), WTFMove(plainDate));
+ auto [plainDate, plainTimeOptional, timeZoneOptional, calendarOptional] = WTFMove(dateTime.value());
+ if (!(timeZoneOptional && timeZoneOptional->m_z))
+ return TemporalPlainDate::create(vm, globalObject->plainDateStructure(), WTFMove(plainDate));
}
throwRangeError(globalObject, scope, "invalid date string"_s);
Modified: trunk/Source/_javascript_Core/runtime/TemporalPlainTime.cpp (290247 => 290248)
--- trunk/Source/_javascript_Core/runtime/TemporalPlainTime.cpp 2022-02-21 17:50:40 UTC (rev 290247)
+++ trunk/Source/_javascript_Core/runtime/TemporalPlainTime.cpp 2022-02-21 17:56:12 UTC (rev 290248)
@@ -415,20 +415,28 @@
return TemporalPlainTime::create(vm, globalObject->plainTimeStructure(), WTFMove(plainTime));
}
+ // https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaltimestring
+ // TemporalTimeString :
+ // CalendarTime
+ // CalendarDateTimeTimeRequired
+
auto string = itemValue.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, { });
- auto time = ISO8601::parseTime(string);
+ auto time = ISO8601::parseCalendarTime(string);
if (time) {
- auto [plainTime, timeZoneOptional] = time.value();
- return TemporalPlainTime::create(vm, globalObject->plainTimeStructure(), WTFMove(plainTime));
+ auto [plainTime, timeZoneOptional, calendarOptional] = WTFMove(time.value());
+ if (!(timeZoneOptional && timeZoneOptional->m_z))
+ return TemporalPlainTime::create(vm, globalObject->plainTimeStructure(), WTFMove(plainTime));
}
- auto dateTime = ISO8601::parseDateTime(string);
+ auto dateTime = ISO8601::parseCalendarDateTime(string);
if (dateTime) {
- auto [plainDate, plainTimeOptional, timeZoneOptional] = dateTime.value();
- if (plainTimeOptional)
- return TemporalPlainTime::create(vm, globalObject->plainTimeStructure(), WTFMove(plainTimeOptional.value()));
+ auto [plainDate, plainTimeOptional, timeZoneOptional, calendarOptional] = WTFMove(dateTime.value());
+ if (plainTimeOptional) {
+ if (!(timeZoneOptional && timeZoneOptional->m_z))
+ return TemporalPlainTime::create(vm, globalObject->plainTimeStructure(), WTFMove(plainTimeOptional.value()));
+ }
}
throwRangeError(globalObject, scope, "invalid time string"_s);