PlainDateTimeConstructor.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Checked.h>
  7. #include <LibJS/Runtime/GlobalObject.h>
  8. #include <LibJS/Runtime/Temporal/Calendar.h>
  9. #include <LibJS/Runtime/Temporal/PlainDateTime.h>
  10. #include <LibJS/Runtime/Temporal/PlainDateTimeConstructor.h>
  11. namespace JS::Temporal {
  12. // 5.1 The Temporal.PlainDateTime Constructor, https://tc39.es/proposal-temporal/#sec-temporal-plaindatetime-constructor
  13. PlainDateTimeConstructor::PlainDateTimeConstructor(GlobalObject& global_object)
  14. : NativeFunction(vm().names.PlainDateTime.as_string(), *global_object.function_prototype())
  15. {
  16. }
  17. void PlainDateTimeConstructor::initialize(GlobalObject& global_object)
  18. {
  19. NativeFunction::initialize(global_object);
  20. auto& vm = this->vm();
  21. // 5.2.1 Temporal.PlainDateTime.prototype, https://tc39.es/proposal-temporal/#sec-temporal-plaindatetime-prototype
  22. define_direct_property(vm.names.prototype, global_object.temporal_plain_date_time_prototype(), 0);
  23. define_direct_property(vm.names.length, Value(3), Attribute::Configurable);
  24. }
  25. // 5.1.1 Temporal.PlainDateTime ( isoYear, isoMonth, isoDay [ , hour [ , minute [ , second [ , millisecond [ , microsecond [ , nanosecond [ , calendarLike ] ] ] ] ] ] ] ), https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime
  26. Value PlainDateTimeConstructor::call()
  27. {
  28. auto& vm = this->vm();
  29. // 1. If NewTarget is undefined, throw a TypeError exception.
  30. vm.throw_exception<TypeError>(global_object(), ErrorType::ConstructorWithoutNew, "Temporal.PlainDateTime");
  31. return {};
  32. }
  33. // 5.1.1 Temporal.PlainDateTime ( isoYear, isoMonth, isoDay [ , hour [ , minute [ , second [ , millisecond [ , microsecond [ , nanosecond [ , calendarLike ] ] ] ] ] ] ] ), https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime
  34. Value PlainDateTimeConstructor::construct(FunctionObject& new_target)
  35. {
  36. auto& vm = this->vm();
  37. auto& global_object = this->global_object();
  38. // 2. Let isoYear be ? ToIntegerOrInfinity(isoYear).
  39. auto iso_year = vm.argument(0).to_integer_or_infinity(global_object);
  40. if (vm.exception())
  41. return {};
  42. // 3. If isoYear is +∞ or -∞, throw a RangeError exception.
  43. if (Value(iso_year).is_infinity()) {
  44. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDateTime);
  45. return {};
  46. }
  47. // 4. Let isoMonth be ? ToIntegerOrInfinity(isoMonth).
  48. auto iso_month = vm.argument(1).to_integer_or_infinity(global_object);
  49. if (vm.exception())
  50. return {};
  51. // 5. If isoMonth is +∞ or -∞, throw a RangeError exception.
  52. if (Value(iso_month).is_infinity()) {
  53. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDateTime);
  54. return {};
  55. }
  56. // 6. Let isoDay be ? ToIntegerOrInfinity(isoDay).
  57. auto iso_day = vm.argument(2).to_integer_or_infinity(global_object);
  58. if (vm.exception())
  59. return {};
  60. // 7. If isoDay is +∞ or -∞, throw a RangeError exception.
  61. if (Value(iso_day).is_infinity()) {
  62. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDateTime);
  63. return {};
  64. }
  65. // 8. Let hour be ? ToIntegerOrInfinity(hour).
  66. auto hour = vm.argument(3).to_integer_or_infinity(global_object);
  67. if (vm.exception())
  68. return {};
  69. // 9. If hour is +∞ or -∞, throw a RangeError exception.
  70. if (Value(hour).is_infinity()) {
  71. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDateTime);
  72. return {};
  73. }
  74. // Let minute be ? ToIntegerOrInfinity(minute).
  75. auto minute = vm.argument(4).to_integer_or_infinity(global_object);
  76. if (vm.exception())
  77. return {};
  78. // 11. If minute is +∞ or -∞, throw a RangeError exception.
  79. if (Value(minute).is_infinity()) {
  80. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDateTime);
  81. return {};
  82. }
  83. // 12. Let second be ? ToIntegerOrInfinity(second).
  84. auto second = vm.argument(5).to_integer_or_infinity(global_object);
  85. if (vm.exception())
  86. return {};
  87. // 13. If second is +∞ or -∞, throw a RangeError exception.
  88. if (Value(second).is_infinity()) {
  89. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDateTime);
  90. return {};
  91. }
  92. // 14. Let millisecond be ? ToIntegerOrInfinity(millisecond).
  93. auto millisecond = vm.argument(6).to_integer_or_infinity(global_object);
  94. if (vm.exception())
  95. return {};
  96. // 15. If millisecond is +∞ or -∞, throw a RangeError exception.
  97. if (Value(millisecond).is_infinity()) {
  98. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDateTime);
  99. return {};
  100. }
  101. // 16. Let microsecond be ? ToIntegerOrInfinity(microsecond).
  102. auto microsecond = vm.argument(7).to_integer_or_infinity(global_object);
  103. if (vm.exception())
  104. return {};
  105. // 17. If microsecond is +∞ or -∞, throw a RangeError exception.
  106. if (Value(microsecond).is_infinity()) {
  107. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDateTime);
  108. return {};
  109. }
  110. // 18. Let nanosecond be ? ToIntegerOrInfinity(nanosecond).
  111. auto nanosecond = vm.argument(8).to_integer_or_infinity(global_object);
  112. if (vm.exception())
  113. return {};
  114. // 19. If nanosecond is +∞ or -∞, throw a RangeError exception.
  115. if (Value(nanosecond).is_infinity()) {
  116. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDateTime);
  117. return {};
  118. }
  119. // 20. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
  120. auto* calendar = to_temporal_calendar_with_iso_default(global_object, vm.argument(9));
  121. if (vm.exception())
  122. return {};
  123. // IMPLEMENTATION DEFINED: This is an optimization that allows us to treat these doubles as normal integers from this point onwards.
  124. // This does not change the exposed behaviour as the call to CreateTemporalDateTime will immediately check that these values are valid
  125. // ISO values (for years: -273975 - 273975, for months: 1 - 12, for days: 1 - 31, for hours: 0 - 23, for minutes and seconds: 0 - 59,
  126. // milliseconds, microseconds, and nanoseconds: 0 - 999) all of which are subsets of this check.
  127. if (!AK::is_within_range<i32>(iso_year) || !AK::is_within_range<u8>(iso_month) || !AK::is_within_range<u8>(iso_day) || !AK::is_within_range<u8>(hour) || !AK::is_within_range<u8>(minute) || !AK::is_within_range<u8>(second) || !AK::is_within_range<u16>(millisecond) || !AK::is_within_range<u16>(microsecond) || !AK::is_within_range<u16>(nanosecond)) {
  128. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDateTime);
  129. return {};
  130. }
  131. // 21. Return ? CreateTemporalDateTime(isoYear, isoMonth, isoDay, hour, minute, second, millisecond, microsecond, nanosecond, calendar, NewTarget).
  132. return create_temporal_date_time(global_object, iso_year, iso_month, iso_day, hour, minute, second, millisecond, microsecond, nanosecond, *calendar, &new_target);
  133. }
  134. }