diff options
author | Linus Groh <mail@linusgroh.de> | 2021-08-16 00:35:05 +0100 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-08-16 14:10:41 +0100 |
commit | ed9d37bd4049c4c178912d321183a8b146d5410f (patch) | |
tree | 76d8fecfd9119f3a0c460458b482733f5f1de798 /Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp | |
parent | c1c12497b56edbdbd02cb3f687a676f1c6a39cac (diff) | |
download | serenity-ed9d37bd4049c4c178912d321183a8b146d5410f.zip |
LibJS: Implement Temporal.Calendar.prototype.yearMonthFromFields()
Diffstat (limited to 'Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp')
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp | 95 |
1 files changed, 87 insertions, 8 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp index 248aa43192..aa61eb9a4b 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp @@ -6,6 +6,7 @@ #include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/GlobalObject.h> +#include <LibJS/Runtime/Temporal/AbstractOperations.h> #include <LibJS/Runtime/Temporal/PlainDate.h> #include <LibJS/Runtime/Temporal/PlainYearMonth.h> #include <LibJS/Runtime/Temporal/PlainYearMonthConstructor.h> @@ -28,19 +29,67 @@ void PlainYearMonth::visit_edges(Visitor& visitor) visitor.visit(&m_calendar); } -// 9.5.5 BalanceISOYearMonth ( year, month ), https://tc39.es/proposal-temporal/#sec-temporal-balanceisoyearmonth -ISOYearMonth balance_iso_year_month(i32 year, i32 month) +// 9.5.2 RegulateISOYearMonth ( year, month, overflow ), https://tc39.es/proposal-temporal/#sec-temporal-regulateisoyearmonth +Optional<ISOYearMonth> regulate_iso_year_month(GlobalObject& global_object, double year, double month, String const& overflow) { + auto& vm = global_object.vm(); + // 1. Assert: year and month are integers. + VERIFY(year == trunc(year) && month == trunc(month)); + + // 2. Assert: overflow is either "constrain" or "reject". + // NOTE: Asserted by the VERIFY_NOT_REACHED at the end + + // 3. If overflow is "constrain", then + if (overflow == "constrain"sv) { + // IMPLEMENTATION DEFINED: This is an optimization that allows us to treat `year` (a double) as normal integer from this point onwards. + // This does not change the exposed behaviour as the subsequent call to CreateTemporalYearMonth will check that its value is a valid ISO + // values (for years: -273975 - 273975) which is a subset of this check. + // If RegulateISOYearMonth is ever used outside ISOYearMonthFromFields, this may need to be changed. + if (!AK::is_within_range<i32>(year)) { + vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainYearMonth); + return {}; + } + + // a. Return ! ConstrainISOYearMonth(year, month). + return constrain_iso_year_month(year, month); + } - // 2. Set year to year + floor((month - 1) / 12). - year += (month - 1) / 12; + // 4. If overflow is "reject", then + if (overflow == "reject"sv) { + // IMPLEMENTATION DEFINED: This is an optimization that allows us to treat these doubles as normal integers from this point onwards. + // This does not change the exposed behaviour as the call to IsValidISOMonth and subsequent call to CreateTemporalDateTime will check + // that these values are valid ISO values (for years: -273975 - 273975, for months: 1 - 12) all of which are subsets of this check. + if (!AK::is_within_range<i32>(year) || !AK::is_within_range<u8>(month)) { + vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainYearMonth); + return {}; + } + + // a. If ! IsValidISOMonth(month) is false, throw a RangeError exception. + if (!is_valid_iso_month(month)) { + vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainYearMonth); + return {}; + } + + // b. Return the new Record { [[Year]]: year, [[Month]]: month }. + return ISOYearMonth { .year = static_cast<i32>(year), .month = static_cast<u8>(month), .reference_iso_day = 0 }; + } - // 3. Set month to (month − 1) modulo 12 + 1. - month = (month - 1) % 12 + 1; + VERIFY_NOT_REACHED(); +} - // 4. Return the new Record { [[Year]]: year, [[Month]]: month }. - return ISOYearMonth { .year = year, .month = static_cast<u8>(month) }; +// 9.5.3 IsValidISOMonth ( month ), https://tc39.es/proposal-temporal/#sec-temporal-isvalidisomonth +bool is_valid_iso_month(u8 month) +{ + // 1. Assert: month is an integer. + // 2. If month < 1 or month > 12, then + if (month < 1 || month > 12) { + // a.Return false. + return false; + } + + // 3. Return true. + return true; } // 9.5.4 ISOYearMonthWithinLimits ( year, month ), https://tc39.es/proposal-temporal/#sec-temporal-isoyearmonthwithinlimits @@ -70,6 +119,36 @@ bool iso_year_month_within_limits(i32 year, u8 month) return true; } +// 9.5.5 BalanceISOYearMonth ( year, month ), https://tc39.es/proposal-temporal/#sec-temporal-balanceisoyearmonth +ISOYearMonth balance_iso_year_month(double year, double month) +{ + // 1. Assert: year and month are integers. + VERIFY(year == trunc(year) && month == trunc(month)); + + // 2. Set year to year + floor((month - 1) / 12). + year += floor((month - 1) / 12); + + // 3. Set month to (month − 1) modulo 12 + 1. + month = fmod(month - 1, 12) + 1; + + // 4. Return the new Record { [[Year]]: year, [[Month]]: month }. + return ISOYearMonth { .year = static_cast<i32>(year), .month = static_cast<u8>(month), .reference_iso_day = 0 }; +} + +// 9.5.6 ConstrainISOYearMonth ( year, month ), https://tc39.es/proposal-temporal/#sec-temporal-constrainisoyearmonth +ISOYearMonth constrain_iso_year_month(double year, double month) +{ + // 1. Assert: year and month are integers. + VERIFY(year == trunc(year) && month == trunc(month)); + + // 2. Set month to ! ConstrainToRange(month, 1, 12). + month = constrain_to_range(month, 1, 12); + + // 3. Return the Record { [[Year]]: year, [[Month]]: month }. + // NOTE: `year` is known to be in the i32 range. + return ISOYearMonth { .year = static_cast<i32>(year), .month = static_cast<u8>(month), .reference_iso_day = 0 }; +} + // 9.5.7 CreateTemporalYearMonth ( isoYear, isoMonth, calendar, referenceISODay [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporalyearmonth PlainYearMonth* create_temporal_year_month(GlobalObject& global_object, i32 iso_year, u8 iso_month, Object& calendar, u8 reference_iso_day, FunctionObject* new_target) { |