summaryrefslogtreecommitdiff
path: root/Libraries/LibJS
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-03-28 11:48:52 +0100
committerAndreas Kling <kling@serenityos.org>2020-03-28 11:51:44 +0100
commit14de45296eb93a42282782769b03e2e42739a2aa (patch)
tree5a1aa57d443ceacdf267bb87bf75639486abe995 /Libraries/LibJS
parentf1a074a262a9815a1063b17d20df1d1a15308cef (diff)
downloadserenity-14de45296eb93a42282782769b03e2e42739a2aa.zip
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. :^)
Diffstat (limited to 'Libraries/LibJS')
-rw-r--r--Libraries/LibJS/Parser.cpp13
-rw-r--r--Libraries/LibJS/Tests/parser-unary-associativity.js18
2 files changed, 26 insertions, 5 deletions
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<Expression> Parser::parse_primary_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()) {
case TokenType::PlusPlus:
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:
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:
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:
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:
consume();
- return create_ast_node<UnaryExpression>(UnaryOp::Typeof, parse_primary_expression());
+ return create_ast_node<UnaryExpression>(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);
+}