mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 03:58:12 +00:00
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. :^)
This commit is contained in:
parent
37fe16a99c
commit
a3d92b1210
6 changed files with 41 additions and 1 deletions
|
@ -241,6 +241,8 @@ Value BinaryExpression::execute(Interpreter& interpreter) const
|
||||||
return left_shift(lhs_result, rhs_result);
|
return left_shift(lhs_result, rhs_result);
|
||||||
case BinaryOp::RightShift:
|
case BinaryOp::RightShift:
|
||||||
return right_shift(lhs_result, rhs_result);
|
return right_shift(lhs_result, rhs_result);
|
||||||
|
case BinaryOp::InstanceOf:
|
||||||
|
return instance_of(lhs_result, rhs_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
|
@ -368,6 +370,9 @@ void BinaryExpression::dump(int indent) const
|
||||||
case BinaryOp::RightShift:
|
case BinaryOp::RightShift:
|
||||||
op_string = ">>";
|
op_string = ">>";
|
||||||
break;
|
break;
|
||||||
|
case BinaryOp::InstanceOf:
|
||||||
|
op_string = "instanceof";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_indent(indent);
|
print_indent(indent);
|
||||||
|
|
|
@ -302,6 +302,7 @@ enum class BinaryOp {
|
||||||
BitwiseXor,
|
BitwiseXor,
|
||||||
LeftShift,
|
LeftShift,
|
||||||
RightShift,
|
RightShift,
|
||||||
|
InstanceOf,
|
||||||
};
|
};
|
||||||
|
|
||||||
class BinaryExpression : public Expression {
|
class BinaryExpression : public Expression {
|
||||||
|
|
|
@ -393,6 +393,9 @@ NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expre
|
||||||
case TokenType::ExclamationMarkEquals:
|
case TokenType::ExclamationMarkEquals:
|
||||||
consume();
|
consume();
|
||||||
return create_ast_node<BinaryExpression>(BinaryOp::AbstractInequals, move(lhs), parse_expression(min_precedence, associativity));
|
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:
|
case TokenType::ParenOpen:
|
||||||
return parse_call_expression(move(lhs));
|
return parse_call_expression(move(lhs));
|
||||||
case TokenType::Equals:
|
case TokenType::Equals:
|
||||||
|
@ -722,7 +725,8 @@ bool Parser::match_secondary_expression() const
|
||||||
|| type == TokenType::Period
|
|| type == TokenType::Period
|
||||||
|| type == TokenType::BracketOpen
|
|| type == TokenType::BracketOpen
|
||||||
|| type == TokenType::PlusPlus
|
|| type == TokenType::PlusPlus
|
||||||
|| type == TokenType::MinusMinus;
|
|| type == TokenType::MinusMinus
|
||||||
|
|| type == TokenType::Instanceof;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Parser::match_statement() const
|
bool Parser::match_statement() const
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/FlyString.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <LibJS/Heap/Heap.h>
|
#include <LibJS/Heap/Heap.h>
|
||||||
#include <LibJS/Runtime/Object.h>
|
#include <LibJS/Runtime/Object.h>
|
||||||
|
@ -253,6 +254,27 @@ Value eq(Value lhs, Value rhs)
|
||||||
return Value(false);
|
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)
|
const LogStream& operator<<(const LogStream& stream, const Value& value)
|
||||||
{
|
{
|
||||||
return stream << value.to_string();
|
return stream << value.to_string();
|
||||||
|
|
|
@ -189,6 +189,7 @@ Value mul(Value lhs, Value rhs);
|
||||||
Value div(Value lhs, Value rhs);
|
Value div(Value lhs, Value rhs);
|
||||||
Value eq(Value lhs, Value rhs);
|
Value eq(Value lhs, Value rhs);
|
||||||
Value typed_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&);
|
const LogStream& operator<<(const LogStream&, const Value&);
|
||||||
|
|
||||||
|
|
7
Libraries/LibJS/Tests/instanceof-basic.js
Normal file
7
Libraries/LibJS/Tests/instanceof-basic.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
function Foo() {
|
||||||
|
this.x = 123;
|
||||||
|
}
|
||||||
|
|
||||||
|
var foo = new Foo();
|
||||||
|
if (foo instanceof Foo)
|
||||||
|
console.log("PASS");
|
Loading…
Add table
Add a link
Reference in a new issue