mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 18:07:34 +00:00
LibJS: Start implementing Temporal.TimeZone
Here we got our first Temporal object :^) This patch adds the TimeZone object itself, its constructor and prototype (currently empty), and a bunch of required abstract operations
This commit is contained in:
parent
6735353b96
commit
265e89367e
12 changed files with 338 additions and 2 deletions
|
@ -121,8 +121,12 @@ set(SOURCES
|
|||
Runtime/SymbolConstructor.cpp
|
||||
Runtime/SymbolObject.cpp
|
||||
Runtime/SymbolPrototype.cpp
|
||||
Runtime/Temporal/ISO8601.cpp
|
||||
Runtime/Temporal/Now.cpp
|
||||
Runtime/Temporal/Temporal.cpp
|
||||
Runtime/Temporal/TimeZone.cpp
|
||||
Runtime/Temporal/TimeZoneConstructor.cpp
|
||||
Runtime/Temporal/TimeZonePrototype.cpp
|
||||
Runtime/TypedArray.cpp
|
||||
Runtime/TypedArrayConstructor.cpp
|
||||
Runtime/TypedArrayPrototype.cpp
|
||||
|
|
|
@ -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(TimeZone, time_zone, TimeZonePrototype, TimeZoneConstructor)
|
||||
|
||||
#define JS_ENUMERATE_ITERATOR_PROTOTYPES \
|
||||
__JS_ENUMERATE(Iterator, iterator) \
|
||||
|
|
|
@ -68,6 +68,8 @@
|
|||
#include <LibJS/Runtime/SymbolConstructor.h>
|
||||
#include <LibJS/Runtime/SymbolPrototype.h>
|
||||
#include <LibJS/Runtime/Temporal/Temporal.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZoneConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZonePrototype.h>
|
||||
#include <LibJS/Runtime/TypedArray.h>
|
||||
#include <LibJS/Runtime/TypedArrayConstructor.h>
|
||||
#include <LibJS/Runtime/TypedArrayPrototype.h>
|
||||
|
@ -243,7 +245,6 @@ void GlobalObject::visit_edges(Visitor& visitor)
|
|||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
visitor.visit(m_##snake_name##_constructor); \
|
||||
visitor.visit(m_##snake_name##_prototype);
|
||||
JS_ENUMERATE_NATIVE_ERRORS
|
||||
JS_ENUMERATE_BUILTIN_TYPES
|
||||
#undef __JS_ENUMERATE
|
||||
|
||||
|
|
21
Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp
Normal file
21
Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <LibJS/Runtime/Temporal/ISO8601.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
// 13.33 ISO 8601 grammar, https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar
|
||||
|
||||
// TimeZoneNumericUTCOffset, https://tc39.es/proposal-temporal/#prod-TimeZoneNumericUTCOffset
|
||||
bool is_valid_time_zone_numeric_utc_offset(String const&)
|
||||
{
|
||||
// TODO: Implement me :^)
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
17
Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h
Normal file
17
Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
// 13.33 ISO 8601 grammar, https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar
|
||||
|
||||
bool is_valid_time_zone_numeric_utc_offset(String const&);
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Temporal/Now.h>
|
||||
#include <LibJS/Runtime/Temporal/Temporal.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZoneConstructor.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
|
@ -24,6 +25,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.TimeZone, global_object.temporal_time_zone_constructor(), attr);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
95
Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp
Normal file
95
Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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/ISO8601.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZone.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZoneConstructor.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
// 11 Temporal.TimeZone Objects, https://tc39.es/proposal-temporal/#sec-temporal-timezone-objects
|
||||
TimeZone::TimeZone(String identifier, Object& prototype)
|
||||
: Object(prototype)
|
||||
, m_identifier(move(identifier))
|
||||
{
|
||||
}
|
||||
|
||||
// 11.1.1 IsValidTimeZoneName ( timeZone ), https://tc39.es/proposal-temporal/#sec-isvalidtimezonename
|
||||
// NOTE: This is the minimum implementation of IsValidTimeZoneName, supporting only the "UTC" time zone.
|
||||
bool is_valid_time_zone_name(String const& time_zone)
|
||||
{
|
||||
// 1. Assert: Type(timeZone) is String.
|
||||
|
||||
// 2. Let tzText be ! StringToCodePoints(timeZone).
|
||||
// 3. Let tzUpperText be the result of toUppercase(tzText), according to the Unicode Default Case Conversion algorithm.
|
||||
// 4. Let tzUpper be ! CodePointsToString(tzUpperText).
|
||||
auto tz_upper = time_zone.to_uppercase();
|
||||
|
||||
// 5. If tzUpper and "UTC" are the same sequence of code points, return true.
|
||||
if (tz_upper == "UTC")
|
||||
return true;
|
||||
|
||||
// 6. Return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
// 11.1.2 CanonicalizeTimeZoneName ( timeZone ), https://tc39.es/proposal-temporal/#sec-canonicalizetimezonename
|
||||
// NOTE: This is the minimum implementation of CanonicalizeTimeZoneName, supporting only the "UTC" time zone.
|
||||
String canonicalize_time_zone_name(String const& time_zone)
|
||||
{
|
||||
// 1. Assert: Type(timeZone) is String.
|
||||
|
||||
// 2. Assert: ! IsValidTimeZoneName(timeZone) is true.
|
||||
VERIFY(is_valid_time_zone_name(time_zone));
|
||||
|
||||
// 3. Return "UTC".
|
||||
return "UTC";
|
||||
}
|
||||
|
||||
// 11.1.3 DefaultTimeZone ( ), https://tc39.es/proposal-temporal/#sec-defaulttimezone
|
||||
// NOTE: This is the minimum implementation of DefaultTimeZone, supporting only the "UTC" time zone.
|
||||
String default_time_zone()
|
||||
{
|
||||
// 1. Return "UTC".
|
||||
return "UTC";
|
||||
}
|
||||
|
||||
// 11.6.2 CreateTemporalTimeZone ( identifier [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporaltimezone
|
||||
Object* create_temporal_time_zone(GlobalObject& global_object, String const& identifier, FunctionObject* new_target)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. If newTarget is not present, set it to %Temporal.TimeZone%.
|
||||
if (!new_target)
|
||||
new_target = global_object.temporal_time_zone_constructor();
|
||||
|
||||
// 2. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.TimeZone.prototype%", « [[InitializedTemporalTimeZone]], [[Identifier]], [[OffsetNanoseconds]] »).
|
||||
// 3. Set object.[[Identifier]] to identifier.
|
||||
auto* object = ordinary_create_from_constructor<TimeZone>(global_object, *new_target, &GlobalObject::temporal_time_zone_prototype, identifier);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// 4. If identifier satisfies the syntax of a TimeZoneNumericUTCOffset (see 13.33), then
|
||||
if (is_valid_time_zone_numeric_utc_offset(identifier)) {
|
||||
// TODO:
|
||||
// a. Set object.[[OffsetNanoseconds]] to ! ParseTimeZoneOffsetString(identifier).
|
||||
}
|
||||
// 5. Else,
|
||||
else {
|
||||
// a. Assert: ! CanonicalizeTimeZoneName(identifier) is identifier.
|
||||
VERIFY(canonicalize_time_zone_name(identifier) == identifier);
|
||||
|
||||
// b. Set object.[[OffsetNanoseconds]] to undefined.
|
||||
// NOTE: No-op.
|
||||
}
|
||||
|
||||
// 6. Return object.
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
43
Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.h
Normal file
43
Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
class TimeZone final : public Object {
|
||||
JS_OBJECT(TimeZone, Object);
|
||||
|
||||
// Needs to store values in the range -8.64 * 10^21 to 8.64 * 10^21
|
||||
using OffsetType = double;
|
||||
|
||||
public:
|
||||
explicit TimeZone(String identifier, Object& prototype);
|
||||
virtual ~TimeZone() override = default;
|
||||
|
||||
String const& identifier() const { return m_identifier; }
|
||||
Optional<OffsetType> const& offset_nanoseconds() const { return m_offset_nanoseconds; }
|
||||
void set_offset_nanoseconds(u32 offset_nanoseconds) { m_offset_nanoseconds = offset_nanoseconds; };
|
||||
|
||||
private:
|
||||
// 11.5 Properties of Temporal.TimeZone Instances, https://tc39.es/proposal-temporal/#sec-properties-of-temporal-timezone-instances
|
||||
|
||||
// [[Identifier]]
|
||||
String m_identifier;
|
||||
|
||||
// [[OffsetNanoseconds]]
|
||||
Optional<OffsetType> m_offset_nanoseconds;
|
||||
};
|
||||
|
||||
bool is_valid_time_zone_name(String const& time_zone);
|
||||
String canonicalize_time_zone_name(String const& time_zone);
|
||||
String default_time_zone();
|
||||
Object* create_temporal_time_zone(GlobalObject&, String const& identifier, FunctionObject* new_target = nullptr);
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Temporal/ISO8601.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZone.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZoneConstructor.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
// 11.2 The Temporal.TimeZone Constructor, https://tc39.es/proposal-temporal/#sec-temporal-timezone-constructor
|
||||
TimeZoneConstructor::TimeZoneConstructor(GlobalObject& global_object)
|
||||
: NativeFunction(vm().names.TimeZone.as_string(), *global_object.function_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void TimeZoneConstructor::initialize(GlobalObject& global_object)
|
||||
{
|
||||
NativeFunction::initialize(global_object);
|
||||
|
||||
auto& vm = this->vm();
|
||||
|
||||
// 11.3.1 Temporal.TimeZone.prototype, https://tc39.es/proposal-temporal/#sec-temporal-timezone-prototype
|
||||
define_direct_property(vm.names.prototype, global_object.temporal_time_zone_prototype(), 0);
|
||||
|
||||
define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
|
||||
}
|
||||
|
||||
// 11.2.1 Temporal.TimeZone ( identifier ), https://tc39.es/proposal-temporal/#sec-temporal.timezone
|
||||
Value TimeZoneConstructor::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.TimeZone");
|
||||
return {};
|
||||
}
|
||||
|
||||
// 11.2.1 Temporal.TimeZone ( identifier ), https://tc39.es/proposal-temporal/#sec-temporal.timezone
|
||||
Value TimeZoneConstructor::construct(FunctionObject& new_target)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
auto& global_object = this->global_object();
|
||||
|
||||
// 2. Set identifier to ? ToString(identifier).
|
||||
auto identifier = vm.argument(0).to_string(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
String canonical;
|
||||
|
||||
// 3. If identifier satisfies the syntax of a TimeZoneNumericUTCOffset (see 13.33), then
|
||||
if (is_valid_time_zone_numeric_utc_offset(identifier)) {
|
||||
// TODO:
|
||||
// a. Let offsetNanoseconds be ? ParseTimeZoneOffsetString(identifier).
|
||||
// b. Let canonical be ! FormatTimeZoneOffsetString(offsetNanoseconds).
|
||||
}
|
||||
// 4. Else,
|
||||
else {
|
||||
// a. If ! IsValidTimeZoneName(identifier) is false, then
|
||||
if (!is_valid_time_zone_name(identifier)) {
|
||||
// i. Throw a RangeError exception.
|
||||
vm.throw_exception<RangeError>(global_object);
|
||||
return {};
|
||||
}
|
||||
|
||||
// b. Let canonical be ! CanonicalizeTimeZoneName(identifier).
|
||||
canonical = canonicalize_time_zone_name(identifier);
|
||||
}
|
||||
|
||||
// 5. Return ? CreateTemporalTimeZone(canonical, NewTarget).
|
||||
return create_temporal_time_zone(global_object, canonical, &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 TimeZoneConstructor final : public NativeFunction {
|
||||
JS_OBJECT(TimeZoneConstructor, NativeFunction);
|
||||
|
||||
public:
|
||||
explicit TimeZoneConstructor(GlobalObject&);
|
||||
virtual void initialize(GlobalObject&) override;
|
||||
virtual ~TimeZoneConstructor() 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/TimeZonePrototype.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
// 11.4 Properties of the Temporal.TimeZone Prototype Object, https://tc39.es/proposal-temporal/#sec-properties-of-the-temporal-timezone-prototype-object
|
||||
TimeZonePrototype::TimeZonePrototype(GlobalObject& global_object)
|
||||
: Object(*global_object.object_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void TimeZonePrototype::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 TimeZonePrototype final : public Object {
|
||||
JS_OBJECT(TimeZonePrototype, Object);
|
||||
|
||||
public:
|
||||
explicit TimeZonePrototype(GlobalObject&);
|
||||
virtual void initialize(GlobalObject&) override;
|
||||
virtual ~TimeZonePrototype() override = default;
|
||||
};
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue