plugeth/vendor/github.com/robertkrimen/otto/parser/expression.go
Péter Szilágyi 289b30715d Godeps, vendor: convert dependency management to trash (#3198)
This commit converts the dependency management from Godeps to the vendor
folder, also switching the tool from godep to trash. Since the upstream tool
lacks a few features proposed via a few PRs, until those PRs are merged in
(if), use github.com/karalabe/trash.

You can update dependencies via trash --update.

All dependencies have been updated to their latest version.

Parts of the build system are reworked to drop old notions of Godeps and
invocation of the go vet command so that it doesn't run against the vendor
folder, as that will just blow up during vetting.

The conversion drops OpenCL (and hence GPU mining support) from ethash and our
codebase. The short reasoning is that there's noone to maintain and having
opencl libs in our deps messes up builds as go install ./... tries to build
them, failing with unsatisfied link errors for the C OpenCL deps.

golang.org/x/net/context is not vendored in. We expect it to be fetched by the
user (i.e. using go get). To keep ci.go builds reproducible the package is
"vendored" in build/_vendor.
2016-10-28 19:05:01 +02:00

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
}