diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index c612c3028cf..b9ee359d4a8 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 5fe383a3159..f4cc905285e 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 2ddc4dfe174..d1211c2d396 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)); }