aboutsummaryrefslogblamecommitdiffstats
path: root/vendor/github.com/robertkrimen/otto/parser/expression.go
blob: 63a169d402c05e7f013610b64266e7f087d1ae37 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                                                        


                                                       
                   
                               


                              
 



                                                
                  









































































                                                                                   


                                                 






















































































                                                                                                                                          


                                                 





                                                                 


                                                 












                                                                                   
                                                 
                                                               
                 
                                                                       
                                         


                                              


                                                 










                                                    
                                                                

                                                               


                                                   
                   
 






















                                                                            
                             


                                                         
                                                       

                                                          
                                                         













                                                                  
                                                         













                                                                  


                                                     

                                
                            



                                                        

                                         
                                                      

                  





                                                                        
                                                                 
                                              


                                                         



                                   


                                                     

                                              
                                  






                                                         



                                                                          



                                                                                         

                                                                  
                         
                                                    
                                   

                                

                                                       

                                          
                                                      


                                                         

                                                


                                                     


                                                
                                 






                                                                                               


                                         


                                                  

                                                               
                                                                

                                                                


                                                      


                                                         


                                   


                                         





                                                                              
                                   




                                               

                                         
                                                

                  

















                                                                         
                                            






























                                                                             

                                         
                                                 

         








                                                                   



                                                               


                                                    
                                         
                                                 

         


                                                        
                                                            


















                                                                            





                                                               
                                                


                                                                                            
                



                                                               


                                                    
                                         
                                                 

         

























                                                                


                                                 







                                                                                 
                                            




                                          

                                                 
                                                        


                          












                                                                   


                                                 
                           
 
                                            






                                                              
                                                 
                                             
                 

                                                      























                                                                                 


                                                 
                           
 















                                                                   


                                                 
                           
 
















                                                                                


                                                 
                           
 






















                                                                                    


                                                 
                           
 
                                             




                                                                     
                          

                                 


                                                 
                           
 
                                             



                                                                   
                          




                                   


                                                 
                           
 
                                             



                                                                   
                          











                                                                                          


                                                 
                           
 















                                                                 


                                                 

                                 
 














                                                                         


                                                 

                                 
 














                                                                


                                                 

                                 
 














                                                                 


                                                 

                                 
 














                                                                


                                                 

                                 
 













                                                                 


                                                 
                           
 
                                                              
                                                 
                                             
                 
                                        
                                                  



                                                                     
 
                          






































                                                                 


                                                 







                                                                                       
 
                                             



                                                                   

                                                 
                                                        


                          
























                                                           
package parser

import (
    "regexp"

    "github.com/robertkrimen/otto/ast"
    "github.com/robertkrimen/otto/file"
    "github.com/robertkrimen/otto/token"
)

func (self *_parser) parseIdentifier() *ast.Identifier {
    literal := self.literal
    idx := self.idx
    if self.mode&StoreComments != 0 {
        self.comments.MarkComments(ast.LEADING)
    }
    self.next()
    exp := &ast.Identifier{
        Name: literal,
        Idx:  idx,
    }

    if self.mode&StoreComments != 0 {
        self.comments.SetExpression(exp)
    }

    return exp
}

func (self *_parser) parsePrimaryExpression() ast.Expression {
    literal := self.literal
    idx := self.idx
    switch self.token {
    case token.IDENTIFIER:
        self.next()
        if len(literal) > 1 {
            tkn, strict := token.IsKeyword(literal)
            if tkn == token.KEYWORD {
                if !strict {
                    self.error(idx, "Unexpected reserved word")
                }
            }
        }
        return &ast.Identifier{
            Name: literal,
            Idx:  idx,
        }
    case token.NULL:
        self.next()
        return &ast.NullLiteral{
            Idx:     idx,
            Literal: literal,
        }
    case token.BOOLEAN:
        self.next()
        value := false
        switch literal {
        case "true":
            value = true
        case "false":
            value = false
        default:
            self.error(idx, "Illegal boolean literal")
        }
        return &ast.BooleanLiteral{
            Idx:     idx,
            Literal: literal,
            Value:   value,
        }
    case token.STRING:
        self.next()
        value, err := parseStringLiteral(literal[1 : len(literal)-1])
        if err != nil {
            self.error(idx, err.Error())
        }
        return &ast.StringLiteral{
            Idx:     idx,
            Literal: literal,
            Value:   value,
        }
    case token.NUMBER:
        self.next()
        value, err := parseNumberLiteral(literal)
        if err != nil {
            self.error(idx, err.Error())
            value = 0
        }
        return &ast.NumberLiteral{
            Idx:     idx,
            Literal: literal,
            Value:   value,
        }
    case token.SLASH, token.QUOTIENT_ASSIGN:
        return self.parseRegExpLiteral()
    case token.LEFT_BRACE:
        return self.parseObjectLiteral()
    case token.LEFT_BRACKET:
        return self.parseArrayLiteral()
    case token.LEFT_PARENTHESIS:
        self.expect(token.LEFT_PARENTHESIS)
        expression := self.parseExpression()
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.expect(token.RIGHT_PARENTHESIS)
        return expression
    case token.THIS:
        self.next()
        return &ast.ThisExpression{
            Idx: idx,
        }
    case token.FUNCTION:
        return self.parseFunction(false)
    }

    self.errorUnexpectedToken(self.token)
    self.nextStatement()
    return &ast.BadExpression{From: idx, To: self.idx}
}

func (self *_parser) parseRegExpLiteral() *ast.RegExpLiteral {

    offset := self.chrOffset - 1 // Opening slash already gotten
    if self.token == token.QUOTIENT_ASSIGN {
        offset -= 1 // =
    }
    idx := self.idxOf(offset)

    pattern, err := self.scanString(offset)
    endOffset := self.chrOffset

    self.next()
    if err == nil {
        pattern = pattern[1 : len(pattern)-1]
    }

    flags := ""
    if self.token == token.IDENTIFIER { // gim

        flags = self.literal
        self.next()
        endOffset = self.chrOffset - 1
    }

    var value string
    // TODO 15.10
    {
        // Test during parsing that this is a valid regular expression
        // Sorry, (?=) and (?!) are invalid (for now)
        pattern, err := TransformRegExp(pattern)
        if err != nil {
            if pattern == "" || self.mode&IgnoreRegExpErrors == 0 {
                self.error(idx, "Invalid regular expression: %s", err.Error())
            }
        } else {
            _, err = regexp.Compile(pattern)
            if err != nil {
                // We should not get here, ParseRegExp should catch any errors
                self.error(idx, "Invalid regular expression: %s", err.Error()[22:]) // Skip redundant "parse regexp error"
            } else {
                value = pattern
            }
        }
    }

    literal := self.str[offset:endOffset]

    return &ast.RegExpLiteral{
        Idx:     idx,
        Literal: literal,
        Pattern: pattern,
        Flags:   flags,
        Value:   value,
    }
}

func (self *_parser) parseVariableDeclaration(declarationList *[]*ast.VariableExpression) ast.Expression {

    if self.token != token.IDENTIFIER {
        idx := self.expect(token.IDENTIFIER)
        self.nextStatement()
        return &ast.BadExpression{From: idx, To: self.idx}
    }

    literal := self.literal
    idx := self.idx
    self.next()
    node := &ast.VariableExpression{
        Name: literal,
        Idx:  idx,
    }
    if self.mode&StoreComments != 0 {
        self.comments.SetExpression(node)
    }

    if declarationList != nil {
        *declarationList = append(*declarationList, node)
    }

    if self.token == token.ASSIGN {
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()
        node.Initializer = self.parseAssignmentExpression()
    }

    return node
}

func (self *_parser) parseVariableDeclarationList(var_ file.Idx) []ast.Expression {

    var declarationList []*ast.VariableExpression // Avoid bad expressions
    var list []ast.Expression

    for {
        if self.mode&StoreComments != 0 {
            self.comments.MarkComments(ast.LEADING)
        }
        decl := self.parseVariableDeclaration(&declarationList)
        list = append(list, decl)
        if self.token != token.COMMA {
            break
        }
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()
    }

    self.scope.declare(&ast.VariableDeclaration{
        Var:  var_,
        List: declarationList,
    })

    return list
}

func (self *_parser) parseObjectPropertyKey() (string, string) {
    idx, tkn, literal := self.idx, self.token, self.literal
    value := ""
    if self.mode&StoreComments != 0 {
        self.comments.MarkComments(ast.KEY)
    }
    self.next()

    switch tkn {
    case token.IDENTIFIER:
        value = literal
    case token.NUMBER:
        var err error
        _, err = parseNumberLiteral(literal)
        if err != nil {
            self.error(idx, err.Error())
        } else {
            value = literal
        }
    case token.STRING:
        var err error
        value, err = parseStringLiteral(literal[1 : len(literal)-1])
        if err != nil {
            self.error(idx, err.Error())
        }
    default:
        // null, false, class, etc.
        if matchIdentifier.MatchString(literal) {
            value = literal
        }
    }
    return literal, value
}

func (self *_parser) parseObjectProperty() ast.Property {
    literal, value := self.parseObjectPropertyKey()
    if literal == "get" && self.token != token.COLON {
        idx := self.idx
        _, value := self.parseObjectPropertyKey()
        parameterList := self.parseFunctionParameterList()

        node := &ast.FunctionLiteral{
            Function:      idx,
            ParameterList: parameterList,
        }
        self.parseFunctionBlock(node)
        return ast.Property{
            Key:   value,
            Kind:  "get",
            Value: node,
        }
    } else if literal == "set" && self.token != token.COLON {
        idx := self.idx
        _, value := self.parseObjectPropertyKey()
        parameterList := self.parseFunctionParameterList()

        node := &ast.FunctionLiteral{
            Function:      idx,
            ParameterList: parameterList,
        }
        self.parseFunctionBlock(node)
        return ast.Property{
            Key:   value,
            Kind:  "set",
            Value: node,
        }
    }

    if self.mode&StoreComments != 0 {
        self.comments.MarkComments(ast.COLON)
    }
    self.expect(token.COLON)

    exp := ast.Property{
        Key:   value,
        Kind:  "value",
        Value: self.parseAssignmentExpression(),
    }

    if self.mode&StoreComments != 0 {
        self.comments.SetExpression(exp.Value)
    }
    return exp
}

func (self *_parser) parseObjectLiteral() ast.Expression {
    var value []ast.Property
    idx0 := self.expect(token.LEFT_BRACE)
    for self.token != token.RIGHT_BRACE && self.token != token.EOF {
        value = append(value, self.parseObjectProperty())
        if self.token == token.COMMA {
            if self.mode&StoreComments != 0 {
                self.comments.Unset()
            }
            self.next()
            continue
        }
    }
    if self.mode&StoreComments != 0 {
        self.comments.MarkComments(ast.FINAL)
    }
    idx1 := self.expect(token.RIGHT_BRACE)

    return &ast.ObjectLiteral{
        LeftBrace:  idx0,
        RightBrace: idx1,
        Value:      value,
    }
}

func (self *_parser) parseArrayLiteral() ast.Expression {
    idx0 := self.expect(token.LEFT_BRACKET)
    var value []ast.Expression
    for self.token != token.RIGHT_BRACKET && self.token != token.EOF {
        if self.token == token.COMMA {
            // This kind of comment requires a special empty expression node.
            empty := &ast.EmptyExpression{self.idx, self.idx}

            if self.mode&StoreComments != 0 {
                self.comments.SetExpression(empty)
                self.comments.Unset()
            }
            value = append(value, empty)
            self.next()
            continue
        }

        exp := self.parseAssignmentExpression()

        value = append(value, exp)
        if self.token != token.RIGHT_BRACKET {
            if self.mode&StoreComments != 0 {
                self.comments.Unset()
            }
            self.expect(token.COMMA)
        }
    }
    if self.mode&StoreComments != 0 {
        self.comments.MarkComments(ast.FINAL)
    }
    idx1 := self.expect(token.RIGHT_BRACKET)

    return &ast.ArrayLiteral{
        LeftBracket:  idx0,
        RightBracket: idx1,
        Value:        value,
    }
}

func (self *_parser) parseArgumentList() (argumentList []ast.Expression, idx0, idx1 file.Idx) {
    if self.mode&StoreComments != 0 {
        self.comments.Unset()
    }
    idx0 = self.expect(token.LEFT_PARENTHESIS)
    if self.token != token.RIGHT_PARENTHESIS {
        for {
            exp := self.parseAssignmentExpression()
            if self.mode&StoreComments != 0 {
                self.comments.SetExpression(exp)
            }
            argumentList = append(argumentList, exp)
            if self.token != token.COMMA {
                break
            }
            if self.mode&StoreComments != 0 {
                self.comments.Unset()
            }
            self.next()
        }
    }
    if self.mode&StoreComments != 0 {
        self.comments.Unset()
    }
    idx1 = self.expect(token.RIGHT_PARENTHESIS)
    return
}

func (self *_parser) parseCallExpression(left ast.Expression) ast.Expression {
    argumentList, idx0, idx1 := self.parseArgumentList()
    exp := &ast.CallExpression{
        Callee:           left,
        LeftParenthesis:  idx0,
        ArgumentList:     argumentList,
        RightParenthesis: idx1,
    }

    if self.mode&StoreComments != 0 {
        self.comments.SetExpression(exp)
    }
    return exp
}

func (self *_parser) parseDotMember(left ast.Expression) ast.Expression {
    period := self.expect(token.PERIOD)

    literal := self.literal
    idx := self.idx

    if !matchIdentifier.MatchString(literal) {
        self.expect(token.IDENTIFIER)
        self.nextStatement()
        return &ast.BadExpression{From: period, To: self.idx}
    }

    self.next()

    return &ast.DotExpression{
        Left: left,
        Identifier: &ast.Identifier{
            Idx:  idx,
            Name: literal,
        },
    }
}

func (self *_parser) parseBracketMember(left ast.Expression) ast.Expression {
    idx0 := self.expect(token.LEFT_BRACKET)
    member := self.parseExpression()
    idx1 := self.expect(token.RIGHT_BRACKET)
    return &ast.BracketExpression{
        LeftBracket:  idx0,
        Left:         left,
        Member:       member,
        RightBracket: idx1,
    }
}

func (self *_parser) parseNewExpression() ast.Expression {
    idx := self.expect(token.NEW)
    callee := self.parseLeftHandSideExpression()
    node := &ast.NewExpression{
        New:    idx,
        Callee: callee,
    }
    if self.token == token.LEFT_PARENTHESIS {
        argumentList, idx0, idx1 := self.parseArgumentList()
        node.ArgumentList = argumentList
        node.LeftParenthesis = idx0
        node.RightParenthesis = idx1
    }

    if self.mode&StoreComments != 0 {
        self.comments.SetExpression(node)
    }

    return node
}

func (self *_parser) parseLeftHandSideExpression() ast.Expression {

    var left ast.Expression
    if self.token == token.NEW {
        left = self.parseNewExpression()
    } else {
        if self.mode&StoreComments != 0 {
            self.comments.MarkComments(ast.LEADING)
            self.comments.MarkPrimary()
        }
        left = self.parsePrimaryExpression()
    }

    if self.mode&StoreComments != 0 {
        self.comments.SetExpression(left)
    }

    for {
        if self.token == token.PERIOD {
            left = self.parseDotMember(left)
        } else if self.token == token.LEFT_BRACKET {
            left = self.parseBracketMember(left)
        } else {
            break
        }
    }

    return left
}

func (self *_parser) parseLeftHandSideExpressionAllowCall() ast.Expression {

    allowIn := self.scope.allowIn
    self.scope.allowIn = true
    defer func() {
        self.scope.allowIn = allowIn
    }()

    var left ast.Expression
    if self.token == token.NEW {
        var newComments []*ast.Comment
        if self.mode&StoreComments != 0 {
            newComments = self.comments.FetchAll()
            self.comments.MarkComments(ast.LEADING)
            self.comments.MarkPrimary()
        }
        left = self.parseNewExpression()
        if self.mode&StoreComments != 0 {
            self.comments.CommentMap.AddComments(left, newComments, ast.LEADING)
        }
    } else {
        if self.mode&StoreComments != 0 {
            self.comments.MarkComments(ast.LEADING)
            self.comments.MarkPrimary()
        }
        left = self.parsePrimaryExpression()
    }

    if self.mode&StoreComments != 0 {
        self.comments.SetExpression(left)
    }

    for {
        if self.token == token.PERIOD {
            left = self.parseDotMember(left)
        } else if self.token == token.LEFT_BRACKET {
            left = self.parseBracketMember(left)
        } else if self.token == token.LEFT_PARENTHESIS {
            left = self.parseCallExpression(left)
        } else {
            break
        }
    }

    return left
}

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

    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
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()
        switch operand.(type) {
        case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression:
        default:
            self.error(idx, "Invalid left-hand side in assignment")
            self.nextStatement()
            return &ast.BadExpression{From: idx, To: self.idx}
        }
        exp := &ast.UnaryExpression{
            Operator: tkn,
            Idx:      idx,
            Operand:  operand,
            Postfix:  true,
        }

        if self.mode&StoreComments != 0 {
            self.comments.SetExpression(exp)
        }

        return exp
    }

    return operand
}

func (self *_parser) parseUnaryExpression() ast.Expression {

    switch self.token {
    case token.PLUS, token.MINUS, token.NOT, token.BITWISE_NOT:
        fallthrough
    case token.DELETE, token.VOID, token.TYPEOF:
        tkn := self.token
        idx := self.idx
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()

        return &ast.UnaryExpression{
            Operator: tkn,
            Idx:      idx,
            Operand:  self.parseUnaryExpression(),
        }
    case token.INCREMENT, token.DECREMENT:
        tkn := self.token
        idx := self.idx
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()
        operand := self.parseUnaryExpression()
        switch operand.(type) {
        case *ast.Identifier, *ast.DotExpression, *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,
        }
    }

    return self.parsePostfixExpression()
}

func (self *_parser) parseMultiplicativeExpression() ast.Expression {
    next := self.parseUnaryExpression
    left := next()

    for self.token == token.MULTIPLY || self.token == token.SLASH ||
        self.token == token.REMAINDER {
        tkn := self.token
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()

        left = &ast.BinaryExpression{
            Operator: tkn,
            Left:     left,
            Right:    next(),
        }
    }

    return left
}

func (self *_parser) parseAdditiveExpression() ast.Expression {
    next := self.parseMultiplicativeExpression
    left := next()

    for self.token == token.PLUS || self.token == token.MINUS {
        tkn := self.token
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()

        left = &ast.BinaryExpression{
            Operator: tkn,
            Left:     left,
            Right:    next(),
        }
    }

    return left
}

func (self *_parser) parseShiftExpression() ast.Expression {
    next := self.parseAdditiveExpression
    left := next()

    for self.token == token.SHIFT_LEFT || self.token == token.SHIFT_RIGHT ||
        self.token == token.UNSIGNED_SHIFT_RIGHT {
        tkn := self.token
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()

        left = &ast.BinaryExpression{
            Operator: tkn,
            Left:     left,
            Right:    next(),
        }
    }

    return left
}

func (self *_parser) parseRelationalExpression() ast.Expression {
    next := self.parseShiftExpression
    left := next()

    allowIn := self.scope.allowIn
    self.scope.allowIn = true
    defer func() {
        self.scope.allowIn = allowIn
    }()

    switch self.token {
    case token.LESS, token.LESS_OR_EQUAL, token.GREATER, token.GREATER_OR_EQUAL:
        tkn := self.token
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()

        exp := &ast.BinaryExpression{
            Operator:   tkn,
            Left:       left,
            Right:      self.parseRelationalExpression(),
            Comparison: true,
        }
        return exp
    case token.INSTANCEOF:
        tkn := self.token
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()

        exp := &ast.BinaryExpression{
            Operator: tkn,
            Left:     left,
            Right:    self.parseRelationalExpression(),
        }
        return exp
    case token.IN:
        if !allowIn {
            return left
        }
        tkn := self.token
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()

        exp := &ast.BinaryExpression{
            Operator: tkn,
            Left:     left,
            Right:    self.parseRelationalExpression(),
        }
        return exp
    }

    return left
}

func (self *_parser) parseEqualityExpression() ast.Expression {
    next := self.parseRelationalExpression
    left := next()

    for self.token == token.EQUAL || self.token == token.NOT_EQUAL ||
        self.token == token.STRICT_EQUAL || self.token == token.STRICT_NOT_EQUAL {
        tkn := self.token
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()

        left = &ast.BinaryExpression{
            Operator:   tkn,
            Left:       left,
            Right:      next(),
            Comparison: true,
        }
    }

    return left
}

func (self *_parser) parseBitwiseAndExpression() ast.Expression {
    next := self.parseEqualityExpression
    left := next()

    for self.token == token.AND {
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        tkn := self.token
        self.next()

        left = &ast.BinaryExpression{
            Operator: tkn,
            Left:     left,
            Right:    next(),
        }
    }

    return left
}

func (self *_parser) parseBitwiseExclusiveOrExpression() ast.Expression {
    next := self.parseBitwiseAndExpression
    left := next()

    for self.token == token.EXCLUSIVE_OR {
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        tkn := self.token
        self.next()

        left = &ast.BinaryExpression{
            Operator: tkn,
            Left:     left,
            Right:    next(),
        }
    }

    return left
}

func (self *_parser) parseBitwiseOrExpression() ast.Expression {
    next := self.parseBitwiseExclusiveOrExpression
    left := next()

    for self.token == token.OR {
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        tkn := self.token
        self.next()

        left = &ast.BinaryExpression{
            Operator: tkn,
            Left:     left,
            Right:    next(),
        }
    }

    return left
}

func (self *_parser) parseLogicalAndExpression() ast.Expression {
    next := self.parseBitwiseOrExpression
    left := next()

    for self.token == token.LOGICAL_AND {
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        tkn := self.token
        self.next()

        left = &ast.BinaryExpression{
            Operator: tkn,
            Left:     left,
            Right:    next(),
        }
    }

    return left
}

func (self *_parser) parseLogicalOrExpression() ast.Expression {
    next := self.parseLogicalAndExpression
    left := next()

    for self.token == token.LOGICAL_OR {
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        tkn := self.token
        self.next()

        left = &ast.BinaryExpression{
            Operator: tkn,
            Left:     left,
            Right:    next(),
        }
    }

    return left
}

func (self *_parser) parseConditionlExpression() ast.Expression {
    left := self.parseLogicalOrExpression()

    if self.token == token.QUESTION_MARK {
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()

        consequent := self.parseAssignmentExpression()
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.expect(token.COLON)
        exp := &ast.ConditionalExpression{
            Test:       left,
            Consequent: consequent,
            Alternate:  self.parseAssignmentExpression(),
        }

        return exp
    }

    return left
}

func (self *_parser) parseAssignmentExpression() ast.Expression {
    left := self.parseConditionlExpression()
    var operator token.Token
    switch self.token {
    case token.ASSIGN:
        operator = self.token
    case token.ADD_ASSIGN:
        operator = token.PLUS
    case token.SUBTRACT_ASSIGN:
        operator = token.MINUS
    case token.MULTIPLY_ASSIGN:
        operator = token.MULTIPLY
    case token.QUOTIENT_ASSIGN:
        operator = token.SLASH
    case token.REMAINDER_ASSIGN:
        operator = token.REMAINDER
    case token.AND_ASSIGN:
        operator = token.AND
    case token.AND_NOT_ASSIGN:
        operator = token.AND_NOT
    case token.OR_ASSIGN:
        operator = token.OR
    case token.EXCLUSIVE_OR_ASSIGN:
        operator = token.EXCLUSIVE_OR
    case token.SHIFT_LEFT_ASSIGN:
        operator = token.SHIFT_LEFT
    case token.SHIFT_RIGHT_ASSIGN:
        operator = token.SHIFT_RIGHT
    case token.UNSIGNED_SHIFT_RIGHT_ASSIGN:
        operator = token.UNSIGNED_SHIFT_RIGHT
    }

    if operator != 0 {
        idx := self.idx
        if self.mode&StoreComments != 0 {
            self.comments.Unset()
        }
        self.next()
        switch left.(type) {
        case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression:
        default:
            self.error(left.Idx0(), "Invalid left-hand side in assignment")
            self.nextStatement()
            return &ast.BadExpression{From: idx, To: self.idx}
        }

        exp := &ast.AssignExpression{
            Left:     left,
            Operator: operator,
            Right:    self.parseAssignmentExpression(),
        }

        if self.mode&StoreComments != 0 {
            self.comments.SetExpression(exp)
        }

        return exp
    }

    return left
}

func (self *_parser) parseExpression() ast.Expression {
    next := self.parseAssignmentExpression
    left := next()

    if self.token == token.COMMA {
        sequence := []ast.Expression{left}
        for {
            if self.token != token.COMMA {
                break
            }
            self.next()
            sequence = append(sequence, next())
        }
        return &ast.SequenceExpression{
            Sequence: sequence,
        }
    }

    return left
}