LibJS: Start implementing Temporal.ZonedDateTime
This commit adds the ZonedDateTime object itself, its constructor and prototype (currently empty), and the CreateTemporalZonedDateTime abstract operation.
This commit is contained in:
parent
1b9b995f93
commit
cfb77b66e5
Notes:
sideshowbarker
2024-07-18 07:38:24 +09:00
Author: https://github.com/linusg Commit: https://github.com/SerenityOS/serenity/commit/cfb77b66e51 Pull-request: https://github.com/SerenityOS/serenity/pull/9160 Reviewed-by: https://github.com/IdanHo ✅
11 changed files with 297 additions and 1 deletions
|
@ -148,6 +148,9 @@ set(SOURCES
|
|||
Runtime/Temporal/TimeZone.cpp
|
||||
Runtime/Temporal/TimeZoneConstructor.cpp
|
||||
Runtime/Temporal/TimeZonePrototype.cpp
|
||||
Runtime/Temporal/ZonedDateTime.cpp
|
||||
Runtime/Temporal/ZonedDateTimeConstructor.cpp
|
||||
Runtime/Temporal/ZonedDateTimePrototype.cpp
|
||||
Runtime/TypedArray.cpp
|
||||
Runtime/TypedArrayConstructor.cpp
|
||||
Runtime/TypedArrayPrototype.cpp
|
||||
|
|
|
@ -83,7 +83,8 @@
|
|||
__JS_ENUMERATE(PlainDate, plain_date, PlainDatePrototype, PlainDateConstructor) \
|
||||
__JS_ENUMERATE(PlainDateTime, plain_date_time, PlainDateTimePrototype, PlainDateTimeConstructor) \
|
||||
__JS_ENUMERATE(PlainTime, plain_time, PlainTimePrototype, PlainTimeConstructor) \
|
||||
__JS_ENUMERATE(TimeZone, time_zone, TimeZonePrototype, TimeZoneConstructor)
|
||||
__JS_ENUMERATE(TimeZone, time_zone, TimeZonePrototype, TimeZoneConstructor) \
|
||||
__JS_ENUMERATE(ZonedDateTime, zoned_date_time, ZonedDateTimePrototype, ZonedDateTimeConstructor)
|
||||
|
||||
#define JS_ENUMERATE_ITERATOR_PROTOTYPES \
|
||||
__JS_ENUMERATE(Iterator, iterator) \
|
||||
|
|
|
@ -84,6 +84,8 @@
|
|||
#include <LibJS/Runtime/Temporal/Temporal.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZoneConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZonePrototype.h>
|
||||
#include <LibJS/Runtime/Temporal/ZonedDateTimeConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/ZonedDateTimePrototype.h>
|
||||
#include <LibJS/Runtime/TypedArray.h>
|
||||
#include <LibJS/Runtime/TypedArrayConstructor.h>
|
||||
#include <LibJS/Runtime/TypedArrayPrototype.h>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <LibJS/Runtime/Temporal/PlainTimeConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/Temporal.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZoneConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/ZonedDateTimeConstructor.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
|
@ -41,6 +42,7 @@ void Temporal::initialize(GlobalObject& global_object)
|
|||
define_direct_property(vm.names.PlainDateTime, global_object.temporal_plain_date_time_constructor(), attr);
|
||||
define_direct_property(vm.names.PlainTime, global_object.temporal_plain_time_constructor(), attr);
|
||||
define_direct_property(vm.names.TimeZone, global_object.temporal_time_zone_constructor(), attr);
|
||||
define_direct_property(vm.names.ZonedDateTime, global_object.temporal_zoned_date_time_constructor(), attr);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
61
Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTime.cpp
Normal file
61
Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTime.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Temporal/Instant.h>
|
||||
#include <LibJS/Runtime/Temporal/ZonedDateTime.h>
|
||||
#include <LibJS/Runtime/Temporal/ZonedDateTimeConstructor.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
// 6 Temporal.ZonedDateTime Objects, https://tc39.es/proposal-temporal/#sec-temporal-zoneddatetime-objects
|
||||
ZonedDateTime::ZonedDateTime(BigInt& nanoseconds, Object& time_zone, Object& calendar, Object& prototype)
|
||||
: Object(prototype)
|
||||
, m_nanoseconds(nanoseconds)
|
||||
, m_time_zone(time_zone)
|
||||
, m_calendar(calendar)
|
||||
{
|
||||
}
|
||||
|
||||
void ZonedDateTime::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
|
||||
visitor.visit(&m_nanoseconds);
|
||||
visitor.visit(&m_time_zone);
|
||||
visitor.visit(&m_calendar);
|
||||
}
|
||||
|
||||
// 6.5.3 CreateTemporalZonedDateTime ( epochNanoseconds, timeZone, calendar [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporalzoneddatetime
|
||||
ZonedDateTime* create_temporal_zoned_date_time(GlobalObject& global_object, BigInt& epoch_nanoseconds, Object& time_zone, Object& calendar, FunctionObject* new_target)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. Assert: Type(epochNanoseconds) is BigInt.
|
||||
// 3. Assert: Type(timeZone) is Object.
|
||||
// 4. Assert: Type(calendar) is Object.
|
||||
|
||||
// 2. Assert: ! IsValidEpochNanoseconds(epochNanoseconds) is true.
|
||||
VERIFY(is_valid_epoch_nanoseconds(epoch_nanoseconds));
|
||||
|
||||
// 5. If newTarget is not present, set it to %Temporal.ZonedDateTime%.
|
||||
if (!new_target)
|
||||
new_target = global_object.temporal_zoned_date_time_constructor();
|
||||
|
||||
// 6. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.ZonedDateTime.prototype%", « [[InitializedTemporalZonedDateTime]], [[Nanoseconds]], [[TimeZone]], [[Calendar]] »).
|
||||
// 7. Set object.[[Nanoseconds]] to epochNanoseconds.
|
||||
// 8. Set object.[[TimeZone]] to timeZone.
|
||||
// 9. Set object.[[Calendar]] to calendar.
|
||||
auto* object = ordinary_create_from_constructor<ZonedDateTime>(global_object, *new_target, &GlobalObject::temporal_time_zone_prototype, epoch_nanoseconds, time_zone, calendar);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// 10. Return object.
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
39
Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTime.h
Normal file
39
Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTime.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/BigInt.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
class ZonedDateTime final : public Object {
|
||||
JS_OBJECT(ZonedDateTime, Object);
|
||||
|
||||
public:
|
||||
ZonedDateTime(BigInt& nanoseconds, Object& time_zone, Object& calendar, Object& prototype);
|
||||
virtual ~ZonedDateTime() override = default;
|
||||
|
||||
BigInt const& nanoseconds() const { return m_nanoseconds; }
|
||||
BigInt& nanoseconds() { return m_nanoseconds; }
|
||||
Object const& time_zone() const { return m_time_zone; }
|
||||
Object& time_zone() { return m_time_zone; }
|
||||
Object const& calendar() const { return m_calendar; }
|
||||
Object& calendar() { return m_calendar; }
|
||||
|
||||
private:
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
// 6.4 Properties of Temporal.ZonedDateTime Instances, https://tc39.es/proposal-temporal/#sec-properties-of-temporal-zoneddatetime-instances
|
||||
BigInt& m_nanoseconds; // [[Nanoseconds]]
|
||||
Object& m_time_zone; // [[TimeZone]]
|
||||
Object& m_calendar; // [[Calendar]]
|
||||
};
|
||||
|
||||
ZonedDateTime* create_temporal_zoned_date_time(GlobalObject&, BigInt& epoch_nanoseconds, Object& time_zone, Object& calendar, FunctionObject* new_target = nullptr);
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Temporal/Calendar.h>
|
||||
#include <LibJS/Runtime/Temporal/Instant.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZone.h>
|
||||
#include <LibJS/Runtime/Temporal/ZonedDateTime.h>
|
||||
#include <LibJS/Runtime/Temporal/ZonedDateTimeConstructor.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
// 6.1 The Temporal.ZonedDateTime Constructor, https://tc39.es/proposal-temporal/#sec-temporal-zoneddatetime-constructor
|
||||
ZonedDateTimeConstructor::ZonedDateTimeConstructor(GlobalObject& global_object)
|
||||
: NativeFunction(vm().names.ZonedDateTime.as_string(), *global_object.function_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void ZonedDateTimeConstructor::initialize(GlobalObject& global_object)
|
||||
{
|
||||
NativeFunction::initialize(global_object);
|
||||
|
||||
auto& vm = this->vm();
|
||||
|
||||
// 6.2.1 Temporal.ZonedDateTime.prototype, https://tc39.es/proposal-temporal/#sec-temporal-zoneddatetime-prototype
|
||||
define_direct_property(vm.names.prototype, global_object.temporal_zoned_date_time_prototype(), 0);
|
||||
|
||||
define_direct_property(vm.names.length, Value(2), Attribute::Configurable);
|
||||
}
|
||||
|
||||
// 6.1.1 Temporal.ZonedDateTime ( epochNanoseconds, timeZoneLike [ , calendarLike ] ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime
|
||||
Value ZonedDateTimeConstructor::call()
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
// 1. If NewTarget is undefined, then
|
||||
// a. Throw a TypeError exception.
|
||||
vm.throw_exception<TypeError>(global_object(), ErrorType::ConstructorWithoutNew, "Temporal.ZonedDateTime");
|
||||
return {};
|
||||
}
|
||||
|
||||
// 6.1.1 Temporal.ZonedDateTime ( epochNanoseconds, timeZoneLike [ , calendarLike ] ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime
|
||||
Value ZonedDateTimeConstructor::construct(FunctionObject& new_target)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
auto& global_object = this->global_object();
|
||||
|
||||
// 2. Set epochNanoseconds to ? ToBigInt(epochNanoseconds).
|
||||
auto* epoch_nanoseconds = vm.argument(0).to_bigint(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// 3. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
|
||||
if (!is_valid_epoch_nanoseconds(*epoch_nanoseconds)) {
|
||||
vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidEpochNanoseconds);
|
||||
return {};
|
||||
}
|
||||
|
||||
// 4. Let timeZone be ? ToTemporalTimeZone(timeZoneLike).
|
||||
auto* time_zone = to_temporal_time_zone(global_object, vm.argument(1));
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// 5. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
|
||||
auto* calendar = to_temporal_calendar_with_iso_default(global_object, vm.argument(2));
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// 6. Return ? CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar, NewTarget).
|
||||
return create_temporal_zoned_date_time(global_object, *epoch_nanoseconds, *time_zone, *calendar, &new_target);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
class ZonedDateTimeConstructor final : public NativeFunction {
|
||||
JS_OBJECT(ZonedDateTimeConstructor, NativeFunction);
|
||||
|
||||
public:
|
||||
explicit ZonedDateTimeConstructor(GlobalObject&);
|
||||
virtual void initialize(GlobalObject&) override;
|
||||
virtual ~ZonedDateTimeConstructor() override = default;
|
||||
|
||||
virtual Value call() override;
|
||||
virtual Value construct(FunctionObject& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Temporal/ZonedDateTimePrototype.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
// 6.3 Properties of the Temporal.ZonedDateTime Prototype Object, https://tc39.es/proposal-temporal/#sec-properties-of-the-temporal-zoneddatetime-prototype-object
|
||||
ZonedDateTimePrototype::ZonedDateTimePrototype(GlobalObject& global_object)
|
||||
: Object(*global_object.object_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void ZonedDateTimePrototype::initialize(GlobalObject& global_object)
|
||||
{
|
||||
Object::initialize(global_object);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
class ZonedDateTimePrototype final : public Object {
|
||||
JS_OBJECT(ZonedDateTimePrototype, Object);
|
||||
|
||||
public:
|
||||
explicit ZonedDateTimePrototype(GlobalObject&);
|
||||
virtual void initialize(GlobalObject&) override;
|
||||
virtual ~ZonedDateTimePrototype() override = default;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
describe("errors", () => {
|
||||
test("called without new", () => {
|
||||
expect(() => {
|
||||
Temporal.ZonedDateTime();
|
||||
}).toThrowWithMessage(
|
||||
TypeError,
|
||||
"Temporal.ZonedDateTime constructor must be called with 'new'"
|
||||
);
|
||||
});
|
||||
|
||||
test("out-of-range epoch nanoseconds value", () => {
|
||||
expect(() => {
|
||||
new Temporal.ZonedDateTime(8_640_000_000_000_000_000_001n);
|
||||
}).toThrowWithMessage(
|
||||
RangeError,
|
||||
"Invalid epoch nanoseconds value, must be in range -86400 * 10^17 to 86400 * 10^17"
|
||||
);
|
||||
expect(() => {
|
||||
new Temporal.ZonedDateTime(-8_640_000_000_000_000_000_001n);
|
||||
}).toThrowWithMessage(
|
||||
RangeError,
|
||||
"Invalid epoch nanoseconds value, must be in range -86400 * 10^17 to 86400 * 10^17"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("normal behavior", () => {
|
||||
test("length is 2", () => {
|
||||
expect(Temporal.ZonedDateTime).toHaveLength(2);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const timeZone = new Temporal.TimeZone("UTC");
|
||||
const zonedDateTime = new Temporal.ZonedDateTime(0n, timeZone);
|
||||
expect(typeof zonedDateTime).toBe("object");
|
||||
expect(zonedDateTime).toBeInstanceOf(Temporal.ZonedDateTime);
|
||||
expect(Object.getPrototypeOf(zonedDateTime)).toBe(Temporal.ZonedDateTime.prototype);
|
||||
});
|
||||
});
|
Loading…
Add table
Reference in a new issue