diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:35:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:35:29 +0000 |
commit | 59203c63bb777a3bacec32fb8830fba33540e809 (patch) | |
tree | 58298e711c0ff0575818c30485b44a2f21bf28a0 /js/src/builtin/temporal/PlainDate.cpp | |
parent | Adding upstream version 126.0.1. (diff) | |
download | firefox-59203c63bb777a3bacec32fb8830fba33540e809.tar.xz firefox-59203c63bb777a3bacec32fb8830fba33540e809.zip |
Adding upstream version 127.0.upstream/127.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/builtin/temporal/PlainDate.cpp')
-rw-r--r-- | js/src/builtin/temporal/PlainDate.cpp | 476 |
1 files changed, 262 insertions, 214 deletions
diff --git a/js/src/builtin/temporal/PlainDate.cpp b/js/src/builtin/temporal/PlainDate.cpp index a4ad0e418f..a15d95cdc1 100644 --- a/js/src/builtin/temporal/PlainDate.cpp +++ b/js/src/builtin/temporal/PlainDate.cpp @@ -7,6 +7,7 @@ #include "builtin/temporal/PlainDate.h" #include "mozilla/Assertions.h" +#include "mozilla/Casting.h" #include "mozilla/FloatingPoint.h" #include "mozilla/Maybe.h" @@ -99,20 +100,15 @@ static bool IsValidISODate(T year, T month, T day) { // Step 3. int32_t daysInMonth = js::temporal::ISODaysInMonth(year, int32_t(month)); - // Step 4. - if (day < 1 || day > daysInMonth) { - return false; - } - - // Step 5. - return true; + // Steps 4-5. + return 1 <= day && day <= daysInMonth; } /** * IsValidISODate ( year, month, day ) */ bool js::temporal::IsValidISODate(const PlainDate& date) { - auto& [year, month, day] = date; + const auto& [year, month, day] = date; return ::IsValidISODate(year, month, day); } @@ -170,20 +166,15 @@ static bool ThrowIfInvalidISODate(JSContext* cx, T year, T month, T day) { // Step 3. int32_t daysInMonth = js::temporal::ISODaysInMonth(year, int32_t(month)); - // Step 4. - if (!ThrowIfInvalidDateValue(cx, "day", 1, daysInMonth, day)) { - return false; - } - - // Step 5. - return true; + // Steps 4-5. + return ThrowIfInvalidDateValue(cx, "day", 1, daysInMonth, day); } /** * IsValidISODate ( year, month, day ) */ bool js::temporal::ThrowIfInvalidISODate(JSContext* cx, const PlainDate& date) { - auto& [year, month, day] = date; + const auto& [year, month, day] = date; return ::ThrowIfInvalidISODate(cx, year, month, day); } @@ -201,7 +192,7 @@ bool js::temporal::ThrowIfInvalidISODate(JSContext* cx, double year, * With |overflow = "constrain"|. */ static PlainDate ConstrainISODate(const PlainDate& date) { - auto& [year, month, day] = date; + const auto& [year, month, day] = date; // Step 1.a. int32_t m = std::clamp(month, 1, 12); @@ -316,13 +307,16 @@ static PlainDateObject* CreateTemporalDate(JSContext* cx, const CallArgs& args, } // Step 5. - object->setFixedSlot(PlainDateObject::ISO_YEAR_SLOT, Int32Value(isoYear)); + object->setFixedSlot(PlainDateObject::ISO_YEAR_SLOT, + Int32Value(int32_t(isoYear))); // Step 6. - object->setFixedSlot(PlainDateObject::ISO_MONTH_SLOT, Int32Value(isoMonth)); + object->setFixedSlot(PlainDateObject::ISO_MONTH_SLOT, + Int32Value(int32_t(isoMonth))); // Step 7. - object->setFixedSlot(PlainDateObject::ISO_DAY_SLOT, Int32Value(isoDay)); + object->setFixedSlot(PlainDateObject::ISO_DAY_SLOT, + Int32Value(int32_t(isoDay))); // Step 8. object->setFixedSlot(PlainDateObject::CALENDAR_SLOT, calendar.toValue()); @@ -336,7 +330,7 @@ static PlainDateObject* CreateTemporalDate(JSContext* cx, const CallArgs& args, */ PlainDateObject* js::temporal::CreateTemporalDate( JSContext* cx, const PlainDate& date, Handle<CalendarValue> calendar) { - auto& [isoYear, isoMonth, isoDay] = date; + const auto& [isoYear, isoMonth, isoDay] = date; // Step 1. if (!ThrowIfInvalidISODate(cx, date)) { @@ -602,30 +596,28 @@ bool js::temporal::ToTemporalDate(JSContext* cx, Handle<Value> item, /** * Mathematical Operations, "modulo" notation. */ -static int32_t NonNegativeModulo(double x, int32_t y) { - MOZ_ASSERT(IsInteger(x)); +static int32_t NonNegativeModulo(int64_t x, int32_t y) { MOZ_ASSERT(y > 0); - double r = std::fmod(x, y); - - int32_t result; - MOZ_ALWAYS_TRUE(mozilla::NumberEqualsInt32(r, &result)); - + int32_t result = mozilla::AssertedCast<int32_t>(x % y); return (result < 0) ? (result + y) : result; } struct BalancedYearMonth final { - double year = 0; + int64_t year = 0; int32_t month = 0; }; /** * BalanceISOYearMonth ( year, month ) */ -static BalancedYearMonth BalanceISOYearMonth(double year, double month) { - // Step 1. - MOZ_ASSERT(IsInteger(year)); - MOZ_ASSERT(IsInteger(month)); +static BalancedYearMonth BalanceISOYearMonth(int64_t year, int64_t month) { + MOZ_ASSERT(std::abs(year) < (int64_t(1) << 33), + "year is the addition of plain-date year with duration years"); + MOZ_ASSERT(std::abs(month) < (int64_t(1) << 33), + "month is the addition of plain-date month with duration months"); + + // Step 1. (Not applicable in our implementation.) // Note: If either abs(year) or abs(month) is greater than 2^53 (the double // integral precision limit), the additions resp. subtractions below are @@ -633,18 +625,17 @@ static BalancedYearMonth BalanceISOYearMonth(double year, double month) { // function (AddISODate) will throw an error for large values anyway. // Step 2. - year = year + std::floor((month - 1) / 12); - MOZ_ASSERT(IsInteger(year) || std::isinf(year)); + int64_t balancedYear = year + temporal::FloorDiv(month - 1, 12); // Step 3. - int32_t mon = NonNegativeModulo(month - 1, 12) + 1; - MOZ_ASSERT(1 <= mon && mon <= 12); + int32_t balancedMonth = NonNegativeModulo(month - 1, 12) + 1; + MOZ_ASSERT(1 <= balancedMonth && balancedMonth <= 12); // Step 4. - return {year, mon}; + return {balancedYear, balancedMonth}; } -static bool CanBalanceISOYear(double year) { +static bool CanBalanceISOYear(int64_t year) { // TODO: Export these values somewhere. constexpr int32_t minYear = -271821; constexpr int32_t maxYear = 275760; @@ -654,7 +645,7 @@ static bool CanBalanceISOYear(double year) { return minYear <= year && year <= maxYear; } -static bool CanBalanceISODay(double day) { +static bool CanBalanceISODay(int64_t day) { // The maximum number of seconds from the epoch is 8.64 * 10^12. constexpr int64_t maxInstantSeconds = 8'640'000'000'000; @@ -684,10 +675,9 @@ PlainDate js::temporal::BalanceISODateNew(int32_t year, int32_t month, MOZ_ASSERT(1 <= month && month <= 12); // Steps 1-3. - int64_t ms = MakeDate(year, month, day); + double ms = double(MakeDate(year, month, day)); - // FIXME: spec issue - |ms| can be non-finite - // https://github.com/tc39/proposal-temporal/issues/2315 + // TODO: Add ISODateToEpochDays & friends which handle larger inputs. // TODO: This approach isn't efficient, because MonthFromTime and DayFromTime // both recompute YearFromTime. @@ -700,15 +690,19 @@ PlainDate js::temporal::BalanceISODateNew(int32_t year, int32_t month, /** * BalanceISODate ( year, month, day ) */ -bool js::temporal::BalanceISODate(JSContext* cx, int32_t year, int32_t month, - int64_t day, PlainDate* result) { +bool js::temporal::BalanceISODate(JSContext* cx, const PlainDate& date, + int64_t days, PlainDate* result) { + MOZ_ASSERT(IsValidISODate(date)); + MOZ_ASSERT(ISODateTimeWithinLimits(date)); + + int64_t day = int64_t(date.day) + days; if (!CanBalanceISODay(day)) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TEMPORAL_PLAIN_DATE_INVALID); return false; } - *result = BalanceISODate(year, month, int32_t(day)); + *result = BalanceISODate(date.year, date.month, int32_t(day)); return true; } @@ -725,9 +719,8 @@ PlainDate js::temporal::BalanceISODate(int32_t year, int32_t month, MOZ_ASSERT(1 <= month && month <= 12); MOZ_ASSERT(CanBalanceISODay(day)); - // TODO: BalanceISODate now works using MakeDate + // TODO: BalanceISODate now works using ISODateToEpochDays & friends. // TODO: Can't use JS::MakeDate, because it expects valid month/day values. - // https://github.com/tc39/proposal-temporal/issues/2315 // Step 1. (Not applicable in our implementation.) @@ -811,7 +804,7 @@ PlainDate js::temporal::BalanceISODate(int32_t year, int32_t month, * AddISODate ( year, month, day, years, months, weeks, days, overflow ) */ bool js::temporal::AddISODate(JSContext* cx, const PlainDate& date, - const Duration& duration, + const DateDuration& duration, TemporalOverflow overflow, PlainDate* result) { MOZ_ASSERT(IsValidISODate(date)); MOZ_ASSERT(ISODateTimeWithinLimits(date)); @@ -822,18 +815,11 @@ bool js::temporal::AddISODate(JSContext* cx, const PlainDate& date, // BalanceISODate. MOZ_ASSERT(IsValidDuration(duration)); - // Step 1. - MOZ_ASSERT(IsInteger(duration.years)); - MOZ_ASSERT(IsInteger(duration.months)); - MOZ_ASSERT(IsInteger(duration.weeks)); - MOZ_ASSERT(IsInteger(duration.days)); - - // Step 2. (Not applicable in our implementation.) + // Steps 1-2. (Not applicable in our implementation.) // Step 3. auto yearMonth = BalanceISOYearMonth(date.year + duration.years, date.month + duration.months); - MOZ_ASSERT(IsInteger(yearMonth.year) || std::isinf(yearMonth.year)); MOZ_ASSERT(1 <= yearMonth.month && yearMonth.month <= 12); // FIXME: spec issue? @@ -881,7 +867,7 @@ bool js::temporal::AddISODate(JSContext* cx, const PlainDate& date, // about imprecise number arithmetic here. // Steps 5-6. - double d = regulated.day + (duration.days + duration.weeks * 7); + int64_t d = regulated.day + (duration.days + duration.weeks * 7); // Just as with |yearMonth.year|, also directly throw an error if the |days| // value is too large. @@ -952,65 +938,51 @@ static bool HasYearsMonthsOrWeeks(const Duration& duration) { return duration.years != 0 || duration.months != 0 || duration.weeks != 0; } -static bool AddDate(JSContext* cx, const PlainDate& date, - const Duration& duration, Handle<JSObject*> maybeOptions, - PlainDate* result) { - MOZ_ASSERT(!HasYearsMonthsOrWeeks(duration)); +static bool HasYearsMonthsOrWeeks(const DateDuration& duration) { + return duration.years != 0 || duration.months != 0 || duration.weeks != 0; +} - // Steps 1-3. (Not applicable) +/** + * AddDate ( calendarRec, plainDate, duration [ , options ] ) + */ +static bool AddDate(JSContext* cx, const PlainDate& date, + const NormalizedDuration& duration, + TemporalOverflow overflow, PlainDate* result) { + MOZ_ASSERT(!HasYearsMonthsOrWeeks(duration.date)); + MOZ_ASSERT(IsValidDuration(duration)); - // Step 4. - auto overflow = TemporalOverflow::Constrain; - if (maybeOptions) { - if (!ToTemporalOverflow(cx, maybeOptions, &overflow)) { - return false; - } - } + // Steps 1-4. (Not applicable) - // Step 5. - TimeDuration daysDuration; - if (!BalanceTimeDuration(cx, duration, TemporalUnit::Day, &daysDuration)) { - return false; - } + // Step 5. (Not applicable) + const auto& timeDuration = duration.time; // Step 6. - return AddISODate(cx, date, {0, 0, 0, daysDuration.days}, overflow, result); + int64_t balancedDays = + BalanceTimeDuration(timeDuration, TemporalUnit::Day).days; + int64_t days = duration.date.days + balancedDays; + + // Step 7. + return AddISODate(cx, date, {0, 0, 0, days}, overflow, result); } static bool AddDate(JSContext* cx, Handle<Wrapped<PlainDateObject*>> date, - const Duration& duration, Handle<JSObject*> maybeOptions, - PlainDate* result) { + const NormalizedDuration& duration, + TemporalOverflow overflow, PlainDate* result) { auto* unwrappedDate = date.unwrap(cx); if (!unwrappedDate) { return false; } - return ::AddDate(cx, ToPlainDate(unwrappedDate), duration, maybeOptions, - result); -} - -static PlainDateObject* AddDate(JSContext* cx, Handle<CalendarRecord> calendar, - Handle<Wrapped<PlainDateObject*>> date, - const Duration& duration, - Handle<JSObject*> maybeOptions) { - // Steps 1-3. (Not applicable) - - // Steps 4-6. - PlainDate resultDate; - if (!::AddDate(cx, date, duration, maybeOptions, &resultDate)) { - return nullptr; - } - - // Step 7. - return CreateTemporalDate(cx, resultDate, calendar.receiver()); + return ::AddDate(cx, ToPlainDate(unwrappedDate), duration, overflow, result); } /** * AddDate ( calendarRec, plainDate, duration [ , options ] ) */ -Wrapped<PlainDateObject*> js::temporal::AddDate( - JSContext* cx, Handle<CalendarRecord> calendar, - Handle<Wrapped<PlainDateObject*>> date, const Duration& duration, - Handle<JSObject*> options) { +static Wrapped<PlainDateObject*> AddDate(JSContext* cx, + Handle<CalendarRecord> calendar, + Handle<Wrapped<PlainDateObject*>> date, + const Duration& duration, + Handle<JSObject*> options) { // Step 1. MOZ_ASSERT( CalendarMethodsRecordHasLookedUp(calendar, CalendarMethod::DateAdd)); @@ -1022,8 +994,23 @@ Wrapped<PlainDateObject*> js::temporal::AddDate( return temporal::CalendarDateAdd(cx, calendar, date, duration, options); } - // Steps 4-7. - return ::AddDate(cx, calendar, date, duration, options); + // Step 4. + auto overflow = TemporalOverflow::Constrain; + if (!ToTemporalOverflow(cx, options, &overflow)) { + return nullptr; + } + + // Step 5. + auto normalized = CreateNormalizedDurationRecord(duration); + + // Steps 6-7. + PlainDate resultDate; + if (!::AddDate(cx, date, normalized, overflow, &resultDate)) { + return nullptr; + } + + // Step 8. + return CreateTemporalDate(cx, resultDate, calendar.receiver()); } /** @@ -1031,7 +1018,7 @@ Wrapped<PlainDateObject*> js::temporal::AddDate( */ Wrapped<PlainDateObject*> js::temporal::AddDate( JSContext* cx, Handle<CalendarRecord> calendar, - Handle<Wrapped<PlainDateObject*>> date, const Duration& duration) { + Handle<Wrapped<PlainDateObject*>> date, const DateDuration& duration) { // Step 1. MOZ_ASSERT( CalendarMethodsRecordHasLookedUp(calendar, CalendarMethod::DateAdd)); @@ -1043,8 +1030,20 @@ Wrapped<PlainDateObject*> js::temporal::AddDate( return CalendarDateAdd(cx, calendar, date, duration); } - // Steps 4-7. - return ::AddDate(cx, calendar, date, duration, nullptr); + // Step 4. + auto overflow = TemporalOverflow::Constrain; + + // Step 5. + auto normalized = NormalizedDuration{duration}; + + // Steps 6-7. + PlainDate resultDate; + if (!::AddDate(cx, date, normalized, overflow, &resultDate)) { + return nullptr; + } + + // Step 8. + return CreateTemporalDate(cx, resultDate, calendar.receiver()); } /** @@ -1052,33 +1051,15 @@ Wrapped<PlainDateObject*> js::temporal::AddDate( */ Wrapped<PlainDateObject*> js::temporal::AddDate( JSContext* cx, Handle<CalendarRecord> calendar, - Handle<Wrapped<PlainDateObject*>> date, - Handle<Wrapped<DurationObject*>> durationObj) { - auto* unwrappedDuration = durationObj.unwrap(cx); - if (!unwrappedDuration) { - return nullptr; - } - auto duration = ToDuration(unwrappedDuration); - - // Step 1. - MOZ_ASSERT( - CalendarMethodsRecordHasLookedUp(calendar, CalendarMethod::DateAdd)); - - // Step 2. (Not applicable in our implementation.) - - // Step 3. - if (HasYearsMonthsOrWeeks(duration)) { - return CalendarDateAdd(cx, calendar, date, durationObj); - } - - // Steps 4-7. - return ::AddDate(cx, calendar, date, duration, nullptr); + Handle<Wrapped<PlainDateObject*>> date, const DateDuration& duration, + Handle<JSObject*> options) { + return ::AddDate(cx, calendar, date, duration.toDuration(), options); } /** * AddDate ( calendarRec, plainDate, duration [ , options ] ) */ -Wrapped<PlainDateObject*> js::temporal::AddDate( +static Wrapped<PlainDateObject*> AddDate( JSContext* cx, Handle<CalendarRecord> calendar, Handle<Wrapped<PlainDateObject*>> date, Handle<Wrapped<DurationObject*>> durationObj, Handle<JSObject*> options) { @@ -1099,15 +1080,30 @@ Wrapped<PlainDateObject*> js::temporal::AddDate( return temporal::CalendarDateAdd(cx, calendar, date, durationObj, options); } - // Steps 4-7. - return ::AddDate(cx, calendar, date, duration, options); + // Step 4. + auto overflow = TemporalOverflow::Constrain; + if (!ToTemporalOverflow(cx, options, &overflow)) { + return nullptr; + } + + // Step 5. + auto normalized = CreateNormalizedDurationRecord(duration); + + // Steps 6-7. + PlainDate resultDate; + if (!::AddDate(cx, date, normalized, overflow, &resultDate)) { + return nullptr; + } + + // Step 8. + return CreateTemporalDate(cx, resultDate, calendar.receiver()); } /** * AddDate ( calendarRec, plainDate, duration [ , options ] ) */ bool js::temporal::AddDate(JSContext* cx, Handle<CalendarRecord> calendar, - const PlainDate& date, const Duration& duration, + const PlainDate& date, const DateDuration& duration, Handle<JSObject*> options, PlainDate* result) { // Step 1. MOZ_ASSERT( @@ -1121,8 +1117,17 @@ bool js::temporal::AddDate(JSContext* cx, Handle<CalendarRecord> calendar, result); } - // Steps 4-7. - return ::AddDate(cx, date, duration, options, result); + // Step 4. + auto overflow = TemporalOverflow::Constrain; + if (!ToTemporalOverflow(cx, options, &overflow)) { + return false; + } + + // Step 5. + auto normalized = NormalizedDuration{duration}; + + // Steps 5-8. + return ::AddDate(cx, date, normalized, overflow, result); } /** @@ -1130,7 +1135,7 @@ bool js::temporal::AddDate(JSContext* cx, Handle<CalendarRecord> calendar, */ bool js::temporal::AddDate(JSContext* cx, Handle<CalendarRecord> calendar, Handle<Wrapped<PlainDateObject*>> date, - const Duration& duration, PlainDate* result) { + const DateDuration& duration, PlainDate* result) { // Step 1. MOZ_ASSERT( CalendarMethodsRecordHasLookedUp(calendar, CalendarMethod::DateAdd)); @@ -1142,8 +1147,14 @@ bool js::temporal::AddDate(JSContext* cx, Handle<CalendarRecord> calendar, return CalendarDateAdd(cx, calendar, date, duration, result); } - // Steps 4-7. - return ::AddDate(cx, date, duration, nullptr, result); + // Step 4. + auto overflow = TemporalOverflow::Constrain; + + // Step 5. + auto normalized = NormalizedDuration{duration}; + + // Steps 6-8. + return ::AddDate(cx, date, normalized, overflow, result); } /** @@ -1153,8 +1164,9 @@ bool js::temporal::DifferenceDate(JSContext* cx, Handle<CalendarRecord> calendar, Handle<Wrapped<PlainDateObject*>> one, Handle<Wrapped<PlainDateObject*>> two, + TemporalUnit largestUnit, Handle<PlainObject*> options, - Duration* result) { + DateDuration* result) { auto* unwrappedOne = one.unwrap(cx); if (!unwrappedOne) { return false; @@ -1172,8 +1184,7 @@ bool js::temporal::DifferenceDate(JSContext* cx, // Step 3. MOZ_ASSERT(options->staticPrototype() == nullptr); - // Step 4. - MOZ_ASSERT(options->containsPure(cx->names().largestUnit)); + // Step 4. (Not applicable in our implementation.) // Step 5. if (oneDate == twoDate) { @@ -1182,30 +1193,18 @@ bool js::temporal::DifferenceDate(JSContext* cx, } // Step 6. - Rooted<JS::Value> largestUnit(cx); - if (!GetProperty(cx, options, options, cx->names().largestUnit, - &largestUnit)) { - return false; - } - - if (largestUnit.isString()) { - bool isDay; - if (!EqualStrings(cx, largestUnit.toString(), cx->names().day, &isDay)) { - return false; - } - - if (isDay) { - // Step 6.a. - int32_t days = DaysUntil(oneDate, twoDate); + if (largestUnit == TemporalUnit::Day) { + // Step 6.a. + int32_t days = DaysUntil(oneDate, twoDate); - // Step 6.b. - *result = {0, 0, 0, double(days)}; - return true; - } + // Step 6.b. + *result = {0, 0, 0, days}; + return true; } // Step 7. - return CalendarDateUntil(cx, calendar, one, two, options, result); + return CalendarDateUntil(cx, calendar, one, two, largestUnit, options, + result); } /** @@ -1215,7 +1214,8 @@ bool js::temporal::DifferenceDate(JSContext* cx, Handle<CalendarRecord> calendar, Handle<Wrapped<PlainDateObject*>> one, Handle<Wrapped<PlainDateObject*>> two, - TemporalUnit largestUnit, Duration* result) { + TemporalUnit largestUnit, + DateDuration* result) { auto* unwrappedOne = one.unwrap(cx); if (!unwrappedOne) { return false; @@ -1242,7 +1242,69 @@ bool js::temporal::DifferenceDate(JSContext* cx, int32_t days = DaysUntil(oneDate, twoDate); // Step 6.b. - *result = {0, 0, 0, double(days)}; + *result = {0, 0, 0, days}; + return true; + } + + // Step 7. + return CalendarDateUntil(cx, calendar, one, two, largestUnit, result); +} + +/** + * DifferenceDate ( calendarRec, one, two, options ) + */ +bool js::temporal::DifferenceDate(JSContext* cx, + Handle<CalendarRecord> calendar, + const PlainDate& one, const PlainDate& two, + TemporalUnit largestUnit, + Handle<PlainObject*> options, + DateDuration* result) { + // Steps 1-4. (Not applicable in our implementation.) + + // Step 5. + if (one == two) { + *result = {}; + return true; + } + + // Step 6. + if (largestUnit == TemporalUnit::Day) { + // Step 6.a. + int32_t days = DaysUntil(one, two); + + // Step 6.b. + *result = {0, 0, 0, days}; + return true; + } + + // Step 7. + return CalendarDateUntil(cx, calendar, one, two, largestUnit, options, + result); +} + +/** + * DifferenceDate ( calendarRec, one, two, options ) + */ +bool js::temporal::DifferenceDate(JSContext* cx, + Handle<CalendarRecord> calendar, + const PlainDate& one, const PlainDate& two, + TemporalUnit largestUnit, + DateDuration* result) { + // Steps 1-4. (Not applicable in our implementation.) + + // Step 5. + if (one == two) { + *result = {}; + return true; + } + + // Step 6. + if (largestUnit == TemporalUnit::Day) { + // Step 6.a. + int32_t days = DaysUntil(one, two); + + // Step 6.b. + *result = {0, 0, 0, days}; return true; } @@ -1280,8 +1342,8 @@ int32_t js::temporal::CompareISODate(const PlainDate& one, static DateDuration CreateDateDurationRecord(int32_t years, int32_t months, int32_t weeks, int32_t days) { MOZ_ASSERT(IsValidDuration( - {double(years), double(months), double(weeks), double(days)})); - return {double(years), double(months), double(weeks), double(days)}; + Duration{double(years), double(months), double(weeks), double(days)})); + return {years, months, weeks, days}; } /** @@ -1577,31 +1639,19 @@ static bool DifferenceTemporalPlainDate(JSContext* cx, } // Steps 8-9. - Duration duration; + DateDuration difference; if (resolvedOptions) { - // Step 8. - Rooted<Value> largestUnitValue( - cx, StringValue(TemporalUnitToString(cx, settings.largestUnit))); - if (!DefineDataProperty(cx, resolvedOptions, cx->names().largestUnit, - largestUnitValue)) { - return false; - } - - // Step 9. - Duration result; - if (!DifferenceDate(cx, calendar, temporalDate, other, resolvedOptions, - &result)) { + // Steps 8-9. + if (!DifferenceDate(cx, calendar, temporalDate, other, settings.largestUnit, + resolvedOptions, &difference)) { return false; } - duration = result.date(); } else { // Steps 8-9. - Duration result; if (!DifferenceDate(cx, calendar, temporalDate, other, settings.largestUnit, - &result)) { + &difference)) { return false; } - duration = result.date(); } // Step 10. @@ -1611,8 +1661,8 @@ static bool DifferenceTemporalPlainDate(JSContext* cx, // Step 11. if (!roundingGranularityIsNoop) { // Steps 11.a-b. - Duration roundResult; - if (!temporal::RoundDuration(cx, duration.date(), + NormalizedDuration roundResult; + if (!temporal::RoundDuration(cx, {difference, {}}, settings.roundingIncrement, settings.smallestUnit, settings.roundingMode, temporalDate, calendar, &roundResult)) { @@ -1622,19 +1672,21 @@ static bool DifferenceTemporalPlainDate(JSContext* cx, // Step 11.c. DateDuration balanceResult; if (!temporal::BalanceDateDurationRelative( - cx, roundResult.date(), settings.largestUnit, settings.smallestUnit, + cx, roundResult.date, settings.largestUnit, settings.smallestUnit, temporalDate, calendar, &balanceResult)) { return false; } - duration = balanceResult.toDuration(); + difference = balanceResult; } // Step 12. + auto duration = difference.toDuration(); if (operation == TemporalDifference::Since) { duration = duration.negate(); } + MOZ_ASSERT(IsValidDuration(duration)); - auto* obj = CreateTemporalDuration(cx, duration.date()); + auto* obj = CreateTemporalDuration(cx, duration); if (!obj) { return false; } @@ -2235,14 +2287,14 @@ static bool PlainDate_toPlainDateTime(JSContext* cx, const CallArgs& args) { // Default initialize the time component to all zero. PlainDateTime dateTime = {ToPlainDate(temporalDate), {}}; - // Step 4. (Reordered) + // Step 3. (Inlined ToTemporalTimeOrMidnight) if (args.hasDefined(0)) { if (!ToTemporalTime(cx, args[0], &dateTime.time)) { return false; } } - // Steps 3 and 5. + // Step 4. auto* obj = CreateTemporalDateTime(cx, dateTime, calendar); if (!obj) { return false; @@ -2433,8 +2485,7 @@ static bool PlainDate_subtract(JSContext* cx, const CallArgs& args) { } // Step 7. - auto result = - temporal::AddDate(cx, calendar, temporalDate, negatedDuration, options); + auto result = ::AddDate(cx, calendar, temporalDate, negatedDuration, options); if (!result) { return false; } @@ -2465,13 +2516,11 @@ static bool PlainDate_with(JSContext* cx, const CallArgs& args) { if (!temporalDateLike) { return false; } - - // Step 4. - if (!RejectTemporalLikeObject(cx, temporalDateLike)) { + if (!ThrowIfTemporalLikeObject(cx, temporalDateLike)) { return false; } - // Step 5. + // Step 4. Rooted<PlainObject*> resolvedOptions(cx); if (args.hasDefined(1)) { Rooted<JSObject*> options(cx, @@ -2487,7 +2536,7 @@ static bool PlainDate_with(JSContext* cx, const CallArgs& args) { return false; } - // Step 6. + // Step 5. Rooted<CalendarValue> calendarValue(cx, temporalDate->calendar()); Rooted<CalendarRecord> calendar(cx); if (!CreateCalendarMethodsRecord(cx, calendarValue, @@ -2500,7 +2549,7 @@ static bool PlainDate_with(JSContext* cx, const CallArgs& args) { return false; } - // Step 7. + // Step 6. JS::RootedVector<PropertyKey> fieldNames(cx); if (!CalendarFields(cx, calendar, {CalendarField::Day, CalendarField::Month, @@ -2509,34 +2558,34 @@ static bool PlainDate_with(JSContext* cx, const CallArgs& args) { return false; } - // Step 8. + // Step 7. Rooted<PlainObject*> fields( cx, PrepareTemporalFields(cx, temporalDate, fieldNames)); if (!fields) { return false; } - // Step 9. + // Step 8. Rooted<PlainObject*> partialDate( cx, PreparePartialTemporalFields(cx, temporalDateLike, fieldNames)); if (!partialDate) { return false; } - // Step 10. + // Step 9. Rooted<JSObject*> mergedFields( cx, CalendarMergeFields(cx, calendar, fields, partialDate)); if (!mergedFields) { return false; } - // Step 11. + // Step 10. fields = PrepareTemporalFields(cx, mergedFields, fieldNames); if (!fields) { return false; } - // Step 12. + // Step 11. auto result = temporal::CalendarDateFromFields(cx, calendar, fields, resolvedOptions); if (!result) { @@ -2677,7 +2726,7 @@ static bool PlainDate_toZonedDateTime(JSContext* cx, const CallArgs& args) { // Steps 3-4 Rooted<TimeZoneValue> timeZone(cx); - Rooted<Value> temporalTime(cx); + PlainTime time = {}; if (args.get(0).isObject()) { Rooted<JSObject*> item(cx, &args[0].toObject()); @@ -2686,8 +2735,7 @@ static bool PlainDate_toZonedDateTime(JSContext* cx, const CallArgs& args) { // Step 3.a.i. timeZone.set(TimeZoneValue(item)); - // Step 3.a.ii. - temporalTime.setUndefined(); + // Step 3.a.ii. (Not applicable in our implementation.) } else { // Step 3.b.i. Rooted<Value> timeZoneLike(cx); @@ -2702,8 +2750,7 @@ static bool PlainDate_toZonedDateTime(JSContext* cx, const CallArgs& args) { return false; } - // Step 3.b.ii.2. - temporalTime.setUndefined(); + // Step 3.b.ii.2. (Not applicable in our implementation.) } else { // Step 3.b.iii.1. if (!ToTemporalTimeZone(cx, timeZoneLike, &timeZone)) { @@ -2711,10 +2758,18 @@ static bool PlainDate_toZonedDateTime(JSContext* cx, const CallArgs& args) { } // Step 3.b.iii.2. + Rooted<Value> temporalTime(cx); if (!GetProperty(cx, item, item, cx->names().plainTime, &temporalTime)) { return false; } + + // Step 5. (Inlined ToTemporalTimeOrMidnight) + if (!temporalTime.isUndefined()) { + if (!ToTemporalTime(cx, temporalTime, &time)) { + return false; + } + } } } } else { @@ -2723,19 +2778,12 @@ static bool PlainDate_toZonedDateTime(JSContext* cx, const CallArgs& args) { return false; } - // Step 4.b. - temporalTime.setUndefined(); + // Step 4.b. (Not applicable in our implementation.) } - // Step 6.a. - PlainTime time = {}; - if (!temporalTime.isUndefined()) { - if (!ToTemporalTime(cx, temporalTime, &time)) { - return false; - } - } + // Step 5. (Moved next to step 3.b.iii.2.) - // Steps 5.a and 6.b + // Step 6. Rooted<PlainDateTimeWithCalendar> temporalDateTime(cx); if (!CreateTemporalDateTime(cx, {date, time}, calendar, &temporalDateTime)) { return false; |