PlainMonthDay.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. * Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
  3. * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
  4. * Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include <LibJS/Runtime/AbstractOperations.h>
  9. #include <LibJS/Runtime/Intrinsics.h>
  10. #include <LibJS/Runtime/Realm.h>
  11. #include <LibJS/Runtime/Temporal/AbstractOperations.h>
  12. #include <LibJS/Runtime/Temporal/Calendar.h>
  13. #include <LibJS/Runtime/Temporal/PlainMonthDay.h>
  14. #include <LibJS/Runtime/Temporal/PlainMonthDayConstructor.h>
  15. #include <LibJS/Runtime/VM.h>
  16. namespace JS::Temporal {
  17. GC_DEFINE_ALLOCATOR(PlainMonthDay);
  18. // 10 Temporal.PlainMonthDay Objects, https://tc39.es/proposal-temporal/#sec-temporal-plainmonthday-objects
  19. PlainMonthDay::PlainMonthDay(ISODate iso_date, String calendar, Object& prototype)
  20. : Object(ConstructWithPrototypeTag::Tag, prototype)
  21. , m_iso_date(iso_date)
  22. , m_calendar(move(calendar))
  23. {
  24. }
  25. // 10.5.1 ToTemporalMonthDay ( item [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalmonthday
  26. ThrowCompletionOr<GC::Ref<PlainMonthDay>> to_temporal_month_day(VM& vm, Value item, Value options)
  27. {
  28. // 1. If options is not present, set options to undefined.
  29. // 2. If item is a Object, then
  30. if (item.is_object()) {
  31. auto const& object = item.as_object();
  32. // a. If item has an [[InitializedTemporalMonthDay]] internal slot, then
  33. if (is<PlainMonthDay>(object)) {
  34. auto const& plain_month_day = static_cast<PlainMonthDay const&>(object);
  35. // i. Let resolvedOptions be ? GetOptionsObject(options).
  36. auto resolved_options = TRY(get_options_object(vm, options));
  37. // ii. Perform ? GetTemporalOverflowOption(resolvedOptions).
  38. TRY(get_temporal_overflow_option(vm, resolved_options));
  39. // iii. Return ! CreateTemporalMonthDay(item.[[ISODate]], item.[[Calendar]]).
  40. return MUST(create_temporal_month_day(vm, plain_month_day.iso_date(), plain_month_day.calendar()));
  41. }
  42. // b. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(item).
  43. auto calendar = TRY(get_temporal_calendar_identifier_with_iso_default(vm, object));
  44. // c. Let fields be ? PrepareCalendarFields(calendar, item, « YEAR, MONTH, MONTH-CODE, DAY », «», «»).
  45. auto fields = TRY(prepare_calendar_fields(vm, calendar, object, { { CalendarField::Year, CalendarField::Month, CalendarField::MonthCode, CalendarField::Day } }, {}, CalendarFieldList {}));
  46. // d. Let resolvedOptions be ? GetOptionsObject(options).
  47. auto resolved_options = TRY(get_options_object(vm, options));
  48. // e. Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
  49. auto overflow = TRY(get_temporal_overflow_option(vm, resolved_options));
  50. // f. Let isoDate be ? CalendarMonthDayFromFields(calendar, fields, overflow).
  51. auto iso_date = TRY(calendar_month_day_from_fields(vm, calendar, move(fields), overflow));
  52. // g. Return ! CreateTemporalMonthDay(isoDate, calendar).
  53. return MUST(create_temporal_month_day(vm, iso_date, move(calendar)));
  54. }
  55. // 3. If item is not a String, throw a TypeError exception.
  56. if (!item.is_string())
  57. return vm.throw_completion<TypeError>(ErrorType::TemporalInvalidPlainMonthDay);
  58. // 4. Let result be ? ParseISODateTime(item, « TemporalMonthDayString »).
  59. auto parse_result = TRY(parse_iso_date_time(vm, item.as_string().utf8_string_view(), { { Production::TemporalMonthDayString } }));
  60. // 5. Let calendar be result.[[Calendar]].
  61. // 6. If calendar is empty, set calendar to "iso8601".
  62. auto calendar = parse_result.calendar.value_or("iso8601"_string);
  63. // 7. Set calendar to ? CanonicalizeCalendar(calendar).
  64. calendar = TRY(canonicalize_calendar(vm, calendar));
  65. // 8. Let resolvedOptions be ? GetOptionsObject(options).
  66. auto resolved_options = TRY(get_options_object(vm, options));
  67. // 9. Perform ? GetTemporalOverflowOption(resolvedOptions).
  68. TRY(get_temporal_overflow_option(vm, resolved_options));
  69. // 10. If result.[[Year]] is empty, then
  70. if (!parse_result.year.has_value()) {
  71. // a. Assert: calendar is "iso8601".
  72. VERIFY(calendar == "iso8601"sv);
  73. // b. Let referenceISOYear be 1972 (the first ISO 8601 leap year after the epoch).
  74. static constexpr i32 reference_iso_year = 1972;
  75. // c. Let isoDate be CreateISODateRecord(referenceISOYear, result.[[Month]], result.[[Day]]).
  76. auto iso_date = create_iso_date_record(reference_iso_year, parse_result.month, parse_result.day);
  77. // d. Return ! CreateTemporalMonthDay(isoDate, calendar).
  78. return MUST(create_temporal_month_day(vm, iso_date, move(calendar)));
  79. }
  80. // 11. Let isoDate be CreateISODateRecord(result.[[Year]], result.[[Month]], result.[[Day]]).
  81. auto iso_date = create_iso_date_record(*parse_result.year, parse_result.month, parse_result.day);
  82. // 12. Set result to ISODateToFields(calendar, isoDate, MONTH-DAY).
  83. auto result = iso_date_to_fields(calendar, iso_date, DateType::MonthDay);
  84. // 13. NOTE: The following operation is called with CONSTRAIN regardless of the value of overflow, in order for the
  85. // calendar to store a canonical value in the [[Year]] field of the [[ISODate]] internal slot of the result.
  86. // 14. Set isoDate to ? CalendarMonthDayFromFields(calendar, result, CONSTRAIN).
  87. iso_date = TRY(calendar_month_day_from_fields(vm, calendar, result, Overflow::Constrain));
  88. // 15. Return ! CreateTemporalMonthDay(isoDate, calendar).
  89. return MUST(create_temporal_month_day(vm, iso_date, move(calendar)));
  90. }
  91. // 10.5.2 CreateTemporalMonthDay ( isoDate, calendar [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporalmonthday
  92. ThrowCompletionOr<GC::Ref<PlainMonthDay>> create_temporal_month_day(VM& vm, ISODate iso_date, String calendar, GC::Ptr<FunctionObject> new_target)
  93. {
  94. auto& realm = *vm.current_realm();
  95. // 1. If ISODateWithinLimits(isoDate) is false, throw a RangeError exception.
  96. if (!iso_date_within_limits(iso_date))
  97. return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidPlainMonthDay);
  98. // 2. If newTarget is not present, set newTarget to %Temporal.PlainMonthDay%.
  99. if (!new_target)
  100. new_target = realm.intrinsics().temporal_plain_month_day_constructor();
  101. // 3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.PlainMonthDay.prototype%", « [[InitializedTemporalMonthDay]], [[ISODate]], [[Calendar]] »).
  102. // 4. Set object.[[ISODate]] to isoDate.
  103. // 5. Set object.[[Calendar]] to calendar.
  104. auto object = TRY(ordinary_create_from_constructor<PlainMonthDay>(vm, *new_target, &Intrinsics::temporal_plain_month_day_prototype, iso_date, move(calendar)));
  105. // 6. Return object.
  106. return object;
  107. }
  108. }