2021-07-11 21:04:11 +03:00
/*
* Copyright ( c ) 2021 , Idan Horowitz < idan . horowitz @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2021-07-14 21:01:12 +01:00
# include <LibJS/Runtime/AbstractOperations.h>
# include <LibJS/Runtime/GlobalObject.h>
2021-07-19 00:29:26 +03:00
# include <LibJS/Runtime/Temporal/AbstractOperations.h>
2021-07-11 21:04:11 +03:00
# include <LibJS/Runtime/Temporal/Calendar.h>
2021-07-14 21:01:12 +01:00
# include <LibJS/Runtime/Temporal/CalendarConstructor.h>
2021-07-19 00:29:26 +03:00
# include <LibJS/Runtime/Temporal/PlainDate.h>
2021-07-11 21:04:11 +03:00
# include <LibJS/Runtime/Value.h>
namespace JS : : Temporal {
2021-07-14 21:01:12 +01:00
// 12 Temporal.Calendar Objects, https://tc39.es/proposal-temporal/#sec-temporal-calendar-objects
Calendar : : Calendar ( String identifier , Object & prototype )
: Object ( prototype )
, m_identifier ( move ( identifier ) )
{
}
// 12.1.1 CreateTemporalCalendar ( identifier [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporalcalendar
Calendar * create_temporal_calendar ( GlobalObject & global_object , String const & identifier , FunctionObject * new_target )
{
auto & vm = global_object . vm ( ) ;
// 1. Assert: ! IsBuiltinCalendar(identifier) is true.
VERIFY ( is_builtin_calendar ( identifier ) ) ;
// 2. If newTarget is not provided, set newTarget to %Temporal.Calendar%.
if ( ! new_target )
new_target = global_object . temporal_calendar_constructor ( ) ;
// 3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.Calendar.prototype%", « [[InitializedTemporalCalendar]], [[Identifier]] »).
// 4. Set object.[[Identifier]] to identifier.
auto * object = ordinary_create_from_constructor < Calendar > ( global_object , * new_target , & GlobalObject : : temporal_calendar_prototype , identifier ) ;
if ( vm . exception ( ) )
return { } ;
// 5. Return object.
return object ;
}
// 12.1.2 IsBuiltinCalendar ( id ), https://tc39.es/proposal-temporal/#sec-temporal-isbuiltincalendar
// NOTE: This is the minimum IsBuiltinCalendar implementation for engines without ECMA-402.
bool is_builtin_calendar ( String const & identifier )
{
// 1. If id is not "iso8601", return false.
if ( identifier ! = " iso8601 " sv )
return false ;
// 2. Return true.
return true ;
}
2021-07-19 00:29:26 +03:00
// 12.1.3 GetBuiltinCalendar ( id )
Calendar * get_builtin_calendar ( GlobalObject & global_object , String const & identifier )
{
auto & vm = global_object . vm ( ) ;
// 1. If ! IsBuiltinCalendar(id) is false, throw a RangeError exception.
if ( ! is_builtin_calendar ( identifier ) ) {
vm . throw_exception < RangeError > ( global_object , ErrorType : : TemporalInvalidCalendarIdentifier , identifier ) ;
return { } ;
}
// 2. Return ? Construct(%Temporal.Calendar%, « id »).
MarkedValueList arguments ( vm . heap ( ) ) ;
arguments . append ( js_string ( vm , identifier ) ) ;
auto calendar = vm . construct ( * global_object . temporal_calendar_constructor ( ) , * global_object . temporal_calendar_constructor ( ) , move ( arguments ) ) ;
if ( vm . exception ( ) )
return { } ;
return static_cast < Calendar * > ( & calendar . as_object ( ) ) ;
}
// 12.1.4 GetISO8601Calendar ( )
Calendar * get_iso8601_calendar ( GlobalObject & global_object )
{
// 1. Return ? GetBuiltinCalendar("iso8601").
return get_builtin_calendar ( global_object , " iso8601 " ) ;
}
// 12.1.21 ToTemporalCalendar ( temporalCalendarLike ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalcalendar
Object * to_temporal_calendar ( GlobalObject & global_object , Value temporal_calendar_like )
{
auto & vm = global_object . vm ( ) ;
// 1. If Type(temporalCalendarLike) is Object, then
if ( temporal_calendar_like . is_object ( ) ) {
auto & temporal_calendar_like_object = temporal_calendar_like . as_object ( ) ;
// a. If temporalCalendarLike has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
// TODO: The rest of the Temporal built-ins
if ( is < PlainDate > ( temporal_calendar_like_object ) ) {
// i. Return temporalCalendarLike.[[Calendar]].
return & static_cast < PlainDate & > ( temporal_calendar_like_object ) . calendar ( ) ;
}
// b. If ? HasProperty(temporalCalendarLike, "calendar") is false, return temporalCalendarLike.
auto has_property = temporal_calendar_like_object . has_property ( vm . names . calendar ) ;
if ( vm . exception ( ) )
return { } ;
if ( ! has_property )
return & temporal_calendar_like_object ;
// c. Set temporalCalendarLike to ? Get(temporalCalendarLike, "calendar").
temporal_calendar_like = temporal_calendar_like_object . get ( vm . names . calendar ) ;
if ( vm . exception ( ) )
return { } ;
// d. If Type(temporalCalendarLike) is Object and ? HasProperty(temporalCalendarLike, "calendar") is false, return temporalCalendarLike.
if ( temporal_calendar_like . is_object ( ) ) {
has_property = temporal_calendar_like . as_object ( ) . has_property ( vm . names . calendar ) ;
if ( vm . exception ( ) )
return { } ;
if ( ! has_property )
return & temporal_calendar_like . as_object ( ) ;
}
}
// 2. Let identifier be ? ToString(temporalCalendarLike).
auto identifier = temporal_calendar_like . to_string ( global_object ) ;
if ( vm . exception ( ) )
return { } ;
// 3. If ! IsBuiltinCalendar(identifier) is false, then
if ( ! is_builtin_calendar ( identifier ) ) {
// a. Let identifier be ? ParseTemporalCalendarString(identifier).
2021-07-21 19:58:17 +03:00
auto parsed_identifier = parse_temporal_calendar_string ( global_object , identifier ) ;
2021-07-19 00:29:26 +03:00
if ( vm . exception ( ) )
return { } ;
2021-07-21 19:58:17 +03:00
identifier = move ( * parsed_identifier ) ;
2021-07-19 00:29:26 +03:00
}
// 4. Return ? CreateTemporalCalendar(identifier).
return create_temporal_calendar ( global_object , identifier ) ;
}
// 12.1.22 ToTemporalCalendarWithISODefault ( temporalCalendarLike ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalcalendarwithisodefault
Object * to_temporal_calendar_with_iso_default ( GlobalObject & global_object , Value temporal_calendar_like )
{
// 1. If temporalCalendarLike is undefined, then
if ( temporal_calendar_like . is_undefined ( ) ) {
// a. Return ? GetISO8601Calendar().
return get_iso8601_calendar ( global_object ) ;
}
// 2. Return ? ToTemporalCalendar(temporalCalendarLike).
return to_temporal_calendar ( global_object , temporal_calendar_like ) ;
}
2021-07-11 21:04:11 +03:00
// 12.1.30 IsISOLeapYear ( year ), https://tc39.es/proposal-temporal/#sec-temporal-isisoleapyear
bool is_iso_leap_year ( i32 year )
{
// 1. Assert: year is an integer.
// 2. If year modulo 4 ≠ 0, return false.
if ( year % 4 ! = 0 )
return false ;
// 3. If year modulo 400 = 0, return true.
if ( year % 400 = = 0 )
return true ;
// 4. If year modulo 100 = 0, return false.
if ( year % 100 = = 0 )
return false ;
// 5. Return true.
return true ;
}
// 12.1.32 ISODaysInMonth ( year, month ), https://tc39.es/proposal-temporal/#sec-temporal-isodaysinmonth
i32 iso_days_in_month ( i32 year , i32 month )
{
// 1. Assert: year is an integer.
// 2. Assert: month is an integer, month ≥ 1, and month ≤ 12.
VERIFY ( month > = 1 & & month < = 12 ) ;
// 3. If month is 1, 3, 5, 7, 8, 10, or 12, return 31.
if ( month = = 1 | | month = = 3 | | month = = 5 | | month = = 7 | | month = = 8 | | month = = 10 | | month = = 12 )
return 31 ;
// 4. If month is 4, 6, 9, or 11, return 30.
if ( month = = 4 | | month = = 6 | | month = = 9 | | month = = 11 )
return 30 ;
// 5. If ! IsISOLeapYear(year) is true, return 29.
if ( is_iso_leap_year ( year ) )
return 29 ;
// 6. Return 28.
return 28 ;
}
}