Calendar.cpp 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102
  1. /*
  2. * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
  3. * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <LibJS/Runtime/AbstractOperations.h>
  8. #include <LibJS/Runtime/Array.h>
  9. #include <LibJS/Runtime/GlobalObject.h>
  10. #include <LibJS/Runtime/Temporal/AbstractOperations.h>
  11. #include <LibJS/Runtime/Temporal/Calendar.h>
  12. #include <LibJS/Runtime/Temporal/CalendarConstructor.h>
  13. #include <LibJS/Runtime/Temporal/PlainDate.h>
  14. #include <LibJS/Runtime/Temporal/PlainDateTime.h>
  15. #include <LibJS/Runtime/Temporal/PlainMonthDay.h>
  16. #include <LibJS/Runtime/Temporal/PlainTime.h>
  17. #include <LibJS/Runtime/Temporal/PlainYearMonth.h>
  18. #include <LibJS/Runtime/Temporal/ZonedDateTime.h>
  19. #include <LibJS/Runtime/Value.h>
  20. namespace JS::Temporal {
  21. // 12 Temporal.Calendar Objects, https://tc39.es/proposal-temporal/#sec-temporal-calendar-objects
  22. Calendar::Calendar(String identifier, Object& prototype)
  23. : Object(prototype)
  24. , m_identifier(move(identifier))
  25. {
  26. }
  27. // 12.1.1 CreateTemporalCalendar ( identifier [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporalcalendar
  28. Calendar* create_temporal_calendar(GlobalObject& global_object, String const& identifier, FunctionObject const* new_target)
  29. {
  30. // 1. Assert: ! IsBuiltinCalendar(identifier) is true.
  31. VERIFY(is_builtin_calendar(identifier));
  32. // 2. If newTarget is not provided, set newTarget to %Temporal.Calendar%.
  33. if (!new_target)
  34. new_target = global_object.temporal_calendar_constructor();
  35. // 3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.Calendar.prototype%", « [[InitializedTemporalCalendar]], [[Identifier]] »).
  36. // 4. Set object.[[Identifier]] to identifier.
  37. auto* object = TRY_OR_DISCARD(ordinary_create_from_constructor<Calendar>(global_object, *new_target, &GlobalObject::temporal_calendar_prototype, identifier));
  38. // 5. Return object.
  39. return object;
  40. }
  41. // 12.1.2 IsBuiltinCalendar ( id ), https://tc39.es/proposal-temporal/#sec-temporal-isbuiltincalendar
  42. // NOTE: This is the minimum IsBuiltinCalendar implementation for engines without ECMA-402.
  43. bool is_builtin_calendar(String const& identifier)
  44. {
  45. // 1. If id is not "iso8601", return false.
  46. if (identifier != "iso8601"sv)
  47. return false;
  48. // 2. Return true.
  49. return true;
  50. }
  51. // 12.1.3 GetBuiltinCalendar ( id ), https://tc39.es/proposal-temporal/#sec-temporal-getbuiltincalendar
  52. Calendar* get_builtin_calendar(GlobalObject& global_object, String const& identifier)
  53. {
  54. auto& vm = global_object.vm();
  55. // 1. If ! IsBuiltinCalendar(id) is false, throw a RangeError exception.
  56. if (!is_builtin_calendar(identifier)) {
  57. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidCalendarIdentifier, identifier);
  58. return {};
  59. }
  60. // 2. Return ? Construct(%Temporal.Calendar%, « id »).
  61. MarkedValueList arguments(vm.heap());
  62. arguments.append(js_string(vm, identifier));
  63. auto calendar = vm.construct(*global_object.temporal_calendar_constructor(), *global_object.temporal_calendar_constructor(), move(arguments));
  64. if (vm.exception())
  65. return {};
  66. return static_cast<Calendar*>(&calendar.as_object());
  67. }
  68. // 12.1.4 GetISO8601Calendar ( )
  69. Calendar* get_iso8601_calendar(GlobalObject& global_object)
  70. {
  71. // 1. Return ! GetBuiltinCalendar("iso8601").
  72. return get_builtin_calendar(global_object, "iso8601");
  73. }
  74. // 12.1.5 CalendarFields ( calendar, fieldNames ), https://tc39.es/proposal-temporal/#sec-temporal-calendarfields
  75. Vector<String> calendar_fields(GlobalObject& global_object, Object& calendar, Vector<StringView> const& field_names)
  76. {
  77. auto& vm = global_object.vm();
  78. // 1. Let fields be ? GetMethod(calendar, "fields").
  79. auto fields = Value(&calendar).get_method(global_object, vm.names.fields);
  80. if (vm.exception())
  81. return {};
  82. // 2. Let fieldsArray be ! CreateArrayFromList(fieldNames).
  83. auto field_names_values = MarkedValueList { vm.heap() };
  84. for (auto& field_name : field_names)
  85. field_names_values.append(js_string(vm, field_name));
  86. Value fields_array = Array::create_from(global_object, field_names_values);
  87. // 3. If fields is not undefined, then
  88. if (fields) {
  89. // a. Set fieldsArray to ? Call(fields, calendar, « fieldsArray »).
  90. fields_array = vm.call(*fields, &calendar, fields_array);
  91. if (vm.exception())
  92. return {};
  93. }
  94. // 4. Return ? IterableToListOfType(fieldsArray, « String »).
  95. auto list = TRY_OR_DISCARD(iterable_to_list_of_type(global_object, fields_array, { OptionType::String }));
  96. Vector<String> result;
  97. for (auto& value : list)
  98. result.append(value.as_string().string());
  99. return result;
  100. }
  101. // 12.1.9 CalendarYear ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendaryear
  102. double calendar_year(GlobalObject& global_object, Object& calendar, Object& date_like)
  103. {
  104. auto& vm = global_object.vm();
  105. // 1. Assert: Type(calendar) is Object.
  106. // 2. Let result be ? Invoke(calendar, "year", « dateLike »).
  107. auto result = Value(&calendar).invoke(global_object, vm.names.year, &date_like);
  108. if (vm.exception())
  109. return {};
  110. // 3. If result is undefined, throw a RangeError exception.
  111. if (result.is_undefined()) {
  112. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidCalendarFunctionResult, vm.names.year.as_string(), vm.names.undefined.as_string());
  113. return {};
  114. }
  115. // 4. Return ? ToIntegerThrowOnInfinity(result).
  116. return TRY_OR_DISCARD(to_integer_throw_on_infinity(global_object, result, ErrorType::TemporalInvalidCalendarFunctionResult, vm.names.year.as_string(), vm.names.Infinity.as_string()));
  117. }
  118. // 12.1.10 CalendarMonth ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendarmonth
  119. double calendar_month(GlobalObject& global_object, Object& calendar, Object& date_like)
  120. {
  121. auto& vm = global_object.vm();
  122. // 1. Assert: Type(calendar) is Object.
  123. // 2. Let result be ? Invoke(calendar, "month", « dateLike »).
  124. auto result = Value(&calendar).invoke(global_object, vm.names.month, &date_like);
  125. if (vm.exception())
  126. return {};
  127. // 3. If result is undefined, throw a RangeError exception.
  128. if (result.is_undefined()) {
  129. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidCalendarFunctionResult, vm.names.month.as_string(), vm.names.undefined.as_string());
  130. return {};
  131. }
  132. // 4. Return ? ToPositiveInteger(result).
  133. return to_positive_integer(global_object, result);
  134. }
  135. // 12.1.11 CalendarMonthCode ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendarmonthcode
  136. String calendar_month_code(GlobalObject& global_object, Object& calendar, Object& date_like)
  137. {
  138. auto& vm = global_object.vm();
  139. // 1. Assert: Type(calendar) is Object.
  140. // 2. Let result be ? Invoke(calendar, "monthCode", « dateLike »).
  141. auto result = Value(&calendar).invoke(global_object, vm.names.monthCode, &date_like);
  142. if (vm.exception())
  143. return {};
  144. // 3. If result is undefined, throw a RangeError exception.
  145. if (result.is_undefined()) {
  146. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidCalendarFunctionResult, vm.names.monthCode.as_string(), vm.names.undefined.as_string());
  147. return {};
  148. }
  149. // 4. Return ? ToString(result).
  150. return result.to_string(global_object);
  151. }
  152. // 12.1.12 CalendarDay ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendarday
  153. double calendar_day(GlobalObject& global_object, Object& calendar, Object& date_like)
  154. {
  155. auto& vm = global_object.vm();
  156. // 1. Assert: Type(calendar) is Object.
  157. // 2. Let result be ? Invoke(calendar, "day", « dateLike »).
  158. auto result = Value(&calendar).invoke(global_object, vm.names.day, &date_like);
  159. if (vm.exception())
  160. return {};
  161. // 3. If result is undefined, throw a RangeError exception.
  162. if (result.is_undefined()) {
  163. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidCalendarFunctionResult, vm.names.day.as_string(), vm.names.undefined.as_string());
  164. return {};
  165. }
  166. // 4. Return ? ToPositiveInteger(result).
  167. return to_positive_integer(global_object, result);
  168. }
  169. // 12.1.13 CalendarDayOfWeek ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendardayofweek
  170. Value calendar_day_of_week(GlobalObject& global_object, Object& calendar, Object& date_like)
  171. {
  172. auto& vm = global_object.vm();
  173. // 1. Assert: Type(calendar) is Object.
  174. // 2. Return ? Invoke(calendar, "dayOfWeek", « dateLike »).
  175. return Value(&calendar).invoke(global_object, vm.names.dayOfWeek, &date_like);
  176. }
  177. // 12.1.14 CalendarDayOfYear ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendardayofyear
  178. Value calendar_day_of_year(GlobalObject& global_object, Object& calendar, Object& date_like)
  179. {
  180. auto& vm = global_object.vm();
  181. // 1. Assert: Type(calendar) is Object.
  182. // 2. Return ? Invoke(calendar, "dayOfYear", « dateLike »).
  183. return Value(&calendar).invoke(global_object, vm.names.dayOfYear, &date_like);
  184. }
  185. // 12.1.15 CalendarWeekOfYear ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendarweekofyear
  186. Value calendar_week_of_year(GlobalObject& global_object, Object& calendar, Object& date_like)
  187. {
  188. auto& vm = global_object.vm();
  189. // 1. Assert: Type(calendar) is Object.
  190. // 2. Return ? Invoke(calendar, "weekOfYear", « dateLike »).
  191. return Value(&calendar).invoke(global_object, vm.names.weekOfYear, &date_like);
  192. }
  193. // 12.1.16 CalendarDaysInWeek ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendardaysinweek
  194. Value calendar_days_in_week(GlobalObject& global_object, Object& calendar, Object& date_like)
  195. {
  196. auto& vm = global_object.vm();
  197. // 1. Assert: Type(calendar) is Object.
  198. // 2. Return ? Invoke(calendar, "daysInWeek", « dateLike »).
  199. return Value(&calendar).invoke(global_object, vm.names.daysInWeek, &date_like);
  200. }
  201. // 12.1.17 CalendarDaysInMonth ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendardaysinmonth
  202. Value calendar_days_in_month(GlobalObject& global_object, Object& calendar, Object& date_like)
  203. {
  204. auto& vm = global_object.vm();
  205. // 1. Assert: Type(calendar) is Object.
  206. // 2. Return ? Invoke(calendar, "daysInMonth", « dateLike »).
  207. return Value(&calendar).invoke(global_object, vm.names.daysInMonth, &date_like);
  208. }
  209. // 12.1.18 CalendarDaysInYear ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendardaysinyear
  210. Value calendar_days_in_year(GlobalObject& global_object, Object& calendar, Object& date_like)
  211. {
  212. auto& vm = global_object.vm();
  213. // 1. Assert: Type(calendar) is Object.
  214. // 2. Return ? Invoke(calendar, "daysInYear", « dateLike »).
  215. return Value(&calendar).invoke(global_object, vm.names.daysInYear, &date_like);
  216. }
  217. // 12.1.19 CalendarMonthsInYear ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendarmonthsinyear
  218. Value calendar_months_in_year(GlobalObject& global_object, Object& calendar, Object& date_like)
  219. {
  220. auto& vm = global_object.vm();
  221. // 1. Assert: Type(calendar) is Object.
  222. // 2. Return ? Invoke(calendar, "monthsInYear", « dateLike »).
  223. return Value(&calendar).invoke(global_object, vm.names.monthsInYear, &date_like);
  224. }
  225. // 12.1.20 CalendarInLeapYear ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendarinleapyear
  226. Value calendar_in_leap_year(GlobalObject& global_object, Object& calendar, Object& date_like)
  227. {
  228. auto& vm = global_object.vm();
  229. // 1. Assert: Type(calendar) is Object.
  230. // 2. Return ? Invoke(calendar, "inLeapYear", « dateLike »).
  231. return Value(&calendar).invoke(global_object, vm.names.inLeapYear, &date_like);
  232. }
  233. // 15.6.1.2 CalendarEra ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendarera
  234. Value calendar_era(GlobalObject& global_object, Object& calendar, Object& date_like)
  235. {
  236. auto& vm = global_object.vm();
  237. // 1. Assert: Type(calendar) is Object.
  238. // 2. Let result be ? Invoke(calendar, "era", « dateLike »).
  239. auto result = Value(&calendar).invoke(global_object, vm.names.era, &date_like);
  240. if (vm.exception())
  241. return {};
  242. // 3. If result is not undefined, set result to ? ToString(result).
  243. if (!result.is_undefined()) {
  244. auto result_string = result.to_string(global_object);
  245. if (vm.exception())
  246. return {};
  247. result = js_string(vm, move(result_string));
  248. }
  249. // 4. Return result.
  250. return result;
  251. }
  252. // 15.6.1.3 CalendarEraYear ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendarerayear
  253. Value calendar_era_year(GlobalObject& global_object, Object& calendar, Object& date_like)
  254. {
  255. auto& vm = global_object.vm();
  256. // 1. Assert: Type(calendar) is Object.
  257. // 2. Let result be ? Invoke(calendar, "eraYear", « dateLike »).
  258. auto result = Value(&calendar).invoke(global_object, vm.names.eraYear, &date_like);
  259. if (vm.exception())
  260. return {};
  261. // 3. If result is not undefined, set result to ? ToIntegerThrowOnInfinity(result).
  262. if (!result.is_undefined())
  263. result = Value(TRY_OR_DISCARD(to_integer_throw_on_infinity(global_object, result, ErrorType::TemporalInvalidCalendarFunctionResult, vm.names.eraYear.as_string(), "Infinity"sv)));
  264. // 4. Return result.
  265. return result;
  266. }
  267. // 12.1.21 ToTemporalCalendar ( temporalCalendarLike ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalcalendar
  268. Object* to_temporal_calendar(GlobalObject& global_object, Value temporal_calendar_like)
  269. {
  270. auto& vm = global_object.vm();
  271. // 1. If Type(temporalCalendarLike) is Object, then
  272. if (temporal_calendar_like.is_object()) {
  273. auto& temporal_calendar_like_object = temporal_calendar_like.as_object();
  274. // a. If temporalCalendarLike has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
  275. // i. Return temporalCalendarLike.[[Calendar]].
  276. if (is<PlainDate>(temporal_calendar_like_object))
  277. return &static_cast<PlainDate&>(temporal_calendar_like_object).calendar();
  278. if (is<PlainDateTime>(temporal_calendar_like_object))
  279. return &static_cast<PlainDateTime&>(temporal_calendar_like_object).calendar();
  280. if (is<PlainMonthDay>(temporal_calendar_like_object))
  281. return &static_cast<PlainMonthDay&>(temporal_calendar_like_object).calendar();
  282. if (is<PlainTime>(temporal_calendar_like_object))
  283. return &static_cast<PlainTime&>(temporal_calendar_like_object).calendar();
  284. if (is<PlainYearMonth>(temporal_calendar_like_object))
  285. return &static_cast<PlainYearMonth&>(temporal_calendar_like_object).calendar();
  286. if (is<ZonedDateTime>(temporal_calendar_like_object))
  287. return &static_cast<ZonedDateTime&>(temporal_calendar_like_object).calendar();
  288. // b. If ? HasProperty(temporalCalendarLike, "calendar") is false, return temporalCalendarLike.
  289. auto has_property = temporal_calendar_like_object.has_property(vm.names.calendar);
  290. if (vm.exception())
  291. return {};
  292. if (!has_property)
  293. return &temporal_calendar_like_object;
  294. // c. Set temporalCalendarLike to ? Get(temporalCalendarLike, "calendar").
  295. temporal_calendar_like = temporal_calendar_like_object.get(vm.names.calendar);
  296. if (vm.exception())
  297. return {};
  298. // d. If Type(temporalCalendarLike) is Object and ? HasProperty(temporalCalendarLike, "calendar") is false, return temporalCalendarLike.
  299. if (temporal_calendar_like.is_object()) {
  300. has_property = temporal_calendar_like.as_object().has_property(vm.names.calendar);
  301. if (vm.exception())
  302. return {};
  303. if (!has_property)
  304. return &temporal_calendar_like.as_object();
  305. }
  306. }
  307. // 2. Let identifier be ? ToString(temporalCalendarLike).
  308. auto identifier = temporal_calendar_like.to_string(global_object);
  309. if (vm.exception())
  310. return {};
  311. // 3. If ! IsBuiltinCalendar(identifier) is false, then
  312. if (!is_builtin_calendar(identifier)) {
  313. // a. Let identifier be ? ParseTemporalCalendarString(identifier).
  314. identifier = TRY_OR_DISCARD(parse_temporal_calendar_string(global_object, identifier));
  315. }
  316. // 4. Return ! CreateTemporalCalendar(identifier).
  317. return create_temporal_calendar(global_object, identifier);
  318. }
  319. // 12.1.22 ToTemporalCalendarWithISODefault ( temporalCalendarLike ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalcalendarwithisodefault
  320. Object* to_temporal_calendar_with_iso_default(GlobalObject& global_object, Value temporal_calendar_like)
  321. {
  322. // 1. If temporalCalendarLike is undefined, then
  323. if (temporal_calendar_like.is_undefined()) {
  324. // a. Return ! GetISO8601Calendar().
  325. return get_iso8601_calendar(global_object);
  326. }
  327. // 2. Return ? ToTemporalCalendar(temporalCalendarLike).
  328. return to_temporal_calendar(global_object, temporal_calendar_like);
  329. }
  330. // 12.1.23 GetTemporalCalendarWithISODefault ( item ), https://tc39.es/proposal-temporal/#sec-temporal-gettemporalcalendarwithisodefault
  331. Object* get_temporal_calendar_with_iso_default(GlobalObject& global_object, Object& item)
  332. {
  333. auto& vm = global_object.vm();
  334. // 1. If item has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
  335. // a. Return item.[[Calendar]].
  336. if (is<PlainDate>(item))
  337. return &static_cast<PlainDate&>(item).calendar();
  338. if (is<PlainDateTime>(item))
  339. return &static_cast<PlainDateTime&>(item).calendar();
  340. if (is<PlainMonthDay>(item))
  341. return &static_cast<PlainMonthDay&>(item).calendar();
  342. if (is<PlainTime>(item))
  343. return &static_cast<PlainTime&>(item).calendar();
  344. if (is<PlainYearMonth>(item))
  345. return &static_cast<PlainYearMonth&>(item).calendar();
  346. if (is<ZonedDateTime>(item))
  347. return &static_cast<ZonedDateTime&>(item).calendar();
  348. // 2. Let calendar be ? Get(item, "calendar").
  349. auto calendar = item.get(vm.names.calendar);
  350. if (vm.exception())
  351. return {};
  352. // 3. Return ? ToTemporalCalendarWithISODefault(calendar).
  353. return to_temporal_calendar_with_iso_default(global_object, calendar);
  354. }
  355. // 12.1.24 DateFromFields ( calendar, fields, options ), https://tc39.es/proposal-temporal/#sec-temporal-datefromfields
  356. PlainDate* date_from_fields(GlobalObject& global_object, Object& calendar, Object const& fields, Object const& options)
  357. {
  358. auto& vm = global_object.vm();
  359. // 1. Assert: Type(calendar) is Object.
  360. // 2. Assert: Type(fields) is Object.
  361. // 3. Let date be ? Invoke(calendar, "dateFromFields", « fields, options »).
  362. auto date = Value(&calendar).invoke(global_object, vm.names.dateFromFields, &fields, &options);
  363. if (vm.exception())
  364. return {};
  365. // 4. Perform ? RequireInternalSlot(date, [[InitializedTemporalDate]]).
  366. auto* date_object = date.to_object(global_object);
  367. if (!date_object)
  368. return {};
  369. if (!is<PlainDate>(date_object)) {
  370. vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObjectOfType, "Temporal.PlainDate");
  371. return {};
  372. }
  373. // 5. Return date.
  374. return static_cast<PlainDate*>(date_object);
  375. }
  376. // 12.1.25 YearMonthFromFields ( calendar, fields [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal-yearmonthfromfields
  377. PlainYearMonth* year_month_from_fields(GlobalObject& global_object, Object& calendar, Object const& fields, Object const* options)
  378. {
  379. auto& vm = global_object.vm();
  380. // 1. Assert: Type(calendar) is Object.
  381. // 2. Assert: Type(fields) is Object.
  382. // 3. If options is not present, then
  383. // a. Set options to undefined.
  384. // 4. Else,
  385. // a. Assert: Type(options) is Object.
  386. // 5. Let yearMonth be ? Invoke(calendar, "yearMonthFromFields", « fields, options »).
  387. auto year_month = Value(&calendar).invoke(global_object, vm.names.yearMonthFromFields, &fields, options ?: js_undefined());
  388. if (vm.exception())
  389. return {};
  390. // 6. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  391. auto* year_month_object = year_month.to_object(global_object);
  392. if (!year_month_object)
  393. return {};
  394. if (!is<PlainYearMonth>(year_month_object)) {
  395. vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObjectOfType, "Temporal.PlainYearMonth");
  396. return {};
  397. }
  398. // 7. Return yearMonth.
  399. return static_cast<PlainYearMonth*>(year_month_object);
  400. }
  401. // 12.1.26 MonthDayFromFields ( calendar, fields [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal-monthdayfromfields
  402. PlainMonthDay* month_day_from_fields(GlobalObject& global_object, Object& calendar, Object const& fields, Object const* options)
  403. {
  404. auto& vm = global_object.vm();
  405. // 1. Assert: Type(calendar) is Object.
  406. // 2. Assert: Type(fields) is Object.
  407. // 3. If options is not present, then
  408. // a. Set options to undefined.
  409. // 4. Else,
  410. // a. Assert: Type(options) is Object.
  411. // 5. Let monthDay be ? Invoke(calendar, "monthDayFromFields", « fields, options »).
  412. auto month_day = Value(&calendar).invoke(global_object, vm.names.monthDayFromFields, &fields, options ?: js_undefined());
  413. if (vm.exception())
  414. return {};
  415. // 6. Perform ? RequireInternalSlot(monthDay, [[InitializedTemporalMonthDay]]).
  416. auto* month_day_object = month_day.to_object(global_object);
  417. if (!month_day_object)
  418. return {};
  419. if (!is<PlainMonthDay>(month_day_object)) {
  420. vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObjectOfType, "Temporal.PlainMonthDay");
  421. return {};
  422. }
  423. // 7. Return monthDay.
  424. return static_cast<PlainMonthDay*>(month_day_object);
  425. }
  426. // 12.1.27 FormatCalendarAnnotation ( id, showCalendar ), https://tc39.es/proposal-temporal/#sec-temporal-formatcalendarannotation
  427. String format_calendar_annotation(StringView id, StringView show_calendar)
  428. {
  429. // 1. Assert: showCalendar is "auto", "always", or "never".
  430. VERIFY(show_calendar == "auto"sv || show_calendar == "always"sv || show_calendar == "never"sv);
  431. // 2. If showCalendar is "never", return the empty String.
  432. if (show_calendar == "never"sv)
  433. return String::empty();
  434. // 3. If showCalendar is "auto" and id is "iso8601", return the empty String.
  435. if (show_calendar == "auto"sv && id == "iso8601"sv)
  436. return String::empty();
  437. // 4. Return the string-concatenation of "[u-ca=", id, and "]".
  438. return String::formatted("[u-ca={}]", id);
  439. }
  440. // 12.1.28 CalendarEquals ( one, two ), https://tc39.es/proposal-temporal/#sec-temporal-calendarequals
  441. bool calendar_equals(GlobalObject& global_object, Object& one, Object& two)
  442. {
  443. auto& vm = global_object.vm();
  444. // 1. If one and two are the same Object value, return true.
  445. if (&one == &two)
  446. return true;
  447. // 2. Let calendarOne be ? ToString(one).
  448. auto calendar_one = Value(&one).to_string(global_object);
  449. if (vm.exception())
  450. return {};
  451. // 3. Let calendarTwo be ? ToString(two).
  452. auto calendar_two = Value(&two).to_string(global_object);
  453. if (vm.exception())
  454. return {};
  455. // 4. If calendarOne is calendarTwo, return true.
  456. if (calendar_one == calendar_two)
  457. return true;
  458. // 5. Return false.
  459. return false;
  460. }
  461. // 12.1.29 ConsolidateCalendars ( one, two ), https://tc39.es/proposal-temporal/#sec-temporal-consolidatecalendars
  462. Object* consolidate_calendars(GlobalObject& global_object, Object& one, Object& two)
  463. {
  464. auto& vm = global_object.vm();
  465. // 1. If one and two are the same Object value, return two.
  466. if (&one == &two)
  467. return &two;
  468. // 2. Let calendarOne be ? ToString(one).
  469. auto calendar_one = Value(&one).to_string(global_object);
  470. if (vm.exception())
  471. return {};
  472. // 3. Let calendarTwo be ? ToString(two).
  473. auto calendar_two = Value(&two).to_string(global_object);
  474. if (vm.exception())
  475. return {};
  476. // 4. If calendarOne is calendarTwo, return two.
  477. if (calendar_one == calendar_two)
  478. return &two;
  479. // 5. If calendarOne is "iso8601", return two.
  480. if (calendar_one == "iso8601"sv)
  481. return &two;
  482. // 6. If calendarTwo is "iso8601", return one.
  483. if (calendar_two == "iso8601"sv)
  484. return &one;
  485. // 7. Throw a RangeError exception.
  486. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidCalendar);
  487. return {};
  488. }
  489. // 12.1.30 IsISOLeapYear ( year ), https://tc39.es/proposal-temporal/#sec-temporal-isisoleapyear
  490. bool is_iso_leap_year(i32 year)
  491. {
  492. // 1. Assert: year is an integer.
  493. // 2. If year modulo 4 ≠ 0, return false.
  494. if (year % 4 != 0)
  495. return false;
  496. // 3. If year modulo 400 = 0, return true.
  497. if (year % 400 == 0)
  498. return true;
  499. // 4. If year modulo 100 = 0, return false.
  500. if (year % 100 == 0)
  501. return false;
  502. // 5. Return true.
  503. return true;
  504. }
  505. // 12.1.31 ISODaysInYear ( year ), https://tc39.es/proposal-temporal/#sec-temporal-isodaysinyear
  506. u16 iso_days_in_year(i32 year)
  507. {
  508. // 1. Assert: year is an integer.
  509. // 2. If ! IsISOLeapYear(year) is true, then
  510. if (is_iso_leap_year(year)) {
  511. // a. Return 366.
  512. return 366;
  513. }
  514. // 3. Return 365.
  515. return 365;
  516. }
  517. // 12.1.32 ISODaysInMonth ( year, month ), https://tc39.es/proposal-temporal/#sec-temporal-isodaysinmonth
  518. u8 iso_days_in_month(i32 year, u8 month)
  519. {
  520. // 1. Assert: year is an integer.
  521. // 2. Assert: month is an integer, month ≥ 1, and month ≤ 12.
  522. VERIFY(month >= 1 && month <= 12);
  523. // 3. If month is 1, 3, 5, 7, 8, 10, or 12, return 31.
  524. if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
  525. return 31;
  526. // 4. If month is 4, 6, 9, or 11, return 30.
  527. if (month == 4 || month == 6 || month == 9 || month == 11)
  528. return 30;
  529. // 5. If ! IsISOLeapYear(year) is true, return 29.
  530. if (is_iso_leap_year(year))
  531. return 29;
  532. // 6. Return 28.
  533. return 28;
  534. }
  535. // 12.1.33 ToISODayOfWeek ( year, month, day ), https://tc39.es/proposal-temporal/#sec-temporal-toisodayofweek
  536. u8 to_iso_day_of_week(i32 year, u8 month, u8 day)
  537. {
  538. // 1. Assert: year is an integer.
  539. // 2. Assert: month is an integer.
  540. // 3. Assert: day is an integer.
  541. // 4. Let date be the date given by year, month, and day.
  542. // 5. Return date's day of the week according to ISO-8601.
  543. // NOTE: Implemented based on https://cs.uwaterloo.ca/~alopez-o/math-faq/node73.html
  544. auto normalized_month = month + (month < 3 ? 10 : -2);
  545. auto normalized_year = year - (month < 3 ? 1 : 0);
  546. auto century = normalized_year / 100;
  547. auto truncated_year = normalized_year - (century * 100);
  548. auto result = (day + static_cast<u8>((2.6 * normalized_month) - 0.2) - (2 * century) + truncated_year + (truncated_year / 4) + (century / 4)) % 7;
  549. if (result <= 0) // Mathematical modulo
  550. result += 7;
  551. return result;
  552. }
  553. // 12.1.34 ToISODayOfYear ( year, month, day ), https://tc39.es/proposal-temporal/#sec-temporal-toisodayofyear
  554. u16 to_iso_day_of_year(i32 year, u8 month, u8 day)
  555. {
  556. // 1. Assert: year is an integer.
  557. // 2. Assert: month is an integer.
  558. // 3. Assert: day is an integer.
  559. // 4. Let date be the date given by year, month, and day.
  560. // 5. Return date's ordinal date in the year according to ISO-8601.
  561. u16 days = day;
  562. for (u8 i = month - 1; i > 0; --i)
  563. days += iso_days_in_month(year, i);
  564. return days;
  565. }
  566. // 12.1.35 ToISOWeekOfYear ( year, month, day ), https://tc39.es/proposal-temporal/#sec-temporal-toisoweekofyear
  567. u8 to_iso_week_of_year(i32 year, u8 month, u8 day)
  568. {
  569. // 1. Assert: year is an integer.
  570. // 2. Assert: month is an integer.
  571. // 3. Assert: day is an integer.
  572. // 4. Let date be the date given by year, month, and day.
  573. // 5. Return date's week number according to ISO-8601.
  574. auto day_of_year = to_iso_day_of_year(year, month, day);
  575. auto day_of_week = to_iso_day_of_week(year, month, day);
  576. auto week = (day_of_year - day_of_week + 10) / 7;
  577. if (week < 1) {
  578. auto day_of_jump = to_iso_day_of_week(year, 1, 1);
  579. if (day_of_jump == 5 || (is_iso_leap_year(year) && day_of_jump == 6))
  580. return 53;
  581. else
  582. return 52;
  583. } else if (week == 53) {
  584. auto days_in_year = iso_days_in_year(year);
  585. if (days_in_year - day_of_year < 4 - day_of_week)
  586. return 1;
  587. }
  588. return week;
  589. }
  590. // 12.1.36 BuildISOMonthCode ( month ), https://tc39.es/proposal-temporal/#sec-buildisomonthcode
  591. String build_iso_month_code(u8 month)
  592. {
  593. return String::formatted("M{:02}", month);
  594. }
  595. // 12.1.37 ResolveISOMonth ( fields ), https://tc39.es/proposal-temporal/#sec-temporal-resolveisomonth
  596. double resolve_iso_month(GlobalObject& global_object, Object const& fields)
  597. {
  598. auto& vm = global_object.vm();
  599. // 1. Let month be ? Get(fields, "month").
  600. auto month = fields.get(vm.names.month);
  601. if (vm.exception())
  602. return {};
  603. // 2. Let monthCode be ? Get(fields, "monthCode").
  604. auto month_code = fields.get(vm.names.monthCode);
  605. if (vm.exception())
  606. return {};
  607. // 3. If monthCode is undefined, then
  608. if (month_code.is_undefined()) {
  609. // a. If month is undefined, throw a TypeError exception.
  610. if (month.is_undefined()) {
  611. vm.throw_exception<TypeError>(global_object, ErrorType::TemporalMissingRequiredProperty, vm.names.month.as_string());
  612. return {};
  613. }
  614. // b. Return month.
  615. return month.as_double();
  616. }
  617. // 4. Assert: Type(monthCode) is String.
  618. VERIFY(month_code.is_string());
  619. auto& month_code_string = month_code.as_string().string();
  620. // 5. Let monthLength be the length of monthCode.
  621. auto month_length = month_code_string.length();
  622. // 6. If monthLength is not 3, throw a RangeError exception.
  623. if (month_length != 3) {
  624. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidMonthCode);
  625. return {};
  626. }
  627. // 7. Let numberPart be the substring of monthCode from 1.
  628. auto number_part = month_code_string.substring(1);
  629. // 8. Set numberPart to ! ToIntegerOrInfinity(numberPart).
  630. auto number_part_integer = Value(js_string(vm, move(number_part))).to_integer_or_infinity(global_object);
  631. // 9. If numberPart < 1 or numberPart > 12, throw a RangeError exception.
  632. if (number_part_integer < 1 || number_part_integer > 12) {
  633. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidMonthCode);
  634. return {};
  635. }
  636. // 10. If month is not undefined, and month ≠ numberPart, then
  637. if (!month.is_undefined() && month.as_double() != number_part_integer) {
  638. // a. Throw a RangeError exception.
  639. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidMonthCode);
  640. return {};
  641. }
  642. // 11. If ! SameValueNonNumeric(monthCode, ! BuildISOMonthCode(numberPart)) is false, then
  643. if (month_code_string != build_iso_month_code(number_part_integer)) {
  644. // a. Throw a RangeError exception.
  645. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidMonthCode);
  646. return {};
  647. }
  648. // 12. Return numberPart.
  649. return number_part_integer;
  650. }
  651. // 12.1.38 ISODateFromFields ( fields, options ), https://tc39.es/proposal-temporal/#sec-temporal-isodatefromfields
  652. Optional<ISODate> iso_date_from_fields(GlobalObject& global_object, Object const& fields, Object const& options)
  653. {
  654. auto& vm = global_object.vm();
  655. // 1. Assert: Type(fields) is Object.
  656. // 2. Let overflow be ? ToTemporalOverflow(options).
  657. auto overflow = TRY_OR_DISCARD(to_temporal_overflow(global_object, options));
  658. // 3. Set fields to ? PrepareTemporalFields(fields, « "day", "month", "monthCode", "year" », «»).
  659. auto* prepared_fields = prepare_temporal_fields(global_object, fields, { "day", "month", "monthCode", "year" }, {});
  660. if (vm.exception())
  661. return {};
  662. // 4. Let year be ? Get(fields, "year").
  663. auto year = prepared_fields->get(vm.names.year);
  664. if (vm.exception())
  665. return {};
  666. // 5. If year is undefined, throw a TypeError exception.
  667. if (year.is_undefined()) {
  668. vm.throw_exception<TypeError>(global_object, ErrorType::TemporalMissingRequiredProperty, vm.names.year.as_string());
  669. return {};
  670. }
  671. // 6. Let month be ? ResolveISOMonth(fields).
  672. auto month = resolve_iso_month(global_object, *prepared_fields);
  673. if (vm.exception())
  674. return {};
  675. // 7. Let day be ? Get(fields, "day").
  676. auto day = prepared_fields->get(vm.names.day);
  677. if (vm.exception())
  678. return {};
  679. // 8. If day is undefined, throw a TypeError exception.
  680. if (day.is_undefined()) {
  681. vm.throw_exception<TypeError>(global_object, ErrorType::TemporalMissingRequiredProperty, vm.names.day.as_string());
  682. return {};
  683. }
  684. // 9. Return ? RegulateISODate(year, month, day, overflow).
  685. return regulate_iso_date(global_object, year.as_double(), month, day.as_double(), overflow);
  686. }
  687. // 12.1.39 ISOYearMonthFromFields ( fields, options ), https://tc39.es/proposal-temporal/#sec-temporal-isoyearmonthfromfields
  688. Optional<ISOYearMonth> iso_year_month_from_fields(GlobalObject& global_object, Object const& fields, Object const& options)
  689. {
  690. auto& vm = global_object.vm();
  691. // 1. Assert: Type(fields) is Object.
  692. // 2. Let overflow be ? ToTemporalOverflow(options).
  693. auto overflow = TRY_OR_DISCARD(to_temporal_overflow(global_object, options));
  694. // 3. Set fields to ? PrepareTemporalFields(fields, « "month", "monthCode", "year" », «»).
  695. auto* prepared_fields = prepare_temporal_fields(global_object, fields, { "month"sv, "monthCode"sv, "year"sv }, {});
  696. if (vm.exception())
  697. return {};
  698. // 4. Let year be ? Get(fields, "year").
  699. auto year = prepared_fields->get(vm.names.year);
  700. if (vm.exception())
  701. return {};
  702. // 5. If year is undefined, throw a TypeError exception.
  703. if (year.is_undefined()) {
  704. vm.throw_exception<TypeError>(global_object, ErrorType::TemporalMissingRequiredProperty, vm.names.year.as_string());
  705. return {};
  706. }
  707. // 6. Let month be ? ResolveISOMonth(fields).
  708. auto month = resolve_iso_month(global_object, *prepared_fields);
  709. if (vm.exception())
  710. return {};
  711. // 7. Let result be ? RegulateISOYearMonth(year, month, overflow).
  712. auto result = TRY_OR_DISCARD(regulate_iso_year_month(global_object, year.as_double(), month, overflow));
  713. // 8. Return the Record { [[Year]]: result.[[Year]], [[Month]]: result.[[Month]], [[ReferenceISODay]]: 1 }.
  714. return ISOYearMonth { .year = result.year, .month = result.month, .reference_iso_day = 1 };
  715. }
  716. // 12.1.40 ISOMonthDayFromFields ( fields, options ), https://tc39.es/proposal-temporal/#sec-temporal-isomonthdayfromfields
  717. Optional<ISOMonthDay> iso_month_day_from_fields(GlobalObject& global_object, Object const& fields, Object const& options)
  718. {
  719. auto& vm = global_object.vm();
  720. // 1. Assert: Type(fields) is Object.
  721. // 2. Let overflow be ? ToTemporalOverflow(options).
  722. auto overflow = TRY_OR_DISCARD(to_temporal_overflow(global_object, options));
  723. // 3. Set fields to ? PrepareTemporalFields(fields, « "day", "month", "monthCode", "year" », «»).
  724. auto* prepared_fields = prepare_temporal_fields(global_object, fields, { "day"sv, "month"sv, "monthCode"sv, "year"sv }, {});
  725. if (vm.exception())
  726. return {};
  727. // 4. Let month be ? Get(fields, "month").
  728. auto month_value = prepared_fields->get(vm.names.month);
  729. if (vm.exception())
  730. return {};
  731. // 5. Let monthCode be ? Get(fields, "monthCode").
  732. auto month_code = prepared_fields->get(vm.names.monthCode);
  733. if (vm.exception())
  734. return {};
  735. // 6. Let year be ? Get(fields, "year").
  736. auto year = prepared_fields->get(vm.names.year);
  737. if (vm.exception())
  738. return {};
  739. // 7. If month is not undefined, and monthCode and year are both undefined, then
  740. if (!month_value.is_undefined() && month_code.is_undefined() && year.is_undefined()) {
  741. // a. Throw a TypeError exception.
  742. vm.throw_exception<TypeError>(global_object, ErrorType::TemporalMissingRequiredProperty, "monthCode or year");
  743. return {};
  744. }
  745. // 8. Set month to ? ResolveISOMonth(fields).
  746. auto month = resolve_iso_month(global_object, *prepared_fields);
  747. if (vm.exception())
  748. return {};
  749. // 9. Let day be ? Get(fields, "day").
  750. auto day = prepared_fields->get(vm.names.day);
  751. if (vm.exception())
  752. return {};
  753. // 10. If day is undefined, throw a TypeError exception.
  754. if (day.is_undefined()) {
  755. vm.throw_exception<TypeError>(global_object, ErrorType::TemporalMissingRequiredProperty, vm.names.day.as_string());
  756. return {};
  757. }
  758. // 11. Let referenceISOYear be 1972 (the first leap year after the Unix epoch).
  759. i32 reference_iso_year = 1972;
  760. Optional<ISODate> result;
  761. // 12. If monthCode is undefined, then
  762. if (month_code.is_undefined()) {
  763. // a. Let result be ? RegulateISODate(year, month, day, overflow).
  764. result = regulate_iso_date(global_object, year.as_double(), month, day.as_double(), overflow);
  765. }
  766. // 13. Else,
  767. else {
  768. // a. Let result be ? RegulateISODate(referenceISOYear, month, day, overflow).
  769. result = regulate_iso_date(global_object, reference_iso_year, month, day.as_double(), overflow);
  770. }
  771. if (vm.exception())
  772. return {};
  773. // 14. Return the Record { [[Month]]: result.[[Month]], [[Day]]: result.[[Day]], [[ReferenceISOYear]]: referenceISOYear }.
  774. return ISOMonthDay { .month = result->month, .day = result->day, .reference_iso_year = reference_iso_year };
  775. }
  776. // 12.1.41 ISOYear ( temporalObject ), https://tc39.es/proposal-temporal/#sec-temporal-isoyear
  777. i32 iso_year(Object& temporal_object)
  778. {
  779. // 1. Assert: temporalObject has an [[ISOYear]] internal slot.
  780. // NOTE: Asserted by the VERIFY_NOT_REACHED at the end
  781. // 2. Return 𝔽(temporalObject.[[ISOYear]]).
  782. if (is<PlainDate>(temporal_object))
  783. return static_cast<PlainDate&>(temporal_object).iso_year();
  784. if (is<PlainDateTime>(temporal_object))
  785. return static_cast<PlainDateTime&>(temporal_object).iso_year();
  786. if (is<PlainYearMonth>(temporal_object))
  787. return static_cast<PlainYearMonth&>(temporal_object).iso_year();
  788. if (is<PlainMonthDay>(temporal_object))
  789. return static_cast<PlainMonthDay&>(temporal_object).iso_year();
  790. VERIFY_NOT_REACHED();
  791. }
  792. // 12.1.42 ISOMonth ( temporalObject ), https://tc39.es/proposal-temporal/#sec-temporal-isomonth
  793. u8 iso_month(Object& temporal_object)
  794. {
  795. // 1. Assert: temporalObject has an [[ISOMonth]] internal slot.
  796. // NOTE: Asserted by the VERIFY_NOT_REACHED at the end
  797. // 2. Return 𝔽(temporalObject.[[ISOMonth]]).
  798. if (is<PlainDate>(temporal_object))
  799. return static_cast<PlainDate&>(temporal_object).iso_month();
  800. if (is<PlainDateTime>(temporal_object))
  801. return static_cast<PlainDateTime&>(temporal_object).iso_month();
  802. if (is<PlainYearMonth>(temporal_object))
  803. return static_cast<PlainYearMonth&>(temporal_object).iso_month();
  804. if (is<PlainMonthDay>(temporal_object))
  805. return static_cast<PlainMonthDay&>(temporal_object).iso_month();
  806. VERIFY_NOT_REACHED();
  807. }
  808. // 12.1.43 ISOMonthCode ( temporalObject ), https://tc39.es/proposal-temporal/#sec-temporal-isomonthcode
  809. String iso_month_code(Object& temporal_object)
  810. {
  811. // 1. Assert: temporalObject has an [[ISOMonth]] internal slot.
  812. // NOTE: Asserted by the VERIFY_NOT_REACHED at the end
  813. // 2. Return ! BuildISOMonthCode(temporalObject.[[ISOMonth]]).
  814. if (is<PlainDate>(temporal_object))
  815. return build_iso_month_code(static_cast<PlainDate&>(temporal_object).iso_month());
  816. if (is<PlainDateTime>(temporal_object))
  817. return build_iso_month_code(static_cast<PlainDateTime&>(temporal_object).iso_month());
  818. if (is<PlainYearMonth>(temporal_object))
  819. return build_iso_month_code(static_cast<PlainYearMonth&>(temporal_object).iso_month());
  820. if (is<PlainMonthDay>(temporal_object))
  821. return build_iso_month_code(static_cast<PlainMonthDay&>(temporal_object).iso_month());
  822. VERIFY_NOT_REACHED();
  823. }
  824. // 12.1.44 ISODay ( temporalObject ), https://tc39.es/proposal-temporal/#sec-temporal-isomonthcode
  825. u8 iso_day(Object& temporal_object)
  826. {
  827. // 1. Assert: temporalObject has an [[ISODay]] internal slot.
  828. // NOTE: Asserted by the VERIFY_NOT_REACHED at the end
  829. // 2. Return 𝔽(temporalObject.[[ISODay]]).
  830. if (is<PlainDate>(temporal_object))
  831. return static_cast<PlainDate&>(temporal_object).iso_day();
  832. if (is<PlainDateTime>(temporal_object))
  833. return static_cast<PlainDateTime&>(temporal_object).iso_day();
  834. if (is<PlainYearMonth>(temporal_object))
  835. return static_cast<PlainYearMonth&>(temporal_object).iso_day();
  836. if (is<PlainMonthDay>(temporal_object))
  837. return static_cast<PlainMonthDay&>(temporal_object).iso_day();
  838. VERIFY_NOT_REACHED();
  839. }
  840. // 12.1.45 DefaultMergeFields ( fields, additionalFields ), https://tc39.es/proposal-temporal/#sec-temporal-defaultmergefields
  841. Object* default_merge_fields(GlobalObject& global_object, Object const& fields, Object const& additional_fields)
  842. {
  843. auto& vm = global_object.vm();
  844. // 1. Let merged be ! OrdinaryObjectCreate(%Object.prototype%).
  845. auto* merged = Object::create(global_object, global_object.object_prototype());
  846. // 2. Let originalKeys be ? EnumerableOwnPropertyNames(fields, key).
  847. auto original_keys = fields.enumerable_own_property_names(Object::PropertyKind::Key);
  848. if (vm.exception())
  849. return {};
  850. // 3. For each element nextKey of originalKeys, do
  851. for (auto& next_key : original_keys) {
  852. // a. If nextKey is not "month" or "monthCode", then
  853. if (next_key.as_string().string() != vm.names.month.as_string() && next_key.as_string().string() != vm.names.monthCode.as_string()) {
  854. auto property_name = PropertyName::from_value(global_object, next_key);
  855. // i. Let propValue be ? Get(fields, nextKey).
  856. auto prop_value = fields.get(property_name);
  857. if (vm.exception())
  858. return {};
  859. // ii. If propValue is not undefined, then
  860. if (!prop_value.is_undefined()) {
  861. // 1. Perform ! CreateDataPropertyOrThrow(merged, nextKey, propValue).
  862. merged->create_data_property_or_throw(property_name, prop_value);
  863. }
  864. }
  865. }
  866. // 4. Let newKeys be ? EnumerableOwnPropertyNames(additionalFields, key).
  867. auto new_keys = additional_fields.enumerable_own_property_names(Object::PropertyKind::Key);
  868. if (vm.exception())
  869. return {};
  870. // IMPLEMENTATION DEFINED: This is an optimization, so we don't have to iterate new_keys three times (worst case), but only once.
  871. bool new_keys_contains_month_or_month_code_property = false;
  872. // 5. For each element nextKey of newKeys, do
  873. for (auto& next_key : new_keys) {
  874. auto property_name = PropertyName::from_value(global_object, next_key);
  875. // a. Let propValue be ? Get(additionalFields, nextKey).
  876. auto prop_value = additional_fields.get(property_name);
  877. if (vm.exception())
  878. return {};
  879. // b. If propValue is not undefined, then
  880. if (!prop_value.is_undefined()) {
  881. // i. Perform ! CreateDataPropertyOrThrow(merged, nextKey, propValue).
  882. merged->create_data_property_or_throw(property_name, prop_value);
  883. }
  884. // See comment above.
  885. new_keys_contains_month_or_month_code_property |= next_key.as_string().string() == vm.names.month.as_string() || next_key.as_string().string() == vm.names.monthCode.as_string();
  886. }
  887. // 6. If newKeys does not contain either "month" or "monthCode", then
  888. if (!new_keys_contains_month_or_month_code_property) {
  889. // a. Let month be ? Get(fields, "month").
  890. auto month = fields.get(vm.names.month);
  891. if (vm.exception())
  892. return {};
  893. // b. If month is not undefined, then
  894. if (!month.is_undefined()) {
  895. // i. Perform ! CreateDataPropertyOrThrow(merged, "month", month).
  896. merged->create_data_property_or_throw(vm.names.month, month);
  897. }
  898. // c. Let monthCode be ? Get(fields, "monthCode").
  899. auto month_code = fields.get(vm.names.monthCode);
  900. if (vm.exception())
  901. return {};
  902. // d. If monthCode is not undefined, then
  903. if (!month_code.is_undefined()) {
  904. // i. Perform ! CreateDataPropertyOrThrow(merged, "monthCode", monthCode).
  905. merged->create_data_property_or_throw(vm.names.monthCode, month_code);
  906. }
  907. }
  908. // 7. Return merged.
  909. return merged;
  910. }
  911. }