From 14de45296eb93a42282782769b03e2e42739a2aa Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 28 Mar 2020 11:48:52 +0100 Subject: 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. :^) --- Libraries/LibJS/Parser.cpp | 13 ++++++++----- Libraries/LibJS/Tests/parser-unary-associativity.js | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 Libraries/LibJS/Tests/parser-unary-associativity.js (limited to 'Libraries/LibJS') diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index ef0791622b..c4f2a3966f 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -150,6 +150,7 @@ Associativity Parser::operator_associativity(TokenType type) const case TokenType::ExclamationMarkEquals: case TokenType::EqualsEqualsEquals: case TokenType::ExclamationMarkEqualsEquals: + case TokenType::Typeof: case TokenType::Ampersand: case TokenType::Caret: case TokenType::Pipe: @@ -256,22 +257,24 @@ NonnullRefPtr Parser::parse_primary_expression() NonnullRefPtr 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()) { case TokenType::PlusPlus: consume(); - return create_ast_node(UpdateOp::Increment, parse_primary_expression(), true); + return create_ast_node(UpdateOp::Increment, parse_expression(precedence, associativity), true); case TokenType::MinusMinus: consume(); - return create_ast_node(UpdateOp::Decrement, parse_primary_expression(), true); + return create_ast_node(UpdateOp::Decrement, parse_expression(precedence, associativity), true); case TokenType::ExclamationMark: consume(); - return create_ast_node(UnaryOp::Not, parse_primary_expression()); + return create_ast_node(UnaryOp::Not, parse_expression(precedence, associativity)); case TokenType::Tilde: consume(); - return create_ast_node(UnaryOp::BitwiseNot, parse_primary_expression()); + return create_ast_node(UnaryOp::BitwiseNot, parse_expression(precedence, associativity)); case TokenType::Typeof: consume(); - return create_ast_node(UnaryOp::Typeof, parse_primary_expression()); + return create_ast_node(UnaryOp::Typeof, parse_expression(precedence, associativity)); default: m_has_errors = true; expected("primary expression (missing switch case)"); diff --git a/Libraries/LibJS/Tests/parser-unary-associativity.js b/Libraries/LibJS/Tests/parser-unary-associativity.js new file mode 100644 index 0000000000..240b20f61c --- /dev/null +++ b/Libraries/LibJS/Tests/parser-unary-associativity.js @@ -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); +} -- cgit v1.2.3