Changeset 290248 in webkit


Ignore:
Timestamp:
Feb 21, 2022 9:56:12 AM (5 months ago)
Author:
ysuzuki@apple.com
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/JavaScriptCore:

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

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r290213 r290248  
     12022-02-21  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Add CalendarDateTime parsing
     4        https://bugs.webkit.org/show_bug.cgi?id=236886
     5
     6        Reviewed by Dean Jackson.
     7
     8        * stress/temporal-instant.js:
     9        * stress/temporal-plaindate.js:
     10        * stress/temporal-plaintime.js:
     11
    1122022-02-19  Commit Queue  <commit-queue@webkit.org>
    213
  • trunk/JSTests/stress/temporal-instant.js

    r285178 r290248  
    314314shouldBe(`${Temporal.Instant.from('1976-11-18T15Z')}`, '1976-11-18T15:00:00Z');
    315315// ignores any specified calendar
    316 // FIXME: parse calendar
    317 // shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.123456789Z[u-ca=discord]')}`, '1976-11-18T15:23:30.123456789Z');
     316shouldBe(`${Temporal.Instant.from('1976-11-18T15:23:30.123456789Z[u-ca=discord]')}`, '1976-11-18T15:23:30.123456789Z');
    318317// no junk at end of string
    319318shouldThrow(() => Temporal.Instant.from('1976-11-18T15:23:30.123456789Zjunk'), RangeError);
  • trunk/JSTests/stress/temporal-plaindate.js

    r290209 r290248  
    4848shouldBe(String(Temporal.PlainDate.from('2007-01-09t03:24:30')), `2007-01-09`);
    4949shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30')), `2007-01-09`);
    50 shouldBe(String(Temporal.PlainDate.from('2007-01-09T03:24:30Z')), `2007-01-09`);
    5150shouldBe(String(Temporal.PlainDate.from('2007-01-09T03:24:30+20:20:59')), `2007-01-09`);
    5251shouldBe(String(Temporal.PlainDate.from('2007-01-09T03:24:30-20:20:59')), `2007-01-09`);
     
    7877shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[-01:00]')), `2007-01-09`);
    7978shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[\u221201:00]')), `2007-01-09`);
     79shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[u-ca=japanese]')), `2007-01-09`);
     80shouldBe(String(Temporal.PlainDate.from('2007-01-09 03:24:30+01:00[Europe/Brussels][u-ca=japanese]')), `2007-01-09`);
     81shouldBe(String(Temporal.PlainDate.from('2007-01-09[u-ca=japanese]')), `2007-01-09`);
    8082{
    8183    let date = Temporal.PlainDate.from('2007-01-09T03:24:30+01:00[Europe/Brussels]')
     
    143145    "2007-01-09 03:24:30+01:00[0200:00.123456789]",
    144146    "2007-01-09 03:24:30+01:00[02:00:60.123456789]",
     147    "2007-01-09T03:24:30Z", // UTCDesignator
     148    "2007-01-09 03:24:30[u-ca=japanese][Europe/Brussels]",
     149    "2007-01-09 03:24:30+01:00[u-ca=japanese][Europe/Brussels]",
    145150];
    146151
  • trunk/JSTests/stress/temporal-plaintime.js

    r282125 r290248  
    103103shouldBe(String(Temporal.PlainTime.from('2020-01')), `20:20:00`); // -01 UTC offset
    104104shouldBe(String(Temporal.PlainTime.from('01-01')), `01:00:00`); // -01 UTC offset
     105shouldBe(String(Temporal.PlainTime.from('03:24:30[u-ca=japanese]')), `03:24:30`);
     106shouldBe(String(Temporal.PlainTime.from('03:24:30+01:00[Europe/Brussels][u-ca=japanese]')), `03:24:30`);
     107shouldBe(String(Temporal.PlainTime.from('03:24:30+01:00[u-ca=japanese]')), `03:24:30`);
     108shouldBe(String(Temporal.PlainTime.from('T03:24:30+01:00[Europe/Brussels][u-ca=japanese]')), `03:24:30`);
     109shouldBe(String(Temporal.PlainTime.from('T03:24:30+01:00[u-ca=japanese]')), `03:24:30`);
    105110shouldBe(String(Temporal.PlainTime.from('1995-12-07T03:24:30')), `03:24:30`);
    106111shouldBe(String(Temporal.PlainTime.from('1995-12-07t03:24:30')), `03:24:30`);
    107112shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30')), `03:24:30`);
    108 shouldBe(String(Temporal.PlainTime.from('1995-12-07T03:24:30Z')), `03:24:30`);
    109113shouldBe(String(Temporal.PlainTime.from('1995-12-07T03:24:30+20:20:59')), `03:24:30`);
    110114shouldBe(String(Temporal.PlainTime.from('1995-12-07T03:24:30-20:20:59')), `03:24:30`);
     
    136140shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30+01:00[-01:00]')), `03:24:30`);
    137141shouldBe(String(Temporal.PlainTime.from('1995-12-07 03:24:30+01:00[\u221201:00]')), `03:24:30`);
     142shouldBe(String(Temporal.PlainTime.from('2007-01-09 03:24:30+01:00[u-ca=japanese]')), `03:24:30`);
     143shouldBe(String(Temporal.PlainTime.from('2007-01-09 03:24:30+01:00[Europe/Brussels][u-ca=japanese]')), `03:24:30`);
     144shouldBe(String(Temporal.PlainTime.from('2007-01-09 03:24:30[u-ca=japanese]')), `03:24:30`);
    138145{
    139146    let time = Temporal.PlainTime.from('1995-12-07T03:24:30+01:00[Europe/Brussels]')
     
    250257    "1995-12-07 03:24:30+01:00[0200:00.123456789]",
    251258    "1995-12-07 03:24:30+01:00[02:00:60.123456789]",
     259    "1995-12-07T03:24:30Z", // UTCDesignator
     260    "2007-01-09 03:24:30[u-ca=japanese][Europe/Brussels]",
     261    "2007-01-09 03:24:30+01:00[u-ca=japanese][Europe/Brussels]",
    252262];
    253263
  • trunk/Source/JavaScriptCore/ChangeLog

    r290213 r290248  
     12022-02-21  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Add CalendarDateTime parsing
     4        https://bugs.webkit.org/show_bug.cgi?id=236886
     5
     6        Reviewed by Dean Jackson.
     7
     8        This patch adds calendar parsing code to ISO8601 so that Temporal.Instant / Temporal.PlainDate / Temporal.PlainTime
     9        can parse string with calendar correctly via "from" methods. Currently, we are just ignoring these calendar values,
     10        but we should create a calendar instance from that in a subsequent patch.
     11
     12        * runtime/ISO8601.cpp:
     13        (JSC::ISO8601::canBeCalendar):
     14        (JSC::ISO8601::canBeTimeZone):
     15        (JSC::ISO8601::parseTimeZone):
     16        (JSC::ISO8601::parseCalendar):
     17        (JSC::ISO8601::parseTime):
     18        (JSC::ISO8601::parseDateTime):
     19        (JSC::ISO8601::parseCalendarTime):
     20        (JSC::ISO8601::parseCalendarDateTime):
     21        (JSC::ISO8601::parseInstant):
     22        * runtime/ISO8601.h:
     23        * runtime/TemporalPlainDate.cpp:
     24        (JSC::TemporalPlainDate::from):
     25        * runtime/TemporalPlainTime.cpp:
     26        (JSC::TemporalPlainTime::from):
     27
    1282022-02-19  Commit Queue  <commit-queue@webkit.org>
    229
  • trunk/Source/JavaScriptCore/runtime/ISO8601.cpp

    r290209 r290248  
    434434
    435435template<typename CharacterType>
     436static bool canBeCalendar(const StringParsingBuffer<CharacterType>& buffer)
     437{
     438    // https://tc39.es/proposal-temporal/#prod-Calendar
     439    // Calendar :
     440    //     [u-ca= CalendarName]
     441    return buffer.lengthRemaining() >= 6 && buffer[0] == '[' && buffer[1] == 'u' && buffer[2] == '-' && buffer[3] == 'c' && buffer[4] == 'a' && buffer[5] == '=';
     442}
     443
     444template<typename CharacterType>
     445static bool canBeTimeZone(const StringParsingBuffer<CharacterType>& buffer, CharacterType character)
     446{
     447    switch (static_cast<UChar>(character)) {
     448    // UTCDesignator
     449    // https://tc39.es/proposal-temporal/#prod-UTCDesignator
     450    case 'z':
     451    case 'Z':
     452    // TimeZoneUTCOffsetSign
     453    // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetSign
     454    case '+':
     455    case '-':
     456    case minusSign:
     457        return true;
     458    // TimeZoneBracketedAnnotation
     459    // https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedAnnotation
     460    case '[': {
     461        // We should reject calendar extension case.
     462        // https://tc39.es/proposal-temporal/#prod-Calendar
     463        // Calendar :
     464        //     [u-ca= CalendarName]
     465        if (canBeCalendar(buffer))
     466            return false;
     467        return true;
     468    }
     469    default:
     470        return false;
     471    }
     472}
     473
     474template<typename CharacterType>
    436475static std::optional<std::variant<Vector<LChar>, int64_t>> parseTimeZoneBracketedAnnotation(StringParsingBuffer<CharacterType>& buffer)
    437476{
     
    586625
    587626template<typename CharacterType>
    588 static bool canBeTimeZone(const StringParsingBuffer<CharacterType>& buffer, CharacterType character)
    589 {
    590     switch (static_cast<UChar>(character)) {
    591     // UTCDesignator
    592     // https://tc39.es/proposal-temporal/#prod-UTCDesignator
    593     case 'z':
    594     case 'Z':
    595     // TimeZoneUTCOffsetSign
    596     // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetSign
    597     case '+':
    598     case '-':
    599     case minusSign:
    600     // TimeZoneBracketedAnnotation
    601     // https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedAnnotation
    602     case '[': {
    603         // We should reject calendar extension case.
    604         // https://tc39.es/proposal-temporal/#prod-Calendar
    605         // Calendar :
    606         //     [u-ca= CalendarName]
    607         if (buffer.lengthRemaining() >= 6 && buffer[1] == 'u' && buffer[2] == '-' && buffer[3] == 'c' && buffer[4] == 'a' && buffer[5] == '=')
    608             return false;
    609         return true;
    610     }
    611     default:
    612         return false;
    613     }
    614 }
    615 
    616 template<typename CharacterType>
    617627static std::optional<TimeZoneRecord> parseTimeZone(StringParsingBuffer<CharacterType>& buffer)
    618628{
     
    625635    case 'Z': {
    626636        buffer.advance();
    627         if (!buffer.atEnd() && *buffer == '[') {
     637        if (!buffer.atEnd() && *buffer == '[' && canBeTimeZone(buffer, *buffer)) {
    628638            auto timeZone = parseTimeZoneBracketedAnnotation(buffer);
    629639            if (!timeZone)
     
    641651        if (!offset)
    642652            return std::nullopt;
    643         if (!buffer.atEnd() && *buffer == '[') {
     653        if (!buffer.atEnd() && *buffer == '[' && canBeTimeZone(buffer, *buffer)) {
    644654            auto timeZone = parseTimeZoneBracketedAnnotation(buffer);
    645655            if (!timeZone)
     
    663673
    664674template<typename CharacterType>
     675static std::optional<CalendarRecord> parseCalendar(StringParsingBuffer<CharacterType>& buffer)
     676{
     677    // https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedAnnotation
     678    // Calendar :
     679    //     [u-ca= CalendarName ]
     680    //
     681    // CalendarName :
     682    //     CalendarNameComponent
     683    //     CalendarNameComponent - CalendarName
     684    //
     685    // CalendarNameComponent :
     686    //     CalChar CalChar CalChar CalChar[opt] CalChar[opt] CalChar[opt] CalChar[opt] CalChar[opt]
     687    //
     688    // CalChar :
     689    //     Alpha
     690    //     Digit
     691
     692    if (!canBeCalendar(buffer))
     693        return std::nullopt;
     694    buffer.advanceBy(6);
     695
     696    if (buffer.atEnd())
     697        return std::nullopt;
     698
     699    unsigned nameLength = 0;
     700    {
     701        unsigned index = 0;
     702        for (; index < buffer.lengthRemaining(); ++index) {
     703            auto character = buffer[index];
     704            if (character == ']')
     705                break;
     706            if (!isASCIIAlpha(character) && !isASCIIDigit(character) && character != '-')
     707                return std::nullopt;
     708        }
     709        if (!index)
     710            return std::nullopt;
     711        nameLength = index;
     712    }
     713
     714    auto isValidComponent = [&](unsigned start, unsigned end) {
     715        unsigned componentLength = end - start;
     716        if (componentLength < minCalendarLength)
     717            return false;
     718        if (componentLength > maxCalendarLength)
     719            return false;
     720        return true;
     721    };
     722
     723    unsigned currentNameComponentStartIndex = 0;
     724    bool isLeadingCharacterInNameComponent = true;
     725    for (unsigned index = 0; index < nameLength; ++index) {
     726        auto character = buffer[index];
     727        if (isLeadingCharacterInNameComponent) {
     728            if (!(isASCIIAlpha(character) || isASCIIDigit(character)))
     729                return std::nullopt;
     730
     731            currentNameComponentStartIndex = index;
     732            isLeadingCharacterInNameComponent = false;
     733            continue;
     734        }
     735
     736        if (character == '-') {
     737            if (!isValidComponent(currentNameComponentStartIndex, index))
     738                return std::nullopt;
     739            isLeadingCharacterInNameComponent = true;
     740            continue;
     741        }
     742
     743        if (!(isASCIIAlpha(character) || isASCIIDigit(character)))
     744            return std::nullopt;
     745    }
     746    if (isLeadingCharacterInNameComponent)
     747        return std::nullopt;
     748    if (!isValidComponent(currentNameComponentStartIndex, nameLength))
     749        return std::nullopt;
     750
     751    Vector<LChar, maxCalendarLength> result;
     752    result.reserveInitialCapacity(nameLength);
     753    for (unsigned index = 0; index < nameLength; ++index)
     754        result.uncheckedAppend(buffer[index]);
     755    buffer.advanceBy(nameLength);
     756
     757    if (buffer.atEnd())
     758        return std::nullopt;
     759    if (*buffer != ']')
     760        return std::nullopt;
     761    buffer.advance();
     762    return CalendarRecord { WTFMove(result) };
     763}
     764
     765template<typename CharacterType>
    665766static std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>>> parseTime(StringParsingBuffer<CharacterType>& buffer)
    666767{
     
    672773        return std::nullopt;
    673774    if (buffer.atEnd())
    674         return std::tuple { plainTime.value(), std::nullopt };
     775        return std::tuple { WTFMove(plainTime.value()), std::nullopt };
    675776    if (canBeTimeZone(buffer, *buffer)) {
    676777        auto timeZone = parseTimeZone(buffer);
    677778        if (!timeZone)
    678779            return std::nullopt;
    679         return std::tuple { plainTime.value(), timeZone };
    680     }
    681     return std::tuple { plainTime.value(), std::nullopt };
     780        return std::tuple { WTFMove(plainTime.value()), WTFMove(timeZone) };
     781    }
     782    return std::tuple { WTFMove(plainTime.value()), std::nullopt };
    682783}
    683784
     
    840941        return std::nullopt;
    841942    if (buffer.atEnd())
    842         return std::tuple { plainDate.value(), std::nullopt, std::nullopt };
     943        return std::tuple { WTFMove(plainDate.value()), std::nullopt, std::nullopt };
    843944
    844945    if (*buffer == ' ' || *buffer == 'T' || *buffer == 't') {
     
    847948        if (!plainTimeAndTimeZone)
    848949            return std::nullopt;
    849         auto [plainTime, timeZone] = plainTimeAndTimeZone.value();
    850         return std::tuple { plainDate.value(), plainTime, timeZone };
     950        auto [plainTime, timeZone] = WTFMove(plainTimeAndTimeZone.value());
     951        return std::tuple { WTFMove(plainDate.value()), WTFMove(plainTime), WTFMove(timeZone) };
    851952    }
    852953
     
    855956        if (!timeZone)
    856957            return std::nullopt;
    857         return std::tuple { plainDate.value(), std::nullopt, timeZone };
    858     }
    859 
    860     return std::tuple { plainDate.value(), std::nullopt, std::nullopt };
     958        return std::tuple { WTFMove(plainDate.value()), std::nullopt, WTFMove(timeZone) };
     959    }
     960
     961    return std::tuple { WTFMove(plainDate.value()), std::nullopt, std::nullopt };
     962}
     963
     964template<typename CharacterType>
     965static std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> parseCalendarTime(StringParsingBuffer<CharacterType>& buffer)
     966{
     967    // https://tc39.es/proposal-temporal/#prod-CalendarTime
     968    // CalendarTime :
     969    //     TimeDesignator TimeSpec TimeZone[opt] Calendar[opt]
     970    //     TimeSpec TimeZone[opt] Calendar
     971    //     TimeSpecWithOptionalTimeZoneNotAmbiguous
     972
     973    if (buffer.atEnd())
     974        return std::nullopt;
     975
     976    if (*buffer == 'T' || *buffer == 't')
     977        buffer.advance();
     978
     979    auto plainTime = parseTimeSpec(buffer, Second60Mode::Accept);
     980    if (!plainTime)
     981        return std::nullopt;
     982    if (buffer.atEnd())
     983        return std::tuple { WTFMove(plainTime.value()), std::nullopt, std::nullopt };
     984
     985    std::optional<TimeZoneRecord> timeZoneOptional;
     986    if (canBeTimeZone(buffer, *buffer)) {
     987        auto timeZone = parseTimeZone(buffer);
     988        if (!timeZone)
     989            return std::nullopt;
     990        timeZoneOptional = WTFMove(timeZone);
     991    }
     992
     993    if (buffer.atEnd())
     994        return std::tuple { WTFMove(plainTime.value()), WTFMove(timeZoneOptional), std::nullopt };
     995
     996    std::optional<CalendarRecord> calendarOptional;
     997    if (canBeCalendar(buffer)) {
     998        auto calendar = parseCalendar(buffer);
     999        if (!calendar)
     1000            return std::nullopt;
     1001        calendarOptional = WTFMove(calendar);
     1002    }
     1003
     1004    return std::tuple { WTFMove(plainTime.value()), WTFMove(timeZoneOptional), WTFMove(calendarOptional) };
     1005}
     1006
     1007template<typename CharacterType>
     1008static std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> parseCalendarDateTime(StringParsingBuffer<CharacterType>& buffer)
     1009{
     1010    // https://tc39.es/proposal-temporal/#prod-DateTime
     1011    // CalendarDateTime :
     1012    //     DateTime CalendarName[opt]
     1013    //
     1014    auto dateTime = parseDateTime(buffer);
     1015    if (!dateTime)
     1016        return std::nullopt;
     1017
     1018    auto [plainDate, plainTimeOptional, timeZoneOptional] = WTFMove(dateTime.value());
     1019
     1020    if (!buffer.atEnd() && canBeCalendar(buffer)) {
     1021        auto calendar = parseCalendar(buffer);
     1022        if (!calendar)
     1023            return std::nullopt;
     1024        return std::tuple { WTFMove(plainDate), WTFMove(plainTimeOptional), WTFMove(timeZoneOptional), WTFMove(calendar) };
     1025    }
     1026
     1027    return std::tuple { WTFMove(plainDate), WTFMove(plainTimeOptional), WTFMove(timeZoneOptional), std::nullopt };
    8611028}
    8621029
     
    8711038}
    8721039
     1040std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> parseCalendarTime(StringView string)
     1041{
     1042    return readCharactersForParsing(string, [](auto buffer) -> std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> {
     1043        auto result = parseCalendarTime(buffer);
     1044        if (!buffer.atEnd())
     1045            return std::nullopt;
     1046        return result;
     1047    });
     1048}
     1049
    8731050std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>>> parseDateTime(StringView string)
    8741051{
    8751052    return readCharactersForParsing(string, [](auto buffer) -> std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>>> {
    8761053        auto result = parseDateTime(buffer);
     1054        if (!buffer.atEnd())
     1055            return std::nullopt;
     1056        return result;
     1057    });
     1058}
     1059
     1060std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> parseCalendarDateTime(StringView string)
     1061{
     1062    return readCharactersForParsing(string, [](auto buffer) -> std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> {
     1063        auto result = parseCalendarDateTime(buffer);
    8771064        if (!buffer.atEnd())
    8781065            return std::nullopt;
     
    8931080
    8941081    return readCharactersForParsing(string, [](auto buffer) -> std::optional<ExactTime> {
    895         auto datetime = parseDateTime(buffer);
     1082        auto datetime = parseCalendarDateTime(buffer);
    8961083        if (!datetime)
    8971084            return std::nullopt;
    898         auto [date, maybeTime, maybeTimeZone] = datetime.value();
    899         if (!maybeTimeZone || (!maybeTimeZone->m_z && !maybeTimeZone->m_offset))
    900             return std::nullopt;
    901         // FIXME: parse calendar annotation
     1085        auto [plainDate, plainTimeOptional, timeZoneOptional, calendarOptional] = WTFMove(datetime.value());
     1086        if (!timeZoneOptional || (!timeZoneOptional->m_z && !timeZoneOptional->m_offset))
     1087            return std::nullopt;
    9021088        if (!buffer.atEnd())
    9031089            return std::nullopt;
    9041090
    905         PlainTime time;
    906         if (maybeTime)
    907             time = maybeTime.value();
    908 
    909         int64_t offset = maybeTimeZone->m_z ? 0 : *maybeTimeZone->m_offset;
    910         return { ExactTime::fromISOPartsAndOffset(date.year(), date.month(), date.day(), time.hour(), time.minute(), time.second(), time.millisecond(), time.microsecond(), time.nanosecond(), offset) };
     1091        PlainTime plainTime = plainTimeOptional.value_or(PlainTime());
     1092
     1093        int64_t offset = timeZoneOptional->m_z ? 0 : *timeZoneOptional->m_offset;
     1094        return { ExactTime::fromISOPartsAndOffset(plainDate.year(), plainDate.month(), plainDate.day(), plainTime.hour(), plainTime.minute(), plainTime.second(), plainTime.millisecond(), plainTime.microsecond(), plainTime.nanosecond(), offset) };
    9111095    });
    9121096}
  • trunk/Source/JavaScriptCore/runtime/ISO8601.h

    r290209 r290248  
    248248    WTF_MAKE_FAST_ALLOCATED(PlainDate);
    249249public:
    250     constexpr PlainDate() = default;
     250    constexpr PlainDate()
     251        : m_year(0)
     252        , m_month(1)
     253        , m_day(1)
     254    {
     255    }
     256
    251257    constexpr PlainDate(int32_t year, unsigned month, unsigned day)
    252258        : m_year(year)
     
    261267
    262268private:
    263     int32_t m_year { 0 };
    264     uint8_t m_month { 1 };
    265     uint8_t m_day { 1 };
    266 };
     269    int32_t m_year : 21; // ECMAScript max / min date's year can be represented <= 20 bits.
     270    int32_t m_month : 5;
     271    int32_t m_day : 6;
     272};
     273#if COMPILER(GCC_COMPATIBLE)
     274static_assert(sizeof(PlainDate) == sizeof(int32_t));
     275#endif
    267276
    268277using TimeZone = std::variant<TimeZoneID, int64_t>;
     
    276285};
    277286
     287static constexpr unsigned minCalendarLength = 3;
     288static constexpr unsigned maxCalendarLength = 8;
     289struct CalendarRecord {
     290    Vector<LChar, maxCalendarLength> m_name;
     291};
     292
    278293// https://tc39.es/proposal-temporal/#sup-isvalidtimezonename
    279294std::optional<TimeZoneID> parseTimeZoneName(StringView);
     
    282297enum class ValidateTimeZoneID { Yes, No };
    283298std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>>> parseTime(StringView);
     299std::optional<std::tuple<PlainTime, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> parseCalendarTime(StringView);
    284300std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>>> parseDateTime(StringView);
     301std::optional<std::tuple<PlainDate, std::optional<PlainTime>, std::optional<TimeZoneRecord>, std::optional<CalendarRecord>>> parseCalendarDateTime(StringView);
    285302String formatTimeZoneOffsetString(int64_t);
    286303String temporalTimeToString(PlainTime, std::tuple<Precision, unsigned> precision);
  • trunk/Source/JavaScriptCore/runtime/TemporalPlainDate.cpp

    r290209 r290248  
    152152    RETURN_IF_EXCEPTION(scope, { });
    153153
    154     auto dateTime = ISO8601::parseDateTime(string);
     154    // https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaldatestring
     155    // TemporalDateString :
     156    //     CalendarDateTime
     157    auto dateTime = ISO8601::parseCalendarDateTime(string);
    155158    if (dateTime) {
    156         auto [plainDate, plainTimeOptional, timeZoneOptional] = dateTime.value();
    157         return TemporalPlainDate::create(vm, globalObject->plainDateStructure(), WTFMove(plainDate));
     159        auto [plainDate, plainTimeOptional, timeZoneOptional, calendarOptional] = WTFMove(dateTime.value());
     160        if (!(timeZoneOptional && timeZoneOptional->m_z))
     161            return TemporalPlainDate::create(vm, globalObject->plainDateStructure(), WTFMove(plainDate));
    158162    }
    159163
  • trunk/Source/JavaScriptCore/runtime/TemporalPlainTime.cpp

    r285730 r290248  
    416416    }
    417417
     418    // https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaltimestring
     419    // TemporalTimeString :
     420    //    CalendarTime
     421    //    CalendarDateTimeTimeRequired
     422
    418423    auto string = itemValue.toWTFString(globalObject);
    419424    RETURN_IF_EXCEPTION(scope, { });
    420425
    421     auto time = ISO8601::parseTime(string);
     426    auto time = ISO8601::parseCalendarTime(string);
    422427    if (time) {
    423         auto [plainTime, timeZoneOptional] = time.value();
    424         return TemporalPlainTime::create(vm, globalObject->plainTimeStructure(), WTFMove(plainTime));
    425     }
    426 
    427     auto dateTime = ISO8601::parseDateTime(string);
     428        auto [plainTime, timeZoneOptional, calendarOptional] = WTFMove(time.value());
     429        if (!(timeZoneOptional && timeZoneOptional->m_z))
     430            return TemporalPlainTime::create(vm, globalObject->plainTimeStructure(), WTFMove(plainTime));
     431    }
     432
     433    auto dateTime = ISO8601::parseCalendarDateTime(string);
    428434    if (dateTime) {
    429         auto [plainDate, plainTimeOptional, timeZoneOptional] = dateTime.value();
    430         if (plainTimeOptional)
    431             return TemporalPlainTime::create(vm, globalObject->plainTimeStructure(), WTFMove(plainTimeOptional.value()));
     435        auto [plainDate, plainTimeOptional, timeZoneOptional, calendarOptional] = WTFMove(dateTime.value());
     436        if (plainTimeOptional) {
     437            if (!(timeZoneOptional && timeZoneOptional->m_z))
     438                return TemporalPlainTime::create(vm, globalObject->plainTimeStructure(), WTFMove(plainTimeOptional.value()));
     439        }
    432440    }
    433441
Note: See TracChangeset for help on using the changeset viewer.