mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-29 14:14:45 +03:00
LibJS: Implement the GetMethod() abstract operation as a Value method
This was a standalone function previously (get_method()), but instead of passing a Value to it, we can just make it a method. Also add spec step comments and fix the receiver value by using GetV().
This commit is contained in:
parent
31f5797e89
commit
337ad6d15c
Notes:
sideshowbarker
2024-07-18 11:28:24 +09:00
@ -39,25 +39,6 @@ Value require_object_coercible(GlobalObject& global_object, Value value)
|
||||
return value;
|
||||
}
|
||||
|
||||
// 7.3.10 GetMethod ( V, P ), https://tc39.es/ecma262/#sec-getmethod
|
||||
Function* get_method(GlobalObject& global_object, Value value, PropertyName const& property_name)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
auto* object = value.to_object(global_object);
|
||||
if (vm.exception())
|
||||
return nullptr;
|
||||
auto property_value = object->get(property_name);
|
||||
if (vm.exception())
|
||||
return nullptr;
|
||||
if (property_value.is_empty() || property_value.is_nullish())
|
||||
return nullptr;
|
||||
if (!property_value.is_function()) {
|
||||
vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, property_value.to_string_without_side_effects());
|
||||
return nullptr;
|
||||
}
|
||||
return &property_value.as_function();
|
||||
}
|
||||
|
||||
// 7.3.18 LengthOfArrayLike ( obj ), https://tc39.es/ecma262/#sec-lengthofarraylike
|
||||
size_t length_of_array_like(GlobalObject& global_object, Object const& object)
|
||||
{
|
||||
|
@ -18,7 +18,6 @@ ObjectEnvironmentRecord* new_object_environment(Object&, bool is_with_environmen
|
||||
EnvironmentRecord& get_this_environment(VM&);
|
||||
Object* get_super_constructor(VM&);
|
||||
Value require_object_coercible(GlobalObject&, Value);
|
||||
Function* get_method(GlobalObject& global_object, Value, PropertyName const&);
|
||||
size_t length_of_array_like(GlobalObject&, Object const&);
|
||||
MarkedValueList create_list_from_array_like(GlobalObject&, Value, AK::Function<Result<void, ErrorType>(Value)> = {});
|
||||
Function* species_constructor(GlobalObject&, Object const&, Function& default_constructor);
|
||||
|
@ -101,7 +101,7 @@ void iterator_close(Object& iterator)
|
||||
vm.unwind(unwind_until, unwind_until_label);
|
||||
};
|
||||
|
||||
auto return_method = get_method(global_object, &iterator, vm.names.return_);
|
||||
auto return_method = Value(&iterator).get_method(global_object, vm.names.return_);
|
||||
if (!return_method)
|
||||
return restore_completion(); // If return is undefined, return Completion(completion).
|
||||
|
||||
|
@ -62,7 +62,7 @@ Object* ProxyObject::prototype()
|
||||
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||
return nullptr;
|
||||
}
|
||||
auto trap = get_method(global_object(), Value(&m_handler), vm.names.getPrototypeOf);
|
||||
auto trap = Value(&m_handler).get_method(global_object(), vm.names.getPrototypeOf);
|
||||
if (vm.exception())
|
||||
return nullptr;
|
||||
if (!trap)
|
||||
@ -108,7 +108,7 @@ bool ProxyObject::set_prototype(Object* object)
|
||||
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||
return false;
|
||||
}
|
||||
auto trap = get_method(global_object(), Value(&m_handler), vm.names.setPrototypeOf);
|
||||
auto trap = Value(&m_handler).get_method(global_object(), vm.names.setPrototypeOf);
|
||||
if (vm.exception())
|
||||
return false;
|
||||
if (!trap)
|
||||
@ -135,7 +135,7 @@ bool ProxyObject::is_extensible() const
|
||||
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||
return false;
|
||||
}
|
||||
auto trap = get_method(global_object(), Value(&m_handler), vm.names.isExtensible);
|
||||
auto trap = Value(&m_handler).get_method(global_object(), vm.names.isExtensible);
|
||||
if (vm.exception())
|
||||
return false;
|
||||
if (!trap)
|
||||
@ -158,7 +158,7 @@ bool ProxyObject::prevent_extensions()
|
||||
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||
return false;
|
||||
}
|
||||
auto trap = get_method(global_object(), Value(&m_handler), vm.names.preventExtensions);
|
||||
auto trap = Value(&m_handler).get_method(global_object(), vm.names.preventExtensions);
|
||||
if (vm.exception())
|
||||
return false;
|
||||
if (!trap)
|
||||
@ -181,7 +181,7 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(const Prop
|
||||
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||
return {};
|
||||
}
|
||||
auto trap = get_method(global_object(), Value(&m_handler), vm.names.getOwnPropertyDescriptor);
|
||||
auto trap = Value(&m_handler).get_method(global_object(), vm.names.getOwnPropertyDescriptor);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
if (!trap)
|
||||
@ -232,7 +232,7 @@ bool ProxyObject::define_property(const StringOrSymbol& property_name, const Obj
|
||||
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||
return false;
|
||||
}
|
||||
auto trap = get_method(global_object(), Value(&m_handler), vm.names.defineProperty);
|
||||
auto trap = Value(&m_handler).get_method(global_object(), vm.names.defineProperty);
|
||||
if (vm.exception())
|
||||
return false;
|
||||
if (!trap)
|
||||
@ -279,7 +279,7 @@ bool ProxyObject::has_property(const PropertyName& name) const
|
||||
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||
return false;
|
||||
}
|
||||
auto trap = get_method(global_object(), Value(&m_handler), vm.names.has);
|
||||
auto trap = Value(&m_handler).get_method(global_object(), vm.names.has);
|
||||
if (vm.exception())
|
||||
return false;
|
||||
if (!trap)
|
||||
@ -319,7 +319,7 @@ Value ProxyObject::get(const PropertyName& name, Value receiver, AllowSideEffect
|
||||
}
|
||||
if (receiver.is_empty())
|
||||
receiver = Value(const_cast<ProxyObject*>(this));
|
||||
auto trap = get_method(global_object(), Value(&m_handler), vm.names.get);
|
||||
auto trap = Value(&m_handler).get_method(global_object(), vm.names.get);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
if (!trap)
|
||||
@ -352,7 +352,7 @@ bool ProxyObject::put(const PropertyName& name, Value value, Value receiver)
|
||||
}
|
||||
if (receiver.is_empty())
|
||||
receiver = Value(const_cast<ProxyObject*>(this));
|
||||
auto trap = get_method(global_object(), Value(&m_handler), vm.names.set);
|
||||
auto trap = Value(&m_handler).get_method(global_object(), vm.names.set);
|
||||
if (vm.exception())
|
||||
return false;
|
||||
if (!trap)
|
||||
@ -382,7 +382,7 @@ bool ProxyObject::delete_property(PropertyName const& name, bool force_throw_exc
|
||||
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||
return false;
|
||||
}
|
||||
auto trap = get_method(global_object(), Value(&m_handler), vm.names.deleteProperty);
|
||||
auto trap = Value(&m_handler).get_method(global_object(), vm.names.deleteProperty);
|
||||
if (vm.exception())
|
||||
return false;
|
||||
if (!trap)
|
||||
@ -422,7 +422,7 @@ Value ProxyObject::call()
|
||||
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||
return {};
|
||||
}
|
||||
auto trap = get_method(global_object(), Value(&m_handler), vm.names.apply);
|
||||
auto trap = Value(&m_handler).get_method(global_object(), vm.names.apply);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
if (!trap)
|
||||
@ -451,7 +451,7 @@ Value ProxyObject::construct(Function& new_target)
|
||||
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||
return {};
|
||||
}
|
||||
auto trap = get_method(global_object(), Value(&m_handler), vm.names.construct);
|
||||
auto trap = Value(&m_handler).get_method(global_object(), vm.names.construct);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
if (!trap)
|
||||
|
@ -262,7 +262,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_match)
|
||||
return {};
|
||||
bool global = global_value.to_boolean();
|
||||
// FIXME: Implement and use RegExpExec, this does something different - https://tc39.es/ecma262/#sec-regexpexec
|
||||
auto* exec = get_method(global_object, rx, vm.names.exec);
|
||||
auto* exec = Value(rx).get_method(global_object, vm.names.exec);
|
||||
if (!exec)
|
||||
return js_undefined();
|
||||
// FIXME end
|
||||
@ -295,7 +295,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_replace)
|
||||
rx->regex().start_offset = 0;
|
||||
|
||||
// FIXME: Implement and use RegExpExec - https://tc39.es/ecma262/#sec-regexpexec
|
||||
auto* exec = get_method(global_object, rx, vm.names.exec);
|
||||
auto* exec = Value(rx).get_method(global_object, vm.names.exec);
|
||||
if (!exec)
|
||||
return {};
|
||||
|
||||
|
@ -702,7 +702,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::match)
|
||||
return {};
|
||||
auto regexp = vm.argument(0);
|
||||
if (!regexp.is_nullish()) {
|
||||
if (auto* matcher = get_method(global_object, regexp, *vm.well_known_symbol_match()))
|
||||
if (auto* matcher = regexp.get_method(global_object, *vm.well_known_symbol_match()))
|
||||
return vm.call(*matcher, regexp, this_object);
|
||||
}
|
||||
auto s = this_object.to_string(global_object);
|
||||
@ -740,7 +740,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::match_all)
|
||||
return {};
|
||||
}
|
||||
}
|
||||
if (auto* matcher = get_method(global_object, regexp, *vm.well_known_symbol_match_all()))
|
||||
if (auto* matcher = regexp.get_method(global_object, *vm.well_known_symbol_match_all()))
|
||||
return vm.call(*matcher, regexp, this_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
@ -764,7 +764,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::replace)
|
||||
auto replace_value = vm.argument(1);
|
||||
|
||||
if (!search_value.is_nullish()) {
|
||||
if (auto* replacer = get_method(global_object, search_value, *vm.well_known_symbol_replace()))
|
||||
if (auto* replacer = search_value.get_method(global_object, *vm.well_known_symbol_replace()))
|
||||
return vm.call(*replacer, search_value, this_object, replace_value);
|
||||
}
|
||||
|
||||
@ -812,7 +812,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::search)
|
||||
return {};
|
||||
auto regexp = vm.argument(0);
|
||||
if (!regexp.is_nullish()) {
|
||||
if (auto* searcher = get_method(global_object, regexp, *vm.well_known_symbol_search()))
|
||||
if (auto* searcher = regexp.get_method(global_object, *vm.well_known_symbol_search()))
|
||||
return vm.call(*searcher, regexp, this_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
@ -413,7 +413,7 @@ Value Value::to_primitive(GlobalObject& global_object, PreferredType preferred_t
|
||||
};
|
||||
if (is_object()) {
|
||||
auto& vm = global_object.vm();
|
||||
auto to_primitive_method = get_method(global_object, *this, *vm.well_known_symbol_to_primitive());
|
||||
auto to_primitive_method = get_method(global_object, *vm.well_known_symbol_to_primitive());
|
||||
if (vm.exception())
|
||||
return {};
|
||||
if (to_primitive_method) {
|
||||
@ -805,6 +805,32 @@ Value Value::get(GlobalObject& global_object, PropertyName const& property_name)
|
||||
return object->get(property_name, *this);
|
||||
}
|
||||
|
||||
// 7.3.10 GetMethod ( V, P ), https://tc39.es/ecma262/#sec-getmethod
|
||||
Function* Value::get_method(GlobalObject& global_object, PropertyName const& property_name) const
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. Assert: IsPropertyKey(P) is true.
|
||||
|
||||
// 2. Let func be ? GetV(V, P).
|
||||
auto function = get(global_object, property_name).value_or(js_undefined());
|
||||
if (vm.exception())
|
||||
return nullptr;
|
||||
|
||||
// 3. If func is either undefined or null, return undefined.
|
||||
if (function.is_nullish())
|
||||
return nullptr;
|
||||
|
||||
// 4. If IsCallable(func) is false, throw a TypeError exception.
|
||||
if (!function.is_function()) {
|
||||
vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, function.to_string_without_side_effects());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 5. Return func.
|
||||
return &function.as_function();
|
||||
}
|
||||
|
||||
// 13.10 Relational Operators, https://tc39.es/ecma262/#sec-relational-operators
|
||||
Value greater_than(GlobalObject& global_object, Value lhs, Value rhs)
|
||||
{
|
||||
@ -1204,7 +1230,7 @@ Value instance_of(GlobalObject& global_object, Value lhs, Value rhs)
|
||||
vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, rhs.to_string_without_side_effects());
|
||||
return {};
|
||||
}
|
||||
auto has_instance_method = get_method(global_object, Value(&rhs.as_object()), *vm.well_known_symbol_has_instance());
|
||||
auto has_instance_method = rhs.get_method(global_object, *vm.well_known_symbol_has_instance());
|
||||
if (vm.exception())
|
||||
return {};
|
||||
if (has_instance_method) {
|
||||
|
@ -288,6 +288,7 @@ public:
|
||||
bool to_boolean() const;
|
||||
|
||||
Value get(GlobalObject&, PropertyName const&) const;
|
||||
Function* get_method(GlobalObject&, PropertyName const&) const;
|
||||
|
||||
String to_string_without_side_effects() const;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user