plugeth/vendor/github.com/robertkrimen/otto/parser/statement.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

939 lines
23 KiB
Go

package parser
import (
"github.com/robertkrimen/otto/ast"
"github.com/robertkrimen/otto/token"
)
func (self *_parser) parseBlockStatement() *ast.BlockStatement {
node := &ast.BlockStatement{}
// Find comments before the leading brace
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(node, self.comments.FetchAll(), ast.LEADING)
self.comments.Unset()
}
node.LeftBrace = self.expect(token.LEFT_BRACE)
node.List = self.parseStatementList()
if self.mode&StoreComments != 0 {
self.comments.Unset()
self.comments.CommentMap.AddComments(node, self.comments.FetchAll(), ast.FINAL)
self.comments.AfterBlock()
}
node.RightBrace = self.expect(token.RIGHT_BRACE)
// Find comments after the trailing brace
if self.mode&StoreComments != 0 {
self.comments.ResetLineBreak()
self.comments.CommentMap.AddComments(node, self.comments.Fetch(), ast.TRAILING)
}
return node
}
func (self *_parser) parseEmptyStatement() ast.Statement {
idx := self.expect(token.SEMICOLON)
return &ast.EmptyStatement{Semicolon: idx}
}
func (self *_parser) parseStatementList() (list []ast.Statement) {
for self.token != token.RIGHT_BRACE && self.token != token.EOF {
statement := self.parseStatement()
list = append(list, statement)
}
return
}
func (self *_parser) parseStatement() ast.Statement {
if self.token == token.EOF {
self.errorUnexpectedToken(self.token)
return &ast.BadStatement{From: self.idx, To: self.idx + 1}
}
if self.mode&StoreComments != 0 {
self.comments.ResetLineBreak()
}
switch self.token {
case token.SEMICOLON:
return self.parseEmptyStatement()
case token.LEFT_BRACE:
return self.parseBlockStatement()
case token.IF:
return self.parseIfStatement()
case token.DO:
statement := self.parseDoWhileStatement()
self.comments.PostProcessNode(statement)
return statement
case token.WHILE:
return self.parseWhileStatement()
case token.FOR:
return self.parseForOrForInStatement()
case token.BREAK:
return self.parseBreakStatement()
case token.CONTINUE:
return self.parseContinueStatement()
case token.DEBUGGER:
return self.parseDebuggerStatement()
case token.WITH:
return self.parseWithStatement()
case token.VAR:
return self.parseVariableStatement()
case token.FUNCTION:
return self.parseFunctionStatement()
case token.SWITCH:
return self.parseSwitchStatement()
case token.RETURN:
return self.parseReturnStatement()
case token.THROW:
return self.parseThrowStatement()
case token.TRY:
return self.parseTryStatement()
}
var comments []*ast.Comment
if self.mode&StoreComments != 0 {
comments = self.comments.FetchAll()
}
expression := self.parseExpression()
if identifier, isIdentifier := expression.(*ast.Identifier); isIdentifier && self.token == token.COLON {
// LabelledStatement
colon := self.idx
if self.mode&StoreComments != 0 {
self.comments.Unset()
}
self.next() // :
label := identifier.Name
for _, value := range self.scope.labels {
if label == value {
self.error(identifier.Idx0(), "Label '%s' already exists", label)
}
}
var labelComments []*ast.Comment
if self.mode&StoreComments != 0 {
labelComments = self.comments.FetchAll()
}
self.scope.labels = append(self.scope.labels, label) // Push the label
statement := self.parseStatement()
self.scope.labels = self.scope.labels[:len(self.scope.labels)-1] // Pop the label
exp := &ast.LabelledStatement{
Label: identifier,
Colon: colon,
Statement: statement,
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(exp, labelComments, ast.LEADING)
}
return exp
}
self.optionalSemicolon()
statement := &ast.ExpressionStatement{
Expression: expression,
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(statement, comments, ast.LEADING)
}
return statement
}
func (self *_parser) parseTryStatement() ast.Statement {
var tryComments []*ast.Comment
if self.mode&StoreComments != 0 {
tryComments = self.comments.FetchAll()
}
node := &ast.TryStatement{
Try: self.expect(token.TRY),
Body: self.parseBlockStatement(),
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(node, tryComments, ast.LEADING)
self.comments.CommentMap.AddComments(node.Body, self.comments.FetchAll(), ast.TRAILING)
}
if self.token == token.CATCH {
catch := self.idx
if self.mode&StoreComments != 0 {
self.comments.Unset()
}
self.next()
self.expect(token.LEFT_PARENTHESIS)
if self.token != token.IDENTIFIER {
self.expect(token.IDENTIFIER)
self.nextStatement()
return &ast.BadStatement{From: catch, To: self.idx}
} else {
identifier := self.parseIdentifier()
self.expect(token.RIGHT_PARENTHESIS)
node.Catch = &ast.CatchStatement{
Catch: catch,
Parameter: identifier,
Body: self.parseBlockStatement(),
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(node.Catch.Body, self.comments.FetchAll(), ast.TRAILING)
}
}
}
if self.token == token.FINALLY {
if self.mode&StoreComments != 0 {
self.comments.Unset()
}
self.next()
if self.mode&StoreComments != 0 {
tryComments = self.comments.FetchAll()
}
node.Finally = self.parseBlockStatement()
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(node.Finally, tryComments, ast.LEADING)
}
}
if node.Catch == nil && node.Finally == nil {
self.error(node.Try, "Missing catch or finally after try")
return &ast.BadStatement{From: node.Try, To: node.Body.Idx1()}
}
return node
}
func (self *_parser) parseFunctionParameterList() *ast.ParameterList {
opening := self.expect(token.LEFT_PARENTHESIS)
if self.mode&StoreComments != 0 {
self.comments.Unset()
}
var list []*ast.Identifier
for self.token != token.RIGHT_PARENTHESIS && self.token != token.EOF {
if self.token != token.IDENTIFIER {
self.expect(token.IDENTIFIER)
} else {
identifier := self.parseIdentifier()
list = append(list, identifier)
}
if self.token != token.RIGHT_PARENTHESIS {
if self.mode&StoreComments != 0 {
self.comments.Unset()
}
self.expect(token.COMMA)
}
}
closing := self.expect(token.RIGHT_PARENTHESIS)
return &ast.ParameterList{
Opening: opening,
List: list,
Closing: closing,
}
}
func (self *_parser) parseParameterList() (list []string) {
for self.token != token.EOF {
if self.token != token.IDENTIFIER {
self.expect(token.IDENTIFIER)
}
list = append(list, self.literal)
self.next()
if self.token != token.EOF {
self.expect(token.COMMA)
}
}
return
}
func (self *_parser) parseFunctionStatement() *ast.FunctionStatement {
var comments []*ast.Comment
if self.mode&StoreComments != 0 {
comments = self.comments.FetchAll()
}
function := &ast.FunctionStatement{
Function: self.parseFunction(true),
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(function, comments, ast.LEADING)
}
return function
}
func (self *_parser) parseFunction(declaration bool) *ast.FunctionLiteral {
node := &ast.FunctionLiteral{
Function: self.expect(token.FUNCTION),
}
var name *ast.Identifier
if self.token == token.IDENTIFIER {
name = self.parseIdentifier()
if declaration {
self.scope.declare(&ast.FunctionDeclaration{
Function: node,
})
}
} else if declaration {
// Use expect error handling
self.expect(token.IDENTIFIER)
}
if self.mode&StoreComments != 0 {
self.comments.Unset()
}
node.Name = name
node.ParameterList = self.parseFunctionParameterList()
self.parseFunctionBlock(node)
node.Source = self.slice(node.Idx0(), node.Idx1())
return node
}
func (self *_parser) parseFunctionBlock(node *ast.FunctionLiteral) {
{
self.openScope()
inFunction := self.scope.inFunction
self.scope.inFunction = true
defer func() {
self.scope.inFunction = inFunction
self.closeScope()
}()
node.Body = self.parseBlockStatement()
node.DeclarationList = self.scope.declarationList
}
}
func (self *_parser) parseDebuggerStatement() ast.Statement {
idx := self.expect(token.DEBUGGER)
node := &ast.DebuggerStatement{
Debugger: idx,
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(node, self.comments.FetchAll(), ast.TRAILING)
}
self.semicolon()
return node
}
func (self *_parser) parseReturnStatement() ast.Statement {
idx := self.expect(token.RETURN)
var comments []*ast.Comment
if self.mode&StoreComments != 0 {
comments = self.comments.FetchAll()
}
if !self.scope.inFunction {
self.error(idx, "Illegal return statement")
self.nextStatement()
return &ast.BadStatement{From: idx, To: self.idx}
}
node := &ast.ReturnStatement{
Return: idx,
}
if !self.implicitSemicolon && self.token != token.SEMICOLON && self.token != token.RIGHT_BRACE && self.token != token.EOF {
node.Argument = self.parseExpression()
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(node, comments, ast.LEADING)
}
self.semicolon()
return node
}
func (self *_parser) parseThrowStatement() ast.Statement {
var comments []*ast.Comment
if self.mode&StoreComments != 0 {
comments = self.comments.FetchAll()
}
idx := self.expect(token.THROW)
if self.implicitSemicolon {
if self.chr == -1 { // Hackish
self.error(idx, "Unexpected end of input")
} else {
self.error(idx, "Illegal newline after throw")
}
self.nextStatement()
return &ast.BadStatement{From: idx, To: self.idx}
}
node := &ast.ThrowStatement{
Argument: self.parseExpression(),
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(node, comments, ast.LEADING)
}
self.semicolon()
return node
}
func (self *_parser) parseSwitchStatement() ast.Statement {
var comments []*ast.Comment
if self.mode&StoreComments != 0 {
comments = self.comments.FetchAll()
}
self.expect(token.SWITCH)
if self.mode&StoreComments != 0 {
comments = append(comments, self.comments.FetchAll()...)
}
self.expect(token.LEFT_PARENTHESIS)
node := &ast.SwitchStatement{
Discriminant: self.parseExpression(),
Default: -1,
}
self.expect(token.RIGHT_PARENTHESIS)
if self.mode&StoreComments != 0 {
comments = append(comments, self.comments.FetchAll()...)
}
self.expect(token.LEFT_BRACE)
inSwitch := self.scope.inSwitch
self.scope.inSwitch = true
defer func() {
self.scope.inSwitch = inSwitch
}()
for index := 0; self.token != token.EOF; index++ {
if self.token == token.RIGHT_BRACE {
self.next()
break
}
clause := self.parseCaseStatement()
if clause.Test == nil {
if node.Default != -1 {
self.error(clause.Case, "Already saw a default in switch")
}
node.Default = index
}
node.Body = append(node.Body, clause)
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(node, comments, ast.LEADING)
}
return node
}
func (self *_parser) parseWithStatement() ast.Statement {
var comments []*ast.Comment
if self.mode&StoreComments != 0 {
comments = self.comments.FetchAll()
}
self.expect(token.WITH)
var withComments []*ast.Comment
if self.mode&StoreComments != 0 {
withComments = self.comments.FetchAll()
}
self.expect(token.LEFT_PARENTHESIS)
node := &ast.WithStatement{
Object: self.parseExpression(),
}
self.expect(token.RIGHT_PARENTHESIS)
if self.mode&StoreComments != 0 {
//comments = append(comments, self.comments.FetchAll()...)
self.comments.CommentMap.AddComments(node, comments, ast.LEADING)
self.comments.CommentMap.AddComments(node, withComments, ast.WITH)
}
node.Body = self.parseStatement()
return node
}
func (self *_parser) parseCaseStatement() *ast.CaseStatement {
node := &ast.CaseStatement{
Case: self.idx,
}
var comments []*ast.Comment
if self.mode&StoreComments != 0 {
comments = self.comments.FetchAll()
self.comments.Unset()
}
if self.token == token.DEFAULT {
self.next()
} else {
self.expect(token.CASE)
node.Test = self.parseExpression()
}
if self.mode&StoreComments != 0 {
self.comments.Unset()
}
self.expect(token.COLON)
for {
if self.token == token.EOF ||
self.token == token.RIGHT_BRACE ||
self.token == token.CASE ||
self.token == token.DEFAULT {
break
}
consequent := self.parseStatement()
node.Consequent = append(node.Consequent, consequent)
}
// Link the comments to the case statement
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(node, comments, ast.LEADING)
}
return node
}
func (self *_parser) parseIterationStatement() ast.Statement {
inIteration := self.scope.inIteration
self.scope.inIteration = true
defer func() {
self.scope.inIteration = inIteration
}()
return self.parseStatement()
}
func (self *_parser) parseForIn(into ast.Expression) *ast.ForInStatement {
// Already have consumed "<into> in"
source := self.parseExpression()
self.expect(token.RIGHT_PARENTHESIS)
body := self.parseIterationStatement()
forin := &ast.ForInStatement{
Into: into,
Source: source,
Body: body,
}
return forin
}
func (self *_parser) parseFor(initializer ast.Expression) *ast.ForStatement {
// Already have consumed "<initializer> ;"
var test, update ast.Expression
if self.token != token.SEMICOLON {
test = self.parseExpression()
}
if self.mode&StoreComments != 0 {
self.comments.Unset()
}
self.expect(token.SEMICOLON)
if self.token != token.RIGHT_PARENTHESIS {
update = self.parseExpression()
}
self.expect(token.RIGHT_PARENTHESIS)
body := self.parseIterationStatement()
forstatement := &ast.ForStatement{
Initializer: initializer,
Test: test,
Update: update,
Body: body,
}
return forstatement
}
func (self *_parser) parseForOrForInStatement() ast.Statement {
var comments []*ast.Comment
if self.mode&StoreComments != 0 {
comments = self.comments.FetchAll()
}
idx := self.expect(token.FOR)
var forComments []*ast.Comment
if self.mode&StoreComments != 0 {
forComments = self.comments.FetchAll()
}
self.expect(token.LEFT_PARENTHESIS)
var left []ast.Expression
forIn := false
if self.token != token.SEMICOLON {
allowIn := self.scope.allowIn
self.scope.allowIn = false
if self.token == token.VAR {
var_ := self.idx
var varComments []*ast.Comment
if self.mode&StoreComments != 0 {
varComments = self.comments.FetchAll()
self.comments.Unset()
}
self.next()
list := self.parseVariableDeclarationList(var_)
if len(list) == 1 && self.token == token.IN {
if self.mode&StoreComments != 0 {
self.comments.Unset()
}
self.next() // in
forIn = true
left = []ast.Expression{list[0]} // There is only one declaration
} else {
left = list
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(left[0], varComments, ast.LEADING)
}
} else {
left = append(left, self.parseExpression())
if self.token == token.IN {
self.next()
forIn = true
}
}
self.scope.allowIn = allowIn
}
if forIn {
switch left[0].(type) {
case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression, *ast.VariableExpression:
// These are all acceptable
default:
self.error(idx, "Invalid left-hand side in for-in")
self.nextStatement()
return &ast.BadStatement{From: idx, To: self.idx}
}
forin := self.parseForIn(left[0])
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(forin, comments, ast.LEADING)
self.comments.CommentMap.AddComments(forin, forComments, ast.FOR)
}
return forin
}
if self.mode&StoreComments != 0 {
self.comments.Unset()
}
self.expect(token.SEMICOLON)
initializer := &ast.SequenceExpression{Sequence: left}
forstatement := self.parseFor(initializer)
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(forstatement, comments, ast.LEADING)
self.comments.CommentMap.AddComments(forstatement, forComments, ast.FOR)
}
return forstatement
}
func (self *_parser) parseVariableStatement() *ast.VariableStatement {
var comments []*ast.Comment
if self.mode&StoreComments != 0 {
comments = self.comments.FetchAll()
}
idx := self.expect(token.VAR)
list := self.parseVariableDeclarationList(idx)
statement := &ast.VariableStatement{
Var: idx,
List: list,
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(statement, comments, ast.LEADING)
self.comments.Unset()
}
self.semicolon()
return statement
}
func (self *_parser) parseDoWhileStatement() ast.Statement {
inIteration := self.scope.inIteration
self.scope.inIteration = true
defer func() {
self.scope.inIteration = inIteration
}()
var comments []*ast.Comment
if self.mode&StoreComments != 0 {
comments = self.comments.FetchAll()
}
self.expect(token.DO)
var doComments []*ast.Comment
if self.mode&StoreComments != 0 {
doComments = self.comments.FetchAll()
}
node := &ast.DoWhileStatement{}
if self.token == token.LEFT_BRACE {
node.Body = self.parseBlockStatement()
} else {
node.Body = self.parseStatement()
}
self.expect(token.WHILE)
var whileComments []*ast.Comment
if self.mode&StoreComments != 0 {
whileComments = self.comments.FetchAll()
}
self.expect(token.LEFT_PARENTHESIS)
node.Test = self.parseExpression()
self.expect(token.RIGHT_PARENTHESIS)
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(node, comments, ast.LEADING)
self.comments.CommentMap.AddComments(node, doComments, ast.DO)
self.comments.CommentMap.AddComments(node, whileComments, ast.WHILE)
}
return node
}
func (self *_parser) parseWhileStatement() ast.Statement {
var comments []*ast.Comment
if self.mode&StoreComments != 0 {
comments = self.comments.FetchAll()
}
self.expect(token.WHILE)
var whileComments []*ast.Comment
if self.mode&StoreComments != 0 {
whileComments = self.comments.FetchAll()
}
self.expect(token.LEFT_PARENTHESIS)
node := &ast.WhileStatement{
Test: self.parseExpression(),
}
self.expect(token.RIGHT_PARENTHESIS)
node.Body = self.parseIterationStatement()
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(node, comments, ast.LEADING)
self.comments.CommentMap.AddComments(node, whileComments, ast.WHILE)
}
return node
}
func (self *_parser) parseIfStatement() ast.Statement {
var comments []*ast.Comment
if self.mode&StoreComments != 0 {
comments = self.comments.FetchAll()
}
self.expect(token.IF)
var ifComments []*ast.Comment
if self.mode&StoreComments != 0 {
ifComments = self.comments.FetchAll()
}
self.expect(token.LEFT_PARENTHESIS)
node := &ast.IfStatement{
Test: self.parseExpression(),
}
self.expect(token.RIGHT_PARENTHESIS)
if self.token == token.LEFT_BRACE {
node.Consequent = self.parseBlockStatement()
} else {
node.Consequent = self.parseStatement()
}
if self.token == token.ELSE {
self.next()
node.Alternate = self.parseStatement()
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(node, comments, ast.LEADING)
self.comments.CommentMap.AddComments(node, ifComments, ast.IF)
}
return node
}
func (self *_parser) parseSourceElement() ast.Statement {
statement := self.parseStatement()
//self.comments.Unset()
return statement
}
func (self *_parser) parseSourceElements() []ast.Statement {
body := []ast.Statement(nil)
for {
if self.token != token.STRING {
break
}
body = append(body, self.parseSourceElement())
}
for self.token != token.EOF {
body = append(body, self.parseSourceElement())
}
return body
}
func (self *_parser) parseProgram() *ast.Program {
self.openScope()
defer self.closeScope()
return &ast.Program{
Body: self.parseSourceElements(),
DeclarationList: self.scope.declarationList,
File: self.file,
}
}
func (self *_parser) parseBreakStatement() ast.Statement {
var comments []*ast.Comment
if self.mode&StoreComments != 0 {
comments = self.comments.FetchAll()
}
idx := self.expect(token.BREAK)
semicolon := self.implicitSemicolon
if self.token == token.SEMICOLON {
semicolon = true
self.next()
}
if semicolon || self.token == token.RIGHT_BRACE {
self.implicitSemicolon = false
if !self.scope.inIteration && !self.scope.inSwitch {
goto illegal
}
breakStatement := &ast.BranchStatement{
Idx: idx,
Token: token.BREAK,
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(breakStatement, comments, ast.LEADING)
self.comments.CommentMap.AddComments(breakStatement, self.comments.FetchAll(), ast.TRAILING)
}
return breakStatement
}
if self.token == token.IDENTIFIER {
identifier := self.parseIdentifier()
if !self.scope.hasLabel(identifier.Name) {
self.error(idx, "Undefined label '%s'", identifier.Name)
return &ast.BadStatement{From: idx, To: identifier.Idx1()}
}
self.semicolon()
breakStatement := &ast.BranchStatement{
Idx: idx,
Token: token.BREAK,
Label: identifier,
}
if self.mode&StoreComments != 0 {
self.comments.CommentMap.AddComments(breakStatement, comments, ast.LEADING)
}
return breakStatement
}
self.expect(token.IDENTIFIER)
illegal:
self.error(idx, "Illegal break statement")
self.nextStatement()
return &ast.BadStatement{From: idx, To: self.idx}
}
func (self *_parser) parseContinueStatement() ast.Statement {
idx := self.expect(token.CONTINUE)
semicolon := self.implicitSemicolon
if self.token == token.SEMICOLON {
semicolon = true
self.next()
}
if semicolon || self.token == token.RIGHT_BRACE {
self.implicitSemicolon = false
if !self.scope.inIteration {
goto illegal
}
return &ast.BranchStatement{
Idx: idx,
Token: token.CONTINUE,
}
}
if self.token == token.IDENTIFIER {
identifier := self.parseIdentifier()
if !self.scope.hasLabel(identifier.Name) {
self.error(idx, "Undefined label '%s'", identifier.Name)
return &ast.BadStatement{From: idx, To: identifier.Idx1()}
}
if !self.scope.inIteration {
goto illegal
}
self.semicolon()
return &ast.BranchStatement{
Idx: idx,
Token: token.CONTINUE,
Label: identifier,
}
}
self.expect(token.IDENTIFIER)
illegal:
self.error(idx, "Illegal continue statement")
self.nextStatement()
return &ast.BadStatement{From: idx, To: self.idx}
}
// Find the next statement after an error (recover)
func (self *_parser) nextStatement() {
for {
switch self.token {
case token.BREAK, token.CONTINUE,
token.FOR, token.IF, token.RETURN, token.SWITCH,
token.VAR, token.DO, token.TRY, token.WITH,
token.WHILE, token.THROW, token.CATCH, token.FINALLY:
// Return only if parser made some progress since last
// sync or if it has not reached 10 next calls without
// progress. Otherwise consume at least one token to
// avoid an endless parser loop
if self.idx == self.recover.idx && self.recover.count < 10 {
self.recover.count++
return
}
if self.idx > self.recover.idx {
self.recover.idx = self.idx
self.recover.count = 0
return
}
// Reaching here indicates a parser bug, likely an
// incorrect token list in this function, but it only
// leads to skipping of possibly correct code if a
// previous error is present, and thus is preferred
// over a non-terminating parse.
case token.EOF:
return
}
self.next()
}
}