summaryrefslogtreecommitdiff
path: root/Libraries
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-03-15 15:01:10 +0100
committerAndreas Kling <kling@serenityos.org>2020-03-15 15:01:10 +0100
commitf7c15d00c9edcd34f555969f9a0a8bb4eccd044b (patch)
tree9499aa41ffc68c9ccc7494db724c6ecd04058ccd /Libraries
parentd02c37f3e35f9f00939c674c79998919e93894dc (diff)
downloadserenity-f7c15d00c9edcd34f555969f9a0a8bb4eccd044b.zip
LibJS: Add basic prototype support
Object will now traverse up the prototype chain when doing a get(). When a function is called on an object, that object will now also be the "this" value inside the function. This stuff is probably not very correct, but we will improve things as we go! :^)
Diffstat (limited to 'Libraries')
-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 };
};
}