From 1a10470c1d69496e8d5a832a6506b6aa8378d6bc Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 19 Mar 2020 17:39:13 +0100 Subject: [PATCH] LibJS: Implement basic object property assignment This is pretty naive, we just walk up the prototype chain and call any NativeProperty setter that we find. If we don't find one, we put/set the value as an own property of the object itself. --- Libraries/LibJS/AST.cpp | 26 +++++++++++++++++++------- Libraries/LibJS/AST.h | 4 ++-- Libraries/LibJS/Runtime/Object.cpp | 11 +++++++++++ 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index c612c3028c..b9ee359d4a 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -24,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -476,31 +477,42 @@ void Identifier::dump(int indent) const Value AssignmentExpression::execute(Interpreter& interpreter) const { - ASSERT(m_lhs->is_identifier()); - auto name = static_cast(*m_lhs).string(); + AK::Function commit; + if (m_lhs->is_identifier()) { + commit = [&](Value value) { + auto name = static_cast(*m_lhs).string(); + interpreter.set_variable(name, value); + }; + } else if (m_lhs->is_member_expression()) { + commit = [&](Value value) { + auto object = static_cast(*m_lhs).object().execute(interpreter).to_object(interpreter.heap()); + ASSERT(object.is_object()); + auto property_name = static_cast(static_cast(*m_lhs).property()).string(); + object.as_object()->put(property_name, value); + }; + } else { + ASSERT_NOT_REACHED(); + } + auto rhs_result = m_rhs->execute(interpreter); switch (m_op) { case AssignmentOp::Assignment: - interpreter.set_variable(name, rhs_result); break; case AssignmentOp::AdditionAssignment: rhs_result = add(m_lhs->execute(interpreter), rhs_result); - interpreter.set_variable(name, rhs_result); break; case AssignmentOp::SubtractionAssignment: rhs_result = sub(m_lhs->execute(interpreter), rhs_result); - interpreter.set_variable(name, rhs_result); break; case AssignmentOp::MultiplicationAssignment: rhs_result = mul(m_lhs->execute(interpreter), rhs_result); - interpreter.set_variable(name, rhs_result); break; case AssignmentOp::DivisionAssignment: rhs_result = div(m_lhs->execute(interpreter), rhs_result); - interpreter.set_variable(name, rhs_result); break; } + commit(rhs_result); return rhs_result; } diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index 5fe383a315..f4cc905285 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -49,6 +49,7 @@ public: virtual Value execute(Interpreter&) const = 0; virtual void dump(int indent) const; virtual bool is_identifier() const { return false; } + virtual bool is_member_expression() const { return false; } protected: ASTNode() {} @@ -124,8 +125,6 @@ private: }; class Expression : public ASTNode { -public: - virtual bool is_member_expression() const { return false; } }; class FunctionNode { @@ -594,6 +593,7 @@ public: virtual void dump(int indent) const override; const Expression& object() const { return *m_object; } + const Expression& property() const { return *m_property; } private: virtual bool is_member_expression() const override { return true; } diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index 2ddc4dfe17..d1211c2d39 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -60,6 +60,17 @@ Value Object::get(String property_name) const void Object::put(String property_name, Value value) { + Object* object = this; + while (object) { + auto value_here = object->m_properties.get(property_name); + if (value_here.has_value()) { + if (value_here.value().is_object() && value_here.value().as_object()->is_native_property()) { + static_cast(value_here.value().as_object())->set(const_cast(this), value); + return; + } + } + object = object->prototype(); + } m_properties.set(property_name, move(value)); }