tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit eb638c7567b660380c749854a1ced136bdb31de8
parent c28ce896b1e416ee498ff64a8e2ff061e3dd56d6
Author: André Bargull <andre.bargull@gmail.com>
Date:   Thu, 27 Nov 2025 10:03:34 +0000

Bug 1999315 - Part 2: Split ISO and non-ISO calendar operations. r=spidermonkey-reviewers,dminor

Implements the editorial changes from <https://github.com/tc39/proposal-temporal/pull/3140>.

Differential Revision: https://phabricator.services.mozilla.com/D272022

Diffstat:
Mjs/src/builtin/temporal/Calendar.cpp | 223+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mjs/src/builtin/temporal/CalendarFields.cpp | 55+++++++++++++++++++++++++++++++------------------------
2 files changed, 165 insertions(+), 113 deletions(-)

diff --git a/js/src/builtin/temporal/Calendar.cpp b/js/src/builtin/temporal/Calendar.cpp @@ -2140,38 +2140,12 @@ static bool RegulateISODate(JSContext* cx, int32_t year, double month, } /** - * CalendarDateToISO ( calendar, fields, overflow ) + * NonISOCalendarDateToISO ( calendar, fields, overflow ) */ -static bool CalendarDateToISO(JSContext* cx, CalendarId calendar, - Handle<CalendarFields> fields, - TemporalOverflow overflow, ISODate* result) { - // Step 1. - if (calendar == CalendarId::ISO8601) { - // Step 1.a. - MOZ_ASSERT(fields.has(CalendarField::Year)); - MOZ_ASSERT(fields.has(CalendarField::Month) || - fields.has(CalendarField::MonthCode)); - MOZ_ASSERT(fields.has(CalendarField::Day)); - - // Remaining steps from CalendarResolveFields to resolve the month. - double month; - if (!ISOCalendarResolveMonth(cx, fields, &month)) { - return false; - } - - int32_t intYear; - if (!mozilla::NumberEqualsInt32(fields.year(), &intYear)) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_TEMPORAL_PLAIN_DATE_INVALID); - return false; - } - - // Step 1.b. - return RegulateISODate(cx, intYear, month, fields.day(), overflow, result); - } - - // Step 2. - +static bool NonISOCalendarDateToISO(JSContext* cx, CalendarId calendar, + Handle<CalendarFields> fields, + TemporalOverflow overflow, + ISODate* result) { EraYears eraYears; if (!CalendarFieldYear(cx, calendar, fields, &eraYears)) { return false; @@ -2199,16 +2173,15 @@ static bool CalendarDateToISO(JSContext* cx, CalendarId calendar, } /** - * CalendarMonthDayToISOReferenceDate ( calendar, fields, overflow ) + * CalendarDateToISO ( calendar, fields, overflow ) */ -static bool CalendarMonthDayToISOReferenceDate(JSContext* cx, - CalendarId calendar, - Handle<CalendarFields> fields, - TemporalOverflow overflow, - ISODate* result) { +static bool CalendarDateToISO(JSContext* cx, CalendarId calendar, + Handle<CalendarFields> fields, + TemporalOverflow overflow, ISODate* result) { // Step 1. if (calendar == CalendarId::ISO8601) { // Step 1.a. + MOZ_ASSERT(fields.has(CalendarField::Year)); MOZ_ASSERT(fields.has(CalendarField::Month) || fields.has(CalendarField::MonthCode)); MOZ_ASSERT(fields.has(CalendarField::Day)); @@ -2219,33 +2192,28 @@ static bool CalendarMonthDayToISOReferenceDate(JSContext* cx, return false; } - // Step 1.b. - int32_t referenceISOYear = 1972; - - // Step 1.c. - double year = - !fields.has(CalendarField::Year) ? referenceISOYear : fields.year(); - int32_t intYear; - if (!mozilla::NumberEqualsInt32(year, &intYear)) { - // Calendar cycles repeat every 400 years in the Gregorian calendar. - intYear = int32_t(std::fmod(year, 400)); - } - - // Step 1.d. - ISODate regulated; - if (!RegulateISODate(cx, intYear, month, fields.day(), overflow, - &regulated)) { + if (!mozilla::NumberEqualsInt32(fields.year(), &intYear)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_TEMPORAL_PLAIN_DATE_INVALID); return false; } - // Step 1.e. - *result = {referenceISOYear, regulated.month, regulated.day}; - return true; + // Step 1.b. + return RegulateISODate(cx, intYear, month, fields.day(), overflow, result); } // Step 2. + return NonISOCalendarDateToISO(cx, calendar, fields, overflow, result); +} +/** + * NonISOMonthDayToISOReferenceDate ( calendar, fields, overflow ) + */ +static bool NonISOMonthDayToISOReferenceDate(JSContext* cx, CalendarId calendar, + Handle<CalendarFields> fields, + TemporalOverflow overflow, + ISODate* result) { EraYears eraYears; if (fields.has(CalendarField::Year) || fields.has(CalendarField::EraYear)) { if (!CalendarFieldYear(cx, calendar, fields, &eraYears)) { @@ -2419,43 +2387,64 @@ static bool CalendarMonthDayToISOReferenceDate(JSContext* cx, return true; } -enum class FieldType { Date, YearMonth, MonthDay }; - /** - * CalendarResolveFields ( calendar, fields, type ) + * CalendarMonthDayToISOReferenceDate ( calendar, fields, overflow ) */ -static bool CalendarResolveFields(JSContext* cx, CalendarId calendar, - Handle<CalendarFields> fields, - FieldType type) { +static bool CalendarMonthDayToISOReferenceDate(JSContext* cx, + CalendarId calendar, + Handle<CalendarFields> fields, + TemporalOverflow overflow, + ISODate* result) { // Step 1. if (calendar == CalendarId::ISO8601) { - // Steps 1.a-e. - const char* missingField = nullptr; - if ((type == FieldType::Date || type == FieldType::YearMonth) && - !fields.has(CalendarField::Year)) { - missingField = "year"; - } else if ((type == FieldType::Date || type == FieldType::MonthDay) && - !fields.has(CalendarField::Day)) { - missingField = "day"; - } else if (!fields.has(CalendarField::MonthCode) && - !fields.has(CalendarField::Month)) { - missingField = "month"; - } + // Step 1.a. + MOZ_ASSERT(fields.has(CalendarField::Month) || + fields.has(CalendarField::MonthCode)); + MOZ_ASSERT(fields.has(CalendarField::Day)); - if (missingField) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_TEMPORAL_CALENDAR_MISSING_FIELD, - missingField); + // Remaining steps from CalendarResolveFields to resolve the month. + double month; + if (!ISOCalendarResolveMonth(cx, fields, &month)) { return false; } - // Steps 1.f-n. (Handled in ISOCalendarResolveMonth.) + // Step 1.b. + int32_t referenceISOYear = 1972; + + // Step 1.c. + double year = + !fields.has(CalendarField::Year) ? referenceISOYear : fields.year(); + + int32_t intYear; + if (!mozilla::NumberEqualsInt32(year, &intYear)) { + // Calendar cycles repeat every 400 years in the Gregorian calendar. + intYear = int32_t(std::fmod(year, 400)); + } + + // Step 1.d. + ISODate regulated; + if (!RegulateISODate(cx, intYear, month, fields.day(), overflow, + &regulated)) { + return false; + } + // Step 1.e. + *result = {referenceISOYear, regulated.month, regulated.day}; return true; } // Step 2. + return NonISOMonthDayToISOReferenceDate(cx, calendar, fields, overflow, + result); +} + +enum class FieldType { Date, YearMonth, MonthDay }; +/** + * NonISOResolveFields ( calendar, fields, type ) + */ +static bool NonISOResolveFields(JSContext* cx, CalendarId calendar, + Handle<CalendarFields> fields, FieldType type) { // Date and Month-Day require |day| to be present. bool requireDay = type == FieldType::Date || type == FieldType::MonthDay; @@ -2497,7 +2486,45 @@ static bool CalendarResolveFields(JSContext* cx, CalendarId calendar, } /** + * CalendarResolveFields ( calendar, fields, type ) + */ +static bool CalendarResolveFields(JSContext* cx, CalendarId calendar, + Handle<CalendarFields> fields, + FieldType type) { + // Step 1. + if (calendar == CalendarId::ISO8601) { + // Steps 1.a-e. + const char* missingField = nullptr; + if ((type == FieldType::Date || type == FieldType::YearMonth) && + !fields.has(CalendarField::Year)) { + missingField = "year"; + } else if ((type == FieldType::Date || type == FieldType::MonthDay) && + !fields.has(CalendarField::Day)) { + missingField = "day"; + } else if (!fields.has(CalendarField::MonthCode) && + !fields.has(CalendarField::Month)) { + missingField = "month"; + } + + if (missingField) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_TEMPORAL_CALENDAR_MISSING_FIELD, + missingField); + return false; + } + + // Steps 1.f-n. (Handled in ISOCalendarResolveMonth.) + + return true; + } + + // Step 2. + return NonISOResolveFields(cx, calendar, fields, type); +} + +/** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[Era]] field. */ @@ -2540,6 +2567,7 @@ bool js::temporal::CalendarEra(JSContext* cx, Handle<CalendarValue> calendar, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[EraYear]] field. */ @@ -2574,6 +2602,7 @@ bool js::temporal::CalendarEraYear(JSContext* cx, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[Year]] field. */ @@ -2606,6 +2635,7 @@ bool js::temporal::CalendarYear(JSContext* cx, Handle<CalendarValue> calendar, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[Month]] field. */ @@ -2634,6 +2664,7 @@ bool js::temporal::CalendarMonth(JSContext* cx, Handle<CalendarValue> calendar, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[MonthCode]] field. */ @@ -2679,6 +2710,7 @@ bool js::temporal::CalendarMonthCode(JSContext* cx, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[Day]] field. */ @@ -2707,6 +2739,7 @@ bool js::temporal::CalendarDay(JSContext* cx, Handle<CalendarValue> calendar, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[DayOfWeek]] field. */ @@ -2745,6 +2778,7 @@ bool js::temporal::CalendarDayOfWeek(JSContext* cx, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[DayOfYear]] field. */ @@ -2806,6 +2840,7 @@ bool js::temporal::CalendarDayOfYear(JSContext* cx, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[WeekOfYear]].[[Week]] field. */ @@ -2833,6 +2868,7 @@ bool js::temporal::CalendarWeekOfYear(JSContext* cx, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[WeekOfYear]].[[Year]] field. */ @@ -2860,6 +2896,7 @@ bool js::temporal::CalendarYearOfWeek(JSContext* cx, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[DaysInWeek]] field. */ @@ -2880,6 +2917,7 @@ bool js::temporal::CalendarDaysInWeek(JSContext* cx, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[DaysInMonth]] field. */ @@ -2909,6 +2947,7 @@ bool js::temporal::CalendarDaysInMonth(JSContext* cx, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[DaysInYear]] field. */ @@ -2938,6 +2977,7 @@ bool js::temporal::CalendarDaysInYear(JSContext* cx, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[MonthsInYear]] field. */ @@ -2967,6 +3007,7 @@ bool js::temporal::CalendarMonthsInYear(JSContext* cx, /** * CalendarISOToDate ( calendar, isoDate ) + * NonISOCalendarISOToDate ( calendar, isoDate ) * * Return the Calendar Date Record's [[InLeapYear]] field. */ @@ -3633,10 +3674,12 @@ static bool AddNonISODate(JSContext* cx, CalendarId calendarId, return true; } -static bool AddCalendarDate(JSContext* cx, CalendarId calendarId, - const ISODate& isoDate, - const DateDuration& duration, - TemporalOverflow overflow, ISODate* result) { +/** + * NonISODateAdd ( calendar, isoDate, duration, overflow ) + */ +static bool NonISODateAdd(JSContext* cx, CalendarId calendarId, + const ISODate& isoDate, const DateDuration& duration, + TemporalOverflow overflow, ISODate* result) { // ICU4X doesn't yet provide a public API for CalendarDateAdd. // // https://github.com/unicode-org/icu4x/issues/3964 @@ -3696,7 +3739,7 @@ bool js::temporal::CalendarDateAdd(JSContext* cx, return false; } } else { - if (!AddCalendarDate(cx, calendarId, isoDate, duration, overflow, result)) { + if (!NonISODateAdd(cx, calendarId, isoDate, duration, overflow, result)) { return false; } } @@ -4028,10 +4071,12 @@ static bool DifferenceNonISODate(JSContext* cx, CalendarId calendarId, return true; } -static bool DifferenceCalendarDate(JSContext* cx, CalendarId calendarId, - const ISODate& one, const ISODate& two, - TemporalUnit largestUnit, - DateDuration* result) { +/** + * NonISODateUntil ( calendar, one, two, largestUnit ) + */ +static bool NonISODateUntil(JSContext* cx, CalendarId calendarId, + const ISODate& one, const ISODate& two, + TemporalUnit largestUnit, DateDuration* result) { // ICU4X doesn't yet provide a public API for CalendarDateUntil. // // https://github.com/unicode-org/icu4x/issues/3964 @@ -4093,5 +4138,5 @@ bool js::temporal::CalendarDateUntil(JSContext* cx, } // Step 2. - return DifferenceCalendarDate(cx, calendarId, one, two, largestUnit, result); + return NonISODateUntil(cx, calendarId, one, two, largestUnit, result); } diff --git a/js/src/builtin/temporal/CalendarFields.cpp b/js/src/builtin/temporal/CalendarFields.cpp @@ -545,31 +545,10 @@ bool js::temporal::PreparePartialCalendarFields( } /** - * CalendarFieldKeysToIgnore ( calendar, keys ) + * NonISOFieldKeysToIgnore ( calendar, keys ) */ -static auto CalendarFieldKeysToIgnore(CalendarId calendar, - mozilla::EnumSet<CalendarField> keys) { - // Step 1. - if (calendar == CalendarId::ISO8601) { - // Steps 1.a and 1.b.i. - auto ignoredKeys = keys; - - // Step 1.b.ii. - if (keys.contains(CalendarField::Month)) { - ignoredKeys += CalendarField::MonthCode; - } - - // Step 1.b.iii. - else if (keys.contains(CalendarField::MonthCode)) { - ignoredKeys += CalendarField::Month; - } - - // Steps 1.c-d. - return ignoredKeys; - } - - // Step 2. - +static auto NonISOFieldKeysToIgnore(CalendarId calendar, + mozilla::EnumSet<CalendarField> keys) { static constexpr auto eraOrEraYear = mozilla::EnumSet{ CalendarField::Era, CalendarField::EraYear, @@ -618,6 +597,34 @@ static auto CalendarFieldKeysToIgnore(CalendarId calendar, } /** + * CalendarFieldKeysToIgnore ( calendar, keys ) + */ +static auto CalendarFieldKeysToIgnore(CalendarId calendar, + mozilla::EnumSet<CalendarField> keys) { + // Step 1. + if (calendar == CalendarId::ISO8601) { + // Steps 1.a and 1.b.i. + auto ignoredKeys = keys; + + // Step 1.b.ii. + if (keys.contains(CalendarField::Month)) { + ignoredKeys += CalendarField::MonthCode; + } + + // Step 1.b.iii. + else if (keys.contains(CalendarField::MonthCode)) { + ignoredKeys += CalendarField::Month; + } + + // Steps 1.c-d. + return ignoredKeys; + } + + // Step 2. + return NonISOFieldKeysToIgnore(calendar, keys); +} + +/** * CalendarMergeFields ( calendar, fields, additionalFields ) */ CalendarFields js::temporal::CalendarMergeFields(