1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 20:07:35 +00:00

LibJS: Add the ToTemporalInstant Abstract Operation & its requirements

This is Abstract Operation is required for the majority of
InstantConstructor's and InstantPrototype's methods.

The implementation is not entirely complete, (specifically 2 of the
underlying required abstract operations, ParseTemporalTimeZoneString
and ParseISODateTime are missing the required lexing, and as such are
TODO()-ed) but the majority of it is done.
This commit is contained in:
Idan Horowitz 2021-07-11 21:04:11 +03:00 committed by Linus Groh
parent 141c46feda
commit b816037739
19 changed files with 888 additions and 13 deletions

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -7,8 +8,11 @@
#include <LibCrypto/BigInt/SignedBigInteger.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
#include <LibJS/Runtime/Temporal/Instant.h>
#include <LibJS/Runtime/Temporal/InstantConstructor.h>
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
#include <LibJS/Runtime/Temporal/TimeZone.h>
namespace JS::Temporal {
@ -42,7 +46,7 @@ bool is_valid_epoch_nanoseconds(BigInt const& epoch_nanoseconds)
}
// 8.5.2 CreateTemporalInstant ( epochNanoseconds [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporalinstant
Object* create_temporal_instant(GlobalObject& global_object, BigInt& epoch_nanoseconds, FunctionObject* new_target)
Instant* create_temporal_instant(GlobalObject& global_object, BigInt& epoch_nanoseconds, FunctionObject* new_target)
{
auto& vm = global_object.vm();
@ -65,4 +69,73 @@ Object* create_temporal_instant(GlobalObject& global_object, BigInt& epoch_nanos
return object;
}
// 8.5.3 ToTemporalInstant ( item ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalinstant
Instant* to_temporal_instant(GlobalObject& global_object, Value item)
{
auto& vm = global_object.vm();
// 1. If Type(item) is Object, then
if (item.is_object()) {
// a. If item has an [[InitializedTemporalInstant]] internal slot, then
if (is<Instant>(item.as_object())) {
// i. Return item.
return &static_cast<Instant&>(item.as_object());
}
// TODO:
// b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
// i. Return ! CreateTemporalInstant(item.[[Nanoseconds]]).
}
// 2. Let string be ? ToString(item).
auto string = item.to_string(global_object);
if (vm.exception())
return {};
// 3. Let epochNanoseconds be ? ParseTemporalInstant(string).
auto* epoch_nanoseconds = parse_temporal_instant(global_object, string);
if (vm.exception())
return {};
return create_temporal_instant(global_object, *epoch_nanoseconds);
}
// 8.5.4 ParseTemporalInstant ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalinstant
BigInt* parse_temporal_instant(GlobalObject& global_object, String const& iso_string)
{
auto& vm = global_object.vm();
// 1. Assert: Type(isoString) is String.
// 2. Let result be ? ParseTemporalInstantString(isoString).
auto result = parse_temporal_instant_string(global_object, iso_string);
if (vm.exception())
return {};
// 3. Let offsetString be result.[[TimeZoneOffsetString]].
auto& offset_string = result->time_zone_offset;
// 4. Assert: offsetString is not undefined.
VERIFY(offset_string.has_value());
// 5. Let utc be ? GetEpochFromISOParts(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]).
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);
if (vm.exception())
return {};
// 6. If utc < 8.64 × 10^21 or utc > 8.64 × 10^21, then
if (utc->big_integer() < INSTANT_NANOSECONDS_MIN || utc->big_integer() > INSTANT_NANOSECONDS_MAX) {
// a. Throw a RangeError exception.
vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidEpochNanoseconds);
return {};
}
// 7. Let offsetNanoseconds be ? ParseTimeZoneOffsetString(offsetString).
auto offset_nanoseconds = parse_time_zone_offset_string(global_object, *offset_string);
if (vm.exception())
return {};
// 8. Return utc offsetNanoseconds.
return js_bigint(vm.heap(), utc->big_integer().minus(Crypto::SignedBigInteger::create_from(offset_nanoseconds)));
}
}