mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 12:05:15 +00:00
LibJS: Implement Temporal's Time Zone Methods Record
Similar to 'Calendar Methods Record', this is part of a refactor to the temporal spec which will need much work for all of the corresponding AOs to be updated to use. Put in a new header file to prevent circular include problems when using this new record.
This commit is contained in:
parent
15977ea42f
commit
fa692ae3f6
Notes:
sideshowbarker
2024-07-17 23:00:03 +09:00
Author: https://github.com/shannonbooth Commit: https://github.com/SerenityOS/serenity/commit/fa692ae3f6 Pull-request: https://github.com/SerenityOS/serenity/pull/23238 Reviewed-by: https://github.com/trflynn89
4 changed files with 180 additions and 0 deletions
|
@ -237,6 +237,7 @@ set(SOURCES
|
|||
Runtime/Temporal/Temporal.cpp
|
||||
Runtime/Temporal/TimeZone.cpp
|
||||
Runtime/Temporal/TimeZoneConstructor.cpp
|
||||
Runtime/Temporal/TimeZoneMethods.cpp
|
||||
Runtime/Temporal/TimeZonePrototype.cpp
|
||||
Runtime/Temporal/ZonedDateTime.cpp
|
||||
Runtime/Temporal/ZonedDateTimeConstructor.cpp
|
||||
|
|
|
@ -292,6 +292,7 @@ struct CalendarMethods;
|
|||
struct DurationRecord;
|
||||
struct DateDurationRecord;
|
||||
struct TimeDurationRecord;
|
||||
struct TimeZoneMethods;
|
||||
struct PartialDurationRecord;
|
||||
};
|
||||
|
||||
|
|
134
Userland/Libraries/LibJS/Runtime/Temporal/TimeZoneMethods.cpp
Normal file
134
Userland/Libraries/LibJS/Runtime/Temporal/TimeZoneMethods.cpp
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Shannon Booth <shannon@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZone.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZoneMethods.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
// 11.5.2 CreateTimeZoneMethodsRecord ( timeZone, methods ), https://tc39.es/proposal-temporal/#sec-temporal-createtimezonemethodsrecord
|
||||
ThrowCompletionOr<TimeZoneMethods> create_time_zone_methods_record(VM& vm, Variant<String, NonnullGCPtr<Object>> time_zone, ReadonlySpan<TimeZoneMethod> methods)
|
||||
{
|
||||
// 1. Let record be the Time Zone Methods Record { [[Receiver]]: timeZone, [[GetOffsetNanosecondsFor]]: undefined, [[GetPossibleInstantsFor]]: undefined }.
|
||||
TimeZoneMethods record {
|
||||
.receiver = move(time_zone),
|
||||
.get_offset_nanoseconds_for = nullptr,
|
||||
.get_possible_instants_for = nullptr,
|
||||
};
|
||||
|
||||
// 2. For each element methodName in methods, do
|
||||
for (TimeZoneMethod method_name : methods) {
|
||||
// a. Perform ? TimeZoneMethodsRecordLookup(record, methodName).
|
||||
TRY(time_zone_methods_record_lookup(vm, record, method_name));
|
||||
}
|
||||
|
||||
// 3. Return record.
|
||||
return record;
|
||||
}
|
||||
|
||||
// 11.5.3 TimeZoneMethodsRecordLookup ( timeZoneRec, methodName ), https://tc39.es/proposal-temporal/#sec-temporal-timezonemethodsrecordlookup
|
||||
ThrowCompletionOr<void> time_zone_methods_record_lookup(VM& vm, TimeZoneMethods& time_zone_record, TimeZoneMethod method_name)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 1. Assert: TimeZoneMethodsRecordHasLookedUp(timeZoneRec, methodName) is false.
|
||||
// 2. If methodName is GET-OFFSET-NANOSECONDS-FOR, then
|
||||
// a. If timeZoneRec.[[Receiver]] is a String, then
|
||||
// i. Set timeZoneRec.[[GetOffsetNanosecondsFor]] to %Temporal.TimeZone.prototype.getOffsetNanosecondsFor%.
|
||||
// b. Else,
|
||||
// i. Set timeZoneRec.[[GetOffsetNanosecondsFor]] to ? GetMethod(timeZoneRec.[[Receiver]], "getOffsetNanosecondsFor").
|
||||
// ii. If timeZoneRec.[[GetOffsetNanosecondsFor]] is undefined, throw a TypeError exception.
|
||||
// 3. Else if methodName is GET-POSSIBLE-INSTANTS-FOR, then
|
||||
// a. If timeZoneRec.[[Receiver]] is a String, then
|
||||
// i. Set timeZoneRec.[[GetPossibleInstantsFor]] to %Temporal.TimeZone.prototype.getPossibleInstantsFor%.
|
||||
// b. Else,
|
||||
// i. Set timeZoneRec.[[GetPossibleInstantsFor]] to ? GetMethod(timeZoneRec.[[Receiver]], "getPossibleInstantsFor").
|
||||
// ii. If timeZoneRec.[[GetPossibleInstantsFor]] is undefined, throw a TypeError exception.
|
||||
switch (method_name) {
|
||||
#define __JS_ENUMERATE(PascalName, camelName, snake_name) \
|
||||
case TimeZoneMethod::PascalName: { \
|
||||
VERIFY(!time_zone_record.snake_name); \
|
||||
if (time_zone_record.receiver.has<String>()) { \
|
||||
const auto& time_zone_prototype = *realm.intrinsics().temporal_time_zone_prototype(); \
|
||||
time_zone_record.snake_name = time_zone_prototype.get_without_side_effects(vm.names.camelName).as_function(); \
|
||||
} else { \
|
||||
Value time_zone { time_zone_record.receiver.get<NonnullGCPtr<Object>>() }; \
|
||||
time_zone_record.snake_name = TRY(time_zone.get_method(vm, vm.names.camelName)); \
|
||||
if (!time_zone_record.snake_name) \
|
||||
return vm.throw_completion<TypeError>(ErrorType::IsUndefined, #camelName##sv); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
JS_ENUMERATE_TIME_ZONE_METHODS
|
||||
#undef __JS_ENUMERATE
|
||||
}
|
||||
// 4. Return UNUSED.
|
||||
return {};
|
||||
}
|
||||
|
||||
// 11.5.4 TimeZoneMethodsRecordHasLookedUp ( timeZoneRec, methodName ), https://tc39.es/proposal-temporal/#sec-temporal-timezonemethodsrecordhaslookedup
|
||||
bool time_zone_methods_record_has_looked_up(TimeZoneMethods const& time_zone_record, TimeZoneMethod method_name)
|
||||
{
|
||||
// 1. If methodName is GET-OFFSET-NANOSECONDS-FOR, then
|
||||
// a. Let method be timeZoneRec.[[GetOffsetNanosecondsFor]].
|
||||
// 2. Else if methodName is GET-POSSIBLE-INSTANTS-FOR, then
|
||||
// a. Let method be timeZoneRec.[[GetPossibleInstantsFor]].
|
||||
// 3. If method is undefined, return false.
|
||||
// 4. Return true.
|
||||
switch (method_name) {
|
||||
#define __JS_ENUMERATE(PascalName, camelName, snake_name) \
|
||||
case TimeZoneMethod::PascalName: { \
|
||||
return time_zone_record.snake_name != nullptr; \
|
||||
}
|
||||
JS_ENUMERATE_TIME_ZONE_METHODS
|
||||
#undef __JS_ENUMERATE
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
// 11.5.5 TimeZoneMethodsRecordIsBuiltin ( timeZoneRec ), https://tc39.es/proposal-temporal/#sec-temporal-timezonemethodsrecordisbuiltin
|
||||
bool time_zone_methods_record_is_builtin(TimeZoneMethods const& time_zone_record)
|
||||
{
|
||||
// 1. If timeZoneRec.[[Receiver]] is a String, return true.
|
||||
if (time_zone_record.receiver.has<String>())
|
||||
return true;
|
||||
|
||||
// 2. Return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
// 11.5.6 TimeZoneMethodsRecordCall ( timeZoneRec, methodName, arguments ), https://tc39.es/proposal-temporal/#sec-temporal-timezonemethodsrecordcall
|
||||
ThrowCompletionOr<Value> time_zone_methods_record_call(VM& vm, TimeZoneMethods const& time_zone_record, TimeZoneMethod method_name, ReadonlySpan<Value> arguments)
|
||||
{
|
||||
// 1. Assert: TimeZoneMethodsRecordHasLookedUp(timeZoneRec, methodName) is true.
|
||||
VERIFY(time_zone_methods_record_has_looked_up(time_zone_record, method_name));
|
||||
|
||||
// 2. Let receiver be timeZoneRec.[[Receiver]].
|
||||
// 3. If TimeZoneMethodsRecordIsBuiltin(timeZoneRec) is true, then
|
||||
// a. Set receiver to ! CreateTemporalTimeZone(timeZoneRec.[[Receiver]]).
|
||||
GCPtr<Object> receiver;
|
||||
if (time_zone_methods_record_is_builtin(time_zone_record))
|
||||
receiver = MUST(create_temporal_time_zone(vm, time_zone_record.receiver.get<String>()));
|
||||
else
|
||||
receiver = time_zone_record.receiver.get<NonnullGCPtr<Object>>();
|
||||
|
||||
// 4. If methodName is GET-OFFSET-NANOSECONDS-FOR, then
|
||||
// a. Return ? Call(timeZoneRec.[[GetOffsetNanosecondsFor]], receiver, arguments).
|
||||
// 5. If methodName is GET-POSSIBLE-INSTANTS-FOR, then
|
||||
// a. Return ? Call(timeZoneRec.[[GetPossibleInstantsFor]], receiver, arguments).
|
||||
switch (method_name) {
|
||||
#define __JS_ENUMERATE(PascalName, camelName, snake_name) \
|
||||
case TimeZoneMethod::PascalName: { \
|
||||
return TRY(call(vm, time_zone_record.snake_name, receiver, arguments)); \
|
||||
}
|
||||
JS_ENUMERATE_TIME_ZONE_METHODS
|
||||
#undef __JS_ENUMERATE
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
44
Userland/Libraries/LibJS/Runtime/Temporal/TimeZoneMethods.h
Normal file
44
Userland/Libraries/LibJS/Runtime/Temporal/TimeZoneMethods.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Shannon Booth <shannon@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/GCPtr.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
// 11.5.1 Time Zone Methods Records, https://tc39.es/proposal-temporal/#sec-temporal-time-zone-methods-records
|
||||
struct TimeZoneMethods {
|
||||
// The time zone object, or a string indicating a built-in time zone.
|
||||
Variant<String, NonnullGCPtr<Object>> receiver; // [[Reciever]]
|
||||
|
||||
// The time zone's getOffsetNanosecondsFor method. For a built-in time zone this is always %Temporal.TimeZone.prototype.getOffsetNanosecondsFor%.
|
||||
GCPtr<FunctionObject> get_offset_nanoseconds_for; // [[GetOffsetNanosecondsFor]]
|
||||
|
||||
// The time zone's getPossibleInstantsFor method. For a built-in time zone this is always %Temporal.TimeZone.prototype.getPossibleInstantsFor%.
|
||||
GCPtr<FunctionObject> get_possible_instants_for; // [[GetPossibleInstantsFor]]
|
||||
};
|
||||
|
||||
#define JS_ENUMERATE_TIME_ZONE_METHODS \
|
||||
__JS_ENUMERATE(GetOffsetNanosecondsFor, getOffsetNanosecondsFor, get_offset_nanoseconds_for) \
|
||||
__JS_ENUMERATE(GetPossibleInstantsFor, getPossibleInstantsFor, get_possible_instants_for)
|
||||
|
||||
enum class TimeZoneMethod {
|
||||
#define __JS_ENUMERATE(PascalName, camelName, snake_name) \
|
||||
PascalName,
|
||||
JS_ENUMERATE_TIME_ZONE_METHODS
|
||||
#undef __JS_ENUMERATE
|
||||
};
|
||||
|
||||
ThrowCompletionOr<void> time_zone_methods_record_lookup(VM&, TimeZoneMethods&, TimeZoneMethod);
|
||||
ThrowCompletionOr<TimeZoneMethods> create_time_zone_methods_record(VM&, Variant<String, NonnullGCPtr<Object>> time_zone, ReadonlySpan<TimeZoneMethod>);
|
||||
bool time_zone_methods_record_has_looked_up(TimeZoneMethods const&, TimeZoneMethod);
|
||||
bool time_zone_methods_record_is_builtin(TimeZoneMethods const&);
|
||||
ThrowCompletionOr<Value> time_zone_methods_record_call(VM&, TimeZoneMethods const&, TimeZoneMethod, ReadonlySpan<Value> arguments);
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue