Title: [290248] trunk
Revision
290248
Author
[email protected]
Date
2022-02-21 09:56:12 -0800 (Mon, 21 Feb 2022)

Log Message

[JSC] Add CalendarDateTime parsing
https://bugs.webkit.org/show_bug.cgi?id=236886

Reviewed by Dean Jackson.

JSTests:

* stress/temporal-instant.js:
* stress/temporal-plaindate.js:
* stress/temporal-plaintime.js:

Source/_javascript_Core:

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):

Modified Paths

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);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to