diff options
author | Wim <wim@42.be> | 2020-01-09 21:52:19 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-09 21:52:19 +0100 |
commit | 9d84d6dd643c4017074e81465671cd9b25f9539a (patch) | |
tree | 8a767f91d655a6cf21d476e4fb7aa6fd8a952df8 /vendor/github.com/d5/tengo/compiler/parser/parser.go | |
parent | 0f708daf2d14dcca261ef98cc698a1b1f2a6aa74 (diff) | |
download | matterbridge-msglm-9d84d6dd643c4017074e81465671cd9b25f9539a.tar.gz matterbridge-msglm-9d84d6dd643c4017074e81465671cd9b25f9539a.tar.bz2 matterbridge-msglm-9d84d6dd643c4017074e81465671cd9b25f9539a.zip |
Update to tengo v2 (#976)
Diffstat (limited to 'vendor/github.com/d5/tengo/compiler/parser/parser.go')
-rw-r--r-- | vendor/github.com/d5/tengo/compiler/parser/parser.go | 1216 |
1 files changed, 0 insertions, 1216 deletions
diff --git a/vendor/github.com/d5/tengo/compiler/parser/parser.go b/vendor/github.com/d5/tengo/compiler/parser/parser.go deleted file mode 100644 index 27dd48f0..00000000 --- a/vendor/github.com/d5/tengo/compiler/parser/parser.go +++ /dev/null @@ -1,1216 +0,0 @@ -/* - Parser parses the Tengo source files. - - Parser is a modified version of Go's parser implementation. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. -*/ - -package parser - -import ( - "fmt" - "io" - "strconv" - - "github.com/d5/tengo/compiler/ast" - "github.com/d5/tengo/compiler/scanner" - "github.com/d5/tengo/compiler/source" - "github.com/d5/tengo/compiler/token" -) - -type bailout struct{} - -// Parser parses the Tengo source files. -type Parser struct { - file *source.File - errors ErrorList - scanner *scanner.Scanner - pos source.Pos - token token.Token - tokenLit string - exprLevel int // < 0: in control clause, >= 0: in expression - syncPos source.Pos // last sync position - syncCount int // number of advance calls without progress - trace bool - indent int - traceOut io.Writer -} - -// NewParser creates a Parser. -func NewParser(file *source.File, src []byte, trace io.Writer) *Parser { - p := &Parser{ - file: file, - trace: trace != nil, - traceOut: trace, - } - - p.scanner = scanner.NewScanner(p.file, src, func(pos source.FilePos, msg string) { - p.errors.Add(pos, msg) - }, 0) - - p.next() - - return p -} - -// ParseFile parses the source and returns an AST file unit. -func (p *Parser) ParseFile() (file *ast.File, err error) { - defer func() { - if e := recover(); e != nil { - if _, ok := e.(bailout); !ok { - panic(e) - } - } - - p.errors.Sort() - err = p.errors.Err() - }() - - if p.trace { - defer un(trace(p, "File")) - } - - if p.errors.Len() > 0 { - return nil, p.errors.Err() - } - - stmts := p.parseStmtList() - if p.errors.Len() > 0 { - return nil, p.errors.Err() - } - - file = &ast.File{ - InputFile: p.file, - Stmts: stmts, - } - - return -} - -func (p *Parser) parseExpr() ast.Expr { - if p.trace { - defer un(trace(p, "Expression")) - } - - expr := p.parseBinaryExpr(token.LowestPrec + 1) - - // ternary conditional expression - if p.token == token.Question { - return p.parseCondExpr(expr) - } - - return expr -} - -func (p *Parser) parseBinaryExpr(prec1 int) ast.Expr { - if p.trace { - defer un(trace(p, "BinaryExpression")) - } - - x := p.parseUnaryExpr() - - for { - op, prec := p.token, p.token.Precedence() - if prec < prec1 { - return x - } - - pos := p.expect(op) - - y := p.parseBinaryExpr(prec + 1) - - x = &ast.BinaryExpr{ - LHS: x, - RHS: y, - Token: op, - TokenPos: pos, - } - } -} - -func (p *Parser) parseCondExpr(cond ast.Expr) ast.Expr { - questionPos := p.expect(token.Question) - - trueExpr := p.parseExpr() - - colonPos := p.expect(token.Colon) - - falseExpr := p.parseExpr() - - return &ast.CondExpr{ - Cond: cond, - True: trueExpr, - False: falseExpr, - QuestionPos: questionPos, - ColonPos: colonPos, - } -} - -func (p *Parser) parseUnaryExpr() ast.Expr { - if p.trace { - defer un(trace(p, "UnaryExpression")) - } - - switch p.token { - case token.Add, token.Sub, token.Not, token.Xor: - pos, op := p.pos, p.token - p.next() - x := p.parseUnaryExpr() - return &ast.UnaryExpr{ - Token: op, - TokenPos: pos, - Expr: x, - } - } - - return p.parsePrimaryExpr() -} - -func (p *Parser) parsePrimaryExpr() ast.Expr { - if p.trace { - defer un(trace(p, "PrimaryExpression")) - } - - x := p.parseOperand() - -L: - for { - switch p.token { - case token.Period: - p.next() - - switch p.token { - case token.Ident: - x = p.parseSelector(x) - default: - pos := p.pos - p.errorExpected(pos, "selector") - p.advance(stmtStart) - return &ast.BadExpr{From: pos, To: p.pos} - } - case token.LBrack: - x = p.parseIndexOrSlice(x) - case token.LParen: - x = p.parseCall(x) - default: - break L - } - } - - return x -} - -func (p *Parser) parseCall(x ast.Expr) *ast.CallExpr { - if p.trace { - defer un(trace(p, "Call")) - } - - lparen := p.expect(token.LParen) - p.exprLevel++ - - var list []ast.Expr - for p.token != token.RParen && p.token != token.EOF { - list = append(list, p.parseExpr()) - - if !p.expectComma(token.RParen, "call argument") { - break - } - } - - p.exprLevel-- - rparen := p.expect(token.RParen) - - return &ast.CallExpr{ - Func: x, - LParen: lparen, - RParen: rparen, - Args: list, - } -} - -func (p *Parser) expectComma(closing token.Token, want string) bool { - if p.token == token.Comma { - p.next() - - if p.token == closing { - p.errorExpected(p.pos, want) - return false - } - - return true - } - - if p.token == token.Semicolon && p.tokenLit == "\n" { - p.next() - } - - return false -} - -func (p *Parser) parseIndexOrSlice(x ast.Expr) ast.Expr { - if p.trace { - defer un(trace(p, "IndexOrSlice")) - } - - lbrack := p.expect(token.LBrack) - p.exprLevel++ - - var index [2]ast.Expr - if p.token != token.Colon { - index[0] = p.parseExpr() - } - numColons := 0 - if p.token == token.Colon { - numColons++ - p.next() - - if p.token != token.RBrack && p.token != token.EOF { - index[1] = p.parseExpr() - } - } - - p.exprLevel-- - rbrack := p.expect(token.RBrack) - - if numColons > 0 { - // slice expression - return &ast.SliceExpr{ - Expr: x, - LBrack: lbrack, - RBrack: rbrack, - Low: index[0], - High: index[1], - } - } - - return &ast.IndexExpr{ - Expr: x, - LBrack: lbrack, - RBrack: rbrack, - Index: index[0], - } -} - -func (p *Parser) parseSelector(x ast.Expr) ast.Expr { - if p.trace { - defer un(trace(p, "Selector")) - } - - sel := p.parseIdent() - - return &ast.SelectorExpr{Expr: x, Sel: &ast.StringLit{ - Value: sel.Name, - ValuePos: sel.NamePos, - Literal: sel.Name, - }} -} - -func (p *Parser) parseOperand() ast.Expr { - if p.trace { - defer un(trace(p, "Operand")) - } - - switch p.token { - case token.Ident: - return p.parseIdent() - - case token.Int: - v, _ := strconv.ParseInt(p.tokenLit, 10, 64) - x := &ast.IntLit{ - Value: v, - ValuePos: p.pos, - Literal: p.tokenLit, - } - p.next() - return x - - case token.Float: - v, _ := strconv.ParseFloat(p.tokenLit, 64) - x := &ast.FloatLit{ - Value: v, - ValuePos: p.pos, - Literal: p.tokenLit, - } - p.next() - return x - - case token.Char: - return p.parseCharLit() - - case token.String: - v, _ := strconv.Unquote(p.tokenLit) - x := &ast.StringLit{ - Value: v, - ValuePos: p.pos, - Literal: p.tokenLit, - } - p.next() - return x - - case token.True: - x := &ast.BoolLit{ - Value: true, - ValuePos: p.pos, - Literal: p.tokenLit, - } - p.next() - return x - - case token.False: - x := &ast.BoolLit{ - Value: false, - ValuePos: p.pos, - Literal: p.tokenLit, - } - p.next() - return x - - case token.Undefined: - x := &ast.UndefinedLit{TokenPos: p.pos} - p.next() - return x - - case token.Import: - return p.parseImportExpr() - - case token.LParen: - lparen := p.pos - p.next() - p.exprLevel++ - x := p.parseExpr() - p.exprLevel-- - rparen := p.expect(token.RParen) - return &ast.ParenExpr{ - LParen: lparen, - Expr: x, - RParen: rparen, - } - - case token.LBrack: // array literal - return p.parseArrayLit() - - case token.LBrace: // map literal - return p.parseMapLit() - - case token.Func: // function literal - return p.parseFuncLit() - - case token.Error: // error expression - return p.parseErrorExpr() - - case token.Immutable: // immutable expression - return p.parseImmutableExpr() - } - - pos := p.pos - p.errorExpected(pos, "operand") - p.advance(stmtStart) - return &ast.BadExpr{From: pos, To: p.pos} -} - -func (p *Parser) parseImportExpr() ast.Expr { - pos := p.pos - - p.next() - - p.expect(token.LParen) - - if p.token != token.String { - p.errorExpected(p.pos, "module name") - p.advance(stmtStart) - return &ast.BadExpr{From: pos, To: p.pos} - } - - // module name - moduleName, _ := strconv.Unquote(p.tokenLit) - - expr := &ast.ImportExpr{ - ModuleName: moduleName, - Token: token.Import, - TokenPos: pos, - } - - p.next() - - p.expect(token.RParen) - - return expr -} - -func (p *Parser) parseCharLit() ast.Expr { - if n := len(p.tokenLit); n >= 3 { - if code, _, _, err := strconv.UnquoteChar(p.tokenLit[1:n-1], '\''); err == nil { - x := &ast.CharLit{ - Value: rune(code), - ValuePos: p.pos, - Literal: p.tokenLit, - } - p.next() - return x - } - } - - pos := p.pos - p.error(pos, "illegal char literal") - p.next() - return &ast.BadExpr{ - From: pos, - To: p.pos, - } -} - -func (p *Parser) parseFuncLit() ast.Expr { - if p.trace { - defer un(trace(p, "FuncLit")) - } - - typ := p.parseFuncType() - - p.exprLevel++ - body := p.parseBody() - p.exprLevel-- - - return &ast.FuncLit{ - Type: typ, - Body: body, - } -} - -func (p *Parser) parseArrayLit() ast.Expr { - if p.trace { - defer un(trace(p, "ArrayLit")) - } - - lbrack := p.expect(token.LBrack) - p.exprLevel++ - - var elements []ast.Expr - for p.token != token.RBrack && p.token != token.EOF { - elements = append(elements, p.parseExpr()) - - if !p.expectComma(token.RBrack, "array element") { - break - } - } - - p.exprLevel-- - rbrack := p.expect(token.RBrack) - - return &ast.ArrayLit{ - Elements: elements, - LBrack: lbrack, - RBrack: rbrack, - } -} - -func (p *Parser) parseErrorExpr() ast.Expr { - pos := p.pos - - p.next() - - lparen := p.expect(token.LParen) - value := p.parseExpr() - rparen := p.expect(token.RParen) - - expr := &ast.ErrorExpr{ - ErrorPos: pos, - Expr: value, - LParen: lparen, - RParen: rparen, - } - - return expr -} - -func (p *Parser) parseImmutableExpr() ast.Expr { - pos := p.pos - - p.next() - - lparen := p.expect(token.LParen) - value := p.parseExpr() - rparen := p.expect(token.RParen) - - expr := &ast.ImmutableExpr{ - ErrorPos: pos, - Expr: value, - LParen: lparen, - RParen: rparen, - } - - return expr -} - -func (p *Parser) parseFuncType() *ast.FuncType { - if p.trace { - defer un(trace(p, "FuncType")) - } - - pos := p.expect(token.Func) - params := p.parseIdentList() - - return &ast.FuncType{ - FuncPos: pos, - Params: params, - } -} - -func (p *Parser) parseBody() *ast.BlockStmt { - if p.trace { - defer un(trace(p, "Body")) - } - - lbrace := p.expect(token.LBrace) - list := p.parseStmtList() - rbrace := p.expect(token.RBrace) - - return &ast.BlockStmt{ - LBrace: lbrace, - RBrace: rbrace, - Stmts: list, - } -} - -func (p *Parser) parseStmtList() (list []ast.Stmt) { - if p.trace { - defer un(trace(p, "StatementList")) - } - - for p.token != token.RBrace && p.token != token.EOF { - list = append(list, p.parseStmt()) - } - - return -} - -func (p *Parser) parseIdent() *ast.Ident { - pos := p.pos - name := "_" - - if p.token == token.Ident { - name = p.tokenLit - p.next() - } else { - p.expect(token.Ident) - } - - return &ast.Ident{ - NamePos: pos, - Name: name, - } -} - -func (p *Parser) parseIdentList() *ast.IdentList { - if p.trace { - defer un(trace(p, "IdentList")) - } - - var params []*ast.Ident - lparen := p.expect(token.LParen) - isVarArgs := false - if p.token != token.RParen { - if p.token == token.Ellipsis { - isVarArgs = true - p.next() - } - - params = append(params, p.parseIdent()) - for !isVarArgs && p.token == token.Comma { - p.next() - if p.token == token.Ellipsis { - isVarArgs = true - p.next() - } - params = append(params, p.parseIdent()) - } - } - - rparen := p.expect(token.RParen) - - return &ast.IdentList{ - LParen: lparen, - RParen: rparen, - VarArgs: isVarArgs, - List: params, - } -} - -func (p *Parser) parseStmt() (stmt ast.Stmt) { - if p.trace { - defer un(trace(p, "Statement")) - } - - switch p.token { - case // simple statements - token.Func, token.Error, token.Immutable, token.Ident, token.Int, token.Float, token.Char, token.String, token.True, token.False, - token.Undefined, token.Import, token.LParen, token.LBrace, token.LBrack, - token.Add, token.Sub, token.Mul, token.And, token.Xor, token.Not: - s := p.parseSimpleStmt(false) - p.expectSemi() - return s - case token.Return: - return p.parseReturnStmt() - case token.Export: - return p.parseExportStmt() - case token.If: - return p.parseIfStmt() - case token.For: - return p.parseForStmt() - case token.Break, token.Continue: - return p.parseBranchStmt(p.token) - case token.Semicolon: - s := &ast.EmptyStmt{Semicolon: p.pos, Implicit: p.tokenLit == "\n"} - p.next() - return s - case token.RBrace: - // semicolon may be omitted before a closing "}" - return &ast.EmptyStmt{Semicolon: p.pos, Implicit: true} - default: - pos := p.pos - p.errorExpected(pos, "statement") - p.advance(stmtStart) - return &ast.BadStmt{From: pos, To: p.pos} - } -} - -func (p *Parser) parseForStmt() ast.Stmt { - if p.trace { - defer un(trace(p, "ForStmt")) - } - - pos := p.expect(token.For) - - // for {} - if p.token == token.LBrace { - body := p.parseBlockStmt() - p.expectSemi() - - return &ast.ForStmt{ - ForPos: pos, - Body: body, - } - } - - prevLevel := p.exprLevel - p.exprLevel = -1 - - var s1 ast.Stmt - if p.token != token.Semicolon { // skipping init - s1 = p.parseSimpleStmt(true) - } - - // for _ in seq {} or - // for value in seq {} or - // for key, value in seq {} - if forInStmt, isForIn := s1.(*ast.ForInStmt); isForIn { - forInStmt.ForPos = pos - p.exprLevel = prevLevel - forInStmt.Body = p.parseBlockStmt() - p.expectSemi() - return forInStmt - } - - // for init; cond; post {} - var s2, s3 ast.Stmt - if p.token == token.Semicolon { - p.next() - if p.token != token.Semicolon { - s2 = p.parseSimpleStmt(false) // cond - } - p.expect(token.Semicolon) - if p.token != token.LBrace { - s3 = p.parseSimpleStmt(false) // post - } - } else { - // for cond {} - s2 = s1 - s1 = nil - } - - // body - p.exprLevel = prevLevel - body := p.parseBlockStmt() - p.expectSemi() - - cond := p.makeExpr(s2, "condition expression") - - return &ast.ForStmt{ - ForPos: pos, - Init: s1, - Cond: cond, - Post: s3, - Body: body, - } - -} - -func (p *Parser) parseBranchStmt(tok token.Token) ast.Stmt { - if p.trace { - defer un(trace(p, "BranchStmt")) - } - - pos := p.expect(tok) - - var label *ast.Ident - if p.token == token.Ident { - label = p.parseIdent() - } - p.expectSemi() - - return &ast.BranchStmt{ - Token: tok, - TokenPos: pos, - Label: label, - } -} - -func (p *Parser) parseIfStmt() ast.Stmt { - if p.trace { - defer un(trace(p, "IfStmt")) - } - - pos := p.expect(token.If) - - init, cond := p.parseIfHeader() - body := p.parseBlockStmt() - - var elseStmt ast.Stmt - if p.token == token.Else { - p.next() - - switch p.token { - case token.If: - elseStmt = p.parseIfStmt() - case token.LBrace: - elseStmt = p.parseBlockStmt() - p.expectSemi() - default: - p.errorExpected(p.pos, "if or {") - elseStmt = &ast.BadStmt{From: p.pos, To: p.pos} - } - } else { - p.expectSemi() - } - - return &ast.IfStmt{ - IfPos: pos, - Init: init, - Cond: cond, - Body: body, - Else: elseStmt, - } -} - -func (p *Parser) parseBlockStmt() *ast.BlockStmt { - if p.trace { - defer un(trace(p, "BlockStmt")) - } - - lbrace := p.expect(token.LBrace) - list := p.parseStmtList() - rbrace := p.expect(token.RBrace) - - return &ast.BlockStmt{ - LBrace: lbrace, - RBrace: rbrace, - Stmts: list, - } -} - -func (p *Parser) parseIfHeader() (init ast.Stmt, cond ast.Expr) { - if p.token == token.LBrace { - p.error(p.pos, "missing condition in if statement") - cond = &ast.BadExpr{From: p.pos, To: p.pos} - return - } - - outer := p.exprLevel - p.exprLevel = -1 - - if p.token == token.Semicolon { - p.error(p.pos, "missing init in if statement") - return - } - - init = p.parseSimpleStmt(false) - - var condStmt ast.Stmt - if p.token == token.LBrace { - condStmt = init - init = nil - } else if p.token == token.Semicolon { - p.next() - - condStmt = p.parseSimpleStmt(false) - } else { - p.error(p.pos, "missing condition in if statement") - } - - if condStmt != nil { - cond = p.makeExpr(condStmt, "boolean expression") - } - - if cond == nil { - cond = &ast.BadExpr{From: p.pos, To: p.pos} - } - - p.exprLevel = outer - - return -} - -func (p *Parser) makeExpr(s ast.Stmt, want string) ast.Expr { - if s == nil { - return nil - } - - if es, isExpr := s.(*ast.ExprStmt); isExpr { - return es.Expr - } - - found := "simple statement" - if _, isAss := s.(*ast.AssignStmt); isAss { - found = "assignment" - } - - p.error(s.Pos(), fmt.Sprintf("expected %s, found %s", want, found)) - - return &ast.BadExpr{From: s.Pos(), To: p.safePos(s.End())} -} - -func (p *Parser) parseReturnStmt() ast.Stmt { - if p.trace { - defer un(trace(p, "ReturnStmt")) - } - - pos := p.pos - p.expect(token.Return) - - var x ast.Expr - if p.token != token.Semicolon && p.token != token.RBrace { - x = p.parseExpr() - } - p.expectSemi() - - return &ast.ReturnStmt{ - ReturnPos: pos, - Result: x, - } -} - -func (p *Parser) parseExportStmt() ast.Stmt { - if p.trace { - defer un(trace(p, "ExportStmt")) - } - - pos := p.pos - p.expect(token.Export) - - x := p.parseExpr() - p.expectSemi() - - return &ast.ExportStmt{ - ExportPos: pos, - Result: x, - } -} - -func (p *Parser) parseSimpleStmt(forIn bool) ast.Stmt { - if p.trace { - defer un(trace(p, "SimpleStmt")) - } - - x := p.parseExprList() - - switch p.token { - case token.Assign, token.Define: // assignment statement - pos, tok := p.pos, p.token - p.next() - - y := p.parseExprList() - - return &ast.AssignStmt{ - LHS: x, - RHS: y, - Token: tok, - TokenPos: pos, - } - case token.In: - if forIn { - p.next() - - y := p.parseExpr() - - var key, value *ast.Ident - var ok bool - - switch len(x) { - case 1: - key = &ast.Ident{Name: "_", NamePos: x[0].Pos()} - - value, ok = x[0].(*ast.Ident) - if !ok { - p.errorExpected(x[0].Pos(), "identifier") - value = &ast.Ident{Name: "_", NamePos: x[0].Pos()} - } - case 2: - key, ok = x[0].(*ast.Ident) - if !ok { - p.errorExpected(x[0].Pos(), "identifier") - key = &ast.Ident{Name: "_", NamePos: x[0].Pos()} - } - value, ok = x[1].(*ast.Ident) - if !ok { - p.errorExpected(x[1].Pos(), "identifier") - value = &ast.Ident{Name: "_", NamePos: x[1].Pos()} - } - } - - return &ast.ForInStmt{ - Key: key, - Value: value, - Iterable: y, - } - } - } - - if len(x) > 1 { - p.errorExpected(x[0].Pos(), "1 expression") - // continue with first expression - } - - switch p.token { - case token.Define, - token.AddAssign, token.SubAssign, token.MulAssign, token.QuoAssign, token.RemAssign, - token.AndAssign, token.OrAssign, token.XorAssign, token.ShlAssign, token.ShrAssign, token.AndNotAssign: - pos, tok := p.pos, p.token - p.next() - - y := p.parseExpr() - - return &ast.AssignStmt{ - LHS: []ast.Expr{x[0]}, - RHS: []ast.Expr{y}, - Token: tok, - TokenPos: pos, - } - case token.Inc, token.Dec: - // increment or decrement statement - s := &ast.IncDecStmt{Expr: x[0], Token: p.token, TokenPos: p.pos} - p.next() - return s - } - - // expression statement - return &ast.ExprStmt{Expr: x[0]} -} - -func (p *Parser) parseExprList() (list []ast.Expr) { - if p.trace { - defer un(trace(p, "ExpressionList")) - } - - list = append(list, p.parseExpr()) - for p.token == token.Comma { - p.next() - list = append(list, p.parseExpr()) - } - - return -} - -func (p *Parser) parseMapElementLit() *ast.MapElementLit { - if p.trace { - defer un(trace(p, "MapElementLit")) - } - - pos := p.pos - name := "_" - - if p.token == token.Ident { - name = p.tokenLit - } else if p.token == token.String { - v, _ := strconv.Unquote(p.tokenLit) - name = v - } else { - p.errorExpected(pos, "map key") - } - - p.next() - - colonPos := p.expect(token.Colon) - valueExpr := p.parseExpr() - - return &ast.MapElementLit{ - Key: name, - KeyPos: pos, - ColonPos: colonPos, - Value: valueExpr, - } -} - -func (p *Parser) parseMapLit() *ast.MapLit { - if p.trace { - defer un(trace(p, "MapLit")) - } - - lbrace := p.expect(token.LBrace) - p.exprLevel++ - - var elements []*ast.MapElementLit - for p.token != token.RBrace && p.token != token.EOF { - elements = append(elements, p.parseMapElementLit()) - - if !p.expectComma(token.RBrace, "map element") { - break - } - } - - p.exprLevel-- - rbrace := p.expect(token.RBrace) - - return &ast.MapLit{ - LBrace: lbrace, - RBrace: rbrace, - Elements: elements, - } -} - -func (p *Parser) expect(token token.Token) source.Pos { - pos := p.pos - - if p.token != token { - p.errorExpected(pos, "'"+token.String()+"'") - } - p.next() - - return pos -} - -func (p *Parser) expectSemi() { - switch p.token { - case token.RParen, token.RBrace: - // semicolon is optional before a closing ')' or '}' - case token.Comma: - // permit a ',' instead of a ';' but complain - p.errorExpected(p.pos, "';'") - fallthrough - case token.Semicolon: - p.next() - default: - p.errorExpected(p.pos, "';'") - p.advance(stmtStart) - } - -} - -func (p *Parser) advance(to map[token.Token]bool) { - for ; p.token != token.EOF; p.next() { - if to[p.token] { - if p.pos == p.syncPos && p.syncCount < 10 { - p.syncCount++ - return - } - - if p.pos > p.syncPos { - p.syncPos = p.pos - p.syncCount = 0 - return - } - } - } -} - -func (p *Parser) error(pos source.Pos, msg string) { - filePos := p.file.Position(pos) - - n := len(p.errors) - if n > 0 && p.errors[n-1].Pos.Line == filePos.Line { - // discard errors reported on the same line - return - } - - if n > 10 { - // too many errors; terminate early - panic(bailout{}) - } - - p.errors.Add(filePos, msg) -} - -func (p *Parser) errorExpected(pos source.Pos, msg string) { - msg = "expected " + msg - if pos == p.pos { - // error happened at the current position: provide more specific - switch { - case p.token == token.Semicolon && p.tokenLit == "\n": - msg += ", found newline" - case p.token.IsLiteral(): - msg += ", found " + p.tokenLit - default: - msg += ", found '" + p.token.String() + "'" - } - } - - p.error(pos, msg) -} - -func (p *Parser) next() { - if p.trace && p.pos.IsValid() { - s := p.token.String() - switch { - case p.token.IsLiteral(): - p.printTrace(s, p.tokenLit) - case p.token.IsOperator(), p.token.IsKeyword(): - p.printTrace(`"` + s + `"`) - default: - p.printTrace(s) - } - } - - p.token, p.tokenLit, p.pos = p.scanner.Scan() -} - -func (p *Parser) printTrace(a ...interface{}) { - const ( - dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " - n = len(dots) - ) - - filePos := p.file.Position(p.pos) - _, _ = fmt.Fprintf(p.traceOut, "%5d: %5d:%3d: ", p.pos, filePos.Line, filePos.Column) - - i := 2 * p.indent - for i > n { - _, _ = fmt.Fprint(p.traceOut, dots) - i -= n - } - _, _ = fmt.Fprint(p.traceOut, dots[0:i]) - _, _ = fmt.Fprintln(p.traceOut, a...) -} - -func (p *Parser) safePos(pos source.Pos) source.Pos { - fileBase := p.file.Base - fileSize := p.file.Size - - if int(pos) < fileBase || int(pos) > fileBase+fileSize { - return source.Pos(fileBase + fileSize) - } - - return pos -} - -func trace(p *Parser, msg string) *Parser { - p.printTrace(msg, "(") - p.indent++ - - return p -} - -func un(p *Parser) { - p.indent-- - p.printTrace(")") -} |