summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Groh <mail@linusgroh.de>2022-03-31 00:48:57 +0100
committerLinus Groh <mail@linusgroh.de>2022-03-31 17:09:10 +0100
commitcfb04765fa83683944f96b535c336e5d607e9b60 (patch)
tree45d30d2a11068b14dfda39eb0cfa6e108a1c5a1d
parentb020b8eea25471b371af2466ace2b80b8cd691ee (diff)
downloadserenity-cfb04765fa83683944f96b535c336e5d607e9b60.zip
LibJS: Correct PlainYearMonth arithmetic for non-ISO calendars
This is a normative change in the Temporal spec. See: https://github.com/tc39/proposal-temporal/commit/61e8dd0
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp4
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h2
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp2
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp2
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp2
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDayPrototype.cpp2
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonthPrototype.cpp70
7 files changed, 48 insertions, 36 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp
index 75d7103fc7..fed58aee8d 100644
--- a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp
@@ -457,7 +457,7 @@ ThrowCompletionOr<Object*> get_temporal_calendar_with_iso_default(GlobalObject&
}
// 12.1.24 DateFromFields ( calendar, fields, options ), https://tc39.es/proposal-temporal/#sec-temporal-datefromfields
-ThrowCompletionOr<PlainDate*> date_from_fields(GlobalObject& global_object, Object& calendar, Object const& fields, Object const& options)
+ThrowCompletionOr<PlainDate*> date_from_fields(GlobalObject& global_object, Object& calendar, Object const& fields, Object const* options)
{
auto& vm = global_object.vm();
@@ -465,7 +465,7 @@ ThrowCompletionOr<PlainDate*> date_from_fields(GlobalObject& global_object, Obje
// 2. Assert: Type(fields) is Object.
// 3. Let date be ? Invoke(calendar, "dateFromFields", « fields, options »).
- auto date = TRY(Value(&calendar).invoke(global_object, vm.names.dateFromFields, &fields, &options));
+ auto date = TRY(Value(&calendar).invoke(global_object, vm.names.dateFromFields, &fields, options ?: js_undefined()));
// 4. Perform ? RequireInternalSlot(date, [[InitializedTemporalDate]]).
auto* date_object = TRY(date.to_object(global_object));
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h
index cd344acd1f..a9d77979fe 100644
--- a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h
@@ -55,7 +55,7 @@ ThrowCompletionOr<Value> calendar_era_year(GlobalObject&, Object& calendar, Obje
ThrowCompletionOr<Object*> to_temporal_calendar(GlobalObject&, Value);
ThrowCompletionOr<Object*> to_temporal_calendar_with_iso_default(GlobalObject&, Value);
ThrowCompletionOr<Object*> get_temporal_calendar_with_iso_default(GlobalObject&, Object&);
-ThrowCompletionOr<PlainDate*> date_from_fields(GlobalObject&, Object& calendar, Object const& fields, Object const& options);
+ThrowCompletionOr<PlainDate*> date_from_fields(GlobalObject&, Object& calendar, Object const& fields, Object const* options = nullptr);
ThrowCompletionOr<PlainYearMonth*> year_month_from_fields(GlobalObject&, Object& calendar, Object const& fields, Object const* options = nullptr);
ThrowCompletionOr<PlainMonthDay*> month_day_from_fields(GlobalObject& global_object, Object& calendar, Object const& fields, Object const* options = nullptr);
String format_calendar_annotation(StringView id, StringView show_calendar);
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp
index 5f83812d9d..c567ce0783 100644
--- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp
@@ -119,7 +119,7 @@ ThrowCompletionOr<PlainDate*> to_temporal_date(GlobalObject& global_object, Valu
auto* fields = TRY(prepare_temporal_fields(global_object, item_object, field_names, {}));
// g. Return ? DateFromFields(calendar, fields, options).
- return date_from_fields(global_object, *calendar, *fields, *options);
+ return date_from_fields(global_object, *calendar, *fields, options);
}
// 4. Perform ? ToTemporalOverflow(options).
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp
index 316da15cf7..ecda31446c 100644
--- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp
@@ -421,7 +421,7 @@ JS_DEFINE_NATIVE_FUNCTION(PlainDatePrototype::with)
fields = TRY(prepare_temporal_fields(global_object, *fields, field_names, {}));
// 12. Return ? DateFromFields(calendar, fields, options).
- return TRY(date_from_fields(global_object, calendar, *fields, *options));
+ return TRY(date_from_fields(global_object, calendar, *fields, options));
}
// 3.3.22 Temporal.PlainDate.prototype.withCalendar ( calendarLike ), https://tc39.es/proposal-temporal/#sec-temporal.plaindate.prototype.withcalendar
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp
index 159d4110ea..e290a2157a 100644
--- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp
@@ -111,7 +111,7 @@ ThrowCompletionOr<ISODateTime> interpret_temporal_date_time_fields(GlobalObject&
auto overflow = TRY(to_temporal_overflow(global_object, options));
// 3. Let temporalDate be ? DateFromFields(calendar, fields, options).
- auto* temporal_date = TRY(date_from_fields(global_object, calendar, fields, options));
+ auto* temporal_date = TRY(date_from_fields(global_object, calendar, fields, &options));
// 4. Let timeResult be ? RegulateTime(timeResult.[[Hour]], timeResult.[[Minute]], timeResult.[[Second]], timeResult.[[Millisecond]], timeResult.[[Microsecond]], timeResult.[[Nanosecond]], overflow).
auto time_result = TRY(regulate_time(global_object, unregulated_time_result.hour, unregulated_time_result.minute, unregulated_time_result.second, unregulated_time_result.millisecond, unregulated_time_result.microsecond, unregulated_time_result.nanosecond, overflow));
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDayPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDayPrototype.cpp
index beca05e6c7..3d02b7bd95 100644
--- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDayPrototype.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDayPrototype.cpp
@@ -252,7 +252,7 @@ JS_DEFINE_NATIVE_FUNCTION(PlainMonthDayPrototype::to_plain_date)
MUST(options->create_data_property_or_throw(vm.names.overflow, js_string(vm, vm.names.reject.as_string())));
// 14. Return ? DateFromFields(calendar, mergedFields, options).
- return TRY(date_from_fields(global_object, calendar, *merged_fields, *options));
+ return TRY(date_from_fields(global_object, calendar, *merged_fields, options));
}
// 10.3.13 Temporal.PlainMonthDay.prototype.getISOFields ( ), https://tc39.es/proposal-temporal/#sec-temporal.plainmonthday.prototype.getisofields
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonthPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonthPrototype.cpp
index 98d55b1d98..bd5e50f0b6 100644
--- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonthPrototype.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonthPrototype.cpp
@@ -258,12 +258,15 @@ JS_DEFINE_NATIVE_FUNCTION(PlainYearMonthPrototype::add)
// 7. Let fieldNames be ? CalendarFields(calendar, « "monthCode", "year" »).
auto field_names = TRY(calendar_fields(global_object, calendar, { "monthCode"sv, "year"sv }));
- // 8. Let sign be ! DurationSign(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], balanceResult.[[Days]], 0, 0, 0, 0, 0, 0).
+ // 8. Let fields be ? PrepareTemporalFields(yearMonth, fieldNames, «»).
+ auto* fields = TRY(prepare_temporal_fields(global_object, *year_month, field_names, {}));
+
+ // 9. Let sign be ! DurationSign(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], balanceResult.[[Days]], 0, 0, 0, 0, 0, 0).
auto sign = duration_sign(duration.years, duration.months, duration.weeks, balance_result.days, 0, 0, 0, 0, 0, 0);
double day;
- // 9. If sign < 0, then
+ // 10. If sign < 0, then
if (sign < 0) {
// a. Let dayFromCalendar be ? CalendarDaysInMonth(calendar, yearMonth).
auto day_from_calendar = TRY(calendar_days_in_month(global_object, calendar, *year_month));
@@ -271,25 +274,28 @@ JS_DEFINE_NATIVE_FUNCTION(PlainYearMonthPrototype::add)
// b. Let day be ? ToPositiveInteger(dayFromCalendar).
day = TRY(to_positive_integer(global_object, day_from_calendar));
}
- // 10. Else,
+ // 11. Else,
else {
// a. Let day be 1.
day = 1;
}
- // 11. Let date be ? CreateTemporalDate(yearMonth.[[ISOYear]], yearMonth.[[ISOMonth]], day, calendar).
- auto* date = TRY(create_temporal_date(global_object, year_month->iso_year(), year_month->iso_month(), day, calendar));
+ // 12. Perform ! CreateDataPropertyOrThrow(fields, "day", day).
+ MUST(fields->create_data_property_or_throw(vm.names.day, Value(day)));
+
+ // 13. Let date be ? DateFromFields(calendar, fields, undefined).
+ auto* date = TRY(date_from_fields(global_object, calendar, *fields, nullptr));
- // 12. Let durationToAdd be ! CreateTemporalDuration(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], balanceResult.[[Days]], 0, 0, 0, 0, 0, 0).
+ // 14. Let durationToAdd be ! CreateTemporalDuration(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], balanceResult.[[Days]], 0, 0, 0, 0, 0, 0).
auto* duration_to_add = MUST(create_temporal_duration(global_object, duration.years, duration.months, duration.weeks, balance_result.days, 0, 0, 0, 0, 0, 0));
- // 13. Let optionsCopy be OrdinaryObjectCreate(%Object.prototype%).
+ // 15. Let optionsCopy be OrdinaryObjectCreate(%Object.prototype%).
auto* options_copy = Object::create(global_object, global_object.object_prototype());
- // 14. Let entries be ? EnumerableOwnPropertyNames(options, key+value).
+ // 16. Let entries be ? EnumerableOwnPropertyNames(options, key+value).
auto entries = TRY(options->enumerable_own_property_names(Object::PropertyKind::KeyAndValue));
- // 15. For each element nextEntry of entries, do
+ // 17. For each element nextEntry of entries, do
for (auto& next_entry : entries) {
auto key = MUST(next_entry.as_array().get_without_side_effects(0).to_property_key(global_object));
auto value = next_entry.as_array().get_without_side_effects(1);
@@ -298,13 +304,13 @@ JS_DEFINE_NATIVE_FUNCTION(PlainYearMonthPrototype::add)
MUST(options_copy->create_data_property_or_throw(key, value));
}
- // 16. Let addedDate be ? CalendarDateAdd(calendar, date, durationToAdd, options).
+ // 18. Let addedDate be ? CalendarDateAdd(calendar, date, durationToAdd, options).
auto* added_date = TRY(calendar_date_add(global_object, calendar, date, *duration_to_add, options));
- // 17. Let addedDateFields be ? PrepareTemporalFields(addedDate, fieldNames, «»).
+ // 19. Let addedDateFields be ? PrepareTemporalFields(addedDate, fieldNames, «»).
auto* added_date_fields = TRY(prepare_temporal_fields(global_object, *added_date, field_names, {}));
- // 18. Return ? YearMonthFromFields(calendar, addedDateFields, optionsCopy).
+ // 20. Return ? YearMonthFromFields(calendar, addedDateFields, optionsCopy).
return TRY(year_month_from_fields(global_object, calendar, *added_date_fields, options_copy));
}
@@ -337,12 +343,15 @@ JS_DEFINE_NATIVE_FUNCTION(PlainYearMonthPrototype::subtract)
// 8. Let fieldNames be ? CalendarFields(calendar, « "monthCode", "year" »).
auto field_names = TRY(calendar_fields(global_object, calendar, { "monthCode"sv, "year"sv }));
- // 9. Let sign be ! DurationSign(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], balanceResult.[[Days]], 0, 0, 0, 0, 0, 0).
+ // 9. Let fields be ? PrepareTemporalFields(yearMonth, fieldNames, «»).
+ auto* fields = TRY(prepare_temporal_fields(global_object, *year_month, field_names, {}));
+
+ // 10. Let sign be ! DurationSign(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], balanceResult.[[Days]], 0, 0, 0, 0, 0, 0).
auto sign = duration_sign(duration->years(), duration->months(), duration->weeks(), balance_result.days, 0, 0, 0, 0, 0, 0);
double day;
- // 10. If sign < 0, then
+ // 11. If sign < 0, then
if (sign < 0) {
// a. Let dayFromCalendar be ? CalendarDaysInMonth(calendar, yearMonth).
auto day_from_calendar = TRY(calendar_days_in_month(global_object, calendar, *year_month));
@@ -350,25 +359,28 @@ JS_DEFINE_NATIVE_FUNCTION(PlainYearMonthPrototype::subtract)
// b. Let day be ? ToPositiveInteger(dayFromCalendar).
day = TRY(to_positive_integer(global_object, day_from_calendar));
}
- // 11. Else,
+ // 12. Else,
else {
// a. Let day be 1.
day = 1;
}
- // 12. Let date be ? CreateTemporalDate(yearMonth.[[ISOYear]], yearMonth.[[ISOMonth]], day, calendar).
- auto* date = TRY(create_temporal_date(global_object, year_month->iso_year(), year_month->iso_month(), day, calendar));
+ // 13. Perform ! CreateDataPropertyOrThrow(fields, "day", day).
+ MUST(fields->create_data_property_or_throw(vm.names.day, Value(day)));
+
+ // 14. Let date be ? DateFromFields(calendar, fields, undefined).
+ auto* date = TRY(date_from_fields(global_object, calendar, *fields, nullptr));
- // 13. Let durationToAdd be ! CreateTemporalDuration(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], balanceResult.[[Days]], 0, 0, 0, 0, 0, 0).
+ // 15. Let durationToAdd be ! CreateTemporalDuration(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], balanceResult.[[Days]], 0, 0, 0, 0, 0, 0).
auto* duration_to_add = MUST(create_temporal_duration(global_object, duration->years(), duration->months(), duration->weeks(), balance_result.days, 0, 0, 0, 0, 0, 0));
- // 14. Let optionsCopy be OrdinaryObjectCreate(%Object.prototype%).
+ // 16. Let optionsCopy be OrdinaryObjectCreate(%Object.prototype%).
auto* options_copy = Object::create(global_object, global_object.object_prototype());
- // 15. Let entries be ? EnumerableOwnPropertyNames(options, key+value).
+ // 17. Let entries be ? EnumerableOwnPropertyNames(options, key+value).
auto entries = TRY(options->enumerable_own_property_names(Object::PropertyKind::KeyAndValue));
- // 16. For each element nextEntry of entries, do
+ // 18. For each element nextEntry of entries, do
for (auto& next_entry : entries) {
auto key = MUST(next_entry.as_array().get_without_side_effects(0).to_property_key(global_object));
auto value = next_entry.as_array().get_without_side_effects(1);
@@ -377,13 +389,13 @@ JS_DEFINE_NATIVE_FUNCTION(PlainYearMonthPrototype::subtract)
MUST(options_copy->create_data_property_or_throw(key, value));
}
- // 17. Let addedDate be ? CalendarDateAdd(calendar, date, durationToAdd, options).
+ // 19. Let addedDate be ? CalendarDateAdd(calendar, date, durationToAdd, options).
auto* added_date = TRY(calendar_date_add(global_object, calendar, date, *duration_to_add, options));
- // 18. Let addedDateFields be ? PrepareTemporalFields(addedDate, fieldNames, «»).
+ // 20. Let addedDateFields be ? PrepareTemporalFields(addedDate, fieldNames, «»).
auto* added_date_fields = TRY(prepare_temporal_fields(global_object, *added_date, field_names, {}));
- // 19. Return ? YearMonthFromFields(calendar, addedDateFields, optionsCopy).
+ // 21. Return ? YearMonthFromFields(calendar, addedDateFields, optionsCopy).
return TRY(year_month_from_fields(global_object, calendar, *added_date_fields, options_copy));
}
@@ -436,7 +448,7 @@ JS_DEFINE_NATIVE_FUNCTION(PlainYearMonthPrototype::until)
// 16. Let otherDate be ? DateFromFields(calendar, otherFields).
// FIXME: Spec doesn't pass required options, see https://github.com/tc39/proposal-temporal/issues/1685.
- auto* other_date = TRY(date_from_fields(global_object, calendar, *other_fields, *options));
+ auto* other_date = TRY(date_from_fields(global_object, calendar, *other_fields, options));
// 17. Let thisFields be ? PrepareTemporalFields(yearMonth, fieldNames, «»).
auto* this_fields = TRY(prepare_temporal_fields(global_object, *year_month, field_names, {}));
@@ -446,7 +458,7 @@ JS_DEFINE_NATIVE_FUNCTION(PlainYearMonthPrototype::until)
// 19. Let thisDate be ? DateFromFields(calendar, thisFields).
// FIXME: Spec doesn't pass required options, see https://github.com/tc39/proposal-temporal/issues/1685.
- auto* this_date = TRY(date_from_fields(global_object, calendar, *this_fields, *options));
+ auto* this_date = TRY(date_from_fields(global_object, calendar, *this_fields, options));
// 20. Let untilOptions be ? MergeLargestUnitOption(options, largestUnit).
auto* until_options = TRY(merge_largest_unit_option(global_object, *options, *largest_unit));
@@ -519,7 +531,7 @@ JS_DEFINE_NATIVE_FUNCTION(PlainYearMonthPrototype::since)
// 17. Let otherDate be ? DateFromFields(calendar, otherFields).
// FIXME: Spec doesn't pass required options, see https://github.com/tc39/proposal-temporal/issues/1685.
- auto* other_date = TRY(date_from_fields(global_object, calendar, *other_fields, *options));
+ auto* other_date = TRY(date_from_fields(global_object, calendar, *other_fields, options));
// 18. Let thisFields be ? PrepareTemporalFields(yearMonth, fieldNames, «»).
auto* this_fields = TRY(prepare_temporal_fields(global_object, *year_month, field_names, {}));
@@ -529,7 +541,7 @@ JS_DEFINE_NATIVE_FUNCTION(PlainYearMonthPrototype::since)
// 20. Let thisDate be ? DateFromFields(calendar, thisFields).
// FIXME: Spec doesn't pass required options, see https://github.com/tc39/proposal-temporal/issues/1685.
- auto* this_date = TRY(date_from_fields(global_object, calendar, *this_fields, *options));
+ auto* this_date = TRY(date_from_fields(global_object, calendar, *this_fields, options));
// 21. Let untilOptions be ? MergeLargestUnitOption(options, largestUnit).
auto* until_options = TRY(merge_largest_unit_option(global_object, *options, *largest_unit));
@@ -677,7 +689,7 @@ JS_DEFINE_NATIVE_FUNCTION(PlainYearMonthPrototype::to_plain_date)
MUST(options->create_data_property_or_throw(vm.names.overflow, js_string(vm, vm.names.reject.as_string())));
// 14. Return ? DateFromFields(calendar, mergedFields, options).
- return TRY(date_from_fields(global_object, calendar, *merged_fields, *options));
+ return TRY(date_from_fields(global_object, calendar, *merged_fields, options));
}
// 9.3.22 Temporal.PlainYearMonth.prototype.getISOFields ( ), https://tc39.es/proposal-temporal/#sec-temporal.plainyearmonth.prototype.getisofields