summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Libraries/LibJS/AST.cpp13
-rw-r--r--Libraries/LibJS/AST.h4
-rw-r--r--Libraries/LibJS/Interpreter.h10
-rw-r--r--Libraries/LibJS/Object.cpp11
-rw-r--r--Libraries/LibJS/Object.h6
5 files changed, 42 insertions, 2 deletions
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp
index c5e670fa7a..9a5ca84aaf 100644
--- a/Libraries/LibJS/AST.cpp
+++ b/Libraries/LibJS/AST.cpp
@@ -63,7 +63,18 @@ Value CallExpression::execute(Interpreter& interpreter) const
for (size_t i = 0; i < m_arguments.size(); ++i)
argument_values.append(m_arguments[i].execute(interpreter));
- return function->call(interpreter, move(argument_values));
+ Value this_value = js_undefined();
+ if (m_callee->is_member_expression())
+ this_value = static_cast<const MemberExpression&>(*m_callee).object().execute(interpreter).to_object(interpreter.heap());
+
+ if (!this_value.is_undefined())
+ interpreter.push_this_value(this_value);
+
+ auto result = function->call(interpreter, move(argument_values));
+
+ if (!this_value.is_undefined())
+ interpreter.pop_this_value();
+ return result;
}
Value ReturnStatement::execute(Interpreter& interpreter) const
diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h
index c5ded7710a..43a2508769 100644
--- a/Libraries/LibJS/AST.h
+++ b/Libraries/LibJS/AST.h
@@ -142,6 +142,7 @@ private:
class Expression : public ASTNode {
public:
+ virtual bool is_member_expression() const { return false; }
};
class ErrorExpression final : public Expression {
@@ -521,7 +522,10 @@ public:
virtual Value execute(Interpreter&) const override;
virtual void dump(int indent) const override;
+ const Expression& object() const { return *m_object; }
+
private:
+ virtual bool is_member_expression() const override { return true; }
virtual const char* class_name() const override { return "MemberExpression"; }
NonnullOwnPtr<Expression> m_object;
diff --git a/Libraries/LibJS/Interpreter.h b/Libraries/LibJS/Interpreter.h
index 61b584c068..79940cac3a 100644
--- a/Libraries/LibJS/Interpreter.h
+++ b/Libraries/LibJS/Interpreter.h
@@ -79,10 +79,20 @@ public:
void enter_scope(const ScopeNode&, Vector<Argument>, ScopeType);
void exit_scope(const ScopeNode&);
+ void push_this_value(Value value) { m_this_stack.append(move(value)); }
+ void pop_this_value() { m_this_stack.take_last(); }
+ Value this_value() const
+ {
+ if (m_this_stack.is_empty())
+ return m_global_object;
+ return m_this_stack.last();
+ }
+
private:
Heap m_heap;
Vector<ScopeFrame> m_scope_stack;
+ Vector<Value> m_this_stack;
Object* m_global_object { nullptr };
};
diff --git a/Libraries/LibJS/Object.cpp b/Libraries/LibJS/Object.cpp
index ae1d43397a..8fdd3721b2 100644
--- a/Libraries/LibJS/Object.cpp
+++ b/Libraries/LibJS/Object.cpp
@@ -42,7 +42,14 @@ Object::~Object()
Value Object::get(String property_name) const
{
- return m_properties.get(property_name).value_or(js_undefined());
+ const Object* object = this;
+ while (object) {
+ auto value = object->m_properties.get(property_name);
+ if (value.has_value())
+ return value.value();
+ object = object->prototype();
+ }
+ return js_undefined();
}
void Object::put(String property_name, Value value)
@@ -58,6 +65,8 @@ void Object::put_native_function(String property_name, AK::Function<Value(Interp
void Object::visit_children(Cell::Visitor& visitor)
{
Cell::visit_children(visitor);
+ if (m_prototype)
+ visitor.visit(m_prototype);
for (auto& it : m_properties)
visitor.visit(it.value);
}
diff --git a/Libraries/LibJS/Object.h b/Libraries/LibJS/Object.h
index 30cc74bf6e..e3b8f1e4f9 100644
--- a/Libraries/LibJS/Object.h
+++ b/Libraries/LibJS/Object.h
@@ -45,12 +45,18 @@ public:
virtual bool is_function() const { return false; }
virtual bool is_native_function() const { return false; }
+ virtual bool is_string_object() const { return false; }
virtual const char* class_name() const override { return "Object"; }
virtual void visit_children(Cell::Visitor&) override;
+ Object* prototype() { return m_prototype; }
+ const Object* prototype() const { return m_prototype; }
+ void set_prototype(Object* prototype) { m_prototype = prototype; }
+
private:
HashMap<String, Value> m_properties;
+ Object* m_prototype { nullptr };
};
}