status-go/vendor/github.com/robertkrimen/otto/parser/expression.go

1006 lines
21 KiB
Go

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
}