289b30715d
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.
1006 lines
21 KiB
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
|
|
}
|