summaryrefslogtreecommitdiff
path: root/Libraries/LibJS
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-03-28 16:56:54 +0100
committerAndreas Kling <kling@serenityos.org>2020-03-28 16:56:54 +0100
commita3d92b1210bad42a7563b6a7d9a8787d6d2586ed (patch)
tree81e9ccca06853492b4cc8ddd20ba85b555288b8f /Libraries/LibJS
parent37fe16a99cd9ce31d6dba0b916be67929ae010a3 (diff)
downloadserenity-a3d92b1210bad42a7563b6a7d9a8787d6d2586ed.zip
LibJS: Implement the "instanceof" operator
This operator walks the prototype chain of the RHS value and looks for a "prototype" property with the same value as the prototype of the LHS. This is pretty cool. :^)
Diffstat (limited to 'Libraries/LibJS')
-rw-r--r--Libraries/LibJS/AST.cpp5
-rw-r--r--Libraries/LibJS/AST.h1
-rw-r--r--Libraries/LibJS/Parser.cpp6
-rw-r--r--Libraries/LibJS/Runtime/Value.cpp22
-rw-r--r--Libraries/LibJS/Runtime/Value.h1
-rw-r--r--Libraries/LibJS/Tests/instanceof-basic.js7
6 files changed, 41 insertions, 1 deletions
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp
index 196901851d..9f23108050 100644
--- a/Libraries/LibJS/AST.cpp
+++ b/Libraries/LibJS/AST.cpp
@@ -241,6 +241,8 @@ Value BinaryExpression::execute(Interpreter& interpreter) const
return left_shift(lhs_result, rhs_result);
case BinaryOp::RightShift:
return right_shift(lhs_result, rhs_result);
+ case BinaryOp::InstanceOf:
+ return instance_of(lhs_result, rhs_result);
}
ASSERT_NOT_REACHED();
@@ -368,6 +370,9 @@ void BinaryExpression::dump(int indent) const
case BinaryOp::RightShift:
op_string = ">>";
break;
+ case BinaryOp::InstanceOf:
+ op_string = "instanceof";
+ break;
}
print_indent(indent);
diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h
index aef19889aa..819ab4b1c9 100644
--- a/Libraries/LibJS/AST.h
+++ b/Libraries/LibJS/AST.h
@@ -302,6 +302,7 @@ enum class BinaryOp {
BitwiseXor,
LeftShift,
RightShift,
+ InstanceOf,
};
class BinaryExpression : public Expression {
diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp
index 4552e22cdb..9bb4001f84 100644
--- a/Libraries/LibJS/Parser.cpp
+++ b/Libraries/LibJS/Parser.cpp
@@ -393,6 +393,9 @@ NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expre
case TokenType::ExclamationMarkEquals:
consume();
return create_ast_node<BinaryExpression>(BinaryOp::AbstractInequals, move(lhs), parse_expression(min_precedence, associativity));
+ case TokenType::Instanceof:
+ consume();
+ return create_ast_node<BinaryExpression>(BinaryOp::InstanceOf, move(lhs), parse_expression(min_precedence, associativity));
case TokenType::ParenOpen:
return parse_call_expression(move(lhs));
case TokenType::Equals:
@@ -722,7 +725,8 @@ bool Parser::match_secondary_expression() const
|| type == TokenType::Period
|| type == TokenType::BracketOpen
|| type == TokenType::PlusPlus
- || type == TokenType::MinusMinus;
+ || type == TokenType::MinusMinus
+ || type == TokenType::Instanceof;
}
bool Parser::match_statement() const
diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp
index 66582e4622..c36d358213 100644
--- a/Libraries/LibJS/Runtime/Value.cpp
+++ b/Libraries/LibJS/Runtime/Value.cpp
@@ -24,6 +24,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <AK/FlyString.h>
#include <AK/String.h>
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/Object.h>
@@ -253,6 +254,27 @@ Value eq(Value lhs, Value rhs)
return Value(false);
}
+Value instance_of(Value lhs, Value rhs)
+{
+ if (!lhs.is_object() || !rhs.is_object())
+ return Value(false);
+
+ auto* instance_prototype = lhs.as_object()->prototype();
+
+ if (!instance_prototype)
+ return Value(false);
+
+ for (auto* constructor_object = rhs.as_object(); constructor_object; constructor_object = constructor_object->prototype()) {
+ auto prototype_property = constructor_object->get_own_property(*constructor_object, "prototype");
+ if (!prototype_property.has_value())
+ continue;
+ if (prototype_property.value().is_object() && prototype_property.value().as_object() == instance_prototype)
+ return Value(true);
+ }
+
+ return Value(false);
+}
+
const LogStream& operator<<(const LogStream& stream, const Value& value)
{
return stream << value.to_string();
diff --git a/Libraries/LibJS/Runtime/Value.h b/Libraries/LibJS/Runtime/Value.h
index 8e2a1daeaf..5250d108fd 100644
--- a/Libraries/LibJS/Runtime/Value.h
+++ b/Libraries/LibJS/Runtime/Value.h
@@ -189,6 +189,7 @@ Value mul(Value lhs, Value rhs);
Value div(Value lhs, Value rhs);
Value eq(Value lhs, Value rhs);
Value typed_eq(Value lhs, Value rhs);
+Value instance_of(Value lhs, Value rhs);
const LogStream& operator<<(const LogStream&, const Value&);
diff --git a/Libraries/LibJS/Tests/instanceof-basic.js b/Libraries/LibJS/Tests/instanceof-basic.js
new file mode 100644
index 0000000000..468da2f7fd
--- /dev/null
+++ b/Libraries/LibJS/Tests/instanceof-basic.js
@@ -0,0 +1,7 @@
+function Foo() {
+ this.x = 123;
+}
+
+var foo = new Foo();
+if (foo instanceof Foo)
+ console.log("PASS");