diff options
Diffstat (limited to 'src/cmd/compile/internal/syntax/parser.go')
-rw-r--r-- | src/cmd/compile/internal/syntax/parser.go | 2803 |
1 files changed, 2803 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go new file mode 100644 index 0000000..ee9761e --- /dev/null +++ b/src/cmd/compile/internal/syntax/parser.go @@ -0,0 +1,2803 @@ +// 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("expected " + 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("expected =") + 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) +} + +// errorAt 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, "expected "): + 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) + } + + // TODO(gri) This may print "unexpected X, expected Y". + // Consider "got X, expected Y" in this case. + p.errorAt(pos, "syntax error: unexpected "+tok+msg) +} + +// tokstring returns the English word for selected punctuation tokens +// for more readable error messages. Use tokstring (not tok.String()) +// for user-facing (error) messages; use tok.String() for debugging +// output. +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 + } + + // Accept import declarations anywhere for error tolerance, but complain. + // { ( ImportDecl | TopLevelDecl ) ";" } + prev := _Import + for p.tok != _EOF { + if p.tok == _Import && prev != _Import { + p.syntaxError("imports must appear before other declarations") + } + prev = p.tok + + switch p.tok { + case _Import: + p.next() + f.DeclList = p.appendGroup(f.DeclList, p.importDecl) + + 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(_Import, _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(_Import, _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(context string, 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("in %s; possibly missing %s or %s", context, 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("grouped declaration", _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.syntaxErrorAt(d.Path.Pos(), "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 { + // d.Name "[" ... + // array/slice type or type parameter list + pos := p.pos() + p.next() + switch p.tok { + case _Name: + // We may have an array type or a type parameter list. + // In either case we expect an expression x (which may + // just be a name, or a more complex expression) which + // we can analyze further. + // + // A type parameter list may have a type bound starting + // with a "[" as in: P []E. In that case, simply parsing + // an expression would lead to an error: P[] is invalid. + // But since index or slice expressions are never constant + // and thus invalid array length expressions, if the name + // is followed by "[" it must be the start of an array or + // slice constraint. Only if we don't see a "[" do we + // need to parse a full expression. Notably, name <- x + // is not a concern because name <- x is a statement and + // not an expression. + var x Expr = p.name() + if p.tok != _Lbrack { + // To parse the expression starting with name, expand + // the call sequence we would get by passing in name + // to parser.expr, and pass in name to parser.pexpr. + p.xnest++ + x = p.binaryExpr(p.pexpr(x, false), 0) + p.xnest-- + } + // Analyze expression x. If we can split x into a type parameter + // name, possibly followed by a type parameter type, we consider + // this the start of a type parameter list, with some caveats: + // a single name followed by "]" tilts the decision towards an + // array declaration; a type parameter type that could also be + // an ordinary expression but which is followed by a comma tilts + // the decision towards a type parameter list. + if pname, ptype := extractName(x, p.tok == _Comma); pname != nil && (ptype != nil || p.tok != _Rbrack) { + // d.Name "[" pname ... + // d.Name "[" pname ptype ... + // d.Name "[" pname ptype "," ... + d.TParamList = p.paramList(pname, ptype, _Rbrack, true) // ptype may be nil + d.Alias = p.gotAssign() + d.Type = p.typeOrNil() + } else { + // d.Name "[" pname "]" ... + // d.Name "[" x ... + d.Type = p.arrayType(pos, x) + } + case _Rbrack: + // d.Name "[" "]" ... + p.next() + d.Type = p.sliceType(pos) + default: + // d.Name "[" ... + 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 +} + +// extractName splits the expression x into (name, expr) if syntactically +// x can be written as name expr. The split only happens if expr is a type +// element (per the isTypeElem predicate) or if force is set. +// If x is just a name, the result is (name, nil). If the split succeeds, +// the result is (name, expr). Otherwise the result is (nil, x). +// Examples: +// +// x force name expr +// ------------------------------------ +// P*[]int T/F P *[]int +// P*E T P *E +// P*E F nil P*E +// P([]int) T/F P []int +// P(E) T P E +// P(E) F nil P(E) +// P*E|F|~G T/F P *E|F|~G +// P*E|F|G T P *E|F|G +// P*E|F|G F nil P*E|F|G +func extractName(x Expr, force bool) (*Name, Expr) { + switch x := x.(type) { + case *Name: + return x, nil + case *Operation: + if x.Y == nil { + break // unary expr + } + switch x.Op { + case Mul: + if name, _ := x.X.(*Name); name != nil && (force || isTypeElem(x.Y)) { + // x = name *x.Y + op := *x + op.X, op.Y = op.Y, nil // change op into unary *op.Y + return name, &op + } + case Or: + if name, lhs := extractName(x.X, force || isTypeElem(x.Y)); name != nil && lhs != nil { + // x = name lhs|x.Y + op := *x + op.X = lhs + return name, &op + } + } + case *CallExpr: + if name, _ := x.Fun.(*Name); name != nil { + if len(x.ArgList) == 1 && !x.HasDots && (force || isTypeElem(x.ArgList[0])) { + // x = name "(" x.ArgList[0] ")" + return name, x.ArgList[0] + } + } + } + return nil, x +} + +// isTypeElem reports whether x is a (possibly parenthesized) type element expression. +// The result is false if x could be a type element OR an ordinary (value) expression. +func isTypeElem(x Expr) bool { + switch x := x.(type) { + case *ArrayType, *StructType, *FuncType, *InterfaceType, *SliceType, *MapType, *ChanType: + return true + case *Operation: + return isTypeElem(x.X) || (x.Y != nil && isTypeElem(x.Y)) || x.Op == Tilde + case *ParenExpr: + return isTypeElem(x.X) + } + return false +} + +// 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() + + var context string + if p.got(_Lparen) { + context = "method" + rcvr := p.paramList(nil, 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 { + f.Name = p.name() + f.TParamList, f.Type = p.funcType(context) + } else { + msg := "expected name or (" + if context != "" { + msg = "expected name" + } + p.syntaxError(msg) + p.advance(_Lbrace, _Semi) + } + + 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(nil, 0) +} + +// Expression = UnaryExpr | Expression binary_op Expression . +func (p *parser) binaryExpr(x Expr, prec int) Expr { + // don't trace binaryExpr - only leads to overly nested trace output + + if x == nil { + 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(nil, 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, Tilde: + 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 <-, expected 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, expected 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(nil, 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(nil, 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 + } + + s.Call = x + 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("function type") + 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("expected 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). +} + +// pexpr parses a PrimaryExpr. +// +// 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(x Expr, keep_parens bool) Expr { + if trace { + defer p.trace("pexpr")() + } + + if x == nil { + 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("expected name or (") + p.advance(_Semi, _Rparen) + } + + case _Lbrack: + p.next() + + var i Expr + if p.tok != _Colon { + var comma bool + if p.tok == _Rbrack { + // invalid empty instance, slice or index expression; accept but complain + p.syntaxError("expected operand") + i = p.badExpr() + } else { + i, comma = p.typeList(false) + } + if comma || p.tok == _Rbrack { + p.want(_Rbrack) + // x[], 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) { + p.syntaxError("expected 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("composite literal", _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("expected 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() + _, t := p.funcType("function type") + return t + + 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("expected type argument list") + x.Index = p.badExpr() + } else { + x.Index, _ = p.typeList(true) + } + p.want(_Rbrack) + return x +} + +// If context != "", type parameters are not permitted. +func (p *parser) funcType(context string) ([]*Field, *FuncType) { + if trace { + defer p.trace("funcType")() + } + + typ := new(FuncType) + typ.pos = p.pos() + + var tparamList []*Field + if p.got(_Lbrack) { + if context != "" { + // accept but complain + p.syntaxErrorAt(typ.pos, context+" must have no type parameters") + } + if p.tok == _Rbrack { + p.syntaxError("empty type parameter list") + p.next() + } else { + tparamList = p.paramList(nil, nil, _Rbrack, true) + } + } + + p.want(_Lparen) + typ.ParamList = p.paramList(nil, nil, _Rparen, false) + typ.ResultList = p.funcResult() + + return tparamList, 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-- + } + if p.tok == _Comma { + // Trailing commas are accepted in type parameter + // lists but not in array type declarations. + // Accept for better error handling but complain. + p.syntaxError("unexpected comma; expected ]") + p.next() + } + 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("struct type", _Semi, _Rbrace, func() bool { + p.fieldDecl(typ) + return false + }) + + return typ +} + +// InterfaceType = "interface" "{" { ( MethodDecl | EmbeddedElem ) ";" } "}" . +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("interface type", _Semi, _Rbrace, func() bool { + var f *Field + if p.tok == _Name { + f = p.methodDecl() + } + if f == nil || f.Name == nil { + f = p.embeddedElem(f) + } + typ.MethodList = append(typ.MethodList, f) + 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, 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 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("expected 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(false) + 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() + + const context = "interface method" + + switch p.tok { + case _Lparen: + // method + f.Name = name + _, f.Type = p.funcType(context) + + case _Lbrack: + // 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 but complain with an error). + 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(context) + } 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, 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(context) + } else { + f.Type = name + } + break + } + + // len(list) > 0 + if list[0].Name != nil { + // generic method + f.Name = name + _, f.Type = p.funcType(context) + p.errorAt(pos, "interface method must have no 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 + + 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("expected ~ term or type") + p.advance(_Operator, _Semi, _Rparen, _Rbrack, _Rbrace) + } + + return t +} + +// ParameterDecl = [ IdentifierList ] [ "..." ] Type . +func (p *parser) paramDeclOrNil(name *Name, follow token) *Field { + if trace { + defer p.trace("paramDeclOrNil")() + } + + // type set notation is ok in type parameter lists + typeSetsOk := follow == _Rbrack + + pos := p.pos() + if name != nil { + pos = name.pos + } else if typeSetsOk && p.tok == _Operator && p.op == Tilde { + // "~" ... + return p.embeddedElem(nil) + } + + f := new(Field) + f.pos = pos + + if p.tok == _Name || name != nil { + // name + if name == nil { + name = p.name() + } + + if p.tok == _Lbrack { + // name "[" ... + f.Type = p.arrayOrTArgs() + if typ, ok := f.Type.(*IndexExpr); ok { + // name "[" ... "]" + typ.X = name + } else { + // name "[" n "]" E + f.Name = name + } + if typeSetsOk && p.tok == _Operator && p.op == Or { + // name "[" ... "]" "|" ... + // name "[" n "]" E "|" ... + f = p.embeddedElem(f) + } + return f + } + + if p.tok == _Dot { + // name "." ... + f.Type = p.qualifiedName(name) + if typeSetsOk && p.tok == _Operator && p.op == Or { + // name "." name "|" ... + f = p.embeddedElem(f) + } + return f + } + + if typeSetsOk && p.tok == _Operator && p.op == Or { + // name "|" ... + f.Type = name + return p.embeddedElem(f) + } + + f.Name = name + } + + if p.tok == _DotDotDot { + // [name] "..." ... + 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 + } + + if typeSetsOk && p.tok == _Operator && p.op == Tilde { + // [name] "~" ... + f.Type = p.embeddedElem(nil).Type + return f + } + + f.Type = p.typeOrNil() + if typeSetsOk && p.tok == _Operator && p.op == Or && f.Type != nil { + // [name] type "|" + f = p.embeddedElem(f) + } + if f.Name != nil || f.Type != nil { + return f + } + + p.syntaxError("expected " + tokstring(follow)) + p.advance(_Comma, follow) + return nil +} + +// Parameters = "(" [ ParameterList [ "," ] ] ")" . +// ParameterList = ParameterDecl { "," ParameterDecl } . +// "(" or "[" has already been consumed. +// If name != nil, it is the first name after "(" or "[". +// If typ != nil, name must be != nil, and (name, typ) is the first field in the list. +// In the result list, either all fields have a name, or no field has a name. +func (p *parser) paramList(name *Name, typ Expr, close token, requireNames bool) (list []*Field) { + if trace { + defer p.trace("paramList")() + } + + // p.list won't invoke its function argument if we're at the end of the + // parameter list. If we have a complete field, handle this case here. + if name != nil && typ != nil && p.tok == close { + p.next() + par := new(Field) + par.pos = name.pos + par.Name = name + par.Type = typ + return []*Field{par} + } + + var named int // number of parameters that have an explicit name and type + var typed int // number of parameters that have an explicit type + end := p.list("parameter list", _Comma, close, func() bool { + var par *Field + if typ != nil { + if debug && name == nil { + panic("initial type provided without name") + } + par = new(Field) + par.pos = name.pos + par.Name = name + par.Type = typ + } else { + par = p.paramDeclOrNil(name, close) + } + name = nil // 1st name was consumed if present + typ = nil // 1st type 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++ + } + if par.Type != nil { + typed++ + } + list = append(list, par) + } + return false + }) + + if len(list) == 0 { + return + } + + // distribute parameter types (len(list) > 0) + if named == 0 && !requireNames { + // all unnamed => found names are named types + for _, par := range list { + if typ := par.Name; typ != nil { + par.Type = typ + par.Name = nil + } + } + } 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 // current type (from right to left) + for i := len(list) - 1; i >= 0; i-- { + par := list[i] + if par.Type != nil { + typ = par.Type + if par.Name == nil { + pos = StartPos(typ) + 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 { + if named == typed { + pos = end // position error at closing ] + msg = "missing type constraint" + } else { + 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("expected := 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("expected { 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", tokstring(keyword))) + } + 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("expected 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, expected { 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("expected 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. + + case _Default: + p.next() + + default: + p.syntaxError("expected case or default or }") + p.advance(_Colon, _Case, _Default, _Rbrace) + } + + c.Colon = p.pos() + p.want(_Colon) + c.Body = p.stmtList() + + return c +} + +// stmtOrNil parses a statement if one is present, or else returns nil. +// +// 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("argument 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("expected 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("expected 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.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 types, +// optionally followed by a comma. If strict is set to false, +// the first element may also be a (non-type) expression. +// 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(strict bool) (x Expr, comma bool) { + if trace { + defer p.trace("typeList")() + } + + p.xnest++ + if strict { + x = p.type_() + } else { + 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 +} |