aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/robertkrimen/otto/parser/expression.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/robertkrimen/otto/parser/expression.go')
-rw-r--r--vendor/github.com/robertkrimen/otto/parser/expression.go1005
1 files changed, 1005 insertions, 0 deletions
diff --git a/vendor/github.com/robertkrimen/otto/parser/expression.go b/vendor/github.com/robertkrimen/otto/parser/expression.go
new file mode 100644
index 000000000..63a169d40
--- /dev/null
+++ b/vendor/github.com/robertkrimen/otto/parser/expression.go
@@ -0,0 +1,1005 @@
+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
+}