diff options
author | Andreas Kling <kling@serenityos.org> | 2020-03-28 16:56:54 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-03-28 16:56:54 +0100 |
commit | a3d92b1210bad42a7563b6a7d9a8787d6d2586ed (patch) | |
tree | 81e9ccca06853492b4cc8ddd20ba85b555288b8f /Libraries/LibJS | |
parent | 37fe16a99cd9ce31d6dba0b916be67929ae010a3 (diff) | |
download | serenity-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.cpp | 5 | ||||
-rw-r--r-- | Libraries/LibJS/AST.h | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Parser.cpp | 6 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Value.cpp | 22 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Value.h | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/instanceof-basic.js | 7 |
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"); |