// Copyright 2016 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 syntax import ( "fmt" "io" "strconv" "strings" ) const debug = false const trace = false type parser struct { file *PosBase errh ErrorHandler mode Mode pragh PragmaHandler scanner base *PosBase // current position base first error // first error encountered errcnt int // number of errors encountered pragma Pragma // pragmas fnest int // function nesting level (for error handling) xnest int // expression nesting level (for complit ambiguity resolution) indent []byte // tracing support } func (p *parser) init(file *PosBase, r io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) { p.file = file p.errh = errh p.mode = mode p.pragh = pragh p.scanner.init( r, // Error and directive handler for scanner. // Because the (line, col) positions passed to the // handler is always at or after the current reading // position, it is safe to use the most recent position // base to compute the corresponding Pos value. func(line, col uint, msg string) { if msg[0] != '/' { p.errorAt(p.posAt(line, col), msg) return } // otherwise it must be a comment containing a line or go: directive. // //line directives must be at the start of the line (column colbase). // /*line*/ directives can be anywhere in the line. text := commentText(msg) if (col == colbase || msg[1] == '*') && strings.HasPrefix(text, "line ") { var pos Pos // position immediately following the comment if msg[1] == '/' { // line comment (newline is part of the comment) pos = MakePos(p.file, line+1, colbase) } else { // regular comment // (if the comment spans multiple lines it's not // a valid line directive and will be discarded // by updateBase) pos = MakePos(p.file, line, col+uint(len(msg))) } p.updateBase(pos, line, col+2+5, text[5:]) // +2 to skip over // or /* return } // go: directive (but be conservative and test) if pragh != nil && strings.HasPrefix(text, "go:") { p.pragma = pragh(p.posAt(line, col+2), p.scanner.blank, text, p.pragma) // +2 to skip over // or /* } }, directives, ) p.base = file p.first = nil p.errcnt = 0 p.pragma = nil p.fnest = 0 p.xnest = 0 p.indent = nil } // takePragma returns the current parsed pragmas // and clears them from the parser state. func (p *parser) takePragma() Pragma { prag := p.pragma p.pragma = nil return prag } // clearPragma is called at the end of a statement or // other Go form that does NOT accept a pragma. // It sends the pragma back to the pragma handler // to be reported as unused. func (p *parser) clearPragma() { if p.pragma != nil { p.pragh(p.pos(), p.scanner.blank, "", p.pragma) p.pragma = nil } } // updateBase sets the current position base to a new line base at pos. // The base's filename, line, and column values are extracted from text // which is positioned at (tline, tcol) (only needed for error messages). func (p *parser) updateBase(pos Pos, tline, tcol uint, text string) { i, n, ok := trailingDigits(text) if i == 0 { return // ignore (not a line directive) } // i > 0 if !ok { // text has a suffix :xxx but xxx is not a number p.errorAt(p.posAt(tline, tcol+i), "invalid line number: "+text[i:]) return } var line, col uint i2, n2, ok2 := trailingDigits(text[:i-1]) if ok2 { //line filename:line:col i, i2 = i2, i line, col = n2, n if col == 0 || col > PosMax { p.errorAt(p.posAt(tline, tcol+i2), "invalid column number: "+text[i2:]) return } text = text[:i2-1] // lop off ":col" } else { //line filename:line line = n } if line == 0 || line > PosMax { p.errorAt(p.posAt(tline, tcol+i), "invalid line number: "+text[i:]) return } // If we have a column (//line filename:line:col form), // an empty filename means to use the previous filename. filename := text[:i-1] // lop off ":line" trimmed := false if filename == "" && ok2 { filename = p.base.Filename() trimmed = p.base.Trimmed() } p.base = NewLineBase(pos, filename, trimmed, line, col) } func commentText(s string) string { if s[:2] == "/*" { return s[2 : len(s)-2] // lop off /* and */ } // line comment (does not include newline) // (on Windows, the line comment may end in \r\n) i := len(s) if s[i-1] == '\r' { i-- } return s[2:i] // lop off //, and \r at end, if any } func trailingDigits(text string) (uint, uint, bool) { // Want to use LastIndexByte below but it's not defined in Go1.4 and bootstrap fails. i := strings.LastIndex(text, ":") // look from right (Windows filenames may contain ':') if i < 0 { return 0, 0, false // no ":" } // i >= 0 n, err := strconv.ParseUint(text[i+1:], 10, 0) return uint(i + 1), uint(n), err == nil } func (p *parser) got(tok token) bool { if p.tok == tok { p.next() return true } return false } func (p *parser) want(tok token) { if !p.got(tok) { p.syntaxError("expecting " + tokstring(tok)) p.advance() } } // gotAssign is like got(_Assign) but it also accepts ":=" // (and reports an error) for better parser error recovery. func (p *parser) gotAssign() bool { switch p.tok { case _Define: p.syntaxError("expecting =") fallthrough case _Assign: p.next() return true } return false } // ---------------------------------------------------------------------------- // Error handling // posAt returns the Pos value for (line, col) and the current position base. func (p *parser) posAt(line, col uint) Pos { return MakePos(p.base, line, col) } // error reports an error at the given position. func (p *parser) errorAt(pos Pos, msg string) { err := Error{pos, msg} if p.first == nil { p.first = err } p.errcnt++ if p.errh == nil { panic(p.first) } p.errh(err) } // syntaxErrorAt reports a syntax error at the given position. func (p *parser) syntaxErrorAt(pos Pos, msg string) { if trace { p.print("syntax error: " + msg) } if p.tok == _EOF && p.first != nil { return // avoid meaningless follow-up errors } // add punctuation etc. as needed to msg switch { case msg == "": // nothing to do case strings.HasPrefix(msg, "in "), strings.HasPrefix(msg, "at "), strings.HasPrefix(msg, "after "): msg = " " + msg case strings.HasPrefix(msg, "expecting "): msg = ", " + msg default: // plain error - we don't care about current token p.errorAt(pos, "syntax error: "+msg) return } // determine token string var tok string switch p.tok { case _Name, _Semi: tok = p.lit case _Literal: tok = "literal " + p.lit case _Operator: tok = p.op.String() case _AssignOp: tok = p.op.String() + "=" case _IncOp: tok = p.op.String() tok += tok default: tok = tokstring(p.tok) } p.errorAt(pos, "syntax error: unexpected "+tok+msg) } // tokstring returns the English word for selected punctuation tokens // for more readable error messages. func tokstring(tok token) string { switch tok { case _Comma: return "comma" case _Semi: return "semicolon or newline" } return tok.String() } // Convenience methods using the current token position. func (p *parser) pos() Pos { return p.posAt(p.line, p.col) } func (p *parser) error(msg string) { p.errorAt(p.pos(), msg) } func (p *parser) syntaxError(msg string) { p.syntaxErrorAt(p.pos(), msg) } // The stopset contains keywords that start a statement. // They are good synchronization points in case of syntax // errors and (usually) shouldn't be skipped over. const stopset uint64 = 1<<_Break | 1<<_Const | 1<<_Continue | 1<<_Defer | 1<<_Fallthrough | 1<<_For | 1<<_Go | 1<<_Goto | 1<<_If | 1<<_Return | 1<<_Select | 1<<_Switch | 1<<_Type | 1<<_Var // Advance consumes tokens until it finds a token of the stopset or followlist. // The stopset is only considered if we are inside a function (p.fnest > 0). // The followlist is the list of valid tokens that can follow a production; // if it is empty, exactly one (non-EOF) token is consumed to ensure progress. func (p *parser) advance(followlist ...token) { if trace { p.print(fmt.Sprintf("advance %s", followlist)) } // compute follow set // (not speed critical, advance is only called in error situations) var followset uint64 = 1 << _EOF // don't skip over EOF if len(followlist) > 0 { if p.fnest > 0 { followset |= stopset } for _, tok := range followlist { followset |= 1 << tok } } for !contains(followset, p.tok) { if trace { p.print("skip " + p.tok.String()) } p.next() if len(followlist) == 0 { break } } if trace { p.print("next " + p.tok.String()) } } // usage: defer p.trace(msg)() func (p *parser) trace(msg string) func() { p.print(msg + " (") const tab = ". " p.indent = append(p.indent, tab...) return func() { p.indent = p.indent[:len(p.indent)-len(tab)] if x := recover(); x != nil { panic(x) // skip print_trace } p.print(")") } } func (p *parser) print(msg string) { fmt.Printf("%5d: %s%s\n", p.line, p.indent, msg) } // ---------------------------------------------------------------------------- // Package files // // Parse methods are annotated with matching Go productions as appropriate. // The annotations are intended as guidelines only since a single Go grammar // rule may be covered by multiple parse methods and vice versa. // // Excluding methods returning slices, parse methods named xOrNil may return // nil; all others are expected to return a valid non-nil node. // SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } . func (p *parser) fileOrNil() *File { if trace { defer p.trace("file")() } f := new(File) f.pos = p.pos() // PackageClause if !p.got(_Package) { p.syntaxError("package statement must be first") return nil } f.Pragma = p.takePragma() f.PkgName = p.name() p.want(_Semi) // don't bother continuing if package clause has errors if p.first != nil { return nil } // { ImportDecl ";" } for p.got(_Import) { f.DeclList = p.appendGroup(f.DeclList, p.importDecl) p.want(_Semi) } // { TopLevelDecl ";" } for p.tok != _EOF { switch p.tok { case _Const: p.next() f.DeclList = p.appendGroup(f.DeclList, p.constDecl) case _Type: p.next() f.DeclList = p.appendGroup(f.DeclList, p.typeDecl) case _Var: p.next() f.DeclList = p.appendGroup(f.DeclList, p.varDecl) case _Func: p.next() if d := p.funcDeclOrNil(); d != nil { f.DeclList = append(f.DeclList, d) } default: if p.tok == _Lbrace && len(f.DeclList) > 0 && isEmptyFuncDecl(f.DeclList[len(f.DeclList)-1]) { // opening { of function declaration on next line p.syntaxError("unexpected semicolon or newline before {") } else { p.syntaxError("non-declaration statement outside function body") } p.advance(_Const, _Type, _Var, _Func) continue } // Reset p.pragma BEFORE advancing to the next token (consuming ';') // since comments before may set pragmas for the next function decl. p.clearPragma() if p.tok != _EOF && !p.got(_Semi) { p.syntaxError("after top level declaration") p.advance(_Const, _Type, _Var, _Func) } } // p.tok == _EOF p.clearPragma() f.EOF = p.pos() return f } func isEmptyFuncDecl(dcl Decl) bool { f, ok := dcl.(*FuncDecl) return ok && f.Body == nil } // ---------------------------------------------------------------------------- // Declarations // list parses a possibly empty, sep-separated list of elements, optionally // followed by sep, and closed by close (or EOF). sep must be one of _Comma // or _Semi, and close must be one of _Rparen, _Rbrace, or _Rbrack. // // For each list element, f is called. Specifically, unless we're at close // (or EOF), f is called at least once. After f returns true, no more list // elements are accepted. list returns the position of the closing token. // // list = [ f { sep f } [sep] ] close . // func (p *parser) list(sep, close token, f func() bool) Pos { if debug && (sep != _Comma && sep != _Semi || close != _Rparen && close != _Rbrace && close != _Rbrack) { panic("invalid sep or close argument for list") } done := false for p.tok != _EOF && p.tok != close && !done { done = f() // sep is optional before close if !p.got(sep) && p.tok != close { p.syntaxError(fmt.Sprintf("expecting %s or %s", tokstring(sep), tokstring(close))) p.advance(_Rparen, _Rbrack, _Rbrace) if p.tok != close { // position could be better but we had an error so we don't care return p.pos() } } } pos := p.pos() p.want(close) return pos } // appendGroup(f) = f | "(" { f ";" } ")" . // ";" is optional before ")" func (p *parser) appendGroup(list []Decl, f func(*Group) Decl) []Decl { if p.tok == _Lparen { g := new(Group) p.clearPragma() p.next() // must consume "(" after calling clearPragma! p.list(_Semi, _Rparen, func() bool { if x := f(g); x != nil { list = append(list, x) } return false }) } else { if x := f(nil); x != nil { list = append(list, x) } } return list } // ImportSpec = [ "." | PackageName ] ImportPath . // ImportPath = string_lit . func (p *parser) importDecl(group *Group) Decl { if trace { defer p.trace("importDecl")() } d := new(ImportDecl) d.pos = p.pos() d.Group = group d.Pragma = p.takePragma() switch p.tok { case _Name: d.LocalPkgName = p.name() case _Dot: d.LocalPkgName = NewName(p.pos(), ".") p.next() } d.Path = p.oliteral() if d.Path == nil { p.syntaxError("missing import path") p.advance(_Semi, _Rparen) return d } if !d.Path.Bad && d.Path.Kind != StringLit { p.syntaxError("import path must be a string") d.Path.Bad = true } // d.Path.Bad || d.Path.Kind == StringLit return d } // ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] . func (p *parser) constDecl(group *Group) Decl { if trace { defer p.trace("constDecl")() } d := new(ConstDecl) d.pos = p.pos() d.Group = group d.Pragma = p.takePragma() d.NameList = p.nameList(p.name()) if p.tok != _EOF && p.tok != _Semi && p.tok != _Rparen { d.Type = p.typeOrNil() if p.gotAssign() { d.Values = p.exprList() } } return d } // TypeSpec = identifier [ TypeParams ] [ "=" ] Type . func (p *parser) typeDecl(group *Group) Decl { if trace { defer p.trace("typeDecl")() } d := new(TypeDecl) d.pos = p.pos() d.Group = group d.Pragma = p.takePragma() d.Name = p.name() if p.tok == _Lbrack { // array/slice or generic type pos := p.pos() p.next() switch p.tok { case _Rbrack: p.next() d.Type = p.sliceType(pos) case _Name: // array or generic type p.xnest++ x := p.expr() p.xnest-- if name0, ok := x.(*Name); p.mode&AllowGenerics != 0 && ok && p.tok != _Rbrack { // generic type d.TParamList = p.paramList(name0, _Rbrack, true) pos := p.pos() if p.gotAssign() { p.syntaxErrorAt(pos, "generic type cannot be alias") } d.Type = p.typeOrNil() } else { // x is the array length expression if debug && x == nil { panic("length expression is nil") } d.Type = p.arrayType(pos, x) } default: d.Type = p.arrayType(pos, nil) } } else { d.Alias = p.gotAssign() d.Type = p.typeOrNil() } if d.Type == nil { d.Type = p.badExpr() p.syntaxError("in type declaration") p.advance(_Semi, _Rparen) } return d } // VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) . func (p *parser) varDecl(group *Group) Decl { if trace { defer p.trace("varDecl")() } d := new(VarDecl) d.pos = p.pos() d.Group = group d.Pragma = p.takePragma() d.NameList = p.nameList(p.name()) if p.gotAssign() { d.Values = p.exprList() } else { d.Type = p.type_() if p.gotAssign() { d.Values = p.exprList() } } return d } // FunctionDecl = "func" FunctionName [ TypeParams ] ( Function | Signature ) . // FunctionName = identifier . // Function = Signature FunctionBody . // MethodDecl = "func" Receiver MethodName ( Function | Signature ) . // Receiver = Parameters . func (p *parser) funcDeclOrNil() *FuncDecl { if trace { defer p.trace("funcDecl")() } f := new(FuncDecl) f.pos = p.pos() f.Pragma = p.takePragma() if p.got(_Lparen) { rcvr := p.paramList(nil, _Rparen, false) switch len(rcvr) { case 0: p.error("method has no receiver") default: p.error("method has multiple receivers") fallthrough case 1: f.Recv = rcvr[0] } } if p.tok != _Name { p.syntaxError("expecting name or (") p.advance(_Lbrace, _Semi) return nil } f.Name = p.name() if p.mode&AllowGenerics != 0 && p.got(_Lbrack) { if p.tok == _Rbrack { p.syntaxError("empty type parameter list") p.next() } else { f.TParamList = p.paramList(nil, _Rbrack, true) } } f.Type = p.funcType() if p.tok == _Lbrace { f.Body = p.funcBody() } return f } func (p *parser) funcBody() *BlockStmt { p.fnest++ errcnt := p.errcnt body := p.blockStmt("") p.fnest-- // Don't check branches if there were syntax errors in the function // as it may lead to spurious errors (e.g., see test/switch2.go) or // possibly crashes due to incomplete syntax trees. if p.mode&CheckBranches != 0 && errcnt == p.errcnt { checkBranches(body, p.errh) } return body } // ---------------------------------------------------------------------------- // Expressions func (p *parser) expr() Expr { if trace { defer p.trace("expr")() } return p.binaryExpr(0) } // Expression = UnaryExpr | Expression binary_op Expression . func (p *parser) binaryExpr(prec int) Expr { // don't trace binaryExpr - only leads to overly nested trace output x := p.unaryExpr() for (p.tok == _Operator || p.tok == _Star) && p.prec > prec { t := new(Operation) t.pos = p.pos() t.Op = p.op tprec := p.prec p.next() t.X = x t.Y = p.binaryExpr(tprec) x = t } return x } // UnaryExpr = PrimaryExpr | unary_op UnaryExpr . func (p *parser) unaryExpr() Expr { if trace { defer p.trace("unaryExpr")() } switch p.tok { case _Operator, _Star: switch p.op { case Mul, Add, Sub, Not, Xor: x := new(Operation) x.pos = p.pos() x.Op = p.op p.next() x.X = p.unaryExpr() return x case And: x := new(Operation) x.pos = p.pos() x.Op = And p.next() // unaryExpr may have returned a parenthesized composite literal // (see comment in operand) - remove parentheses if any x.X = unparen(p.unaryExpr()) return x } case _Arrow: // receive op (<-x) or receive-only channel (<-chan E) pos := p.pos() p.next() // If the next token is _Chan we still don't know if it is // a channel (<-chan int) or a receive op (<-chan int(ch)). // We only know once we have found the end of the unaryExpr. x := p.unaryExpr() // There are two cases: // // <-chan... => <-x is a channel type // <-x => <-x is a receive operation // // In the first case, <- must be re-associated with // the channel type parsed already: // // <-(chan E) => (<-chan E) // <-(chan<-E) => (<-chan (<-E)) if _, ok := x.(*ChanType); ok { // x is a channel type => re-associate <- dir := SendOnly t := x for dir == SendOnly { c, ok := t.(*ChanType) if !ok { break } dir = c.Dir if dir == RecvOnly { // t is type <-chan E but <-<-chan E is not permitted // (report same error as for "type _ <-<-chan E") p.syntaxError("unexpected <-, expecting chan") // already progressed, no need to advance } c.Dir = RecvOnly t = c.Elem } if dir == SendOnly { // channel dir is <- but channel element E is not a channel // (report same error as for "type _ <-chan<-E") p.syntaxError(fmt.Sprintf("unexpected %s, expecting chan", String(t))) // already progressed, no need to advance } return x } // x is not a channel type => we have a receive op o := new(Operation) o.pos = pos o.Op = Recv o.X = x return o } // TODO(mdempsky): We need parens here so we can report an // error for "(x) := true". It should be possible to detect // and reject that more efficiently though. return p.pexpr(true) } // callStmt parses call-like statements that can be preceded by 'defer' and 'go'. func (p *parser) callStmt() *CallStmt { if trace { defer p.trace("callStmt")() } s := new(CallStmt) s.pos = p.pos() s.Tok = p.tok // _Defer or _Go p.next() x := p.pexpr(p.tok == _Lparen) // keep_parens so we can report error below if t := unparen(x); t != x { p.errorAt(x.Pos(), fmt.Sprintf("expression in %s must not be parenthesized", s.Tok)) // already progressed, no need to advance x = t } cx, ok := x.(*CallExpr) if !ok { p.errorAt(x.Pos(), fmt.Sprintf("expression in %s must be function call", s.Tok)) // already progressed, no need to advance cx = new(CallExpr) cx.pos = x.Pos() cx.Fun = x // assume common error of missing parentheses (function invocation) } s.Call = cx return s } // Operand = Literal | OperandName | MethodExpr | "(" Expression ")" . // Literal = BasicLit | CompositeLit | FunctionLit . // BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit . // OperandName = identifier | QualifiedIdent. func (p *parser) operand(keep_parens bool) Expr { if trace { defer p.trace("operand " + p.tok.String())() } switch p.tok { case _Name: return p.name() case _Literal: return p.oliteral() case _Lparen: pos := p.pos() p.next() p.xnest++ x := p.expr() p.xnest-- p.want(_Rparen) // Optimization: Record presence of ()'s only where needed // for error reporting. Don't bother in other cases; it is // just a waste of memory and time. // // Parentheses are not permitted around T in a composite // literal T{}. If the next token is a {, assume x is a // composite literal type T (it may not be, { could be // the opening brace of a block, but we don't know yet). if p.tok == _Lbrace { keep_parens = true } // Parentheses are also not permitted around the expression // in a go/defer statement. In that case, operand is called // with keep_parens set. if keep_parens { px := new(ParenExpr) px.pos = pos px.X = x x = px } return x case _Func: pos := p.pos() p.next() ftyp := p.funcType() if p.tok == _Lbrace { p.xnest++ f := new(FuncLit) f.pos = pos f.Type = ftyp f.Body = p.funcBody() p.xnest-- return f } return ftyp case _Lbrack, _Chan, _Map, _Struct, _Interface: return p.type_() // othertype default: x := p.badExpr() p.syntaxError("expecting expression") p.advance(_Rparen, _Rbrack, _Rbrace) return x } // Syntactically, composite literals are operands. Because a complit // type may be a qualified identifier which is handled by pexpr // (together with selector expressions), complits are parsed there // as well (operand is only called from pexpr). } // PrimaryExpr = // Operand | // Conversion | // PrimaryExpr Selector | // PrimaryExpr Index | // PrimaryExpr Slice | // PrimaryExpr TypeAssertion | // PrimaryExpr Arguments . // // Selector = "." identifier . // Index = "[" Expression "]" . // Slice = "[" ( [ Expression ] ":" [ Expression ] ) | // ( [ Expression ] ":" Expression ":" Expression ) // "]" . // TypeAssertion = "." "(" Type ")" . // Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" . func (p *parser) pexpr(keep_parens bool) Expr { if trace { defer p.trace("pexpr")() } x := p.operand(keep_parens) loop: for { pos := p.pos() switch p.tok { case _Dot: p.next() switch p.tok { case _Name: // pexpr '.' sym t := new(SelectorExpr) t.pos = pos t.X = x t.Sel = p.name() x = t case _Lparen: p.next() if p.got(_Type) { t := new(TypeSwitchGuard) // t.Lhs is filled in by parser.simpleStmt t.pos = pos t.X = x x = t } else { t := new(AssertExpr) t.pos = pos t.X = x t.Type = p.type_() x = t } p.want(_Rparen) default: p.syntaxError("expecting name or (") p.advance(_Semi, _Rparen) } case _Lbrack: p.next() if p.tok == _Rbrack { // invalid empty instance, slice or index expression; accept but complain p.syntaxError("expecting operand") p.next() break } var i Expr if p.tok != _Colon { if p.mode&AllowGenerics == 0 { p.xnest++ i = p.expr() p.xnest-- if p.got(_Rbrack) { // x[i] t := new(IndexExpr) t.pos = pos t.X = x t.Index = i x = t break } } else { var comma bool i, comma = p.typeList() if comma || p.tok == _Rbrack { p.want(_Rbrack) // x[i,] or x[i, j, ...] t := new(IndexExpr) t.pos = pos t.X = x t.Index = i x = t break } } } // x[i:... // For better error message, don't simply use p.want(_Colon) here (issue #47704). if !p.got(_Colon) { if p.mode&AllowGenerics == 0 { p.syntaxError("expecting : or ]") p.advance(_Colon, _Rbrack) } else { p.syntaxError("expecting comma, : or ]") p.advance(_Comma, _Colon, _Rbrack) } } p.xnest++ t := new(SliceExpr) t.pos = pos t.X = x t.Index[0] = i if p.tok != _Colon && p.tok != _Rbrack { // x[i:j... t.Index[1] = p.expr() } if p.tok == _Colon { t.Full = true // x[i:j:...] if t.Index[1] == nil { p.error("middle index required in 3-index slice") t.Index[1] = p.badExpr() } p.next() if p.tok != _Rbrack { // x[i:j:k... t.Index[2] = p.expr() } else { p.error("final index required in 3-index slice") t.Index[2] = p.badExpr() } } p.xnest-- p.want(_Rbrack) x = t case _Lparen: t := new(CallExpr) t.pos = pos p.next() t.Fun = x t.ArgList, t.HasDots = p.argList() x = t case _Lbrace: // operand may have returned a parenthesized complit // type; accept it but complain if we have a complit t := unparen(x) // determine if '{' belongs to a composite literal or a block statement complit_ok := false switch t.(type) { case *Name, *SelectorExpr: if p.xnest >= 0 { // x is possibly a composite literal type complit_ok = true } case *IndexExpr: if p.xnest >= 0 && !isValue(t) { // x is possibly a composite literal type complit_ok = true } case *ArrayType, *SliceType, *StructType, *MapType: // x is a comptype complit_ok = true } if !complit_ok { break loop } if t != x { p.syntaxError("cannot parenthesize type in composite literal") // already progressed, no need to advance } n := p.complitexpr() n.Type = x x = n default: break loop } } return x } // isValue reports whether x syntactically must be a value (and not a type) expression. func isValue(x Expr) bool { switch x := x.(type) { case *BasicLit, *CompositeLit, *FuncLit, *SliceExpr, *AssertExpr, *TypeSwitchGuard, *CallExpr: return true case *Operation: return x.Op != Mul || x.Y != nil // *T may be a type case *ParenExpr: return isValue(x.X) case *IndexExpr: return isValue(x.X) || isValue(x.Index) } return false } // Element = Expression | LiteralValue . func (p *parser) bare_complitexpr() Expr { if trace { defer p.trace("bare_complitexpr")() } if p.tok == _Lbrace { // '{' start_complit braced_keyval_list '}' return p.complitexpr() } return p.expr() } // LiteralValue = "{" [ ElementList [ "," ] ] "}" . func (p *parser) complitexpr() *CompositeLit { if trace { defer p.trace("complitexpr")() } x := new(CompositeLit) x.pos = p.pos() p.xnest++ p.want(_Lbrace) x.Rbrace = p.list(_Comma, _Rbrace, func() bool { // value e := p.bare_complitexpr() if p.tok == _Colon { // key ':' value l := new(KeyValueExpr) l.pos = p.pos() p.next() l.Key = e l.Value = p.bare_complitexpr() e = l x.NKeys++ } x.ElemList = append(x.ElemList, e) return false }) p.xnest-- return x } // ---------------------------------------------------------------------------- // Types func (p *parser) type_() Expr { if trace { defer p.trace("type_")() } typ := p.typeOrNil() if typ == nil { typ = p.badExpr() p.syntaxError("expecting type") p.advance(_Comma, _Colon, _Semi, _Rparen, _Rbrack, _Rbrace) } return typ } func newIndirect(pos Pos, typ Expr) Expr { o := new(Operation) o.pos = pos o.Op = Mul o.X = typ return o } // typeOrNil is like type_ but it returns nil if there was no type // instead of reporting an error. // // Type = TypeName | TypeLit | "(" Type ")" . // TypeName = identifier | QualifiedIdent . // TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType | // SliceType | MapType | Channel_Type . func (p *parser) typeOrNil() Expr { if trace { defer p.trace("typeOrNil")() } pos := p.pos() switch p.tok { case _Star: // ptrtype p.next() return newIndirect(pos, p.type_()) case _Arrow: // recvchantype p.next() p.want(_Chan) t := new(ChanType) t.pos = pos t.Dir = RecvOnly t.Elem = p.chanElem() return t case _Func: // fntype p.next() return p.funcType() case _Lbrack: // '[' oexpr ']' ntype // '[' _DotDotDot ']' ntype p.next() if p.got(_Rbrack) { return p.sliceType(pos) } return p.arrayType(pos, nil) case _Chan: // _Chan non_recvchantype // _Chan _Comm ntype p.next() t := new(ChanType) t.pos = pos if p.got(_Arrow) { t.Dir = SendOnly } t.Elem = p.chanElem() return t case _Map: // _Map '[' ntype ']' ntype p.next() p.want(_Lbrack) t := new(MapType) t.pos = pos t.Key = p.type_() p.want(_Rbrack) t.Value = p.type_() return t case _Struct: return p.structType() case _Interface: return p.interfaceType() case _Name: return p.qualifiedName(nil) case _Lparen: p.next() t := p.type_() p.want(_Rparen) return t } return nil } func (p *parser) typeInstance(typ Expr) Expr { if trace { defer p.trace("typeInstance")() } pos := p.pos() p.want(_Lbrack) x := new(IndexExpr) x.pos = pos x.X = typ if p.tok == _Rbrack { p.syntaxError("expecting type") x.Index = p.badExpr() } else { x.Index, _ = p.typeList() } p.want(_Rbrack) return x } func (p *parser) funcType() *FuncType { if trace { defer p.trace("funcType")() } typ := new(FuncType) typ.pos = p.pos() p.want(_Lparen) typ.ParamList = p.paramList(nil, _Rparen, false) typ.ResultList = p.funcResult() return typ } // "[" has already been consumed, and pos is its position. // If len != nil it is the already consumed array length. func (p *parser) arrayType(pos Pos, len Expr) Expr { if trace { defer p.trace("arrayType")() } if len == nil && !p.got(_DotDotDot) { p.xnest++ len = p.expr() p.xnest-- } p.want(_Rbrack) t := new(ArrayType) t.pos = pos t.Len = len t.Elem = p.type_() return t } // "[" and "]" have already been consumed, and pos is the position of "[". func (p *parser) sliceType(pos Pos) Expr { t := new(SliceType) t.pos = pos t.Elem = p.type_() return t } func (p *parser) chanElem() Expr { if trace { defer p.trace("chanElem")() } typ := p.typeOrNil() if typ == nil { typ = p.badExpr() p.syntaxError("missing channel element type") // assume element type is simply absent - don't advance } return typ } // StructType = "struct" "{" { FieldDecl ";" } "}" . func (p *parser) structType() *StructType { if trace { defer p.trace("structType")() } typ := new(StructType) typ.pos = p.pos() p.want(_Struct) p.want(_Lbrace) p.list(_Semi, _Rbrace, func() bool { p.fieldDecl(typ) return false }) return typ } // InterfaceType = "interface" "{" { ( MethodDecl | EmbeddedElem | TypeList ) ";" } "}" . // TypeList = "type" Type { "," Type } . // TODO(gri) remove TypeList syntax if we accept #45346 func (p *parser) interfaceType() *InterfaceType { if trace { defer p.trace("interfaceType")() } typ := new(InterfaceType) typ.pos = p.pos() p.want(_Interface) p.want(_Lbrace) p.list(_Semi, _Rbrace, func() bool { switch p.tok { case _Name: f := p.methodDecl() if f.Name == nil && p.mode&AllowGenerics != 0 { f = p.embeddedElem(f) } typ.MethodList = append(typ.MethodList, f) return false case _Lparen: // TODO(gri) Need to decide how to adjust this restriction. p.syntaxError("cannot parenthesize embedded type") f := new(Field) f.pos = p.pos() p.next() f.Type = p.qualifiedName(nil) p.want(_Rparen) typ.MethodList = append(typ.MethodList, f) return false case _Operator: if p.op == Tilde && p.mode&AllowGenerics != 0 { typ.MethodList = append(typ.MethodList, p.embeddedElem(nil)) return false } case _Type: // TODO(gri) remove TypeList syntax if we accept #45346 if p.mode&AllowGenerics != 0 { type_ := NewName(p.pos(), "type") // cannot have a method named "type" p.next() if p.tok != _Semi && p.tok != _Rbrace { f := new(Field) f.pos = p.pos() f.Name = type_ f.Type = p.type_() typ.MethodList = append(typ.MethodList, f) for p.got(_Comma) { f := new(Field) f.pos = p.pos() f.Name = type_ f.Type = p.type_() typ.MethodList = append(typ.MethodList, f) } } else { p.syntaxError("expecting type") } return false } default: if p.mode&AllowGenerics != 0 { pos := p.pos() if t := p.typeOrNil(); t != nil { f := new(Field) f.pos = pos f.Type = t typ.MethodList = append(typ.MethodList, p.embeddedElem(f)) return false } } } if p.mode&AllowGenerics != 0 { p.syntaxError("expecting method, type list, or embedded element") p.advance(_Semi, _Rbrace, _Type) // TODO(gri) remove _Type if we don't accept it anymore return false } p.syntaxError("expecting method or interface name") p.advance(_Semi, _Rbrace) return false }) return typ } // Result = Parameters | Type . func (p *parser) funcResult() []*Field { if trace { defer p.trace("funcResult")() } if p.got(_Lparen) { return p.paramList(nil, _Rparen, false) } pos := p.pos() if typ := p.typeOrNil(); typ != nil { f := new(Field) f.pos = pos f.Type = typ return []*Field{f} } return nil } func (p *parser) addField(styp *StructType, pos Pos, name *Name, typ Expr, tag *BasicLit) { if tag != nil { for i := len(styp.FieldList) - len(styp.TagList); i > 0; i-- { styp.TagList = append(styp.TagList, nil) } styp.TagList = append(styp.TagList, tag) } f := new(Field) f.pos = pos f.Name = name f.Type = typ styp.FieldList = append(styp.FieldList, f) if debug && tag != nil && len(styp.FieldList) != len(styp.TagList) { panic("inconsistent struct field list") } } // FieldDecl = (IdentifierList Type | AnonymousField) [ Tag ] . // AnonymousField = [ "*" ] TypeName . // Tag = string_lit . func (p *parser) fieldDecl(styp *StructType) { if trace { defer p.trace("fieldDecl")() } pos := p.pos() switch p.tok { case _Name: name := p.name() if p.tok == _Dot || p.tok == _Literal || p.tok == _Semi || p.tok == _Rbrace { // embedded type typ := p.qualifiedName(name) tag := p.oliteral() p.addField(styp, pos, nil, typ, tag) break } // name1, name2, ... Type [ tag ] names := p.nameList(name) var typ Expr // Careful dance: We don't know if we have an embedded instantiated // type T[P1, P2, ...] or a field T of array/slice type [P]E or []E. if p.mode&AllowGenerics != 0 && len(names) == 1 && p.tok == _Lbrack { typ = p.arrayOrTArgs() if typ, ok := typ.(*IndexExpr); ok { // embedded type T[P1, P2, ...] typ.X = name // name == names[0] tag := p.oliteral() p.addField(styp, pos, nil, typ, tag) break } } else { // T P typ = p.type_() } tag := p.oliteral() for _, name := range names { p.addField(styp, name.Pos(), name, typ, tag) } case _Star: p.next() var typ Expr if p.tok == _Lparen { // *(T) p.syntaxError("cannot parenthesize embedded type") p.next() typ = p.qualifiedName(nil) p.got(_Rparen) // no need to complain if missing } else { // *T typ = p.qualifiedName(nil) } tag := p.oliteral() p.addField(styp, pos, nil, newIndirect(pos, typ), tag) case _Lparen: p.syntaxError("cannot parenthesize embedded type") p.next() var typ Expr if p.tok == _Star { // (*T) pos := p.pos() p.next() typ = newIndirect(pos, p.qualifiedName(nil)) } else { // (T) typ = p.qualifiedName(nil) } p.got(_Rparen) // no need to complain if missing tag := p.oliteral() p.addField(styp, pos, nil, typ, tag) default: p.syntaxError("expecting field name or embedded type") p.advance(_Semi, _Rbrace) } } func (p *parser) arrayOrTArgs() Expr { if trace { defer p.trace("arrayOrTArgs")() } pos := p.pos() p.want(_Lbrack) if p.got(_Rbrack) { return p.sliceType(pos) } // x [n]E or x[n,], x[n1, n2], ... n, comma := p.typeList() p.want(_Rbrack) if !comma { if elem := p.typeOrNil(); elem != nil { // x [n]E t := new(ArrayType) t.pos = pos t.Len = n t.Elem = elem return t } } // x[n,], x[n1, n2], ... t := new(IndexExpr) t.pos = pos // t.X will be filled in by caller t.Index = n return t } func (p *parser) oliteral() *BasicLit { if p.tok == _Literal { b := new(BasicLit) b.pos = p.pos() b.Value = p.lit b.Kind = p.kind b.Bad = p.bad p.next() return b } return nil } // MethodSpec = MethodName Signature | InterfaceTypeName . // MethodName = identifier . // InterfaceTypeName = TypeName . func (p *parser) methodDecl() *Field { if trace { defer p.trace("methodDecl")() } f := new(Field) f.pos = p.pos() name := p.name() // accept potential name list but complain // TODO(gri) We probably don't need this special check anymore. // Nobody writes this kind of code. It's from ancient // Go beginnings. hasNameList := false for p.got(_Comma) { p.name() hasNameList = true } if hasNameList { p.syntaxError("name list not allowed in interface type") // already progressed, no need to advance } switch p.tok { case _Lparen: // method f.Name = name f.Type = p.funcType() case _Lbrack: if p.mode&AllowGenerics != 0 { // Careful dance: We don't know if we have a generic method m[T C](x T) // or an embedded instantiated type T[P1, P2] (we accept generic methods // for generality and robustness of parsing). pos := p.pos() p.next() // Empty type parameter or argument lists are not permitted. // Treat as if [] were absent. if p.tok == _Rbrack { // name[] pos := p.pos() p.next() if p.tok == _Lparen { // name[]( p.errorAt(pos, "empty type parameter list") f.Name = name f.Type = p.funcType() } else { p.errorAt(pos, "empty type argument list") f.Type = name } break } // A type argument list looks like a parameter list with only // types. Parse a parameter list and decide afterwards. list := p.paramList(nil, _Rbrack, false) if len(list) == 0 { // The type parameter list is not [] but we got nothing // due to other errors (reported by paramList). Treat // as if [] were absent. if p.tok == _Lparen { f.Name = name f.Type = p.funcType() } else { f.Type = name } break } // len(list) > 0 if list[0].Name != nil { // generic method f.Name = name f.Type = p.funcType() // TODO(gri) Record list as type parameter list with f.Type // if we want to type-check the generic method. // For now, report an error so this is not a silent event. p.errorAt(pos, "interface method cannot have type parameters") break } // embedded instantiated type t := new(IndexExpr) t.pos = pos t.X = name if len(list) == 1 { t.Index = list[0].Type } else { // len(list) > 1 l := new(ListExpr) l.pos = list[0].Pos() l.ElemList = make([]Expr, len(list)) for i := range list { l.ElemList[i] = list[i].Type } t.Index = l } f.Type = t break } fallthrough default: // embedded type f.Type = p.qualifiedName(name) } return f } // EmbeddedElem = MethodSpec | EmbeddedTerm { "|" EmbeddedTerm } . func (p *parser) embeddedElem(f *Field) *Field { if trace { defer p.trace("embeddedElem")() } if f == nil { f = new(Field) f.pos = p.pos() f.Type = p.embeddedTerm() } for p.tok == _Operator && p.op == Or { t := new(Operation) t.pos = p.pos() t.Op = Or p.next() t.X = f.Type t.Y = p.embeddedTerm() f.Type = t } return f } // EmbeddedTerm = [ "~" ] Type . func (p *parser) embeddedTerm() Expr { if trace { defer p.trace("embeddedTerm")() } if p.tok == _Operator && p.op == Tilde { t := new(Operation) t.pos = p.pos() t.Op = Tilde p.next() t.X = p.type_() return t } t := p.typeOrNil() if t == nil { t = p.badExpr() p.syntaxError("expecting ~ term or type") p.advance(_Operator, _Semi, _Rparen, _Rbrack, _Rbrace) } return t } // ParameterDecl = [ IdentifierList ] [ "..." ] Type . func (p *parser) paramDeclOrNil(name *Name) *Field { if trace { defer p.trace("paramDecl")() } f := new(Field) if name != nil { f.pos = name.pos } else { f.pos = p.pos() } if p.tok == _Name || name != nil { if name == nil { name = p.name() } if p.mode&AllowGenerics != 0 && p.tok == _Lbrack { f.Type = p.arrayOrTArgs() if typ, ok := f.Type.(*IndexExpr); ok { typ.X = name } else { f.Name = name } return f } if p.tok == _Dot { // name_or_type f.Type = p.qualifiedName(name) return f } f.Name = name } if p.tok == _DotDotDot { t := new(DotsType) t.pos = p.pos() p.next() t.Elem = p.typeOrNil() if t.Elem == nil { t.Elem = p.badExpr() p.syntaxError("... is missing type") } f.Type = t return f } f.Type = p.typeOrNil() if f.Name != nil || f.Type != nil { return f } p.syntaxError("expecting )") p.advance(_Comma, _Rparen) return nil } // Parameters = "(" [ ParameterList [ "," ] ] ")" . // ParameterList = ParameterDecl { "," ParameterDecl } . // "(" or "[" has already been consumed. // If name != nil, it is the first name after "(" or "[". // In the result list, either all fields have a name, or no field has a name. func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*Field) { if trace { defer p.trace("paramList")() } var named int // number of parameters that have an explicit name and type/bound p.list(_Comma, close, func() bool { par := p.paramDeclOrNil(name) name = nil // 1st name was consumed if present if par != nil { if debug && par.Name == nil && par.Type == nil { panic("parameter without name or type") } if par.Name != nil && par.Type != nil { named++ } list = append(list, par) } return false }) if len(list) == 0 { return } // distribute parameter types (len(list) > 0) if named == 0 { // all unnamed => found names are named types for _, par := range list { if typ := par.Name; typ != nil { par.Type = typ par.Name = nil } } if requireNames { p.syntaxErrorAt(list[0].Type.Pos(), "type parameters must be named") } } else if named != len(list) { // some named => all must have names and types var pos Pos // left-most error position (or unknown) var typ Expr for i := len(list) - 1; i >= 0; i-- { if par := list[i]; par.Type != nil { typ = par.Type if par.Name == nil { pos = typ.Pos() par.Name = NewName(pos, "_") } } else if typ != nil { par.Type = typ } else { // par.Type == nil && typ == nil => we only have a par.Name pos = par.Name.Pos() t := p.badExpr() t.pos = pos // correct position par.Type = t } } if pos.IsKnown() { var msg string if requireNames { msg = "type parameters must be named" } else { msg = "mixed named and unnamed parameters" } p.syntaxErrorAt(pos, msg) } } return } func (p *parser) badExpr() *BadExpr { b := new(BadExpr) b.pos = p.pos() return b } // ---------------------------------------------------------------------------- // Statements // SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl . func (p *parser) simpleStmt(lhs Expr, keyword token) SimpleStmt { if trace { defer p.trace("simpleStmt")() } if keyword == _For && p.tok == _Range { // _Range expr if debug && lhs != nil { panic("invalid call of simpleStmt") } return p.newRangeClause(nil, false) } if lhs == nil { lhs = p.exprList() } if _, ok := lhs.(*ListExpr); !ok && p.tok != _Assign && p.tok != _Define { // expr pos := p.pos() switch p.tok { case _AssignOp: // lhs op= rhs op := p.op p.next() return p.newAssignStmt(pos, op, lhs, p.expr()) case _IncOp: // lhs++ or lhs-- op := p.op p.next() return p.newAssignStmt(pos, op, lhs, nil) case _Arrow: // lhs <- rhs s := new(SendStmt) s.pos = pos p.next() s.Chan = lhs s.Value = p.expr() return s default: // expr s := new(ExprStmt) s.pos = lhs.Pos() s.X = lhs return s } } // expr_list switch p.tok { case _Assign, _Define: pos := p.pos() var op Operator if p.tok == _Define { op = Def } p.next() if keyword == _For && p.tok == _Range { // expr_list op= _Range expr return p.newRangeClause(lhs, op == Def) } // expr_list op= expr_list rhs := p.exprList() if x, ok := rhs.(*TypeSwitchGuard); ok && keyword == _Switch && op == Def { if lhs, ok := lhs.(*Name); ok { // switch … lhs := rhs.(type) x.Lhs = lhs s := new(ExprStmt) s.pos = x.Pos() s.X = x return s } } return p.newAssignStmt(pos, op, lhs, rhs) default: p.syntaxError("expecting := or = or comma") p.advance(_Semi, _Rbrace) // make the best of what we have if x, ok := lhs.(*ListExpr); ok { lhs = x.ElemList[0] } s := new(ExprStmt) s.pos = lhs.Pos() s.X = lhs return s } } func (p *parser) newRangeClause(lhs Expr, def bool) *RangeClause { r := new(RangeClause) r.pos = p.pos() p.next() // consume _Range r.Lhs = lhs r.Def = def r.X = p.expr() return r } func (p *parser) newAssignStmt(pos Pos, op Operator, lhs, rhs Expr) *AssignStmt { a := new(AssignStmt) a.pos = pos a.Op = op a.Lhs = lhs a.Rhs = rhs return a } func (p *parser) labeledStmtOrNil(label *Name) Stmt { if trace { defer p.trace("labeledStmt")() } s := new(LabeledStmt) s.pos = p.pos() s.Label = label p.want(_Colon) if p.tok == _Rbrace { // We expect a statement (incl. an empty statement), which must be // terminated by a semicolon. Because semicolons may be omitted before // an _Rbrace, seeing an _Rbrace implies an empty statement. e := new(EmptyStmt) e.pos = p.pos() s.Stmt = e return s } s.Stmt = p.stmtOrNil() if s.Stmt != nil { return s } // report error at line of ':' token p.syntaxErrorAt(s.pos, "missing statement after label") // we are already at the end of the labeled statement - no need to advance return nil // avoids follow-on errors (see e.g., fixedbugs/bug274.go) } // context must be a non-empty string unless we know that p.tok == _Lbrace. func (p *parser) blockStmt(context string) *BlockStmt { if trace { defer p.trace("blockStmt")() } s := new(BlockStmt) s.pos = p.pos() // people coming from C may forget that braces are mandatory in Go if !p.got(_Lbrace) { p.syntaxError("expecting { after " + context) p.advance(_Name, _Rbrace) s.Rbrace = p.pos() // in case we found "}" if p.got(_Rbrace) { return s } } s.List = p.stmtList() s.Rbrace = p.pos() p.want(_Rbrace) return s } func (p *parser) declStmt(f func(*Group) Decl) *DeclStmt { if trace { defer p.trace("declStmt")() } s := new(DeclStmt) s.pos = p.pos() p.next() // _Const, _Type, or _Var s.DeclList = p.appendGroup(nil, f) return s } func (p *parser) forStmt() Stmt { if trace { defer p.trace("forStmt")() } s := new(ForStmt) s.pos = p.pos() s.Init, s.Cond, s.Post = p.header(_For) s.Body = p.blockStmt("for clause") return s } func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleStmt) { p.want(keyword) if p.tok == _Lbrace { if keyword == _If { p.syntaxError("missing condition in if statement") cond = p.badExpr() } return } // p.tok != _Lbrace outer := p.xnest p.xnest = -1 if p.tok != _Semi { // accept potential varDecl but complain if p.got(_Var) { p.syntaxError(fmt.Sprintf("var declaration not allowed in %s initializer", keyword.String())) } init = p.simpleStmt(nil, keyword) // If we have a range clause, we are done (can only happen for keyword == _For). if _, ok := init.(*RangeClause); ok { p.xnest = outer return } } var condStmt SimpleStmt var semi struct { pos Pos lit string // valid if pos.IsKnown() } if p.tok != _Lbrace { if p.tok == _Semi { semi.pos = p.pos() semi.lit = p.lit p.next() } else { // asking for a '{' rather than a ';' here leads to a better error message p.want(_Lbrace) if p.tok != _Lbrace { p.advance(_Lbrace, _Rbrace) // for better synchronization (e.g., issue #22581) } } if keyword == _For { if p.tok != _Semi { if p.tok == _Lbrace { p.syntaxError("expecting for loop condition") goto done } condStmt = p.simpleStmt(nil, 0 /* range not permitted */) } p.want(_Semi) if p.tok != _Lbrace { post = p.simpleStmt(nil, 0 /* range not permitted */) if a, _ := post.(*AssignStmt); a != nil && a.Op == Def { p.syntaxErrorAt(a.Pos(), "cannot declare in post statement of for loop") } } } else if p.tok != _Lbrace { condStmt = p.simpleStmt(nil, keyword) } } else { condStmt = init init = nil } done: // unpack condStmt switch s := condStmt.(type) { case nil: if keyword == _If && semi.pos.IsKnown() { if semi.lit != "semicolon" { p.syntaxErrorAt(semi.pos, fmt.Sprintf("unexpected %s, expecting { after if clause", semi.lit)) } else { p.syntaxErrorAt(semi.pos, "missing condition in if statement") } b := new(BadExpr) b.pos = semi.pos cond = b } case *ExprStmt: cond = s.X default: // A common syntax error is to write '=' instead of '==', // which turns an expression into an assignment. Provide // a more explicit error message in that case to prevent // further confusion. var str string if as, ok := s.(*AssignStmt); ok && as.Op == 0 { // Emphasize Lhs and Rhs of assignment with parentheses to highlight '='. // Do it always - it's not worth going through the trouble of doing it // only for "complex" left and right sides. str = "assignment (" + String(as.Lhs) + ") = (" + String(as.Rhs) + ")" } else { str = String(s) } p.syntaxErrorAt(s.Pos(), fmt.Sprintf("cannot use %s as value", str)) } p.xnest = outer return } func (p *parser) ifStmt() *IfStmt { if trace { defer p.trace("ifStmt")() } s := new(IfStmt) s.pos = p.pos() s.Init, s.Cond, _ = p.header(_If) s.Then = p.blockStmt("if clause") if p.got(_Else) { switch p.tok { case _If: s.Else = p.ifStmt() case _Lbrace: s.Else = p.blockStmt("") default: p.syntaxError("else must be followed by if or statement block") p.advance(_Name, _Rbrace) } } return s } func (p *parser) switchStmt() *SwitchStmt { if trace { defer p.trace("switchStmt")() } s := new(SwitchStmt) s.pos = p.pos() s.Init, s.Tag, _ = p.header(_Switch) if !p.got(_Lbrace) { p.syntaxError("missing { after switch clause") p.advance(_Case, _Default, _Rbrace) } for p.tok != _EOF && p.tok != _Rbrace { s.Body = append(s.Body, p.caseClause()) } s.Rbrace = p.pos() p.want(_Rbrace) return s } func (p *parser) selectStmt() *SelectStmt { if trace { defer p.trace("selectStmt")() } s := new(SelectStmt) s.pos = p.pos() p.want(_Select) if !p.got(_Lbrace) { p.syntaxError("missing { after select clause") p.advance(_Case, _Default, _Rbrace) } for p.tok != _EOF && p.tok != _Rbrace { s.Body = append(s.Body, p.commClause()) } s.Rbrace = p.pos() p.want(_Rbrace) return s } func (p *parser) caseClause() *CaseClause { if trace { defer p.trace("caseClause")() } c := new(CaseClause) c.pos = p.pos() switch p.tok { case _Case: p.next() c.Cases = p.exprList() case _Default: p.next() default: p.syntaxError("expecting case or default or }") p.advance(_Colon, _Case, _Default, _Rbrace) } c.Colon = p.pos() p.want(_Colon) c.Body = p.stmtList() return c } func (p *parser) commClause() *CommClause { if trace { defer p.trace("commClause")() } c := new(CommClause) c.pos = p.pos() switch p.tok { case _Case: p.next() c.Comm = p.simpleStmt(nil, 0) // The syntax restricts the possible simple statements here to: // // lhs <- x (send statement) // <-x // lhs = <-x // lhs := <-x // // All these (and more) are recognized by simpleStmt and invalid // syntax trees are flagged later, during type checking. // TODO(gri) eventually may want to restrict valid syntax trees // here. case _Default: p.next() default: p.syntaxError("expecting case or default or }") p.advance(_Colon, _Case, _Default, _Rbrace) } c.Colon = p.pos() p.want(_Colon) c.Body = p.stmtList() return c } // Statement = // Declaration | LabeledStmt | SimpleStmt | // GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt | // FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt | // DeferStmt . func (p *parser) stmtOrNil() Stmt { if trace { defer p.trace("stmt " + p.tok.String())() } // Most statements (assignments) start with an identifier; // look for it first before doing anything more expensive. if p.tok == _Name { p.clearPragma() lhs := p.exprList() if label, ok := lhs.(*Name); ok && p.tok == _Colon { return p.labeledStmtOrNil(label) } return p.simpleStmt(lhs, 0) } switch p.tok { case _Var: return p.declStmt(p.varDecl) case _Const: return p.declStmt(p.constDecl) case _Type: return p.declStmt(p.typeDecl) } p.clearPragma() switch p.tok { case _Lbrace: return p.blockStmt("") case _Operator, _Star: switch p.op { case Add, Sub, Mul, And, Xor, Not: return p.simpleStmt(nil, 0) // unary operators } case _Literal, _Func, _Lparen, // operands _Lbrack, _Struct, _Map, _Chan, _Interface, // composite types _Arrow: // receive operator return p.simpleStmt(nil, 0) case _For: return p.forStmt() case _Switch: return p.switchStmt() case _Select: return p.selectStmt() case _If: return p.ifStmt() case _Fallthrough: s := new(BranchStmt) s.pos = p.pos() p.next() s.Tok = _Fallthrough return s case _Break, _Continue: s := new(BranchStmt) s.pos = p.pos() s.Tok = p.tok p.next() if p.tok == _Name { s.Label = p.name() } return s case _Go, _Defer: return p.callStmt() case _Goto: s := new(BranchStmt) s.pos = p.pos() s.Tok = _Goto p.next() s.Label = p.name() return s case _Return: s := new(ReturnStmt) s.pos = p.pos() p.next() if p.tok != _Semi && p.tok != _Rbrace { s.Results = p.exprList() } return s case _Semi: s := new(EmptyStmt) s.pos = p.pos() return s } return nil } // StatementList = { Statement ";" } . func (p *parser) stmtList() (l []Stmt) { if trace { defer p.trace("stmtList")() } for p.tok != _EOF && p.tok != _Rbrace && p.tok != _Case && p.tok != _Default { s := p.stmtOrNil() p.clearPragma() if s == nil { break } l = append(l, s) // ";" is optional before "}" if !p.got(_Semi) && p.tok != _Rbrace { p.syntaxError("at end of statement") p.advance(_Semi, _Rbrace, _Case, _Default) p.got(_Semi) // avoid spurious empty statement } } return } // argList parses a possibly empty, comma-separated list of arguments, // optionally followed by a comma (if not empty), and closed by ")". // The last argument may be followed by "...". // // argList = [ arg { "," arg } [ "..." ] [ "," ] ] ")" . func (p *parser) argList() (list []Expr, hasDots bool) { if trace { defer p.trace("argList")() } p.xnest++ p.list(_Comma, _Rparen, func() bool { list = append(list, p.expr()) hasDots = p.got(_DotDotDot) return hasDots }) p.xnest-- return } // ---------------------------------------------------------------------------- // Common productions func (p *parser) name() *Name { // no tracing to avoid overly verbose output if p.tok == _Name { n := NewName(p.pos(), p.lit) p.next() return n } n := NewName(p.pos(), "_") p.syntaxError("expecting name") p.advance() return n } // IdentifierList = identifier { "," identifier } . // The first name must be provided. func (p *parser) nameList(first *Name) []*Name { if trace { defer p.trace("nameList")() } if debug && first == nil { panic("first name not provided") } l := []*Name{first} for p.got(_Comma) { l = append(l, p.name()) } return l } // The first name may be provided, or nil. func (p *parser) qualifiedName(name *Name) Expr { if trace { defer p.trace("qualifiedName")() } var x Expr switch { case name != nil: x = name case p.tok == _Name: x = p.name() default: x = NewName(p.pos(), "_") p.syntaxError("expecting name") p.advance(_Dot, _Semi, _Rbrace) } if p.tok == _Dot { s := new(SelectorExpr) s.pos = p.pos() p.next() s.X = x s.Sel = p.name() x = s } if p.mode&AllowGenerics != 0 && p.tok == _Lbrack { x = p.typeInstance(x) } return x } // ExpressionList = Expression { "," Expression } . func (p *parser) exprList() Expr { if trace { defer p.trace("exprList")() } x := p.expr() if p.got(_Comma) { list := []Expr{x, p.expr()} for p.got(_Comma) { list = append(list, p.expr()) } t := new(ListExpr) t.pos = x.Pos() t.ElemList = list x = t } return x } // typeList parses a non-empty, comma-separated list of expressions, // optionally followed by a comma. The first list element may be any // expression, all other list elements must be type expressions. // If there is more than one argument, the result is a *ListExpr. // The comma result indicates whether there was a (separating or // trailing) comma. // // typeList = arg { "," arg } [ "," ] . func (p *parser) typeList() (x Expr, comma bool) { if trace { defer p.trace("typeList")() } p.xnest++ x = p.expr() if p.got(_Comma) { comma = true if t := p.typeOrNil(); t != nil { list := []Expr{x, t} for p.got(_Comma) { if t = p.typeOrNil(); t == nil { break } list = append(list, t) } l := new(ListExpr) l.pos = x.Pos() // == list[0].Pos() l.ElemList = list x = l } } p.xnest-- return } // unparen removes all parentheses around an expression. func unparen(x Expr) Expr { for { p, ok := x.(*ParenExpr) if !ok { break } x = p.X } return x }