InstantConstructor.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/TypeCasts.h>
  7. #include <LibCrypto/BigInt/UnsignedBigInteger.h>
  8. #include <LibJS/Runtime/GlobalObject.h>
  9. #include <LibJS/Runtime/Temporal/Instant.h>
  10. #include <LibJS/Runtime/Temporal/InstantConstructor.h>
  11. namespace JS::Temporal {
  12. // 8.1 The Temporal.Instant Constructor, https://tc39.es/proposal-temporal/#sec-temporal-instant-constructor
  13. InstantConstructor::InstantConstructor(GlobalObject& global_object)
  14. : NativeFunction(vm().names.Instant.as_string(), *global_object.function_prototype())
  15. {
  16. }
  17. void InstantConstructor::initialize(GlobalObject& global_object)
  18. {
  19. NativeFunction::initialize(global_object);
  20. auto& vm = this->vm();
  21. // 8.2.1 Temporal.Instant.prototype, https://tc39.es/proposal-temporal/#sec-temporal-instant-prototype
  22. define_direct_property(vm.names.prototype, global_object.temporal_instant_prototype(), 0);
  23. u8 attr = Attribute::Writable | Attribute::Configurable;
  24. define_native_function(vm.names.from, from, 1, attr);
  25. define_native_function(vm.names.fromEpochSeconds, from_epoch_seconds, 1, attr);
  26. define_native_function(vm.names.fromEpochMilliseconds, from_epoch_milliseconds, 1, attr);
  27. define_native_function(vm.names.fromEpochMicroseconds, from_epoch_microseconds, 1, attr);
  28. define_native_function(vm.names.fromEpochNanoseconds, from_epoch_nanoseconds, 1, attr);
  29. define_native_function(vm.names.compare, compare, 2, attr);
  30. define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
  31. }
  32. // 8.1.1 Temporal.Instant ( epochNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal.instant
  33. Value InstantConstructor::call()
  34. {
  35. auto& vm = this->vm();
  36. // 1. If NewTarget is undefined, then
  37. // a. Throw a TypeError exception.
  38. vm.throw_exception<TypeError>(global_object(), ErrorType::ConstructorWithoutNew, "Temporal.Instant");
  39. return {};
  40. }
  41. // 8.1.1 Temporal.Instant ( epochNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal.instant
  42. Value InstantConstructor::construct(FunctionObject& new_target)
  43. {
  44. auto& vm = this->vm();
  45. auto& global_object = this->global_object();
  46. // 2. Let epochNanoseconds be ? ToBigInt(epochNanoseconds).
  47. auto* epoch_nanoseconds = vm.argument(0).to_bigint(global_object);
  48. if (vm.exception())
  49. return {};
  50. // 3. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
  51. if (!is_valid_epoch_nanoseconds(*epoch_nanoseconds)) {
  52. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidEpochNanoseconds);
  53. return {};
  54. }
  55. // 4. Return ? CreateTemporalInstant(epochNanoseconds, NewTarget).
  56. return TRY_OR_DISCARD(create_temporal_instant(global_object, *epoch_nanoseconds, &new_target));
  57. }
  58. // 8.2.2 Temporal.Instant.from ( item ), https://tc39.es/proposal-temporal/#sec-temporal.instant.from
  59. JS_DEFINE_NATIVE_FUNCTION(InstantConstructor::from)
  60. {
  61. auto item = vm.argument(0);
  62. // 1. If Type(item) is Object and item has an [[InitializedTemporalInstant]] internal slot, then
  63. if (item.is_object() && is<Instant>(item.as_object())) {
  64. // a. Return ! CreateTemporalInstant(item.[[Nanoseconds]]).
  65. return create_temporal_instant(global_object, *js_bigint(vm, static_cast<Instant&>(item.as_object()).nanoseconds().big_integer())).release_value();
  66. }
  67. // 2. Return ? ToTemporalInstant(item).
  68. return TRY_OR_DISCARD(to_temporal_instant(global_object, item));
  69. }
  70. // 8.2.3 Temporal.Instant.fromEpochSeconds ( epochSeconds ), https://tc39.es/proposal-temporal/#sec-temporal.instant.fromepochseconds
  71. JS_DEFINE_NATIVE_FUNCTION(InstantConstructor::from_epoch_seconds)
  72. {
  73. // 1. Set epochSeconds to ? ToNumber(epochSeconds).
  74. auto epoch_seconds_value = vm.argument(0).to_number(global_object);
  75. if (vm.exception())
  76. return {};
  77. // 2. Set epochSeconds to ? NumberToBigInt(epochSeconds).
  78. auto* epoch_seconds = number_to_bigint(global_object, epoch_seconds_value);
  79. if (vm.exception())
  80. return {};
  81. // 3. Let epochNanoseconds be epochSeconds × 10^9ℤ.
  82. auto* epoch_nanoseconds = js_bigint(vm, epoch_seconds->big_integer().multiplied_by(Crypto::UnsignedBigInteger { 1'000'000'000 }));
  83. // 4. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
  84. if (!is_valid_epoch_nanoseconds(*epoch_nanoseconds)) {
  85. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidEpochNanoseconds);
  86. return {};
  87. }
  88. // 5. Return ! CreateTemporalInstant(epochNanoseconds).
  89. return create_temporal_instant(global_object, *epoch_nanoseconds).release_value();
  90. }
  91. // 8.2.4 Temporal.Instant.fromEpochMilliseconds ( epochMilliseconds ), https://tc39.es/proposal-temporal/#sec-temporal.instant.fromepochmilliseconds
  92. JS_DEFINE_NATIVE_FUNCTION(InstantConstructor::from_epoch_milliseconds)
  93. {
  94. // 1. Set epochMilliseconds to ? ToNumber(epochMilliseconds).
  95. auto epoch_milliseconds_value = vm.argument(0).to_number(global_object);
  96. if (vm.exception())
  97. return {};
  98. // 2. Set epochMilliseconds to ? NumberToBigInt(epochMilliseconds).
  99. auto* epoch_milliseconds = number_to_bigint(global_object, epoch_milliseconds_value);
  100. if (vm.exception())
  101. return {};
  102. // 3. Let epochNanoseconds be epochMilliseconds × 10^6ℤ.
  103. auto* epoch_nanoseconds = js_bigint(vm, epoch_milliseconds->big_integer().multiplied_by(Crypto::UnsignedBigInteger { 1'000'000 }));
  104. // 4. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
  105. if (!is_valid_epoch_nanoseconds(*epoch_nanoseconds)) {
  106. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidEpochNanoseconds);
  107. return {};
  108. }
  109. // 5. Return ! CreateTemporalInstant(epochNanoseconds).
  110. return create_temporal_instant(global_object, *epoch_nanoseconds).release_value();
  111. }
  112. // 8.2.5 Temporal.Instant.fromEpochMicroseconds ( epochMicroseconds ), https://tc39.es/proposal-temporal/#sec-temporal.instant.fromepochmicroseconds
  113. JS_DEFINE_NATIVE_FUNCTION(InstantConstructor::from_epoch_microseconds)
  114. {
  115. // 1. Set epochMicroseconds to ? ToBigInt(epochMicroseconds).
  116. auto* epoch_microseconds = vm.argument(0).to_bigint(global_object);
  117. if (vm.exception())
  118. return {};
  119. // 2. Let epochNanoseconds be epochMicroseconds × 1000ℤ.
  120. auto* epoch_nanoseconds = js_bigint(vm, epoch_microseconds->big_integer().multiplied_by(Crypto::UnsignedBigInteger { 1'000 }));
  121. // 3. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
  122. if (!is_valid_epoch_nanoseconds(*epoch_nanoseconds)) {
  123. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidEpochNanoseconds);
  124. return {};
  125. }
  126. // 4. Return ! CreateTemporalInstant(epochNanoseconds).
  127. return create_temporal_instant(global_object, *epoch_nanoseconds).release_value();
  128. }
  129. // 8.2.6 Temporal.Instant.fromEpochNanoseconds ( epochNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal.instant.fromepochnanoseconds
  130. JS_DEFINE_NATIVE_FUNCTION(InstantConstructor::from_epoch_nanoseconds)
  131. {
  132. // 1. Set epochNanoseconds to ? ToBigInt(epochNanoseconds).
  133. auto* epoch_nanoseconds = vm.argument(0).to_bigint(global_object);
  134. if (vm.exception())
  135. return {};
  136. // 2. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
  137. if (!is_valid_epoch_nanoseconds(*epoch_nanoseconds)) {
  138. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidEpochNanoseconds);
  139. return {};
  140. }
  141. // 3. Return ! CreateTemporalInstant(epochNanoseconds).
  142. return create_temporal_instant(global_object, *epoch_nanoseconds).release_value();
  143. }
  144. // 8.2.7 Temporal.Instant.compare ( one, two ), https://tc39.es/proposal-temporal/#sec-temporal.instant.compare
  145. JS_DEFINE_NATIVE_FUNCTION(InstantConstructor::compare)
  146. {
  147. // 1. Set one to ? ToTemporalInstant(one).
  148. auto* one = TRY_OR_DISCARD(to_temporal_instant(global_object, vm.argument(0)));
  149. // 2. Set two to ? ToTemporalInstant(two).
  150. auto* two = TRY_OR_DISCARD(to_temporal_instant(global_object, vm.argument(1)));
  151. // 3. Return 𝔽(! CompareEpochNanoseconds(one.[[Nanoseconds]], two.[[Nanoseconds]])).
  152. return Value(compare_epoch_nanoseconds(one->nanoseconds(), two->nanoseconds()));
  153. }
  154. }