mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 13:18:13 +00:00
LibJS: Implement 'in' operator
This commit is contained in:
parent
396ecfa2d7
commit
11728b7db5
6 changed files with 54 additions and 0 deletions
|
@ -331,6 +331,8 @@ Value BinaryExpression::execute(Interpreter& interpreter) const
|
||||||
return right_shift(interpreter, lhs_result, rhs_result);
|
return right_shift(interpreter, lhs_result, rhs_result);
|
||||||
case BinaryOp::UnsignedRightShift:
|
case BinaryOp::UnsignedRightShift:
|
||||||
return unsigned_right_shift(interpreter, lhs_result, rhs_result);
|
return unsigned_right_shift(interpreter, lhs_result, rhs_result);
|
||||||
|
case BinaryOp::In:
|
||||||
|
return in(interpreter, lhs_result, rhs_result);
|
||||||
case BinaryOp::InstanceOf:
|
case BinaryOp::InstanceOf:
|
||||||
return instance_of(interpreter, lhs_result, rhs_result);
|
return instance_of(interpreter, lhs_result, rhs_result);
|
||||||
}
|
}
|
||||||
|
@ -512,6 +514,9 @@ void BinaryExpression::dump(int indent) const
|
||||||
case BinaryOp::UnsignedRightShift:
|
case BinaryOp::UnsignedRightShift:
|
||||||
op_string = ">>>";
|
op_string = ">>>";
|
||||||
break;
|
break;
|
||||||
|
case BinaryOp::In:
|
||||||
|
op_string = "in";
|
||||||
|
break;
|
||||||
case BinaryOp::InstanceOf:
|
case BinaryOp::InstanceOf:
|
||||||
op_string = "instanceof";
|
op_string = "instanceof";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -343,6 +343,7 @@ enum class BinaryOp {
|
||||||
LeftShift,
|
LeftShift,
|
||||||
RightShift,
|
RightShift,
|
||||||
UnsignedRightShift,
|
UnsignedRightShift,
|
||||||
|
In,
|
||||||
InstanceOf,
|
InstanceOf,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -566,6 +566,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::In:
|
||||||
|
consume();
|
||||||
|
return create_ast_node<BinaryExpression>(BinaryOp::In, move(lhs), parse_expression(min_precedence, associativity));
|
||||||
case TokenType::Instanceof:
|
case TokenType::Instanceof:
|
||||||
consume();
|
consume();
|
||||||
return create_ast_node<BinaryExpression>(BinaryOp::InstanceOf, move(lhs), parse_expression(min_precedence, associativity));
|
return create_ast_node<BinaryExpression>(BinaryOp::InstanceOf, move(lhs), parse_expression(min_precedence, associativity));
|
||||||
|
@ -1076,6 +1079,7 @@ bool Parser::match_secondary_expression() const
|
||||||
|| type == TokenType::BracketOpen
|
|| type == TokenType::BracketOpen
|
||||||
|| type == TokenType::PlusPlus
|
|| type == TokenType::PlusPlus
|
||||||
|| type == TokenType::MinusMinus
|
|| type == TokenType::MinusMinus
|
||||||
|
|| type == TokenType::In
|
||||||
|| type == TokenType::Instanceof
|
|| type == TokenType::Instanceof
|
||||||
|| type == TokenType::QuestionMark
|
|| type == TokenType::QuestionMark
|
||||||
|| type == TokenType::Ampersand
|
|| type == TokenType::Ampersand
|
||||||
|
|
|
@ -382,6 +382,14 @@ Value eq(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
return Value(false);
|
return Value(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value in(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
|
{
|
||||||
|
if (!rhs.is_object())
|
||||||
|
return interpreter.throw_exception<TypeError>("'in' operator must be used on object");
|
||||||
|
|
||||||
|
return Value(rhs.as_object().get(lhs.to_string()).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
Value instance_of(Interpreter&, Value lhs, Value rhs)
|
Value instance_of(Interpreter&, Value lhs, Value rhs)
|
||||||
{
|
{
|
||||||
if (!lhs.is_object() || !rhs.is_object())
|
if (!lhs.is_object() || !rhs.is_object())
|
||||||
|
|
|
@ -222,6 +222,7 @@ Value mod(Interpreter&, Value lhs, Value rhs);
|
||||||
Value exp(Interpreter&, Value lhs, Value rhs);
|
Value exp(Interpreter&, Value lhs, Value rhs);
|
||||||
Value eq(Interpreter&, Value lhs, Value rhs);
|
Value eq(Interpreter&, Value lhs, Value rhs);
|
||||||
Value typed_eq(Interpreter&, Value lhs, Value rhs);
|
Value typed_eq(Interpreter&, Value lhs, Value rhs);
|
||||||
|
Value in(Interpreter&, Value lhs, Value rhs);
|
||||||
Value instance_of(Interpreter&, Value lhs, Value rhs);
|
Value instance_of(Interpreter&, Value lhs, Value rhs);
|
||||||
|
|
||||||
const LogStream& operator<<(const LogStream&, const Value&);
|
const LogStream& operator<<(const LogStream&, const Value&);
|
||||||
|
|
35
Libraries/LibJS/Tests/in-operator-basic.js
Normal file
35
Libraries/LibJS/Tests/in-operator-basic.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
load("test-common.js");
|
||||||
|
|
||||||
|
try {
|
||||||
|
["foo", 123, null, undefined].forEach(value => {
|
||||||
|
assertThrowsError(() => {
|
||||||
|
"prop" in value;
|
||||||
|
}, {
|
||||||
|
error: TypeError,
|
||||||
|
message: "'in' operator must be used on object"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var o = {foo: "bar", bar: undefined};
|
||||||
|
assert("" in o === false);
|
||||||
|
assert("foo" in o === true);
|
||||||
|
assert("bar" in o === true);
|
||||||
|
assert("baz" in o === false);
|
||||||
|
assert("toString" in o === true);
|
||||||
|
|
||||||
|
var a = ["hello", "friends"];
|
||||||
|
assert(0 in a === true);
|
||||||
|
assert(1 in a === true);
|
||||||
|
assert(2 in a === false);
|
||||||
|
assert("0" in a === true);
|
||||||
|
assert("hello" in a === false);
|
||||||
|
assert("friends" in a === false);
|
||||||
|
assert("length" in a === true);
|
||||||
|
|
||||||
|
var s = new String("foo");
|
||||||
|
assert("length" in s);
|
||||||
|
|
||||||
|
console.log("PASS");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("FAIL: " + e);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue