Instant.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /*
  2. * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
  3. * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <LibCrypto/BigInt/SignedBigInteger.h>
  8. #include <LibJS/Runtime/AbstractOperations.h>
  9. #include <LibJS/Runtime/GlobalObject.h>
  10. #include <LibJS/Runtime/Temporal/AbstractOperations.h>
  11. #include <LibJS/Runtime/Temporal/Instant.h>
  12. #include <LibJS/Runtime/Temporal/InstantConstructor.h>
  13. #include <LibJS/Runtime/Temporal/PlainDateTime.h>
  14. #include <LibJS/Runtime/Temporal/TimeZone.h>
  15. namespace JS::Temporal {
  16. // 8 Temporal.Instant Objects, https://tc39.es/proposal-temporal/#sec-temporal-instant-objects
  17. Instant::Instant(BigInt& nanoseconds, Object& prototype)
  18. : Object(prototype)
  19. , m_nanoseconds(nanoseconds)
  20. {
  21. }
  22. void Instant::visit_edges(Cell::Visitor& visitor)
  23. {
  24. Base::visit_edges(visitor);
  25. visitor.visit(&m_nanoseconds);
  26. }
  27. // 8.5.1 IsValidEpochNanoseconds ( epochNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-isvalidepochnanoseconds
  28. bool is_valid_epoch_nanoseconds(BigInt const& epoch_nanoseconds)
  29. {
  30. // 1. Assert: Type(epochNanoseconds) is BigInt.
  31. // 2. If epochNanoseconds < −86400ℤ × 10^17ℤ or epochNanoseconds > 86400ℤ × 10^17ℤ, then
  32. if (epoch_nanoseconds.big_integer() < INSTANT_NANOSECONDS_MIN || epoch_nanoseconds.big_integer() > INSTANT_NANOSECONDS_MAX) {
  33. // a. Return false.
  34. return false;
  35. }
  36. // 3. Return true.
  37. return true;
  38. }
  39. // 8.5.2 CreateTemporalInstant ( epochNanoseconds [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporalinstant
  40. Instant* create_temporal_instant(GlobalObject& global_object, BigInt& epoch_nanoseconds, FunctionObject* new_target)
  41. {
  42. auto& vm = global_object.vm();
  43. // 1. Assert: Type(epochNanoseconds) is BigInt.
  44. // 2. Assert: ! IsValidEpochNanoseconds(epochNanoseconds) is true.
  45. VERIFY(is_valid_epoch_nanoseconds(epoch_nanoseconds));
  46. // 3. If newTarget is not present, set it to %Temporal.Instant%.
  47. if (!new_target)
  48. new_target = global_object.temporal_instant_constructor();
  49. // 4. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.Instant.prototype%", « [[InitializedTemporalInstant]], [[Nanoseconds]] »).
  50. // 5. Set object.[[Nanoseconds]] to epochNanoseconds.
  51. auto* object = ordinary_create_from_constructor<Instant>(global_object, *new_target, &GlobalObject::temporal_instant_prototype, epoch_nanoseconds);
  52. if (vm.exception())
  53. return {};
  54. // 6. Return object.
  55. return object;
  56. }
  57. // 8.5.3 ToTemporalInstant ( item ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalinstant
  58. Instant* to_temporal_instant(GlobalObject& global_object, Value item)
  59. {
  60. auto& vm = global_object.vm();
  61. // 1. If Type(item) is Object, then
  62. if (item.is_object()) {
  63. // a. If item has an [[InitializedTemporalInstant]] internal slot, then
  64. if (is<Instant>(item.as_object())) {
  65. // i. Return item.
  66. return &static_cast<Instant&>(item.as_object());
  67. }
  68. // TODO:
  69. // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
  70. // i. Return ! CreateTemporalInstant(item.[[Nanoseconds]]).
  71. }
  72. // 2. Let string be ? ToString(item).
  73. auto string = item.to_string(global_object);
  74. if (vm.exception())
  75. return {};
  76. // 3. Let epochNanoseconds be ? ParseTemporalInstant(string).
  77. auto* epoch_nanoseconds = parse_temporal_instant(global_object, string);
  78. if (vm.exception())
  79. return {};
  80. return create_temporal_instant(global_object, *epoch_nanoseconds);
  81. }
  82. // 8.5.4 ParseTemporalInstant ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalinstant
  83. BigInt* parse_temporal_instant(GlobalObject& global_object, String const& iso_string)
  84. {
  85. auto& vm = global_object.vm();
  86. // 1. Assert: Type(isoString) is String.
  87. // 2. Let result be ? ParseTemporalInstantString(isoString).
  88. auto result = parse_temporal_instant_string(global_object, iso_string);
  89. if (vm.exception())
  90. return {};
  91. // 3. Let offsetString be result.[[TimeZoneOffsetString]].
  92. auto& offset_string = result->time_zone_offset;
  93. // 4. Assert: offsetString is not undefined.
  94. VERIFY(offset_string.has_value());
  95. // 5. Let utc be ? GetEpochFromISOParts(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]).
  96. auto* utc = get_epoch_from_iso_parts(global_object, result->year, result->month, result->day, result->hour, result->minute, result->second, result->millisecond, result->microsecond, result->nanosecond);
  97. if (vm.exception())
  98. return {};
  99. // 6. If utc < −8.64 × 10^21 or utc > 8.64 × 10^21, then
  100. if (utc->big_integer() < INSTANT_NANOSECONDS_MIN || utc->big_integer() > INSTANT_NANOSECONDS_MAX) {
  101. // a. Throw a RangeError exception.
  102. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidEpochNanoseconds);
  103. return {};
  104. }
  105. // 7. Let offsetNanoseconds be ? ParseTimeZoneOffsetString(offsetString).
  106. auto offset_nanoseconds = parse_time_zone_offset_string(global_object, *offset_string);
  107. if (vm.exception())
  108. return {};
  109. // 8. Return utc − offsetNanoseconds.
  110. return js_bigint(vm.heap(), utc->big_integer().minus(Crypto::SignedBigInteger::create_from(offset_nanoseconds)));
  111. }
  112. }