Skip to content

Commit

Permalink
Fixed the grammar to correctly parse (-1)**2
Browse files Browse the repository at this point in the history
  • Loading branch information
dop251 committed Jul 6, 2023
1 parent b196ae5 commit 1d34ed1
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 43 deletions.
87 changes: 46 additions & 41 deletions parser/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -803,18 +803,13 @@ L:
return left
}

func (self *_parser) parsePostfixExpression() ast.Expression {
operand := self.parseLeftHandSideExpressionAllowCall()

func (self *_parser) parseUpdateExpression() ast.Expression {
switch self.token {
case token.INCREMENT, token.DECREMENT:
// Make sure there is no line terminator here
if self.implicitSemicolon {
break
}
tkn := self.token
idx := self.idx
self.next()
operand := self.parseUnaryExpression()
switch operand.(type) {
case *ast.Identifier, *ast.DotExpression, *ast.PrivateDotExpression, *ast.BracketExpression:
default:
Expand All @@ -826,11 +821,33 @@ func (self *_parser) parsePostfixExpression() ast.Expression {
Operator: tkn,
Idx: idx,
Operand: operand,
Postfix: true,
}
default:
operand := self.parseLeftHandSideExpressionAllowCall()
if self.token == token.INCREMENT || self.token == token.DECREMENT {
// Make sure there is no line terminator here
if self.implicitSemicolon {
return operand
}
tkn := self.token
idx := self.idx
self.next()
switch operand.(type) {
case *ast.Identifier, *ast.DotExpression, *ast.PrivateDotExpression, *ast.BracketExpression:
default:
self.error(idx, "Invalid left-hand side in assignment")
self.nextStatement()
return &ast.BadExpression{From: idx, To: self.idx}
}
return &ast.UnaryExpression{
Operator: tkn,
Idx: idx,
Operand: operand,
Postfix: true,
}
}
return operand
}

return operand
}

func (self *_parser) parseUnaryExpression() ast.Expression {
Expand All @@ -847,23 +864,6 @@ func (self *_parser) parseUnaryExpression() ast.Expression {
Idx: idx,
Operand: self.parseUnaryExpression(),
}
case token.INCREMENT, token.DECREMENT:
tkn := self.token
idx := self.idx
self.next()
operand := self.parseUnaryExpression()
switch operand.(type) {
case *ast.Identifier, *ast.DotExpression, *ast.PrivateDotExpression, *ast.BracketExpression:
default:
self.error(idx, "Invalid left-hand side in assignment")
self.nextStatement()
return &ast.BadExpression{From: idx, To: self.idx}
}
return &ast.UnaryExpression{
Operator: tkn,
Idx: idx,
Operand: operand,
}
case token.AWAIT:
if self.scope.allowAwait {
idx := self.idx
Expand All @@ -885,25 +885,30 @@ func (self *_parser) parseUnaryExpression() ast.Expression {
}
}

return self.parsePostfixExpression()
}

func isUpdateExpression(expr ast.Expression) bool {
if ux, ok := expr.(*ast.UnaryExpression); ok {
return ux.Operator == token.INCREMENT || ux.Operator == token.DECREMENT
}
return true
return self.parseUpdateExpression()
}

func (self *_parser) parseExponentiationExpression() ast.Expression {
parenthesis := self.token == token.LEFT_PARENTHESIS

left := self.parseUnaryExpression()

for self.token == token.EXPONENT && isUpdateExpression(left) {
self.next()
left = &ast.BinaryExpression{
Operator: token.EXPONENT,
Left: left,
Right: self.parseExponentiationExpression(),
if self.token == token.EXPONENT {
if !parenthesis {
if u, isUnary := left.(*ast.UnaryExpression); isUnary && u.Operator != token.INCREMENT && u.Operator != token.DECREMENT {
self.error(self.idx, "Unary operator used immediately before exponentiation expression. Parenthesis must be used to disambiguate operator precedence")
}
}
for {
self.next()
left = &ast.BinaryExpression{
Operator: token.EXPONENT,
Left: left,
Right: self.parseExponentiationExpression(),
}
if self.token != token.EXPONENT {
break
}
}
}

Expand Down
18 changes: 16 additions & 2 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,8 @@ func TestParserErr(t *testing.T) {

test("\n/* Some multiline\ncomment */\n)", "(anonymous): Line 4:1 Unexpected token )")

test("+1 ** 2", "(anonymous): Line 1:4 Unexpected token **")
test("typeof 1 ** 2", "(anonymous): Line 1:10 Unexpected token **")
test("+1 ** 2", "(anonymous): Line 1:4 Unary operator used immediately before exponentiation expression. Parenthesis must be used to disambiguate operator precedence")
test("typeof 1 ** 2", "(anonymous): Line 1:10 Unary operator used immediately before exponentiation expression. Parenthesis must be used to disambiguate operator precedence")

// TODO
//{ set 1 }
Expand Down Expand Up @@ -928,6 +928,20 @@ func TestParser(t *testing.T) {
}
`, nil)
is(len(program.Body), 1)

{
program := test(`(-2)**53`, nil)
st := program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.BinaryExpression)
is(st.Operator, token.EXPONENT)
left := st.Left.(*ast.UnaryExpression)
is(left.Operator, token.MINUS)
op1 := left.Operand.(*ast.NumberLiteral)
is(op1.Literal, "2")

right := st.Right.(*ast.NumberLiteral)
is(right.Literal, "53")
}

})
}

Expand Down

0 comments on commit 1d34ed1

Please sign in to comment.