mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 04:12:43 +00: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
					
				
					 8 changed files with 48 additions and 41 deletions
				
			
		|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Linus Groh
						Linus Groh