mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-19 09:17:38 +03:00
LibJS: Start implementing Temporal.Calendar
Just like the previous Temporal.{Instant,TimeZone} commits, this patch adds the Calendar object itself, its constructor and prototype (currently empty), and two required abstract operations.
This commit is contained in:
parent
48b66c7a68
commit
a2f1d79765
Notes:
sideshowbarker
2024-07-18 09:00:34 +09:00
Author: https://github.com/linusg Commit: https://github.com/SerenityOS/serenity/commit/a2f1d797659 Pull-request: https://github.com/SerenityOS/serenity/pull/8753 Reviewed-by: https://github.com/IdanHo ✅
@ -123,6 +123,8 @@ set(SOURCES
|
||||
Runtime/SymbolPrototype.cpp
|
||||
Runtime/Temporal/AbstractOperations.cpp
|
||||
Runtime/Temporal/Calendar.cpp
|
||||
Runtime/Temporal/CalendarConstructor.cpp
|
||||
Runtime/Temporal/CalendarPrototype.cpp
|
||||
Runtime/Temporal/Instant.cpp
|
||||
Runtime/Temporal/InstantConstructor.cpp
|
||||
Runtime/Temporal/InstantPrototype.cpp
|
||||
|
@ -76,8 +76,9 @@
|
||||
__JS_ENUMERATE(Float32Array, float32_array, Float32ArrayPrototype, Float32ArrayConstructor, float) \
|
||||
__JS_ENUMERATE(Float64Array, float64_array, Float64ArrayPrototype, Float64ArrayConstructor, double)
|
||||
|
||||
#define JS_ENUMERATE_TEMPORAL_OBJECTS \
|
||||
__JS_ENUMERATE(Instant, instant, InstantPrototype, InstantConstructor) \
|
||||
#define JS_ENUMERATE_TEMPORAL_OBJECTS \
|
||||
__JS_ENUMERATE(Calendar, calendar, CalendarPrototype, CalendarConstructor) \
|
||||
__JS_ENUMERATE(Instant, instant, InstantPrototype, InstantConstructor) \
|
||||
__JS_ENUMERATE(TimeZone, time_zone, TimeZonePrototype, TimeZoneConstructor)
|
||||
|
||||
#define JS_ENUMERATE_ITERATOR_PROTOTYPES \
|
||||
|
@ -166,8 +166,9 @@
|
||||
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(TemporalInvalidISODate, "Invalid ISO date") \
|
||||
M(TemporalInvalidCalendarIdentifier, "Invalid calendar identifier '{}'") \
|
||||
M(TemporalInvalidEpochNanoseconds, "Invalid epoch nanoseconds value, must be in range -86400 * 10^17 to 86400 * 10^17") \
|
||||
M(TemporalInvalidISODate, "Invalid ISO date") \
|
||||
M(TemporalInvalidTime, "Invalid time") \
|
||||
M(TemporalInvalidTimeZoneName, "Invalid time zone name") \
|
||||
M(ThisHasNotBeenInitialized, "|this| has not been initialized") \
|
||||
|
@ -68,6 +68,8 @@
|
||||
#include <LibJS/Runtime/StringPrototype.h>
|
||||
#include <LibJS/Runtime/SymbolConstructor.h>
|
||||
#include <LibJS/Runtime/SymbolPrototype.h>
|
||||
#include <LibJS/Runtime/Temporal/CalendarConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/CalendarPrototype.h>
|
||||
#include <LibJS/Runtime/Temporal/InstantConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/InstantPrototype.h>
|
||||
#include <LibJS/Runtime/Temporal/Temporal.h>
|
||||
|
@ -4,11 +4,55 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Temporal/Calendar.h>
|
||||
#include <LibJS/Runtime/Temporal/CalendarConstructor.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
// 12 Temporal.Calendar Objects, https://tc39.es/proposal-temporal/#sec-temporal-calendar-objects
|
||||
Calendar::Calendar(String identifier, Object& prototype)
|
||||
: Object(prototype)
|
||||
, m_identifier(move(identifier))
|
||||
{
|
||||
}
|
||||
|
||||
// 12.1.1 CreateTemporalCalendar ( identifier [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporalcalendar
|
||||
Calendar* create_temporal_calendar(GlobalObject& global_object, String const& identifier, FunctionObject* new_target)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. Assert: ! IsBuiltinCalendar(identifier) is true.
|
||||
VERIFY(is_builtin_calendar(identifier));
|
||||
|
||||
// 2. If newTarget is not provided, set newTarget to %Temporal.Calendar%.
|
||||
if (!new_target)
|
||||
new_target = global_object.temporal_calendar_constructor();
|
||||
|
||||
// 3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.Calendar.prototype%", « [[InitializedTemporalCalendar]], [[Identifier]] »).
|
||||
// 4. Set object.[[Identifier]] to identifier.
|
||||
auto* object = ordinary_create_from_constructor<Calendar>(global_object, *new_target, &GlobalObject::temporal_calendar_prototype, identifier);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// 5. Return object.
|
||||
return object;
|
||||
}
|
||||
|
||||
// 12.1.2 IsBuiltinCalendar ( id ), https://tc39.es/proposal-temporal/#sec-temporal-isbuiltincalendar
|
||||
// NOTE: This is the minimum IsBuiltinCalendar implementation for engines without ECMA-402.
|
||||
bool is_builtin_calendar(String const& identifier)
|
||||
{
|
||||
// 1. If id is not "iso8601", return false.
|
||||
if (identifier != "iso8601"sv)
|
||||
return false;
|
||||
|
||||
// 2. Return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
// 12.1.30 IsISOLeapYear ( year ), https://tc39.es/proposal-temporal/#sec-temporal-isisoleapyear
|
||||
bool is_iso_leap_year(i32 year)
|
||||
{
|
||||
|
@ -1,15 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
class Calendar final : public Object {
|
||||
JS_OBJECT(Calendar, Object);
|
||||
|
||||
public:
|
||||
explicit Calendar(String identifier, Object& prototype);
|
||||
virtual ~Calendar() override = default;
|
||||
|
||||
String const& identifier() const { return m_identifier; }
|
||||
|
||||
private:
|
||||
// 12.5 Properties of Temporal.Calendar Instances, https://tc39.es/proposal-temporal/#sec-properties-of-temporal-calendar-instances
|
||||
|
||||
// [[Identifier]]
|
||||
String m_identifier;
|
||||
};
|
||||
|
||||
Calendar* create_temporal_calendar(GlobalObject&, String const& identifier, FunctionObject* new_target = nullptr);
|
||||
bool is_builtin_calendar(String const& identifier);
|
||||
bool is_iso_leap_year(i32 year);
|
||||
i32 iso_days_in_month(i32 year, i32 month);
|
||||
|
||||
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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/CalendarConstructor.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
// 12.2 The Temporal.Calendar Constructor, https://tc39.es/proposal-temporal/#sec-temporal-calendar-constructor
|
||||
CalendarConstructor::CalendarConstructor(GlobalObject& global_object)
|
||||
: NativeFunction(vm().names.Calendar.as_string(), *global_object.function_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void CalendarConstructor::initialize(GlobalObject& global_object)
|
||||
{
|
||||
NativeFunction::initialize(global_object);
|
||||
|
||||
auto& vm = this->vm();
|
||||
|
||||
// 12.3.1 Temporal.Calendar.prototype, https://tc39.es/proposal-temporal/#sec-temporal-calendar-prototype
|
||||
define_direct_property(vm.names.prototype, global_object.temporal_calendar_prototype(), 0);
|
||||
|
||||
define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
|
||||
}
|
||||
|
||||
// 12.2.1 Temporal.Calendar ( id ), https://tc39.es/proposal-temporal/#sec-temporal.calendar
|
||||
Value CalendarConstructor::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.Calendar");
|
||||
return {};
|
||||
}
|
||||
|
||||
// 12.2.1 Temporal.Calendar ( id ), https://tc39.es/proposal-temporal/#sec-temporal.calendar
|
||||
Value CalendarConstructor::construct(FunctionObject& new_target)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
auto& global_object = this->global_object();
|
||||
|
||||
// 2. Set id to ? ToString(id).
|
||||
auto identifier = vm.argument(0).to_string(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
// 3. If ! IsBuiltinCalendar(id) is false, then
|
||||
if (!is_builtin_calendar(identifier)) {
|
||||
// a. Throw a RangeError exception.
|
||||
vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidCalendarIdentifier, identifier);
|
||||
return {};
|
||||
}
|
||||
|
||||
// 4. Return ? CreateTemporalCalendar(id, NewTarget).
|
||||
return create_temporal_calendar(global_object, identifier, &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 CalendarConstructor final : public NativeFunction {
|
||||
JS_OBJECT(CalendarConstructor, NativeFunction);
|
||||
|
||||
public:
|
||||
explicit CalendarConstructor(GlobalObject&);
|
||||
virtual void initialize(GlobalObject&) override;
|
||||
virtual ~CalendarConstructor() 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/CalendarPrototype.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
// 12.4 Properties of the Temporal.Calendar Prototype Object, https://tc39.es/proposal-temporal/#sec-properties-of-the-temporal-calendar-prototype-object
|
||||
CalendarPrototype::CalendarPrototype(GlobalObject& global_object)
|
||||
: Object(*global_object.object_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void CalendarPrototype::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 CalendarPrototype final : public Object {
|
||||
JS_OBJECT(CalendarPrototype, Object);
|
||||
|
||||
public:
|
||||
explicit CalendarPrototype(GlobalObject&);
|
||||
virtual void initialize(GlobalObject&) override;
|
||||
virtual ~CalendarPrototype() override = default;
|
||||
};
|
||||
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Temporal/CalendarConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/InstantConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/Now.h>
|
||||
#include <LibJS/Runtime/Temporal/Temporal.h>
|
||||
@ -26,6 +27,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.Calendar, global_object.temporal_calendar_constructor(), 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);
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
describe("errors", () => {
|
||||
test("called without new", () => {
|
||||
expect(() => {
|
||||
Temporal.Calendar();
|
||||
}).toThrowWithMessage(TypeError, "Temporal.Calendar constructor must be called with 'new'");
|
||||
});
|
||||
|
||||
test("argument must be coercible to string", () => {
|
||||
expect(() => {
|
||||
new Temporal.Calendar({
|
||||
toString() {
|
||||
throw new Error();
|
||||
},
|
||||
});
|
||||
}).toThrow(Error);
|
||||
});
|
||||
|
||||
test("invalid calendar identifier", () => {
|
||||
expect(() => {
|
||||
new Temporal.Calendar("foo");
|
||||
}).toThrowWithMessage(RangeError, "Invalid calendar identifier 'foo'");
|
||||
});
|
||||
});
|
||||
|
||||
describe("normal behavior", () => {
|
||||
test("length is 1", () => {
|
||||
expect(Temporal.Calendar).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const calendar = new Temporal.Calendar("iso8601");
|
||||
// FIXME: Enable this once Temporal.Calendar.prototype.id is implemented
|
||||
// expect(calendar.id).toBe("iso8601");
|
||||
expect(typeof calendar).toBe("object");
|
||||
expect(calendar).toBeInstanceOf(Temporal.Calendar);
|
||||
expect(Object.getPrototypeOf(calendar)).toBe(Temporal.Calendar.prototype);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user