LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <LibJS/Runtime/Error.h>
|
|
|
|
|
#include <LibJS/Runtime/FunctionObject.h>
|
|
|
|
|
#include <LibJS/Runtime/GlobalObject.h>
|
|
|
|
|
#include <LibJS/Runtime/Object.h>
|
|
|
|
|
#include <LibJS/Runtime/PropertyDescriptor.h>
|
|
|
|
|
#include <LibJS/Runtime/Value.h>
|
|
|
|
|
|
|
|
|
|
namespace JS {
|
|
|
|
|
|
|
|
|
|
// 6.2.5.1 IsAccessorDescriptor ( Desc ), https://tc39.es/ecma262/#sec-isaccessordescriptor
|
|
|
|
|
bool PropertyDescriptor::is_accessor_descriptor() const
|
|
|
|
|
{
|
|
|
|
|
// 1. If Desc is undefined, return false.
|
|
|
|
|
|
|
|
|
|
// 2. If both Desc.[[Get]] and Desc.[[Set]] are absent, return false.
|
|
|
|
|
if (!get.has_value() && !set.has_value())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// 3. Return true.
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6.2.5.2 IsDataDescriptor ( Desc ), https://tc39.es/ecma262/#sec-isdatadescriptor
|
|
|
|
|
bool PropertyDescriptor::is_data_descriptor() const
|
|
|
|
|
{
|
|
|
|
|
// 1. If Desc is undefined, return false.
|
|
|
|
|
|
|
|
|
|
// 2. If both Desc.[[Value]] and Desc.[[Writable]] are absent, return false.
|
|
|
|
|
if (!value.has_value() && !writable.has_value())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// 3. Return true.
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6.2.5.3 IsGenericDescriptor ( Desc ), https://tc39.es/ecma262/#sec-isgenericdescriptor
|
|
|
|
|
bool PropertyDescriptor::is_generic_descriptor() const
|
|
|
|
|
{
|
|
|
|
|
// 1. If Desc is undefined, return false.
|
|
|
|
|
|
|
|
|
|
// 2. If IsAccessorDescriptor(Desc) and IsDataDescriptor(Desc) are both false, return true.
|
|
|
|
|
if (!is_accessor_descriptor() && !is_data_descriptor())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// 3. Return false.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6.2.5.4 FromPropertyDescriptor ( Desc ), https://tc39.es/ecma262/#sec-frompropertydescriptor
|
|
|
|
|
Value from_property_descriptor(GlobalObject& global_object, Optional<PropertyDescriptor> const& property_descriptor)
|
|
|
|
|
{
|
|
|
|
|
if (!property_descriptor.has_value())
|
|
|
|
|
return js_undefined();
|
|
|
|
|
auto& vm = global_object.vm();
|
|
|
|
|
auto* object = Object::create(global_object, global_object.object_prototype());
|
|
|
|
|
if (property_descriptor->value.has_value())
|
2021-10-03 01:18:46 +01:00
|
|
|
MUST(object->create_data_property_or_throw(vm.names.value, *property_descriptor->value));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
if (property_descriptor->writable.has_value())
|
2021-10-03 01:18:46 +01:00
|
|
|
MUST(object->create_data_property_or_throw(vm.names.writable, Value(*property_descriptor->writable)));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
if (property_descriptor->get.has_value())
|
2021-10-03 01:18:46 +01:00
|
|
|
MUST(object->create_data_property_or_throw(vm.names.get, *property_descriptor->get ? Value(*property_descriptor->get) : js_undefined()));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
if (property_descriptor->set.has_value())
|
2021-10-03 01:18:46 +01:00
|
|
|
MUST(object->create_data_property_or_throw(vm.names.set, *property_descriptor->set ? Value(*property_descriptor->set) : js_undefined()));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
if (property_descriptor->enumerable.has_value())
|
2021-10-03 01:18:46 +01:00
|
|
|
MUST(object->create_data_property_or_throw(vm.names.enumerable, Value(*property_descriptor->enumerable)));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
if (property_descriptor->configurable.has_value())
|
2021-10-03 01:18:46 +01:00
|
|
|
MUST(object->create_data_property_or_throw(vm.names.configurable, Value(*property_descriptor->configurable)));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6.2.5.5 ToPropertyDescriptor ( Obj ), https://tc39.es/ecma262/#sec-topropertydescriptor
|
|
|
|
|
PropertyDescriptor to_property_descriptor(GlobalObject& global_object, Value argument)
|
|
|
|
|
{
|
|
|
|
|
auto& vm = global_object.vm();
|
|
|
|
|
if (!argument.is_object()) {
|
|
|
|
|
vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, argument.to_string_without_side_effects());
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
auto& object = argument.as_object();
|
|
|
|
|
PropertyDescriptor descriptor;
|
2021-10-03 02:00:39 +01:00
|
|
|
auto has_enumerable = TRY_OR_DISCARD(object.has_property(vm.names.enumerable));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
if (has_enumerable) {
|
2021-10-02 23:52:27 +01:00
|
|
|
auto enumerable = TRY_OR_DISCARD(object.get(vm.names.enumerable));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
descriptor.enumerable = enumerable.to_boolean();
|
|
|
|
|
}
|
2021-10-03 02:00:39 +01:00
|
|
|
auto has_configurable = TRY_OR_DISCARD(object.has_property(vm.names.configurable));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
if (has_configurable) {
|
2021-10-02 23:52:27 +01:00
|
|
|
auto configurable = TRY_OR_DISCARD(object.get(vm.names.configurable));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
descriptor.configurable = configurable.to_boolean();
|
|
|
|
|
}
|
2021-10-03 02:00:39 +01:00
|
|
|
auto has_value = TRY_OR_DISCARD(object.has_property(vm.names.value));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
if (has_value) {
|
2021-10-02 23:52:27 +01:00
|
|
|
auto value = TRY_OR_DISCARD(object.get(vm.names.value));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
descriptor.value = value;
|
|
|
|
|
}
|
2021-10-03 02:00:39 +01:00
|
|
|
auto has_writable = TRY_OR_DISCARD(object.has_property(vm.names.writable));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
if (has_writable) {
|
2021-10-02 23:52:27 +01:00
|
|
|
auto writable = TRY_OR_DISCARD(object.get(vm.names.writable));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
descriptor.writable = writable.to_boolean();
|
|
|
|
|
}
|
2021-10-03 02:00:39 +01:00
|
|
|
auto has_get = TRY_OR_DISCARD(object.has_property(vm.names.get));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
if (has_get) {
|
2021-10-02 23:52:27 +01:00
|
|
|
auto getter = TRY_OR_DISCARD(object.get(vm.names.get));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
if (!getter.is_function() && !getter.is_undefined()) {
|
|
|
|
|
vm.throw_exception<TypeError>(global_object, ErrorType::AccessorBadField, "get");
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
descriptor.get = getter.is_function() ? &getter.as_function() : nullptr;
|
|
|
|
|
}
|
2021-10-03 02:00:39 +01:00
|
|
|
auto has_set = TRY_OR_DISCARD(object.has_property(vm.names.set));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
if (has_set) {
|
2021-10-02 23:52:27 +01:00
|
|
|
auto setter = TRY_OR_DISCARD(object.get(vm.names.set));
|
LibJS: Add new PropertyDescriptor class and related abstract operations
This is an implementation of 'The Property Descriptor Specification
Type' and related abstract operations, namely:
- IsAccessorDescriptor
- IsDataDescriptor
- IsGenericDescriptor
- FromPropertyDescriptor
- ToPropertyDescriptor
- CompletePropertyDescriptor
It works with Optional<T> to enable omitting certain fields, which will
eventually replace the Attribute::Has{Getter,Setter,Configurable,
Enumerable,Writable} bit flags, which are awkward to work with - being
able to use an initializer list with any of the possible attributes is
much more convenient.
Parts of the current PropertyAttributes implementation as well as the
much simpler PropertyDescriptor struct in Object.h will eventually be
replaced with this and completely go away.
Property storage will still use the PropertyAttributes bit flags, this
is for the layers above.
Note that this is currently guarded behind an #if 0 as if conflicts with
the existing PropertyDescriptor struct, but it's known to compile and
work just fine - I simply want to have this in a separate commit, the
primary object rewrite commit will be large enough as is.
2021-07-03 22:57:21 +01:00
|
|
|
if (!setter.is_function() && !setter.is_undefined()) {
|
|
|
|
|
vm.throw_exception<TypeError>(global_object, ErrorType::AccessorBadField, "set");
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
descriptor.set = setter.is_function() ? &setter.as_function() : nullptr;
|
|
|
|
|
}
|
|
|
|
|
if (descriptor.get.has_value() || descriptor.set.has_value()) {
|
|
|
|
|
if (descriptor.value.has_value() || descriptor.writable.has_value()) {
|
|
|
|
|
vm.throw_exception<TypeError>(global_object, ErrorType::AccessorValueOrWritable);
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return descriptor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6.2.5.6 CompletePropertyDescriptor ( Desc ), https://tc39.es/ecma262/#sec-completepropertydescriptor
|
|
|
|
|
void PropertyDescriptor::complete()
|
|
|
|
|
{
|
|
|
|
|
if (is_generic_descriptor() || is_data_descriptor()) {
|
|
|
|
|
if (!value.has_value())
|
|
|
|
|
value = Value {};
|
|
|
|
|
if (!writable.has_value())
|
|
|
|
|
writable = false;
|
|
|
|
|
} else {
|
|
|
|
|
if (!get.has_value())
|
|
|
|
|
get = nullptr;
|
|
|
|
|
if (!set.has_value())
|
|
|
|
|
set = nullptr;
|
|
|
|
|
}
|
|
|
|
|
if (!enumerable.has_value())
|
|
|
|
|
enumerable = false;
|
|
|
|
|
if (!configurable.has_value())
|
|
|
|
|
configurable = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Non-standard, just a convenient way to get from three Optional<bool> to PropertyAttributes.
|
|
|
|
|
PropertyAttributes PropertyDescriptor::attributes() const
|
|
|
|
|
{
|
|
|
|
|
u8 attributes = 0;
|
|
|
|
|
if (writable.value_or(false))
|
|
|
|
|
attributes |= Attribute::Writable;
|
|
|
|
|
if (enumerable.value_or(false))
|
|
|
|
|
attributes |= Attribute::Enumerable;
|
|
|
|
|
if (configurable.value_or(false))
|
|
|
|
|
attributes |= Attribute::Configurable;
|
|
|
|
|
return { attributes };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|