Prechádzať zdrojové kódy

Fixed the grammar to correctly parse (-1)**2

Dmitry Panov 2 rokov pred
rodič
commit
1d34ed12ae
2 zmenil súbory, kde vykonal 62 pridanie a 43 odobranie
  1. 46 41
      parser/expression.go
  2. 16 2
      parser/parser_test.go

+ 46 - 41
parser/expression.go

@@ -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:
@@ -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 {
@@ -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
@@ -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
+			}
 		}
 	}
 

+ 16 - 2
parser/parser_test.go

@@ -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 }
@@ -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")
+		}
+
 	})
 }