summaryrefslogtreecommitdiffstats
path: root/src/cmd/compile/internal/syntax/parser.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
commit43a123c1ae6613b3efeed291fa552ecd909d3acf (patch)
treefd92518b7024bc74031f78a1cf9e454b65e73665 /src/cmd/compile/internal/syntax/parser.go
parentInitial commit. (diff)
downloadgolang-1.20-upstream.tar.xz
golang-1.20-upstream.zip
Adding upstream version 1.20.14.upstream/1.20.14upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/cmd/compile/internal/syntax/parser.go')
-rw-r--r--src/cmd/compile/internal/syntax/parser.go2803
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
+}