1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 15:07:45 +00:00

LibJS: Introduce ISO Date Records

This is an editorial change in the Temporal spec.

See: d264341
This commit is contained in:
Linus Groh 2022-05-16 20:46:46 +01:00
parent 0558eb6d2f
commit d2c1dd5454
4 changed files with 34 additions and 26 deletions

View file

@ -721,7 +721,7 @@ ThrowCompletionOr<double> resolve_iso_month(GlobalObject& global_object, Object
} }
// 12.2.33 ISODateFromFields ( fields, options ), https://tc39.es/proposal-temporal/#sec-temporal-isodatefromfields // 12.2.33 ISODateFromFields ( fields, options ), https://tc39.es/proposal-temporal/#sec-temporal-isodatefromfields
ThrowCompletionOr<ISODate> iso_date_from_fields(GlobalObject& global_object, Object const& fields, Object const& options) ThrowCompletionOr<ISODateRecord> iso_date_from_fields(GlobalObject& global_object, Object const& fields, Object const& options)
{ {
auto& vm = global_object.vm(); auto& vm = global_object.vm();
@ -825,7 +825,7 @@ ThrowCompletionOr<ISOMonthDay> iso_month_day_from_fields(GlobalObject& global_ob
// 11. Let referenceISOYear be 1972 (the first leap year after the Unix epoch). // 11. Let referenceISOYear be 1972 (the first leap year after the Unix epoch).
i32 reference_iso_year = 1972; i32 reference_iso_year = 1972;
Optional<ISODate> result; Optional<ISODateRecord> result;
// 12. If monthCode is undefined, then // 12. If monthCode is undefined, then
if (month_code.is_undefined()) { if (month_code.is_undefined()) {

View file

@ -66,7 +66,7 @@ u8 iso_days_in_month(i32 year, u8 month);
u8 to_iso_week_of_year(i32 year, u8 month, u8 day); u8 to_iso_week_of_year(i32 year, u8 month, u8 day);
String build_iso_month_code(u8 month); String build_iso_month_code(u8 month);
ThrowCompletionOr<double> resolve_iso_month(GlobalObject&, Object const& fields); ThrowCompletionOr<double> resolve_iso_month(GlobalObject&, Object const& fields);
ThrowCompletionOr<ISODate> iso_date_from_fields(GlobalObject&, Object const& fields, Object const& options); ThrowCompletionOr<ISODateRecord> iso_date_from_fields(GlobalObject&, Object const& fields, Object const& options);
ThrowCompletionOr<ISOYearMonth> iso_year_month_from_fields(GlobalObject&, Object const& fields, Object const& options); ThrowCompletionOr<ISOYearMonth> iso_year_month_from_fields(GlobalObject&, Object const& fields, Object const& options);
ThrowCompletionOr<ISOMonthDay> iso_month_day_from_fields(GlobalObject&, Object const& fields, Object const& options); ThrowCompletionOr<ISOMonthDay> iso_month_day_from_fields(GlobalObject&, Object const& fields, Object const& options);
i32 iso_year(Object& temporal_object); i32 iso_year(Object& temporal_object);

View file

@ -37,6 +37,16 @@ void PlainDate::visit_edges(Visitor& visitor)
visitor.visit(&m_calendar); visitor.visit(&m_calendar);
} }
// 3.5.2 CreateISODateRecord ( year, month, day ), https://tc39.es/proposal-temporal/#sec-temporal-create-iso-date-record
ISODateRecord create_iso_date_record(i32 year, u8 month, u8 day)
{
// 1. Assert: IsValidISODate(year, month, day) is true.
VERIFY(is_valid_iso_date(year, month, day));
// 2. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day }.
return { .year = year, .month = month, .day = day };
}
// 3.5.1 CreateTemporalDate ( isoYear, isoMonth, isoDay, calendar [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporaldate // 3.5.1 CreateTemporalDate ( isoYear, isoMonth, isoDay, calendar [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporaldate
ThrowCompletionOr<PlainDate*> create_temporal_date(GlobalObject& global_object, i32 iso_year, u8 iso_month, u8 iso_day, Object& calendar, FunctionObject const* new_target) ThrowCompletionOr<PlainDate*> create_temporal_date(GlobalObject& global_object, i32 iso_year, u8 iso_month, u8 iso_day, Object& calendar, FunctionObject const* new_target)
{ {
@ -154,10 +164,10 @@ DateDurationRecord difference_iso_date(GlobalObject& global_object, i32 year1, u
return create_date_duration_record(0, 0, 0, 0); return create_date_duration_record(0, 0, 0, 0);
// c. Let start be the Record { [[Year]]: y1, [[Month]]: m1, [[Day]]: d1 }. // c. Let start be the Record { [[Year]]: y1, [[Month]]: m1, [[Day]]: d1 }.
auto start = ISODate { .year = year1, .month = month1, .day = day1 }; auto start = ISODateRecord { .year = year1, .month = month1, .day = day1 };
// d. Let end be the Record { [[Year]]: y2, [[Month]]: m2, [[Day]]: d2 }. // d. Let end be the Record { [[Year]]: y2, [[Month]]: m2, [[Day]]: d2 }.
auto end = ISODate { .year = year2, .month = month2, .day = day2 }; auto end = ISODateRecord { .year = year2, .month = month2, .day = day2 };
// e. Let years be end.[[Year]] - start.[[Year]]. // e. Let years be end.[[Year]] - start.[[Year]].
double years = end.year - start.year; double years = end.year - start.year;
@ -292,15 +302,13 @@ DateDurationRecord difference_iso_date(GlobalObject& global_object, i32 year1, u
} }
// 3.5.4 RegulateISODate ( year, month, day, overflow ), https://tc39.es/proposal-temporal/#sec-temporal-regulateisodate // 3.5.4 RegulateISODate ( year, month, day, overflow ), https://tc39.es/proposal-temporal/#sec-temporal-regulateisodate
ThrowCompletionOr<ISODate> regulate_iso_date(GlobalObject& global_object, double year, double month, double day, StringView overflow) ThrowCompletionOr<ISODateRecord> regulate_iso_date(GlobalObject& global_object, double year, double month, double day, StringView overflow)
{ {
auto& vm = global_object.vm(); auto& vm = global_object.vm();
// 1. Assert: year, month, and day are integers.
VERIFY(year == trunc(year) && month == trunc(month) && day == trunc(day));
// 2. Assert: overflow is either "constrain" or "reject".
// NOTE: Asserted by the VERIFY_NOT_REACHED at the end
// 3. If overflow is "reject", then VERIFY(year == trunc(year) && month == trunc(month) && day == trunc(day));
// 1. If overflow is "reject", then
if (overflow == "reject"sv) { if (overflow == "reject"sv) {
// IMPLEMENTATION DEFINED: This is an optimization that allows us to treat these doubles as normal integers from this point onwards. // 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 behavior as the call to IsValidISODate will immediately check that these values are valid ISO // This does not change the exposed behavior as the call to IsValidISODate will immediately check that these values are valid ISO
@ -316,9 +324,9 @@ ThrowCompletionOr<ISODate> regulate_iso_date(GlobalObject& global_object, double
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidPlainDate); return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidPlainDate);
// b. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day }. // b. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day }.
return ISODate { .year = y, .month = m, .day = d }; return ISODateRecord { .year = y, .month = m, .day = d };
} }
// 4. If overflow is "constrain", then // 2. If overflow is "constrain", then
else if (overflow == "constrain"sv) { else if (overflow == "constrain"sv) {
// IMPLEMENTATION DEFINED: This is an optimization that allows us to treat this double as normal integer from this point onwards. This // IMPLEMENTATION DEFINED: This is an optimization that allows us to treat this double as normal integer from this point onwards. This
// does not change the exposed behavior as the parent's call to CreateTemporalDate will immediately check that this value is a valid // does not change the exposed behavior as the parent's call to CreateTemporalDate will immediately check that this value is a valid
@ -326,19 +334,17 @@ ThrowCompletionOr<ISODate> regulate_iso_date(GlobalObject& global_object, double
if (!AK::is_within_range<i32>(year)) if (!AK::is_within_range<i32>(year))
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidPlainDate); return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidPlainDate);
auto y = static_cast<i32>(year);
// a. Set month to the result of clamping month between 1 and 12. // a. Set month to the result of clamping month between 1 and 12.
month = clamp(month, 1, 12); month = clamp(month, 1, 12);
// b. Let daysInMonth be ! ISODaysInMonth(year, month). // b. Let daysInMonth be ! ISODaysInMonth(year, month).
auto days_in_month = iso_days_in_month(y, (u8)month); auto days_in_month = iso_days_in_month(static_cast<i32>(year), static_cast<u8>(month));
// c. Set day to the result of clamping day between 1 and daysInMonth. // c. Set day to the result of clamping day between 1 and daysInMonth.
day = clamp(day, 1, days_in_month); day = clamp(day, 1, days_in_month);
// d. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day }. // d. Return CreateISODateRecord(year, month, day).
return ISODate { .year = y, .month = static_cast<u8>(month), .day = static_cast<u8>(day) }; return create_iso_date_record(static_cast<i32>(year), static_cast<u8>(month), static_cast<u8>(day));
} }
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
@ -366,7 +372,7 @@ bool is_valid_iso_date(i32 year, u8 month, u8 day)
} }
// 3.5.6 BalanceISODate ( year, month, day ), https://tc39.es/proposal-temporal/#sec-temporal-balanceisodate // 3.5.6 BalanceISODate ( year, month, day ), https://tc39.es/proposal-temporal/#sec-temporal-balanceisodate
ISODate balance_iso_date(double year, double month, double day) ISODateRecord balance_iso_date(double year, double month, double day)
{ {
// 1. Let epochDays be MakeDay(𝔽(year), 𝔽(month - 1), 𝔽(day)). // 1. Let epochDays be MakeDay(𝔽(year), 𝔽(month - 1), 𝔽(day)).
auto epoch_days = make_day(year, month - 1, day); auto epoch_days = make_day(year, month - 1, day);
@ -377,8 +383,8 @@ ISODate balance_iso_date(double year, double month, double day)
// 3. Let ms be MakeDate(epochDays, +0𝔽). // 3. Let ms be MakeDate(epochDays, +0𝔽).
auto ms = make_date(epoch_days, 0); auto ms = make_date(epoch_days, 0);
// 4. Return the Record { [[Year]]: (YearFromTime(ms)), [[Month]]: (MonthFromTime(ms)) + 1, [[Day]]: (DateFromTime(ms)) }. // 4. Return CreateISODateRecord((YearFromTime(ms)), (MonthFromTime(ms)) + 1, (DateFromTime(ms))).
return { .year = year_from_time(ms), .month = static_cast<u8>(month_from_time(ms) + 1), .day = date_from_time(ms) }; return create_iso_date_record(year_from_time(ms), static_cast<u8>(month_from_time(ms) + 1), date_from_time(ms));
} }
// 3.5.7 PadISOYear ( y ), https://tc39.es/proposal-temporal/#sec-temporal-padisoyear // 3.5.7 PadISOYear ( y ), https://tc39.es/proposal-temporal/#sec-temporal-padisoyear
@ -426,7 +432,7 @@ ThrowCompletionOr<String> temporal_date_to_string(GlobalObject& global_object, P
} }
// 3.5.9 AddISODate ( year, month, day, years, months, weeks, days, overflow ), https://tc39.es/proposal-temporal/#sec-temporal-addisodate // 3.5.9 AddISODate ( year, month, day, years, months, weeks, days, overflow ), https://tc39.es/proposal-temporal/#sec-temporal-addisodate
ThrowCompletionOr<ISODate> add_iso_date(GlobalObject& global_object, i32 year, u8 month, u8 day, double years, double months, double weeks, double days, StringView overflow) ThrowCompletionOr<ISODateRecord> add_iso_date(GlobalObject& global_object, i32 year, u8 month, u8 day, double years, double months, double weeks, double days, StringView overflow)
{ {
// 1. Assert: year, month, day, years, months, weeks, and days are integers. // 1. Assert: year, month, day, years, months, weeks, and days are integers.
VERIFY(years == trunc(years) && months == trunc(months) && weeks == trunc(weeks) && days == trunc(days)); VERIFY(years == trunc(years) && months == trunc(months) && weeks == trunc(weeks) && days == trunc(days));

View file

@ -37,21 +37,23 @@ private:
Object& m_calendar; // [[Calendar]] Object& m_calendar; // [[Calendar]]
}; };
struct ISODate { // 3.5.1 ISO Date Records, https://tc39.es/proposal-temporal/#sec-temporal-iso-date-records
struct ISODateRecord {
i32 year; i32 year;
u8 month; u8 month;
u8 day; u8 day;
}; };
ISODateRecord create_iso_date_record(i32 year, u8 month, u8 day);
ThrowCompletionOr<PlainDate*> create_temporal_date(GlobalObject&, i32 iso_year, u8 iso_month, u8 iso_day, Object& calendar, FunctionObject const* new_target = nullptr); ThrowCompletionOr<PlainDate*> create_temporal_date(GlobalObject&, i32 iso_year, u8 iso_month, u8 iso_day, Object& calendar, FunctionObject const* new_target = nullptr);
ThrowCompletionOr<PlainDate*> to_temporal_date(GlobalObject&, Value item, Object const* options = nullptr); ThrowCompletionOr<PlainDate*> to_temporal_date(GlobalObject&, Value item, Object const* options = nullptr);
DateDurationRecord difference_iso_date(GlobalObject&, i32 year1, u8 month1, u8 day1, i32 year2, u8 month2, u8 day2, StringView largest_unit); DateDurationRecord difference_iso_date(GlobalObject&, i32 year1, u8 month1, u8 day1, i32 year2, u8 month2, u8 day2, StringView largest_unit);
ThrowCompletionOr<ISODate> regulate_iso_date(GlobalObject&, double year, double month, double day, StringView overflow); ThrowCompletionOr<ISODateRecord> regulate_iso_date(GlobalObject&, double year, double month, double day, StringView overflow);
bool is_valid_iso_date(i32 year, u8 month, u8 day); bool is_valid_iso_date(i32 year, u8 month, u8 day);
ISODate balance_iso_date(double year, double month, double day); ISODateRecord balance_iso_date(double year, double month, double day);
String pad_iso_year(i32 y); String pad_iso_year(i32 y);
ThrowCompletionOr<String> temporal_date_to_string(GlobalObject&, PlainDate&, StringView show_calendar); ThrowCompletionOr<String> temporal_date_to_string(GlobalObject&, PlainDate&, StringView show_calendar);
ThrowCompletionOr<ISODate> add_iso_date(GlobalObject&, i32 year, u8 month, u8 day, double years, double months, double weeks, double days, StringView overflow); ThrowCompletionOr<ISODateRecord> add_iso_date(GlobalObject&, i32 year, u8 month, u8 day, double years, double months, double weeks, double days, StringView overflow);
i8 compare_iso_date(i32 year1, u8 month1, u8 day1, i32 year2, u8 month2, u8 day2); i8 compare_iso_date(i32 year1, u8 month1, u8 day1, i32 year2, u8 month2, u8 day2);
ThrowCompletionOr<Duration*> difference_temporal_plain_date(GlobalObject&, DifferenceOperation, PlainDate&, Value other, Value options); ThrowCompletionOr<Duration*> difference_temporal_plain_date(GlobalObject&, DifferenceOperation, PlainDate&, Value other, Value options);