summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorLinus Groh <mail@linusgroh.de>2021-07-07 17:41:37 +0100
committerLinus Groh <mail@linusgroh.de>2021-07-07 19:00:42 +0100
commit47fb4286c7247af3faa354ceba97ac46d8bd854f (patch)
tree8204a79fbb2749e26957523156b132205e5788f6 /Userland
parentd9cff591b6ce8b1cedcf70a5c9705a966f0f03d4 (diff)
downloadserenity-47fb4286c7247af3faa354ceba97ac46d8bd854f.zip
LibJS: Start implementing Temporal.Instant
Just like the initial Temporal.TimeZone commit, this patch adds the Instant object itself, its constructor and prototype (currently empty), and two required abstract operations.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibJS/CMakeLists.txt3
-rw-r--r--Userland/Libraries/LibJS/Forward.h3
-rw-r--r--Userland/Libraries/LibJS/Runtime/ErrorTypes.h1
-rw-r--r--Userland/Libraries/LibJS/Runtime/GlobalObject.cpp2
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/Instant.cpp68
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/Instant.h41
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/InstantConstructor.cpp63
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/InstantConstructor.h28
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.cpp23
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.h22
-rw-r--r--Userland/Libraries/LibJS/Runtime/Temporal/Temporal.cpp2
11 files changed, 255 insertions, 1 deletions
diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt
index 8634e41479..3971875f4a 100644
--- a/Userland/Libraries/LibJS/CMakeLists.txt
+++ b/Userland/Libraries/LibJS/CMakeLists.txt
@@ -121,6 +121,9 @@ set(SOURCES
Runtime/SymbolConstructor.cpp
Runtime/SymbolObject.cpp
Runtime/SymbolPrototype.cpp
+ Runtime/Temporal/Instant.cpp
+ Runtime/Temporal/InstantConstructor.cpp
+ Runtime/Temporal/InstantPrototype.cpp
Runtime/Temporal/ISO8601.cpp
Runtime/Temporal/Now.cpp
Runtime/Temporal/Temporal.cpp
diff --git a/Userland/Libraries/LibJS/Forward.h b/Userland/Libraries/LibJS/Forward.h
index 01dd08b3e6..4b47465211 100644
--- a/Userland/Libraries/LibJS/Forward.h
+++ b/Userland/Libraries/LibJS/Forward.h
@@ -76,7 +76,8 @@
__JS_ENUMERATE(Float32Array, float32_array, Float32ArrayPrototype, Float32ArrayConstructor, float) \
__JS_ENUMERATE(Float64Array, float64_array, Float64ArrayPrototype, Float64ArrayConstructor, double)
-#define JS_ENUMERATE_TEMPORAL_OBJECTS \
+#define JS_ENUMERATE_TEMPORAL_OBJECTS \
+ __JS_ENUMERATE(Instant, instant, InstantPrototype, InstantConstructor) \
__JS_ENUMERATE(TimeZone, time_zone, TimeZonePrototype, TimeZoneConstructor)
#define JS_ENUMERATE_ITERATOR_PROTOTYPES \
diff --git a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h
index ffaaa5c2c0..a1f170b600 100644
--- a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h
+++ b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h
@@ -162,6 +162,7 @@
M(StringNonGlobalRegExp, "RegExp argument is non-global") \
M(StringRawCannotConvert, "Cannot convert property 'raw' to object from {}") \
M(StringRepeatCountMustBe, "repeat count must be a {} number") \
+ M(TemporalInvalidEpochNanoseconds, "Invalid epoch nanoseconds value, must be in range -86400 * 10^17 to 86400 * 10^17") \
M(TemporalInvalidTimeZoneName, "Invalid time zone name") \
M(ThisHasNotBeenInitialized, "|this| has not been initialized") \
M(ThisIsAlreadyInitialized, "|this| is already initialized") \
diff --git a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp
index 27997dc4ec..f64ebb9b45 100644
--- a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp
+++ b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp
@@ -67,6 +67,8 @@
#include <LibJS/Runtime/StringPrototype.h>
#include <LibJS/Runtime/SymbolConstructor.h>
#include <LibJS/Runtime/SymbolPrototype.h>
+#include <LibJS/Runtime/Temporal/InstantConstructor.h>
+#include <LibJS/Runtime/Temporal/InstantPrototype.h>
#include <LibJS/Runtime/Temporal/Temporal.h>
#include <LibJS/Runtime/Temporal/TimeZoneConstructor.h>
#include <LibJS/Runtime/Temporal/TimeZonePrototype.h>
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Instant.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/Instant.cpp
new file mode 100644
index 0000000000..df10f993c2
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/Instant.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibCrypto/BigInt/SignedBigInteger.h>
+#include <LibJS/Runtime/AbstractOperations.h>
+#include <LibJS/Runtime/GlobalObject.h>
+#include <LibJS/Runtime/Temporal/Instant.h>
+#include <LibJS/Runtime/Temporal/InstantConstructor.h>
+
+namespace JS::Temporal {
+
+// 8 Temporal.Instant Objects, https://tc39.es/proposal-temporal/#sec-temporal-instant-objects
+Instant::Instant(BigInt& nanoseconds, Object& prototype)
+ : Object(prototype)
+ , m_nanoseconds(nanoseconds)
+{
+}
+
+void Instant::visit_edges(Cell::Visitor& visitor)
+{
+ Base::visit_edges(visitor);
+
+ visitor.visit(&m_nanoseconds);
+}
+
+// 8.5.1 IsValidEpochNanoseconds ( epochNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-isvalidepochnanoseconds
+bool is_valid_epoch_nanoseconds(BigInt const& epoch_nanoseconds)
+{
+ // 1. Assert: Type(epochNanoseconds) is BigInt.
+
+ // 2. If epochNanoseconds < −86400ℤ × 10^17ℤ or epochNanoseconds > 86400ℤ × 10^17ℤ, then
+ if (epoch_nanoseconds.big_integer() < INSTANT_NANOSECONDS_MIN || epoch_nanoseconds.big_integer() > INSTANT_NANOSECONDS_MAX) {
+ // a. Return false.
+ return false;
+ }
+
+ // 3. Return true.
+ return true;
+}
+
+// 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)
+{
+ auto& vm = global_object.vm();
+
+ // 1. Assert: Type(epochNanoseconds) is BigInt.
+
+ // 2. Assert: ! IsValidEpochNanoseconds(epochNanoseconds) is true.
+ VERIFY(is_valid_epoch_nanoseconds(epoch_nanoseconds));
+
+ // 3. If newTarget is not present, set it to %Temporal.Instant%.
+ if (!new_target)
+ new_target = global_object.temporal_instant_constructor();
+
+ // 4. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.Instant.prototype%", « [[InitializedTemporalInstant]], [[Nanoseconds]] »).
+ // 5. Set object.[[Nanoseconds]] to epochNanoseconds.
+ auto* object = ordinary_create_from_constructor<Instant>(global_object, *new_target, &GlobalObject::temporal_instant_prototype, epoch_nanoseconds);
+ if (vm.exception())
+ return {};
+
+ // 6. Return object.
+ return object;
+}
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Instant.h b/Userland/Libraries/LibJS/Runtime/Temporal/Instant.h
new file mode 100644
index 0000000000..7700295d93
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/Instant.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Optional.h>
+#include <LibJS/Runtime/BigInt.h>
+#include <LibJS/Runtime/Object.h>
+
+namespace JS::Temporal {
+
+class Instant final : public Object {
+ JS_OBJECT(Instant, Object);
+
+public:
+ explicit Instant(BigInt& nanoseconds, Object& prototype);
+ virtual ~Instant() override = default;
+
+ BigInt const& nanoseconds() const { return m_nanoseconds; }
+
+private:
+ virtual void visit_edges(Visitor&) override;
+
+ // 8.4 Properties of Temporal.Instant Instances, https://tc39.es/proposal-temporal/#sec-properties-of-temporal-instant-instances
+
+ // [[Nanoseconds]]
+ BigInt& m_nanoseconds;
+};
+
+// -86400 * 10^17
+const auto INSTANT_NANOSECONDS_MIN = Crypto::SignedBigInteger::from_base(10, "-8640000000000000000000");
+// +86400 * 10^17
+const auto INSTANT_NANOSECONDS_MAX = Crypto::SignedBigInteger::from_base(10, "8640000000000000000000");
+
+bool is_valid_epoch_nanoseconds(BigInt const& epoch_nanoseconds);
+Object* create_temporal_instant(GlobalObject&, BigInt& nanoseconds, FunctionObject* new_target = nullptr);
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/InstantConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/InstantConstructor.cpp
new file mode 100644
index 0000000000..c30def6cfd
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/InstantConstructor.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/GlobalObject.h>
+#include <LibJS/Runtime/Temporal/Instant.h>
+#include <LibJS/Runtime/Temporal/InstantConstructor.h>
+
+namespace JS::Temporal {
+
+// 8.1 The Temporal.Instant Constructor, https://tc39.es/proposal-temporal/#sec-temporal-instant-constructor
+InstantConstructor::InstantConstructor(GlobalObject& global_object)
+ : NativeFunction(vm().names.Instant.as_string(), *global_object.function_prototype())
+{
+}
+
+void InstantConstructor::initialize(GlobalObject& global_object)
+{
+ NativeFunction::initialize(global_object);
+
+ auto& vm = this->vm();
+
+ // 8.2.1 Temporal.Instant.prototype, https://tc39.es/proposal-temporal/#sec-temporal-instant-prototype
+ define_direct_property(vm.names.prototype, global_object.temporal_instant_prototype(), 0);
+
+ define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
+}
+
+// 8.1.1 Temporal.Instant ( epochNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal.instant
+Value InstantConstructor::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.Instant");
+ return {};
+}
+
+// 8.1.1 Temporal.Instant ( epochNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal.instant
+Value InstantConstructor::construct(FunctionObject& new_target)
+{
+ auto& vm = this->vm();
+ auto& global_object = this->global_object();
+
+ // 2. Let epochNanoseconds be ? 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. Return ? CreateTemporalInstant(epochNanoseconds, NewTarget).
+ return create_temporal_instant(global_object, *epoch_nanoseconds, &new_target);
+}
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/InstantConstructor.h b/Userland/Libraries/LibJS/Runtime/Temporal/InstantConstructor.h
new file mode 100644
index 0000000000..d449b0a096
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/InstantConstructor.h
@@ -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 InstantConstructor final : public NativeFunction {
+ JS_OBJECT(InstantConstructor, NativeFunction);
+
+public:
+ explicit InstantConstructor(GlobalObject&);
+ virtual void initialize(GlobalObject&) override;
+ virtual ~InstantConstructor() override = default;
+
+ virtual Value call() override;
+ virtual Value construct(FunctionObject& new_target) override;
+
+private:
+ virtual bool has_constructor() const override { return true; }
+};
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.cpp
new file mode 100644
index 0000000000..72b35ea2ca
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.cpp
@@ -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/InstantPrototype.h>
+
+namespace JS::Temporal {
+
+// 8.3 Properties of the Temporal.Instant Prototype Object, https://tc39.es/proposal-temporal/#sec-properties-of-the-temporal-instant-prototype-object
+InstantPrototype::InstantPrototype(GlobalObject& global_object)
+ : Object(*global_object.object_prototype())
+{
+}
+
+void InstantPrototype::initialize(GlobalObject& global_object)
+{
+ Object::initialize(global_object);
+}
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.h b/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.h
new file mode 100644
index 0000000000..78230cb332
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/InstantPrototype.h
@@ -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 InstantPrototype final : public Object {
+ JS_OBJECT(InstantPrototype, Object);
+
+public:
+ explicit InstantPrototype(GlobalObject&);
+ virtual void initialize(GlobalObject&) override;
+ virtual ~InstantPrototype() override = default;
+};
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Temporal.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/Temporal.cpp
index 7c410e702e..b35583c7ab 100644
--- a/Userland/Libraries/LibJS/Runtime/Temporal/Temporal.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Temporal/Temporal.cpp
@@ -5,6 +5,7 @@
*/
#include <LibJS/Runtime/GlobalObject.h>
+#include <LibJS/Runtime/Temporal/InstantConstructor.h>
#include <LibJS/Runtime/Temporal/Now.h>
#include <LibJS/Runtime/Temporal/Temporal.h>
#include <LibJS/Runtime/Temporal/TimeZoneConstructor.h>
@@ -25,6 +26,7 @@ void Temporal::initialize(GlobalObject& global_object)
u8 attr = Attribute::Writable | Attribute::Configurable;
define_direct_property(vm.names.now, heap().allocate<Now>(global_object, global_object), attr);
+ define_direct_property(vm.names.Instant, global_object.temporal_instant_constructor(), attr);
define_direct_property(vm.names.TimeZone, global_object.temporal_time_zone_constructor(), attr);
}