summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/temporal/PlainYearMonth.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/builtin/temporal/PlainYearMonth.cpp')
-rw-r--r--js/src/builtin/temporal/PlainYearMonth.cpp216
1 files changed, 95 insertions, 121 deletions
diff --git a/js/src/builtin/temporal/PlainYearMonth.cpp b/js/src/builtin/temporal/PlainYearMonth.cpp
index b95efd3179..c28277e2be 100644
--- a/js/src/builtin/temporal/PlainYearMonth.cpp
+++ b/js/src/builtin/temporal/PlainYearMonth.cpp
@@ -111,7 +111,7 @@ static PlainYearMonthObject* CreateTemporalYearMonth(
// testing |referenceISODay|?
// Step 2.
- if (!ISOYearMonthWithinLimits(isoYear, isoMonth)) {
+ if (!ISOYearMonthWithinLimits(isoYear, int32_t(isoMonth))) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_TEMPORAL_PLAIN_YEAR_MONTH_INVALID);
return nullptr;
@@ -130,16 +130,19 @@ static PlainYearMonthObject* CreateTemporalYearMonth(
}
// Step 5.
- obj->setFixedSlot(PlainYearMonthObject::ISO_YEAR_SLOT, Int32Value(isoYear));
+ obj->setFixedSlot(PlainYearMonthObject::ISO_YEAR_SLOT,
+ Int32Value(int32_t(isoYear)));
// Step 6.
- obj->setFixedSlot(PlainYearMonthObject::ISO_MONTH_SLOT, Int32Value(isoMonth));
+ obj->setFixedSlot(PlainYearMonthObject::ISO_MONTH_SLOT,
+ Int32Value(int32_t(isoMonth)));
// Step 7.
obj->setFixedSlot(PlainYearMonthObject::CALENDAR_SLOT, calendar.toValue());
// Step 8.
- obj->setFixedSlot(PlainYearMonthObject::ISO_DAY_SLOT, Int32Value(isoDay));
+ obj->setFixedSlot(PlainYearMonthObject::ISO_DAY_SLOT,
+ Int32Value(int32_t(isoDay)));
// Step 9.
return obj;
@@ -151,7 +154,7 @@ static PlainYearMonthObject* CreateTemporalYearMonth(
*/
PlainYearMonthObject* js::temporal::CreateTemporalYearMonth(
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)) {
@@ -251,8 +254,8 @@ static Wrapped<PlainYearMonthObject*> ToTemporalYearMonth(
// Step 3.f.
if (maybeResolvedOptions) {
- return CalendarYearMonthFromFields(cx, calendar, fields,
- maybeResolvedOptions);
+ return temporal::CalendarYearMonthFromFields(cx, calendar, fields,
+ maybeResolvedOptions);
}
return CalendarYearMonthFromFields(cx, calendar, fields);
}
@@ -420,9 +423,6 @@ static bool DifferenceTemporalPlainYearMonth(JSContext* cx,
}
// Step 8.
- // FIXME: spec issue - duplicate CreateDataPropertyOrThrow for "largestUnit".
-
- // Step 9.
Rooted<CalendarRecord> calendarRec(cx);
if (!CreateCalendarMethodsRecord(cx, calendar,
{
@@ -435,7 +435,7 @@ static bool DifferenceTemporalPlainYearMonth(JSContext* cx,
return false;
}
- // Step 10.
+ // Step 9.
JS::RootedVector<PropertyKey> fieldNames(cx);
if (!CalendarFields(cx, calendarRec,
{CalendarField::MonthCode, CalendarField::Year},
@@ -443,101 +443,92 @@ static bool DifferenceTemporalPlainYearMonth(JSContext* cx,
return false;
}
- // Step 11.
+ // Step 10.
Rooted<PlainObject*> thisFields(
cx, PrepareTemporalFields(cx, yearMonth, fieldNames));
if (!thisFields) {
return false;
}
- // Step 12.
+ // Step 11.
Value one = Int32Value(1);
auto handleOne = Handle<Value>::fromMarkedLocation(&one);
if (!DefineDataProperty(cx, thisFields, cx->names().day, handleOne)) {
return false;
}
- // Step 13.
+ // Step 12.
Rooted<Wrapped<PlainDateObject*>> thisDate(
cx, CalendarDateFromFields(cx, calendarRec, thisFields));
if (!thisDate) {
return false;
}
- // Step 14.
+ // Step 13.
Rooted<PlainObject*> otherFields(
cx, PrepareTemporalFields(cx, other, fieldNames));
if (!otherFields) {
return false;
}
- // Step 15.
+ // Step 14.
if (!DefineDataProperty(cx, otherFields, cx->names().day, handleOne)) {
return false;
}
- // Step 16.
+ // Step 15.
Rooted<Wrapped<PlainDateObject*>> otherDate(
cx, CalendarDateFromFields(cx, calendarRec, otherFields));
if (!otherDate) {
return false;
}
- // Steps 17-18.
- Duration result;
+ // Steps 16-17.
+ DateDuration until;
if (resolvedOptions) {
- // Step 17.
- Rooted<Value> largestUnitValue(
- cx, StringValue(TemporalUnitToString(cx, settings.largestUnit)));
- if (!DefineDataProperty(cx, resolvedOptions, cx->names().largestUnit,
- largestUnitValue)) {
- return false;
- }
-
- // Step 18.
if (!CalendarDateUntil(cx, calendarRec, thisDate, otherDate,
- resolvedOptions, &result)) {
+ settings.largestUnit, resolvedOptions, &until)) {
return false;
}
} else {
- // Steps 17-18.
if (!CalendarDateUntil(cx, calendarRec, thisDate, otherDate,
- settings.largestUnit, &result)) {
+ settings.largestUnit, &until)) {
return false;
}
}
// We only care about years and months here, all other fields are set to zero.
- Duration duration = {result.years, result.months};
+ auto dateDuration = DateDuration{until.years, until.months};
- // Step 19.
+ // Step 18.
if (settings.smallestUnit != TemporalUnit::Month ||
settings.roundingIncrement != Increment{1}) {
- // Steps 19.a-b.
- Duration roundResult;
- if (!RoundDuration(cx, duration, settings.roundingIncrement,
+ // Steps 18.a-b.
+ NormalizedDuration roundResult;
+ if (!RoundDuration(cx, {dateDuration, {}}, settings.roundingIncrement,
settings.smallestUnit, settings.roundingMode, thisDate,
calendarRec, &roundResult)) {
return false;
}
- // Step 19.c.
- auto toBalance = Duration{roundResult.years, roundResult.months};
- DateDuration balanceResult;
+ // Step 18.c.
+ auto toBalance =
+ DateDuration{roundResult.date.years, roundResult.date.months};
if (!temporal::BalanceDateDurationRelative(
cx, toBalance, settings.largestUnit, settings.smallestUnit,
- thisDate, calendarRec, &balanceResult)) {
+ thisDate, calendarRec, &dateDuration)) {
return false;
}
- duration = balanceResult.toDuration();
}
- // Step 20.
+ // Step 19.
+ auto duration =
+ Duration{double(dateDuration.years), double(dateDuration.months)};
if (operation == TemporalDifference::Since) {
duration = duration.negate();
}
- auto* obj = CreateTemporalDuration(cx, {duration.years, duration.months});
+ auto* obj = CreateTemporalDuration(cx, duration);
if (!obj) {
return false;
}
@@ -569,16 +560,37 @@ static bool AddDurationToOrSubtractDurationFromPlainYearMonth(
}
// Step 3.
- TimeDuration balanceResult;
- if (!BalanceTimeDuration(cx, duration, TemporalUnit::Day, &balanceResult)) {
+ Rooted<JSObject*> options(cx);
+ if (args.hasDefined(1)) {
+ const char* name =
+ operation == PlainYearMonthDuration::Add ? "add" : "subtract";
+ options = RequireObjectArg(cx, "options", name, args[1]);
+ } else {
+ // TODO: Avoid creating an options object if not necessary.
+ options = NewPlainObjectWithProto(cx, nullptr);
+ }
+ if (!options) {
return false;
}
// Step 4.
- int32_t sign = DurationSign(
- {duration.years, duration.months, duration.weeks, balanceResult.days});
+ auto timeDuration = NormalizeTimeDuration(duration);
// Step 5.
+ auto balancedTime = BalanceTimeDuration(timeDuration, TemporalUnit::Day);
+
+ // Steps 6 and 16. (Reordered)
+ auto durationToAdd = DateDuration{
+ int64_t(duration.years),
+ int64_t(duration.months),
+ int64_t(duration.weeks),
+ int64_t(duration.days) + balancedTime.days,
+ };
+
+ // Step 7.
+ int32_t sign = DurationSign(durationToAdd);
+
+ // Step 8.
Rooted<CalendarValue> calendarValue(cx, yearMonth->calendar());
Rooted<CalendarRecord> calendar(cx);
if (!CreateCalendarMethodsRecord(cx, calendarValue,
@@ -593,7 +605,7 @@ static bool AddDurationToOrSubtractDurationFromPlainYearMonth(
return false;
};
- // Step 6.
+ // Step 9.
JS::RootedVector<PropertyKey> fieldNames(cx);
if (!CalendarFields(cx, calendar,
{CalendarField::MonthCode, CalendarField::Year},
@@ -601,34 +613,34 @@ static bool AddDurationToOrSubtractDurationFromPlainYearMonth(
return false;
}
- // Step 7.
+ // Step 10.
Rooted<PlainObject*> fields(cx,
PrepareTemporalFields(cx, yearMonth, fieldNames));
if (!fields) {
return false;
}
- // Step 8.
+ // Step 11.
Rooted<PlainObject*> fieldsCopy(cx, SnapshotOwnProperties(cx, fields));
if (!fieldsCopy) {
return false;
}
- // Step 9.
+ // Step 12.
Value one = Int32Value(1);
auto handleOne = Handle<Value>::fromMarkedLocation(&one);
if (!DefineDataProperty(cx, fields, cx->names().day, handleOne)) {
return false;
}
- // Step 10.
+ // Step 13.
Rooted<Wrapped<PlainDateObject*>> intermediateDate(
cx, CalendarDateFromFields(cx, calendar, fields));
if (!intermediateDate) {
return false;
}
- // Steps 11-12.
+ // Steps 14-15.
Rooted<Wrapped<PlainDateObject*>> date(cx);
if (sign < 0) {
// |intermediateDate| is initialized to the first day of |yearMonth|'s
@@ -645,10 +657,10 @@ static bool AddDurationToOrSubtractDurationFromPlainYearMonth(
// some days are skipped, for example consider the Julian-to-Gregorian
// calendar transition.
- // Step 11.a.
- Duration oneMonthDuration = {0, 1};
+ // Step 14.a.
+ auto oneMonthDuration = DateDuration{0, 1};
- // Step 11.b.
+ // Step 14.b.
Rooted<Wrapped<PlainDateObject*>> nextMonth(
cx, CalendarDateAdd(cx, calendar, intermediateDate, oneMonthDuration));
if (!nextMonth) {
@@ -661,87 +673,63 @@ static bool AddDurationToOrSubtractDurationFromPlainYearMonth(
}
auto nextMonthDate = ToPlainDate(unwrappedNextMonth);
- // Step 11.c.
- PlainDate endOfMonthISO;
- if (!AddISODate(cx, nextMonthDate, {0, 0, 0, -1},
- TemporalOverflow::Constrain, &endOfMonthISO)) {
- return false;
- }
+ // Step 14.c.
+ auto endOfMonthISO = BalanceISODate(nextMonthDate.year, nextMonthDate.month,
+ nextMonthDate.day - 1);
- // Step 11.d.
+ // Step 14.d.
Rooted<PlainDateWithCalendar> endOfMonth(cx);
if (!CreateTemporalDate(cx, endOfMonthISO, calendar.receiver(),
&endOfMonth)) {
return false;
}
- // Step 11.e.
+ // Step 14.e.
Rooted<Value> day(cx);
if (!CalendarDay(cx, calendar, endOfMonth.date(), &day)) {
return false;
}
- // Step 11.f.
+ // Step 14.f.
if (!DefineDataProperty(cx, fieldsCopy, cx->names().day, day)) {
return false;
}
- // Step 11.g.
+ // Step 14.g.
date = CalendarDateFromFields(cx, calendar, fieldsCopy);
if (!date) {
return false;
}
} else {
- // Step 12.a.
+ // Step 15.a.
date = intermediateDate;
}
- // Step 13.
- Duration durationToAdd = {duration.years, duration.months, duration.weeks,
- balanceResult.days};
-
- // FIXME: spec issue - GetOptionsObject should be called after
- // ToTemporalDurationRecord to validate the input type before performing any
- // other user-visible operations.
- // https://github.com/tc39/proposal-temporal/issues/2721
-
- // Step 14.
- Rooted<JSObject*> options(cx);
- if (args.hasDefined(1)) {
- const char* name =
- operation == PlainYearMonthDuration::Add ? "add" : "subtract";
- options = RequireObjectArg(cx, "options", name, args[1]);
- } else {
- // TODO: Avoid creating an options object if not necessary.
- options = NewPlainObjectWithProto(cx, nullptr);
- }
- if (!options) {
- return false;
- }
+ // Step 16. (Moved above)
- // Step 15.
+ // Step 17.
Rooted<PlainObject*> optionsCopy(cx, SnapshotOwnProperties(cx, options));
if (!optionsCopy) {
return false;
}
- // Step 16.
+ // Step 18.
Rooted<Wrapped<PlainDateObject*>> addedDate(
cx, AddDate(cx, calendar, date, durationToAdd, options));
if (!addedDate) {
return false;
}
- // Step 17.
+ // Step 19.
Rooted<PlainObject*> addedDateFields(
cx, PrepareTemporalFields(cx, addedDate, fieldNames));
if (!addedDateFields) {
return false;
}
- // Step 18.
- auto obj =
- CalendarYearMonthFromFields(cx, calendar, addedDateFields, optionsCopy);
+ // Step 20.
+ auto obj = temporal::CalendarYearMonthFromFields(
+ cx, calendar, addedDateFields, optionsCopy);
if (!obj) {
return false;
}
@@ -1081,13 +1069,11 @@ static bool PlainYearMonth_with(JSContext* cx, const CallArgs& args) {
if (!temporalYearMonthLike) {
return false;
}
-
- // Step 4.
- if (!RejectTemporalLikeObject(cx, temporalYearMonthLike)) {
+ if (!ThrowIfTemporalLikeObject(cx, temporalYearMonthLike)) {
return false;
}
- // Step 5.
+ // Step 4.
Rooted<PlainObject*> resolvedOptions(cx);
if (args.hasDefined(1)) {
Rooted<JSObject*> options(cx,
@@ -1103,7 +1089,7 @@ static bool PlainYearMonth_with(JSContext* cx, const CallArgs& args) {
return false;
}
- // Step 6.
+ // Step 5.
Rooted<CalendarRecord> calendar(cx);
if (!CreateCalendarMethodsRecord(cx, calendarValue,
{
@@ -1115,7 +1101,7 @@ static bool PlainYearMonth_with(JSContext* cx, const CallArgs& args) {
return false;
}
- // Step 7.
+ // Step 6.
JS::RootedVector<PropertyKey> fieldNames(cx);
if (!CalendarFields(
cx, calendar,
@@ -1124,35 +1110,36 @@ static bool PlainYearMonth_with(JSContext* cx, const CallArgs& args) {
return false;
}
- // Step 8.
+ // Step 7.
Rooted<PlainObject*> fields(cx,
PrepareTemporalFields(cx, yearMonth, fieldNames));
if (!fields) {
return false;
}
- // Step 9.
+ // Step 8.
Rooted<PlainObject*> partialYearMonth(
cx, PreparePartialTemporalFields(cx, temporalYearMonthLike, fieldNames));
if (!partialYearMonth) {
return false;
}
- // Step 10.
+ // Step 9.
Rooted<JSObject*> mergedFields(
cx, CalendarMergeFields(cx, calendar, fields, partialYearMonth));
if (!mergedFields) {
return false;
}
- // Step 11.
+ // Step 10.
fields = PrepareTemporalFields(cx, mergedFields, fieldNames);
if (!fields) {
return false;
}
- // Step 12.
- auto obj = CalendarYearMonthFromFields(cx, calendar, fields, resolvedOptions);
+ // Step 11.
+ auto obj = temporal::CalendarYearMonthFromFields(cx, calendar, fields,
+ resolvedOptions);
if (!obj) {
return false;
}
@@ -1466,20 +1453,7 @@ static bool PlainYearMonth_toPlainDate(JSContext* cx, const CallArgs& args) {
}
// Step 12.
- Rooted<PlainObject*> options(cx, NewPlainObjectWithProto(cx, nullptr));
- if (!options) {
- return false;
- }
-
- // Step 13.
- Rooted<Value> overflow(cx, StringValue(cx->names().constrain));
- if (!DefineDataProperty(cx, options, cx->names().overflow, overflow)) {
- return false;
- }
-
- // Step 14.
- auto obj = CalendarDateFromFields(cx, calendar, mergedFromConcatenatedFields,
- options);
+ auto obj = CalendarDateFromFields(cx, calendar, mergedFromConcatenatedFields);
if (!obj) {
return false;
}