mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 22:17:42 +00:00
LibJS: Fix broken parsing of !o.a
Unary expressions parsing now respects precedence and associativity of operators. This patch also makes `typeof` left-associative which was an oversight. Thanks to Conrad for helping me work this out. :^)
This commit is contained in:
parent
f1a074a262
commit
14de45296e
2 changed files with 26 additions and 5 deletions
|
@ -150,6 +150,7 @@ Associativity Parser::operator_associativity(TokenType type) const
|
||||||
case TokenType::ExclamationMarkEquals:
|
case TokenType::ExclamationMarkEquals:
|
||||||
case TokenType::EqualsEqualsEquals:
|
case TokenType::EqualsEqualsEquals:
|
||||||
case TokenType::ExclamationMarkEqualsEquals:
|
case TokenType::ExclamationMarkEqualsEquals:
|
||||||
|
case TokenType::Typeof:
|
||||||
case TokenType::Ampersand:
|
case TokenType::Ampersand:
|
||||||
case TokenType::Caret:
|
case TokenType::Caret:
|
||||||
case TokenType::Pipe:
|
case TokenType::Pipe:
|
||||||
|
@ -256,22 +257,24 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression()
|
||||||
|
|
||||||
NonnullRefPtr<Expression> Parser::parse_unary_prefixed_expression()
|
NonnullRefPtr<Expression> Parser::parse_unary_prefixed_expression()
|
||||||
{
|
{
|
||||||
|
auto precedence = operator_precedence(m_current_token.type());
|
||||||
|
auto associativity = operator_associativity(m_current_token.type());
|
||||||
switch (m_current_token.type()) {
|
switch (m_current_token.type()) {
|
||||||
case TokenType::PlusPlus:
|
case TokenType::PlusPlus:
|
||||||
consume();
|
consume();
|
||||||
return create_ast_node<UpdateExpression>(UpdateOp::Increment, parse_primary_expression(), true);
|
return create_ast_node<UpdateExpression>(UpdateOp::Increment, parse_expression(precedence, associativity), true);
|
||||||
case TokenType::MinusMinus:
|
case TokenType::MinusMinus:
|
||||||
consume();
|
consume();
|
||||||
return create_ast_node<UpdateExpression>(UpdateOp::Decrement, parse_primary_expression(), true);
|
return create_ast_node<UpdateExpression>(UpdateOp::Decrement, parse_expression(precedence, associativity), true);
|
||||||
case TokenType::ExclamationMark:
|
case TokenType::ExclamationMark:
|
||||||
consume();
|
consume();
|
||||||
return create_ast_node<UnaryExpression>(UnaryOp::Not, parse_primary_expression());
|
return create_ast_node<UnaryExpression>(UnaryOp::Not, parse_expression(precedence, associativity));
|
||||||
case TokenType::Tilde:
|
case TokenType::Tilde:
|
||||||
consume();
|
consume();
|
||||||
return create_ast_node<UnaryExpression>(UnaryOp::BitwiseNot, parse_primary_expression());
|
return create_ast_node<UnaryExpression>(UnaryOp::BitwiseNot, parse_expression(precedence, associativity));
|
||||||
case TokenType::Typeof:
|
case TokenType::Typeof:
|
||||||
consume();
|
consume();
|
||||||
return create_ast_node<UnaryExpression>(UnaryOp::Typeof, parse_primary_expression());
|
return create_ast_node<UnaryExpression>(UnaryOp::Typeof, parse_expression(precedence, associativity));
|
||||||
default:
|
default:
|
||||||
m_has_errors = true;
|
m_has_errors = true;
|
||||||
expected("primary expression (missing switch case)");
|
expected("primary expression (missing switch case)");
|
||||||
|
|
18
Libraries/LibJS/Tests/parser-unary-associativity.js
Normal file
18
Libraries/LibJS/Tests/parser-unary-associativity.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
function assert(x) { if (!x) throw 1; }
|
||||||
|
|
||||||
|
try {
|
||||||
|
var o = {};
|
||||||
|
o.a = 1;
|
||||||
|
|
||||||
|
assert(o.a === 1);
|
||||||
|
assert(!o.a === false);
|
||||||
|
assert(!o.a === !(o.a));
|
||||||
|
assert(~o.a === ~(o.a));
|
||||||
|
|
||||||
|
assert((typeof "x" === "string") === true);
|
||||||
|
assert(!(typeof "x" === "string") === false);
|
||||||
|
|
||||||
|
console.log("PASS");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("FAIL: " + e);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue