diff options
author | Linus Groh <mail@linusgroh.de> | 2022-02-02 14:36:55 +0000 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-02-02 14:46:52 +0000 |
commit | 19a2b320653d3de06eb66414131631427a4272b2 (patch) | |
tree | 9ed1784bde2b28bb3c43df6a9ff525f938e5003c /Userland/Libraries | |
parent | 8215b99df186cc70d86aa702d81b7d1a96dbd356 (diff) | |
download | serenity-19a2b320653d3de06eb66414131631427a4272b2.zip |
LibJS: Reject '-000000' as extended year
This is a normative change in the Temporal spec.
See: https://github.com/tc39/proposal-temporal/commit/e60ef9e
Diffstat (limited to 'Userland/Libraries')
7 files changed, 60 insertions, 17 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h index ccb86058cf..1fcb2cd4d0 100644 --- a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h +++ b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h @@ -232,6 +232,7 @@ M(TemporalInvalidDurationString, "Invalid duration string '{}'") \ M(TemporalInvalidDurationStringFractionNotLast, "Invalid duration string '{}': fractional {} must not be proceeded by {}") \ M(TemporalInvalidEpochNanoseconds, "Invalid epoch nanoseconds value, must be in range -86400 * 10^17 to 86400 * 10^17") \ + M(TemporalInvalidExtendedYearNegativeZero, "Invalid extended year, must not be negative zero") \ M(TemporalInvalidInstantString, "Invalid instant string '{}'") \ M(TemporalInvalidISODate, "Invalid ISO date") \ M(TemporalInvalidMonthCode, "Invalid month code") \ diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp index 8105544cfb..f1b61cb6f8 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp @@ -1142,43 +1142,47 @@ ThrowCompletionOr<ISODateTime> parse_iso_date_time(GlobalObject& global_object, else normalized_year = year_part.value_or("0"); - // 7. Set year to ! ToIntegerOrInfinity(year). + // 7. If ! SameValue(year, "-000000") is true, throw a RangeError exception. + if (normalized_year == "-000000"sv) + return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidExtendedYearNegativeZero); + + // 8. Set year to ! ToIntegerOrInfinity(year). auto year = *normalized_year.to_int<i32>(); u8 month; - // 8. If month is undefined, then + // 9. If month is undefined, then if (!month_part.has_value()) { // a. Set month to 1. month = 1; } - // 9. Else, + // 10. Else, else { // a. Set month to ! ToIntegerOrInfinity(month). month = *month_part->to_uint<u8>(); } u8 day; - // 10. If day is undefined, then + // 11. If day is undefined, then if (!day_part.has_value()) { // a. Set day to 1. day = 1; } - // 11. Else, + // 12. Else, else { // a. Set day to ! ToIntegerOrInfinity(day). day = *day_part->to_uint<u8>(); } - // 12. Set hour to ! ToIntegerOrInfinity(hour). + // 13. Set hour to ! ToIntegerOrInfinity(hour). u8 hour = *hour_part.value_or("0"sv).to_uint<u8>(); - // 13. Set minute to ! ToIntegerOrInfinity(minute). + // 14. Set minute to ! ToIntegerOrInfinity(minute). u8 minute = *minute_part.value_or("0"sv).to_uint<u8>(); - // 14. Set second to ! ToIntegerOrInfinity(second). + // 15. Set second to ! ToIntegerOrInfinity(second). u8 second = *second_part.value_or("0"sv).to_uint<u8>(); - // 15. If second is 60, then + // 16. If second is 60, then if (second == 60) { // a. Set second to 59. second = 59; @@ -1187,7 +1191,7 @@ ThrowCompletionOr<ISODateTime> parse_iso_date_time(GlobalObject& global_object, u16 millisecond; u16 microsecond; u16 nanosecond; - // 16. If fraction is not undefined, then + // 17. If fraction is not undefined, then if (fraction_part.has_value()) { // a. Set fraction to the string-concatenation of the previous value of fraction and the string "000000000". auto fraction = String::formatted("{}000000000", *fraction_part); @@ -1201,7 +1205,7 @@ ThrowCompletionOr<ISODateTime> parse_iso_date_time(GlobalObject& global_object, // g. Set nanosecond to ! ToIntegerOrInfinity(nanosecond). nanosecond = *fraction.substring(7, 3).to_uint<u16>(); } - // 17. Else, + // 18. Else, else { // a. Let millisecond be 0. millisecond = 0; @@ -1211,15 +1215,15 @@ ThrowCompletionOr<ISODateTime> parse_iso_date_time(GlobalObject& global_object, nanosecond = 0; } - // 18. If ! IsValidISODate(year, month, day) is false, throw a RangeError exception. + // 19. If ! IsValidISODate(year, month, day) is false, throw a RangeError exception. if (!is_valid_iso_date(year, month, day)) return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidISODate); - // 19. If ! IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is false, throw a RangeError exception. + // 20. If ! IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is false, throw a RangeError exception. if (!is_valid_time(hour, minute, second, millisecond, microsecond, nanosecond)) return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidTime); - // 20. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day, [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond, [[Calendar]]: calendar }. + // 21. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day, [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond, [[Calendar]]: calendar }. return ISODateTime { .year = year, .month = month, .day = day, .hour = hour, .minute = minute, .second = second, .millisecond = millisecond, .microsecond = microsecond, .nanosecond = nanosecond, .calendar = Optional<String>(move(calendar_part)) }; } @@ -1678,16 +1682,24 @@ ThrowCompletionOr<TemporalYearMonth> parse_temporal_year_month_string(GlobalObje return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidYearMonthString, iso_string); } - // 3. If isoString contains a UTCDesignator, then + // FIXME: I don't think this check makes sense - the TemporalYearMonthString syntax check above + // should rule out a string that's '-000000'; it requires a month with a non-zero digit + // in it, and the normalized year is checked separately in ParseISODateTime below. + // :yakshrug: + // 3. If ! SameValue(isoString, "-000000") is true, throw a RangeError exception. + if (iso_string == "-000000"sv) + return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidExtendedYearNegativeZero); + + // 4. If isoString contains a UTCDesignator, then if (parse_result->utc_designator.has_value()) { // a. Throw a RangeError exception. return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidYearMonthStringUTCDesignator, iso_string); } - // 4. Let result be ? ParseISODateTime(isoString). + // 5. Let result be ? ParseISODateTime(isoString). auto result = TRY(parse_iso_date_time(global_object, *parse_result)); - // 5. Return the Record { [[Year]]: result.[[Year]], [[Month]]: result.[[Month]], [[Day]]: result.[[Day]], [[Calendar]]: result.[[Calendar]] }. + // 6. Return the Record { [[Year]]: result.[[Year]], [[Month]]: result.[[Month]], [[Day]]: result.[[Day]], [[Calendar]]: result.[[Calendar]] }. return TemporalYearMonth { .year = result.year, .month = result.month, .day = result.day, .calendar = move(result.calendar) }; } diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.from.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.from.js index 29007334f1..d5e14a4c9b 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.from.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.from.js @@ -49,4 +49,10 @@ describe("errors", () => { Temporal.PlainDate.from("foo"); }).toThrowWithMessage(RangeError, "Invalid date string 'foo'"); }); + + test("extended year must not be negative zero", () => { + expect(() => { + Temporal.PlainDate.from("-000000-01-01"); + }).toThrowWithMessage(RangeError, "Invalid extended year, must not be negative zero"); + }); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDateTime/PlainDateTime.from.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDateTime/PlainDateTime.from.js index 9cc4432aa7..e741713249 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDateTime/PlainDateTime.from.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDateTime/PlainDateTime.from.js @@ -186,4 +186,10 @@ describe("errors", () => { "Invalid date time string '2021-07-06T23:42:01Z': must not contain a UTC designator" ); }); + + test("extended year must not be negative zero", () => { + expect(() => { + Temporal.PlainDateTime.from("-000000-01-01"); + }).toThrowWithMessage(RangeError, "Invalid extended year, must not be negative zero"); + }); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainMonthDay/PlainMonthDay.from.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainMonthDay/PlainMonthDay.from.js index 78388845c3..ffffb51b8f 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainMonthDay/PlainMonthDay.from.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainMonthDay/PlainMonthDay.from.js @@ -75,4 +75,10 @@ describe("errors", () => { "Invalid month day string '2021-07-06T23:42:01Z': must not contain a UTC designator" ); }); + + test("extended year must not be negative zero", () => { + expect(() => { + Temporal.PlainMonthDay.from("-000000-01-01"); + }).toThrowWithMessage(RangeError, "Invalid extended year, must not be negative zero"); + }); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainTime/PlainTime.from.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainTime/PlainTime.from.js index 032b445b99..afacf2096b 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainTime/PlainTime.from.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainTime/PlainTime.from.js @@ -65,6 +65,12 @@ describe("errors", () => { ); }); + test("extended year must not be negative zero", () => { + expect(() => { + Temporal.PlainTime.from("-000000-01-01T00:00:00"); + }).toThrowWithMessage(RangeError, "Invalid extended year, must not be negative zero"); + }); + test("ambiguous string must contain a time designator", () => { const values = [ // YYYY-MM or HHMM-UU diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainYearMonth/PlainYearMonth.from.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainYearMonth/PlainYearMonth.from.js index 78a1fbc031..5579e22244 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainYearMonth/PlainYearMonth.from.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainYearMonth/PlainYearMonth.from.js @@ -101,4 +101,10 @@ describe("errors", () => { "Invalid year month string '2021-07-06T23:42:01Z': must not contain a UTC designator" ); }); + + test("extended year must not be negative zero", () => { + expect(() => { + Temporal.PlainYearMonth.from("-000000-01"); + }).toThrowWithMessage(RangeError, "Invalid extended year, must not be negative zero"); + }); }); |