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