mirror of
https://github.com/RGBCube/serenity
synced 2025-05-30 22:28:12 +00:00

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.
73 lines
2.7 KiB
C++
73 lines
2.7 KiB
C++
/*
|
|
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Optional.h>
|
|
#include <LibJS/Forward.h>
|
|
#include <LibJS/Runtime/Value.h>
|
|
|
|
namespace JS {
|
|
|
|
// Disabled until PropertyDescriptor in Object.h is gone. I want to introduce this thing in a separate commit,
|
|
// but the names conflict - this is the easiest solution. :^)
|
|
#if 0
|
|
// 6.2.5 The Property Descriptor Specification Type, https://tc39.es/ecma262/#sec-property-descriptor-specification-type
|
|
|
|
Value from_property_descriptor(GlobalObject&, Optional<PropertyDescriptor> const&);
|
|
PropertyDescriptor to_property_descriptor(GlobalObject&, Value);
|
|
|
|
class PropertyDescriptor {
|
|
public:
|
|
[[nodiscard]] bool is_accessor_descriptor() const;
|
|
[[nodiscard]] bool is_data_descriptor() const;
|
|
[[nodiscard]] bool is_generic_descriptor() const;
|
|
|
|
[[nodiscard]] PropertyAttributes attributes() const;
|
|
|
|
void complete();
|
|
|
|
// Not a standard abstract operation, but "If every field in Desc is absent".
|
|
[[nodiscard]] bool is_empty() const
|
|
{
|
|
return !value.has_value() && !get.has_value() && !set.has_value() && !writable.has_value() && !enumerable.has_value() && !configurable.has_value();
|
|
}
|
|
|
|
Optional<Value> value {};
|
|
Optional<FunctionObject*> get {};
|
|
Optional<FunctionObject*> set {};
|
|
Optional<bool> writable {};
|
|
Optional<bool> enumerable {};
|
|
Optional<bool> configurable {};
|
|
};
|
|
|
|
}
|
|
|
|
namespace AK {
|
|
|
|
template<>
|
|
struct Formatter<JS::PropertyDescriptor> : Formatter<StringView> {
|
|
void format(FormatBuilder& builder, JS::PropertyDescriptor const& property_descriptor)
|
|
{
|
|
Vector<String> parts;
|
|
if (property_descriptor.value.has_value())
|
|
parts.append(String::formatted("[[Value]]: {}", property_descriptor.value->to_string_without_side_effects()));
|
|
if (property_descriptor.get.has_value())
|
|
parts.append(String::formatted("[[Get]]: JS::Function* @ {:p}", *property_descriptor.get));
|
|
if (property_descriptor.set.has_value())
|
|
parts.append(String::formatted("[[Set]]: JS::Function* @ {:p}", *property_descriptor.set));
|
|
if (property_descriptor.writable.has_value())
|
|
parts.append(String::formatted("[[Writable]]: {}", *property_descriptor.writable));
|
|
if (property_descriptor.enumerable.has_value())
|
|
parts.append(String::formatted("[[Enumerable]]: {}", *property_descriptor.enumerable));
|
|
if (property_descriptor.configurable.has_value())
|
|
parts.append(String::formatted("[[Configurable]]: {}", *property_descriptor.configurable));
|
|
Formatter<StringView>::format(builder, String::formatted("PropertyDescriptor {{ {} }}", String::join(", ", parts)));
|
|
}
|
|
};
|
|
#endif
|
|
|
|
}
|