mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:52:45 +00:00 
			
		
		
		
	LibJS: Virtualize access to an Object's own properties
Object now has virtual get_own_property() and put_own_property() member functions that can be overridden to provide custom behavior. We use these virtuals to move Array-specific access behavior to Array.
This commit is contained in:
		
							parent
							
								
									2a7dbac0c5
								
							
						
					
					
						commit
						324b92fd06
					
				
					 4 changed files with 57 additions and 30 deletions
				
			
		|  | @ -59,4 +59,28 @@ void Array::visit_children(Cell::Visitor& visitor) | ||||||
|         visitor.visit(element); |         visitor.visit(element); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Optional<Value> Array::get_own_property(const String& property_name) const | ||||||
|  | { | ||||||
|  |     bool ok; | ||||||
|  |     i32 index = property_name.to_int(ok); | ||||||
|  |     if (ok) { | ||||||
|  |         if (index >= 0 && index < length()) | ||||||
|  |             return m_elements[index]; | ||||||
|  |     } | ||||||
|  |     return Object::get_own_property(property_name); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Array::put_own_property(const String& property_name, Value value) | ||||||
|  | { | ||||||
|  |     bool ok; | ||||||
|  |     i32 index = property_name.to_int(ok); | ||||||
|  |     if (ok && index >= 0) { | ||||||
|  |         if (index >= length()) | ||||||
|  |             m_elements.resize(index + 1); | ||||||
|  |         m_elements[index] = value; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     return Object::put_own_property(property_name, value); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -45,6 +45,8 @@ private: | ||||||
|     virtual const char* class_name() const override { return "Array"; } |     virtual const char* class_name() const override { return "Array"; } | ||||||
|     virtual void visit_children(Cell::Visitor&) override; |     virtual void visit_children(Cell::Visitor&) override; | ||||||
|     virtual bool is_array() const override { return true; } |     virtual bool is_array() const override { return true; } | ||||||
|  |     virtual Optional<Value> get_own_property(const String& property_name) const override; | ||||||
|  |     virtual bool put_own_property(const String& property_name, Value) override; | ||||||
| 
 | 
 | ||||||
|     Vector<Value> m_elements; |     Vector<Value> m_elements; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -44,54 +44,53 @@ Object::~Object() | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Value Object::get(String property_name) const | Optional<Value> Object::get_own_property(const String& property_name) const | ||||||
|  | { | ||||||
|  |     auto value_here = m_properties.get(property_name); | ||||||
|  |     if (value_here.has_value() && value_here.value().is_object() && value_here.value().as_object()->is_native_property()) | ||||||
|  |         return static_cast<NativeProperty*>(value_here.value().as_object())->get(const_cast<Object*>(this)); | ||||||
|  |     return value_here; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Object::put_own_property(const String& property_name, Value value) | ||||||
|  | { | ||||||
|  |     auto value_here = m_properties.get(property_name); | ||||||
|  |     if (value_here.has_value() && value_here.value().is_object() && value_here.value().as_object()->is_native_property()) { | ||||||
|  |         static_cast<NativeProperty*>(value_here.value().as_object())->set(const_cast<Object*>(this), value); | ||||||
|  |     } else { | ||||||
|  |         m_properties.set(property_name, value); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Value Object::get(const String& property_name) const | ||||||
| { | { | ||||||
|     const Object* object = this; |     const Object* object = this; | ||||||
|     while (object) { |     while (object) { | ||||||
|         if (object->is_array()) { |         auto value = object->get_own_property(property_name); | ||||||
|             auto* array = static_cast<const Array*>(object); |         if (value.has_value()) | ||||||
|             bool ok; |  | ||||||
|             i32 index = property_name.to_int(ok); |  | ||||||
|             if (ok) { |  | ||||||
|                 if (index >= 0 && index < array->length()) |  | ||||||
|                     return array->elements()[index]; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         auto value = object->m_properties.get(property_name); |  | ||||||
|         if (value.has_value()) { |  | ||||||
|             if (value.value().is_object() && value.value().as_object()->is_native_property()) |  | ||||||
|                 return static_cast<const NativeProperty*>(value.value().as_object())->get(const_cast<Object*>(this)); |  | ||||||
|             return value.value(); |             return value.value(); | ||||||
|         } |  | ||||||
|         object = object->prototype(); |         object = object->prototype(); | ||||||
|     } |     } | ||||||
|     return js_undefined(); |     return js_undefined(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Object::put(String property_name, Value value) | void Object::put(const String& property_name, Value value) | ||||||
| { | { | ||||||
|     Object* object = this; |     Object* object = this; | ||||||
|     while (object) { |     while (object) { | ||||||
|         if (object->is_array()) { |  | ||||||
|             auto* array = static_cast<Array*>(object); |  | ||||||
|             bool ok; |  | ||||||
|             i32 index = property_name.to_int(ok); |  | ||||||
|             if (ok && index >= 0) { |  | ||||||
|                 if (index >= array->length()) |  | ||||||
|                     array->elements().resize(index + 1); |  | ||||||
|                 array->elements()[index] = value; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         auto value_here = object->m_properties.get(property_name); |         auto value_here = object->m_properties.get(property_name); | ||||||
|         if (value_here.has_value()) { |         if (value_here.has_value()) { | ||||||
|             if (value_here.value().is_object() && value_here.value().as_object()->is_native_property()) { |             if (value_here.value().is_object() && value_here.value().as_object()->is_native_property()) { | ||||||
|                 static_cast<NativeProperty*>(value_here.value().as_object())->set(const_cast<Object*>(this), value); |                 static_cast<NativeProperty*>(value_here.value().as_object())->set(const_cast<Object*>(this), value); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |             if (object->put_own_property(property_name, value)) | ||||||
|  |                 return; | ||||||
|         } |         } | ||||||
|         object = object->prototype(); |         object = object->prototype(); | ||||||
|     } |     } | ||||||
|     m_properties.set(property_name, move(value)); |     put_own_property(property_name, value); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Object::put_native_function(String property_name, AK::Function<Value(Object*, Vector<Value>)> native_function) | void Object::put_native_function(String property_name, AK::Function<Value(Object*, Vector<Value>)> native_function) | ||||||
|  | @ -147,5 +146,4 @@ Value Object::to_string() const | ||||||
| { | { | ||||||
|     return js_string(heap(), String::format("[object %s]", class_name())); |     return js_string(heap(), String::format("[object %s]", class_name())); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -40,8 +40,11 @@ public: | ||||||
|     Object(); |     Object(); | ||||||
|     virtual ~Object(); |     virtual ~Object(); | ||||||
| 
 | 
 | ||||||
|     Value get(String property_name) const; |     Value get(const String& property_name) const; | ||||||
|     void put(String property_name, Value); |     void put(const String& property_name, Value); | ||||||
|  | 
 | ||||||
|  |     virtual Optional<Value> get_own_property(const String& property_name) const; | ||||||
|  |     virtual bool put_own_property(const String& property_name, Value); | ||||||
| 
 | 
 | ||||||
|     void put_native_function(String property_name, AK::Function<Value(Object*, Vector<Value>)>); |     void put_native_function(String property_name, AK::Function<Value(Object*, Vector<Value>)>); | ||||||
|     void put_native_property(String property_name, AK::Function<Value(Object*)> getter, AK::Function<void(Object*, Value)> setter); |     void put_native_property(String property_name, AK::Function<Value(Object*)> getter, AK::Function<void(Object*, Value)> setter); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling