go/src/cmd/compile/internal/gc/parser.go
Robert Griesemer 68c86a0096 cmd/compile: remove structpkg global variable
The structpkg global variable was only used to verify internal
consistency when declaring methods during import. Track the
value in the parser and binary importer directly and pass it
to the relevant function as an argument.

Change-Id: I7e5e006f9046d84f9a3959616f073798fda36c97
Reviewed-on: https://go-review.googlesource.com/20606
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-03-12 01:39:40 +00:00

3324 lines
67 KiB
Go

// Copyright 2015 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 gc
// The recursive-descent parser is built around a slighty modified grammar
// of Go to accommodate for the constraints imposed by strict one token look-
// ahead, and for better error handling. Subsequent checks of the constructed
// syntax tree restrict the language accepted by the compiler to proper Go.
//
// Semicolons are inserted by the lexer. The parser uses one-token look-ahead
// to handle optional commas and semicolons before a closing ) or } .
import (
"bufio"
"fmt"
"strconv"
"strings"
)
const trace = false // if set, parse tracing can be enabled with -x
// parse_import parses the export data of a package that is imported.
func parse_import(bin *bufio.Reader, indent []byte) {
newparser(bin, indent).import_package()
}
// parse_file parses a single Go source file.
func parse_file(bin *bufio.Reader) {
newparser(bin, nil).file()
}
type parser struct {
lexer
fnest int // function nesting level (for error handling)
xnest int // expression nesting level (for complit ambiguity resolution)
indent []byte // tracing support
// TODO(gri) remove this once we switch to binary export format
structpkg *Pkg // for verification in addmethod only
}
// newparser returns a new parser ready to parse from src.
// indent is the initial indentation for tracing output.
func newparser(src *bufio.Reader, indent []byte) *parser {
var p parser
p.bin = src
p.indent = indent
p.next()
return &p
}
func (p *parser) got(tok int32) bool {
if p.tok == tok {
p.next()
return true
}
return false
}
func (p *parser) want(tok int32) {
if !p.got(tok) {
p.syntax_error("expecting " + tokstring(tok))
p.advance()
}
}
// ----------------------------------------------------------------------------
// Syntax error handling
func (p *parser) syntax_error(msg string) {
if trace && Debug['x'] != 0 {
defer p.trace("syntax_error (" + msg + ")")()
}
if p.tok == EOF && nerrors > 0 {
return // avoid meaningless follow-up errors
}
// add punctuation etc. as needed to msg
switch {
case msg == "":
// nothing to do
case strings.HasPrefix(msg, "in"), strings.HasPrefix(msg, "at"), strings.HasPrefix(msg, "after"):
msg = " " + msg
case strings.HasPrefix(msg, "expecting"):
msg = ", " + msg
default:
// plain error - we don't care about current token
Yyerror("syntax error: %s", msg)
return
}
// determine token string
var tok string
switch p.tok {
case LNAME:
if p.sym_ != nil && p.sym_.Name != "" {
tok = p.sym_.Name
} else {
tok = "name"
}
case LLITERAL:
tok = litbuf
case LOPER:
tok = goopnames[p.op]
case LASOP:
tok = goopnames[p.op] + "="
case LINCOP:
tok = goopnames[p.op] + goopnames[p.op]
default:
tok = tokstring(p.tok)
}
Yyerror("syntax error: unexpected %s", tok+msg)
}
// Like syntax_error, but reports error at given line rather than current lexer line.
func (p *parser) syntax_error_at(lno int32, msg string) {
defer func(lno int32) {
lineno = lno
}(lineno)
lineno = lno
p.syntax_error(msg)
}
// The stoplist contains keywords that start a statement.
// They are good synchronization points in case of syntax
// errors and (usually) shouldn't be skipped over.
var stoplist = map[int32]bool{
LBREAK: true,
LCONST: true,
LCONTINUE: true,
LDEFER: true,
LFALL: true,
LFOR: true,
LFUNC: true,
LGO: true,
LGOTO: true,
LIF: true,
LRETURN: true,
LSELECT: true,
LSWITCH: true,
LTYPE: true,
LVAR: true,
}
// Advance consumes tokens until it finds a token of the stop- or followlist.
// The stoplist 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 token is consumed to ensure progress.
func (p *parser) advance(followlist ...int32) {
if len(followlist) == 0 {
p.next()
return
}
for p.tok != EOF {
if p.fnest > 0 && stoplist[p.tok] {
return
}
for _, follow := range followlist {
if p.tok == follow {
return
}
}
p.next()
}
}
func tokstring(tok int32) string {
switch tok {
case EOF:
return "EOF"
case ',':
return "comma"
case ';':
return "semicolon or newline"
}
if 0 <= tok && tok < 128 {
// get invisibles properly backslashed
s := strconv.QuoteRune(tok)
if n := len(s); n > 0 && s[0] == '\'' && s[n-1] == '\'' {
s = s[1 : n-1]
}
return s
}
if s := tokstrings[tok]; s != "" {
return s
}
// catchall
return fmt.Sprintf("tok-%v", tok)
}
var tokstrings = map[int32]string{
LNAME: "NAME",
LLITERAL: "LITERAL",
LOPER: "op",
LASOP: "op=",
LINCOP: "opop",
LCOLAS: ":=",
LCOMM: "<-",
LDDD: "...",
LBREAK: "break",
LCASE: "case",
LCHAN: "chan",
LCONST: "const",
LCONTINUE: "continue",
LDEFAULT: "default",
LDEFER: "defer",
LELSE: "else",
LFALL: "fallthrough",
LFOR: "for",
LFUNC: "func",
LGO: "go",
LGOTO: "goto",
LIF: "if",
LIMPORT: "import",
LINTERFACE: "interface",
LMAP: "map",
LPACKAGE: "package",
LRANGE: "range",
LRETURN: "return",
LSELECT: "select",
LSTRUCT: "struct",
LSWITCH: "switch",
LTYPE: "type",
LVAR: "var",
}
// usage: defer p.trace(msg)()
func (p *parser) trace(msg string) func() {
fmt.Printf("%5d: %s%s (\n", lineno, p.indent, 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
}
fmt.Printf("%5d: %s)\n", lineno, p.indent)
}
}
// ----------------------------------------------------------------------------
// Parsing 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.
// SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
func (p *parser) file() {
if trace && Debug['x'] != 0 {
defer p.trace("file")()
}
p.package_()
p.want(';')
for p.tok == LIMPORT {
p.import_()
p.want(';')
}
xtop = append(xtop, p.xdcl_list()...)
p.want(EOF)
}
// PackageClause = "package" PackageName .
// PackageName = identifier .
func (p *parser) package_() {
if trace && Debug['x'] != 0 {
defer p.trace("package_")()
}
if !p.got(LPACKAGE) {
p.syntax_error("package statement must be first")
errorexit()
}
mkpackage(p.sym().Name)
}
// ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
func (p *parser) import_() {
if trace && Debug['x'] != 0 {
defer p.trace("import_")()
}
p.want(LIMPORT)
if p.got('(') {
for p.tok != EOF && p.tok != ')' {
p.importdcl()
if !p.osemi(')') {
break
}
}
p.want(')')
} else {
p.importdcl()
}
}
// ImportSpec = [ "." | PackageName ] ImportPath .
// ImportPath = string_lit .
func (p *parser) importdcl() {
if trace && Debug['x'] != 0 {
defer p.trace("importdcl")()
}
var my *Sym
switch p.tok {
case LNAME, '@', '?':
// import with given name
my = p.sym()
case '.':
// import into my name space
my = Lookup(".")
p.next()
}
if p.tok != LLITERAL {
p.syntax_error("missing import path; require quoted string")
p.advance(';', ')')
return
}
line := lineno
// We need to clear importpkg before calling p.next(),
// otherwise it will affect lexlineno.
// TODO(mdempsky): Fix this clumsy API.
importfile(&p.val, p.indent)
ipkg := importpkg
importpkg = nil
p.next()
if ipkg == nil {
if nerrors == 0 {
Fatalf("phase error in import")
}
return
}
ipkg.Direct = true
if my == nil {
my = Lookup(ipkg.Name)
}
pack := Nod(OPACK, nil, nil)
pack.Sym = my
pack.Name.Pkg = ipkg
pack.Lineno = line
if strings.HasPrefix(my.Name, ".") {
importdot(ipkg, pack)
return
}
if my.Name == "init" {
lineno = line
Yyerror("cannot import package as init - init must be a func")
return
}
if my.Name == "_" {
return
}
if my.Def != nil {
lineno = line
redeclare(my, "as imported package name")
}
my.Def = pack
my.Lastlineno = line
my.Block = 1 // at top level
}
// import_package parses the header of an imported package as exported
// in textual format from another package.
func (p *parser) import_package() {
if trace && Debug['x'] != 0 {
defer p.trace("import_package")()
}
p.want(LPACKAGE)
var name string
if p.tok == LNAME {
name = p.sym_.Name
p.next()
} else {
p.import_error()
}
importsafe := false
if p.tok == LNAME {
if p.sym_.Name == "safe" {
importsafe = true
}
p.next()
}
p.want(';')
if importpkg.Name == "" {
importpkg.Name = name
numImport[name]++
} else if importpkg.Name != name {
Yyerror("conflicting names %s and %s for package %q", importpkg.Name, name, importpkg.Path)
}
importpkg.Safe = importsafe
typecheckok = true
defercheckwidth()
p.hidden_import_list()
p.want('$')
// don't read past 2nd '$'
if p.tok != '$' {
p.import_error()
}
resumecheckwidth()
typecheckok = false
}
// Declaration = ConstDecl | TypeDecl | VarDecl .
// ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
// TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
// VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
func (p *parser) common_dcl() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("common_dcl")()
}
var dcl func() []*Node
switch p.tok {
case LVAR:
dcl = p.vardcl
case LCONST:
iota_ = 0
dcl = p.constdcl
case LTYPE:
dcl = p.typedcl
default:
panic("unreachable")
}
p.next()
var s []*Node
if p.got('(') {
for p.tok != EOF && p.tok != ')' {
s = append(s, dcl()...)
if !p.osemi(')') {
break
}
}
p.want(')')
} else {
s = dcl()
}
iota_ = -100000
lastconst = nil
return s
}
// VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
func (p *parser) vardcl() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("vardcl")()
}
names := p.dcl_name_list()
var typ *Node
var exprs []*Node
if p.got('=') {
exprs = p.expr_list()
} else {
typ = p.ntype()
if p.got('=') {
exprs = p.expr_list()
}
}
return variter(names, typ, exprs)
}
// ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] .
func (p *parser) constdcl() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("constdcl")()
}
names := p.dcl_name_list()
var typ *Node
var exprs []*Node
if p.tok != EOF && p.tok != ';' && p.tok != ')' {
typ = p.try_ntype()
if p.got('=') {
exprs = p.expr_list()
}
}
return constiter(names, typ, exprs)
}
// TypeSpec = identifier Type .
func (p *parser) typedcl() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("typedcl")()
}
name := typedcl0(p.sym())
typ := p.try_ntype()
// handle case where type is missing
if typ == nil {
p.syntax_error("in type declaration")
p.advance(';', ')')
}
return []*Node{typedcl1(name, typ, true)}
}
// SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
//
// simple_stmt may return missing_stmt if labelOk is set.
func (p *parser) simple_stmt(labelOk, rangeOk bool) *Node {
if trace && Debug['x'] != 0 {
defer p.trace("simple_stmt")()
}
if rangeOk && p.got(LRANGE) {
// LRANGE expr
r := Nod(ORANGE, nil, p.expr())
r.Etype = 0 // := flag
return r
}
lhs := p.expr_list()
if len(lhs) == 1 && p.tok != '=' && p.tok != LCOLAS && p.tok != LRANGE {
// expr
lhs := lhs[0]
switch p.tok {
case LASOP:
// expr LASOP expr
op := p.op
p.next()
rhs := p.expr()
stmt := Nod(OASOP, lhs, rhs)
stmt.Etype = EType(op) // rathole to pass opcode
return stmt
case LINCOP:
// expr LINCOP
p.next()
stmt := Nod(OASOP, lhs, Nodintconst(1))
stmt.Implicit = true
stmt.Etype = EType(p.op)
return stmt
case ':':
// labelname ':' stmt
if labelOk {
// If we have a labelname, it was parsed by operand
// (calling p.name()) and given an ONAME, ONONAME, OTYPE, OPACK, or OLITERAL node.
// We only have a labelname if there is a symbol (was issue 14006).
switch lhs.Op {
case ONAME, ONONAME, OTYPE, OPACK, OLITERAL:
if lhs.Sym != nil {
lhs = newname(lhs.Sym)
break
}
fallthrough
default:
p.syntax_error("expecting semicolon or newline or }")
// we already progressed, no need to advance
}
lhs := Nod(OLABEL, lhs, nil)
lhs.Sym = dclstack // context, for goto restrictions
p.next() // consume ':' after making label node for correct lineno
return p.labeled_stmt(lhs)
}
fallthrough
default:
// expr
// Since a bare name used as an expression is an error,
// introduce a wrapper node where necessary to give the
// correct line.
return wrapname(lhs)
}
}
// expr_list
switch p.tok {
case '=':
p.next()
if rangeOk && p.got(LRANGE) {
// expr_list '=' LRANGE expr
r := Nod(ORANGE, nil, p.expr())
r.List.Set(lhs)
r.Etype = 0 // := flag
return r
}
// expr_list '=' expr_list
rhs := p.expr_list()
if len(lhs) == 1 && len(rhs) == 1 {
// simple
return Nod(OAS, lhs[0], rhs[0])
}
// multiple
stmt := Nod(OAS2, nil, nil)
stmt.List.Set(lhs)
stmt.Rlist.Set(rhs)
return stmt
case LCOLAS:
lno := lineno
p.next()
if rangeOk && p.got(LRANGE) {
// expr_list LCOLAS LRANGE expr
r := Nod(ORANGE, nil, p.expr())
r.List.Set(lhs)
r.Colas = true
colasdefn(r.List, r)
return r
}
// expr_list LCOLAS expr_list
rhs := p.expr_list()
if rhs[0].Op == OTYPESW {
ts := Nod(OTYPESW, nil, rhs[0].Right)
if len(rhs) > 1 {
Yyerror("expr.(type) must be alone in list")
}
if len(lhs) > 1 {
Yyerror("argument count mismatch: %d = %d", len(lhs), 1)
} else if (lhs[0].Op != ONAME && lhs[0].Op != OTYPE && lhs[0].Op != ONONAME && (lhs[0].Op != OLITERAL || lhs[0].Name == nil)) || isblank(lhs[0]) {
Yyerror("invalid variable name %s in type switch", lhs[0])
} else {
ts.Left = dclname(lhs[0].Sym)
} // it's a colas, so must not re-use an oldname
return ts
}
return colas(lhs, rhs, lno)
default:
p.syntax_error("expecting := or = or comma")
p.advance(';', '}')
return nil
}
}
// LabeledStmt = Label ":" Statement .
// Label = identifier .
func (p *parser) labeled_stmt(label *Node) *Node {
if trace && Debug['x'] != 0 {
defer p.trace("labeled_stmt")()
}
var ls *Node // labeled statement
if p.tok != '}' && p.tok != EOF {
ls = p.stmt()
if ls == missing_stmt {
// report error at line of ':' token
p.syntax_error_at(label.Lineno, "missing statement after label")
// we are already at the end of the labeled statement - no need to advance
return missing_stmt
}
}
label.Name.Defn = ls
l := []*Node{label}
if ls != nil {
if ls.Op == OBLOCK && ls.Ninit.Len() == 0 {
l = append(l, ls.List.Slice()...)
} else {
l = append(l, ls)
}
}
return liststmt(l)
}
// case_ parses a superset of switch and select statement cases.
// Later checks restrict the syntax to valid forms.
//
// ExprSwitchCase = "case" ExpressionList | "default" .
// TypeSwitchCase = "case" TypeList | "default" .
// TypeList = Type { "," Type } .
// CommCase = "case" ( SendStmt | RecvStmt ) | "default" .
// RecvStmt = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr .
// RecvExpr = Expression .
func (p *parser) case_(tswitch *Node) *Node {
if trace && Debug['x'] != 0 {
defer p.trace("case_")()
}
switch p.tok {
case LCASE:
p.next()
cases := p.expr_list() // expr_or_type_list
switch p.tok {
case ':':
// LCASE expr_or_type_list ':'
// will be converted to OCASE
// right will point to next case
// done in casebody()
markdcl() // matching popdcl in caseblock
stmt := Nod(OXCASE, nil, nil)
stmt.List.Set(cases)
if tswitch != nil {
if n := tswitch.Left; n != nil {
// type switch - declare variable
nn := newname(n.Sym)
declare(nn, dclcontext)
stmt.Rlist.Set1(nn)
// keep track of the instances for reporting unused
nn.Name.Defn = tswitch
}
}
p.next() // consume ':' after declaring type switch var for correct lineno
return stmt
case '=':
// LCASE expr_or_type_list '=' expr ':'
p.next()
rhs := p.expr()
// will be converted to OCASE
// right will point to next case
// done in casebody()
markdcl() // matching popdcl in caseblock
stmt := Nod(OXCASE, nil, nil)
var n *Node
if len(cases) == 1 {
n = Nod(OAS, cases[0], rhs)
} else {
n = Nod(OAS2, nil, nil)
n.List.Set(cases)
n.Rlist.Set1(rhs)
}
stmt.List.Set1(n)
p.want(':') // consume ':' after declaring select cases for correct lineno
return stmt
case LCOLAS:
// LCASE expr_or_type_list LCOLAS expr ':'
lno := lineno
p.next()
rhs := p.expr()
// will be converted to OCASE
// right will point to next case
// done in casebody()
markdcl() // matching popdcl in caseblock
stmt := Nod(OXCASE, nil, nil)
stmt.List.Set1(colas(cases, []*Node{rhs}, lno))
p.want(':') // consume ':' after declaring select cases for correct lineno
return stmt
default:
markdcl() // for matching popdcl in caseblock
stmt := Nod(OXCASE, nil, nil) // don't return nil
p.syntax_error("expecting := or = or : or comma")
p.advance(LCASE, LDEFAULT, '}')
return stmt
}
case LDEFAULT:
// LDEFAULT ':'
p.next()
markdcl() // matching popdcl in caseblock
stmt := Nod(OXCASE, nil, nil)
if tswitch != nil {
if n := tswitch.Left; n != nil {
// type switch - declare variable
nn := newname(n.Sym)
declare(nn, dclcontext)
stmt.Rlist.Set1(nn)
// keep track of the instances for reporting unused
nn.Name.Defn = tswitch
}
}
p.want(':') // consume ':' after declaring type switch var for correct lineno
return stmt
default:
markdcl() // matching popdcl in caseblock
stmt := Nod(OXCASE, nil, nil) // don't return nil
p.syntax_error("expecting case or default or }")
p.advance(LCASE, LDEFAULT, '}')
return stmt
}
}
// Block = "{" StatementList "}" .
// StatementList = { Statement ";" } .
func (p *parser) compound_stmt() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("compound_stmt")()
}
markdcl()
p.want('{')
l := p.stmt_list()
p.want('}')
popdcl()
if len(l) == 0 {
return Nod(OEMPTY, nil, nil)
}
return liststmt(l)
}
// caseblock parses a superset of switch and select clauses.
//
// ExprCaseClause = ExprSwitchCase ":" StatementList .
// TypeCaseClause = TypeSwitchCase ":" StatementList .
// CommClause = CommCase ":" StatementList .
func (p *parser) caseblock(tswitch *Node) *Node {
if trace && Debug['x'] != 0 {
defer p.trace("caseblock")()
}
stmt := p.case_(tswitch) // does markdcl
stmt.Xoffset = int64(block)
stmt.Nbody.Set(p.stmt_list())
popdcl()
return stmt
}
// caseblock_list parses a superset of switch and select clause lists.
func (p *parser) caseblock_list(tswitch *Node) (l []*Node) {
if trace && Debug['x'] != 0 {
defer p.trace("caseblock_list")()
}
if !p.got('{') {
p.syntax_error("missing { after switch clause")
p.advance(LCASE, LDEFAULT, '}')
}
for p.tok != EOF && p.tok != '}' {
l = append(l, p.caseblock(tswitch))
}
p.want('}')
return
}
// loop_body parses if and for statement bodies.
func (p *parser) loop_body(context string) []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("loop_body")()
}
markdcl()
if !p.got('{') {
p.syntax_error("missing { after " + context)
p.advance(LNAME, '}')
}
body := p.stmt_list()
popdcl()
p.want('}')
return body
}
// for_header parses the header portion of a for statement.
//
// ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
// Condition = Expression .
func (p *parser) for_header() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("for_header")()
}
init, cond, post := p.header(true)
if init != nil || post != nil {
// init ; test ; incr
if post != nil && post.Colas {
Yyerror("cannot declare in the for-increment")
}
h := Nod(OFOR, nil, nil)
if init != nil {
h.Ninit.Set1(init)
}
h.Left = cond
h.Right = post
return h
}
if cond != nil && cond.Op == ORANGE {
// range_stmt - handled by pexpr
return cond
}
// normal test
h := Nod(OFOR, nil, nil)
h.Left = cond
return h
}
func (p *parser) for_body() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("for_body")()
}
stmt := p.for_header()
body := p.loop_body("for clause")
stmt.Nbody.Append(body...)
return stmt
}
// ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
func (p *parser) for_stmt() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("for_stmt")()
}
p.want(LFOR)
markdcl()
body := p.for_body()
popdcl()
return body
}
// header parses a combination of if, switch, and for statement headers:
//
// Header = [ InitStmt ";" ] [ Expression ] .
// Header = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] . // for_stmt only
// InitStmt = SimpleStmt .
// PostStmt = SimpleStmt .
func (p *parser) header(for_stmt bool) (init, cond, post *Node) {
if p.tok == '{' {
return
}
outer := p.xnest
p.xnest = -1
if p.tok != ';' {
// accept potential vardcl but complain
// (for test/syntax/forvar.go)
if for_stmt && p.tok == LVAR {
Yyerror("var declaration not allowed in for initializer")
p.next()
}
init = p.simple_stmt(false, for_stmt)
// If we have a range clause, we are done.
if for_stmt && init.Op == ORANGE {
cond = init
init = nil
p.xnest = outer
return
}
}
if p.got(';') {
if for_stmt {
if p.tok != ';' {
cond = p.simple_stmt(false, false)
}
p.want(';')
if p.tok != '{' {
post = p.simple_stmt(false, false)
}
} else if p.tok != '{' {
cond = p.simple_stmt(false, false)
}
} else {
cond = init
init = nil
}
p.xnest = outer
return
}
func (p *parser) if_header() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("if_header")()
}
init, cond, _ := p.header(false)
h := Nod(OIF, nil, nil)
if init != nil {
h.Ninit.Set1(init)
}
h.Left = cond
return h
}
// IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
func (p *parser) if_stmt() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("if_stmt")()
}
p.want(LIF)
markdcl()
stmt := p.if_header()
if stmt.Left == nil {
Yyerror("missing condition in if statement")
}
stmt.Nbody.Set(p.loop_body("if clause"))
if p.got(LELSE) {
switch p.tok {
case LIF:
stmt.Rlist.Set1(p.if_stmt())
case '{':
cs := p.compound_stmt()
if cs.Op == OBLOCK && cs.Ninit.Len() == 0 {
stmt.Rlist.Set(cs.List.Slice())
} else {
stmt.Rlist.Set1(cs)
}
default:
p.syntax_error("else must be followed by if or statement block")
p.advance(LNAME, '}')
}
}
popdcl()
return stmt
}
// switch_stmt parses both expression and type switch statements.
//
// SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .
// ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" .
// TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" .
func (p *parser) switch_stmt() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("switch_stmt")()
}
p.want(LSWITCH)
markdcl()
hdr := p.if_header()
hdr.Op = OSWITCH
tswitch := hdr.Left
if tswitch != nil && tswitch.Op != OTYPESW {
tswitch = nil
}
hdr.List.Set(p.caseblock_list(tswitch))
popdcl()
return hdr
}
// SelectStmt = "select" "{" { CommClause } "}" .
func (p *parser) select_stmt() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("select_stmt")()
}
p.want(LSELECT)
hdr := Nod(OSELECT, nil, nil)
hdr.List.Set(p.caseblock_list(nil))
return hdr
}
// Expression = UnaryExpr | Expression binary_op Expression .
func (p *parser) bexpr(prec OpPrec) *Node {
// don't trace bexpr - only leads to overly nested trace output
// prec is precedence of the prior/enclosing binary operator (if any),
// so we only want to parse tokens of greater precedence.
x := p.uexpr()
for p.prec > prec {
op, prec1 := p.op, p.prec
p.next()
x = Nod(op, x, p.bexpr(prec1))
}
return x
}
func (p *parser) expr() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("expr")()
}
return p.bexpr(0)
}
func unparen(x *Node) *Node {
for x.Op == OPAREN {
x = x.Left
}
return x
}
// UnaryExpr = PrimaryExpr | unary_op UnaryExpr .
func (p *parser) uexpr() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("uexpr")()
}
var op Op
switch p.tok {
case '*':
op = OIND
case '&':
p.next()
// uexpr may have returned a parenthesized composite literal
// (see comment in operand) - remove parentheses if any
x := unparen(p.uexpr())
if x.Op == OCOMPLIT {
// Special case for &T{...}: turn into (*T){...}.
x.Right = Nod(OIND, x.Right, nil)
x.Right.Implicit = true
} else {
x = Nod(OADDR, x, nil)
}
return x
case '+':
op = OPLUS
case '-':
op = OMINUS
case '!':
op = ONOT
case '~':
// TODO(gri) do this in the lexer instead (issue 13244)
p.next()
x := p.uexpr()
Yyerror("the bitwise complement operator is ^")
return Nod(OCOM, x, nil)
case '^':
op = OCOM
case LCOMM:
// receive op (<-x) or receive-only channel (<-chan E)
p.next()
// If the next token is LCHAN 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 uexpr.
x := p.uexpr()
// 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 x.Op == OTCHAN {
// x is a channel type => re-associate <-
dir := EType(Csend)
t := x
for ; t.Op == OTCHAN && dir == Csend; t = t.Left {
dir = t.Etype
if dir == Crecv {
// t is type <-chan E but <-<-chan E is not permitted
// (report same error as for "type _ <-<-chan E")
p.syntax_error("unexpected <-, expecting chan")
// already progressed, no need to advance
}
t.Etype = Crecv
}
if dir == Csend {
// channel dir is <- but channel element E is not a channel
// (report same error as for "type _ <-chan<-E")
p.syntax_error(fmt.Sprintf("unexpected %v, expecting chan", t))
// already progressed, no need to advance
}
return x
}
// x is not a channel type => we have a receive op
return Nod(ORECV, x, nil)
default:
return p.pexpr(false)
}
// simple uexpr
p.next()
return Nod(op, p.uexpr(), nil)
}
// pseudocall parses call-like statements that can be preceded by 'defer' and 'go'.
func (p *parser) pseudocall() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("pseudocall")()
}
x := p.pexpr(p.tok == '(') // keep_parens so we can report error below
switch x.Op {
case OCALL:
return x
case OPAREN:
Yyerror("expression in go/defer must not be parenthesized")
// already progressed, no need to advance
default:
Yyerror("expression in go/defer must be function call")
// already progressed, no need to advance
}
return nil
}
// 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) *Node {
if trace && Debug['x'] != 0 {
defer p.trace("operand")()
}
switch p.tok {
case LLITERAL:
x := nodlit(p.val)
p.next()
return x
case LNAME, '@', '?':
return p.name()
case '(':
p.next()
p.xnest++
x := p.expr() // expr_or_type
p.xnest--
p.want(')')
// 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 on lhs of := .
switch x.Op {
case ONAME, ONONAME, OPACK, OTYPE, OLITERAL, OTYPESW:
keep_parens = true
}
// 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 == '{' {
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 {
x = Nod(OPAREN, x, nil)
}
return x
case LFUNC:
t := p.ntype() // fntype
if p.tok == '{' {
// fnlitdcl
closurehdr(t)
// fnliteral
p.next() // consume '{'
p.fnest++
p.xnest++
body := p.stmt_list()
p.xnest--
p.fnest--
p.want('}')
return closurebody(body)
}
return t
case '[', LCHAN, LMAP, LSTRUCT, LINTERFACE:
return p.ntype() // othertype
case '{':
// common case: p.header is missing simple_stmt before { in if, for, switch
p.syntax_error("missing operand")
// '{' will be consumed in pexpr - no need to consume it here
return nil
default:
p.syntax_error("expecting expression")
p.advance()
return nil
}
// Syntactically, composite literals are operands. Because a complit
// type may be a qualified identifier which is handled by pexpr
// (together with selector expressions), complits are parsed there
// as well (operand is only called from pexpr).
}
// PrimaryExpr =
// Operand |
// Conversion |
// PrimaryExpr Selector |
// PrimaryExpr Index |
// PrimaryExpr Slice |
// PrimaryExpr TypeAssertion |
// PrimaryExpr Arguments .
//
// Selector = "." identifier .
// Index = "[" Expression "]" .
// Slice = "[" ( [ Expression ] ":" [ Expression ] ) |
// ( [ Expression ] ":" Expression ":" Expression )
// "]" .
// TypeAssertion = "." "(" Type ")" .
// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
func (p *parser) pexpr(keep_parens bool) *Node {
if trace && Debug['x'] != 0 {
defer p.trace("pexpr")()
}
x := p.operand(keep_parens)
loop:
for {
switch p.tok {
case '.':
p.next()
switch p.tok {
case LNAME, '@', '?':
// pexpr '.' sym
x = p.new_dotname(x)
case '(':
p.next()
switch p.tok {
default:
// pexpr '.' '(' expr_or_type ')'
t := p.expr() // expr_or_type
p.want(')')
x = Nod(ODOTTYPE, x, t)
case LTYPE:
// pexpr '.' '(' LTYPE ')'
p.next()
p.want(')')
x = Nod(OTYPESW, nil, x)
}
default:
p.syntax_error("expecting name or (")
p.advance(';', '}')
}
case '[':
p.next()
p.xnest++
var index [3]*Node
if p.tok != ':' {
index[0] = p.expr()
}
ncol := 0
for ncol < len(index)-1 && p.got(':') {
ncol++
if p.tok != EOF && p.tok != ':' && p.tok != ']' {
index[ncol] = p.expr()
}
}
p.xnest--
p.want(']')
switch ncol {
case 0:
i := index[0]
if i == nil {
Yyerror("missing index in index expression")
}
x = Nod(OINDEX, x, i)
case 1:
i := index[0]
j := index[1]
x = Nod(OSLICE, x, Nod(OKEY, i, j))
case 2:
i := index[0]
j := index[1]
k := index[2]
if j == nil {
Yyerror("middle index required in 3-index slice")
}
if k == nil {
Yyerror("final index required in 3-index slice")
}
x = Nod(OSLICE3, x, Nod(OKEY, i, Nod(OKEY, j, k)))
default:
panic("unreachable")
}
case '(':
// convtype '(' expr ocomma ')'
args, ddd := p.arg_list()
// call or conversion
x = Nod(OCALL, x, nil)
x.List.Set(args)
x.Isddd = ddd
case '{':
// 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 complit or a compound_stmt
complit_ok := false
switch t.Op {
case ONAME, ONONAME, OTYPE, OPACK, OXDOT, ODOT:
if p.xnest >= 0 {
// x is considered a comptype
complit_ok = true
}
case OTARRAY, OTSTRUCT, OTMAP:
// x is a comptype
complit_ok = true
}
if !complit_ok {
break loop
}
if t != x {
p.syntax_error("cannot parenthesize type in composite literal")
// already progressed, no need to advance
}
n := p.complitexpr()
n.Right = x
x = n
default:
break loop
}
}
return x
}
// KeyedElement = [ Key ":" ] Element .
func (p *parser) keyval() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("keyval")()
}
// A composite literal commonly spans several lines,
// so the line number on errors may be misleading.
// Wrap values (but not keys!) that don't carry line
// numbers.
x := p.bare_complitexpr()
if p.got(':') {
// key ':' value
return Nod(OKEY, x, wrapname(p.bare_complitexpr()))
}
// value
return wrapname(x)
}
func wrapname(x *Node) *Node {
// These nodes do not carry line numbers.
// Introduce a wrapper node to give the correct line.
switch x.Op {
case ONAME, ONONAME, OTYPE, OPACK, OLITERAL:
x = Nod(OPAREN, x, nil)
x.Implicit = true
}
return x
}
// Element = Expression | LiteralValue .
func (p *parser) bare_complitexpr() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("bare_complitexpr")()
}
if p.tok == '{' {
// '{' start_complit braced_keyval_list '}'
return p.complitexpr()
}
return p.expr()
}
// LiteralValue = "{" [ ElementList [ "," ] ] "}" .
func (p *parser) complitexpr() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("complitexpr")()
}
// make node early so we get the right line number
n := Nod(OCOMPLIT, nil, nil)
p.want('{')
p.xnest++
var l []*Node
for p.tok != EOF && p.tok != '}' {
l = append(l, p.keyval())
if !p.ocomma('}') {
break
}
}
p.xnest--
p.want('}')
n.List.Set(l)
return n
}
// names and types
// newname is used before declared
// oldname is used after declared
func (p *parser) new_name(sym *Sym) *Node {
if trace && Debug['x'] != 0 {
defer p.trace("new_name")()
}
if sym != nil {
return newname(sym)
}
return nil
}
func (p *parser) dcl_name() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("dcl_name")()
}
symlineno := lineno
sym := p.sym()
if sym == nil {
yyerrorl(symlineno, "invalid declaration")
return nil
}
return dclname(sym)
}
func (p *parser) onew_name() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("onew_name")()
}
switch p.tok {
case LNAME, '@', '?':
return p.new_name(p.sym())
}
return nil
}
func (p *parser) sym() *Sym {
switch p.tok {
case LNAME:
s := p.sym_
p.next()
// during imports, unqualified non-exported identifiers are from builtinpkg
if importpkg != nil && !exportname(s.Name) {
s = Pkglookup(s.Name, builtinpkg)
}
return s
case '@':
return p.hidden_importsym()
case '?':
p.next()
return nil
default:
p.syntax_error("expecting name")
p.advance()
return new(Sym)
}
}
func mkname(sym *Sym) *Node {
n := oldname(sym)
if n.Name != nil && n.Name.Pack != nil {
n.Name.Pack.Used = true
}
return n
}
func (p *parser) name() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("name")()
}
return mkname(p.sym())
}
// [ "..." ] Type
func (p *parser) dotdotdot() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("dotdotdot")()
}
p.want(LDDD)
if typ := p.try_ntype(); typ != nil {
return Nod(ODDD, typ, nil)
}
Yyerror("final argument in variadic function missing type")
return Nod(ODDD, typenod(typ(TINTER)), nil)
}
func (p *parser) ntype() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("ntype")()
}
if typ := p.try_ntype(); typ != nil {
return typ
}
p.syntax_error("")
p.advance()
return nil
}
// try_ntype is like ntype 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 | ChannelType .
func (p *parser) try_ntype() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("try_ntype")()
}
switch p.tok {
case LCOMM:
// recvchantype
p.next()
p.want(LCHAN)
t := Nod(OTCHAN, p.chan_elem(), nil)
t.Etype = Crecv
return t
case LFUNC:
// fntype
p.next()
params := p.param_list()
result := p.fnres()
params = checkarglist(params, 1)
t := Nod(OTFUNC, nil, nil)
t.List.Set(params)
t.Rlist.Set(result)
return t
case '[':
// '[' oexpr ']' ntype
// '[' LDDD ']' ntype
p.next()
p.xnest++
var len *Node
if p.tok != ']' {
if p.got(LDDD) {
len = Nod(ODDD, nil, nil)
} else {
len = p.expr()
}
}
p.xnest--
p.want(']')
return Nod(OTARRAY, len, p.ntype())
case LCHAN:
// LCHAN non_recvchantype
// LCHAN LCOMM ntype
p.next()
var dir EType = Cboth
if p.got(LCOMM) {
dir = Csend
}
t := Nod(OTCHAN, p.chan_elem(), nil)
t.Etype = dir
return t
case LMAP:
// LMAP '[' ntype ']' ntype
p.next()
p.want('[')
key := p.ntype()
p.want(']')
val := p.ntype()
return Nod(OTMAP, key, val)
case LSTRUCT:
return p.structtype()
case LINTERFACE:
return p.interfacetype()
case '*':
// ptrtype
p.next()
return Nod(OIND, p.ntype(), nil)
case LNAME, '@', '?':
return p.dotname()
case '(':
p.next()
t := p.ntype()
p.want(')')
return t
default:
return nil
}
}
func (p *parser) chan_elem() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("chan_elem")()
}
if typ := p.try_ntype(); typ != nil {
return typ
}
p.syntax_error("missing channel element type")
// assume element type is simply absent - don't advance
return nil
}
func (p *parser) new_dotname(obj *Node) *Node {
if trace && Debug['x'] != 0 {
defer p.trace("new_dotname")()
}
sel := p.sym()
if obj.Op == OPACK {
s := restrictlookup(sel.Name, obj.Name.Pkg)
obj.Used = true
return oldname(s)
}
return Nod(OXDOT, obj, newname(sel))
}
func (p *parser) dotname() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("dotname")()
}
name := p.name()
if p.got('.') {
return p.new_dotname(name)
}
return name
}
// StructType = "struct" "{" { FieldDecl ";" } "}" .
func (p *parser) structtype() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("structtype")()
}
p.want(LSTRUCT)
p.want('{')
var l []*Node
for p.tok != EOF && p.tok != '}' {
l = append(l, p.structdcl()...)
if !p.osemi('}') {
break
}
}
p.want('}')
t := Nod(OTSTRUCT, nil, nil)
t.List.Set(l)
return t
}
// InterfaceType = "interface" "{" { MethodSpec ";" } "}" .
func (p *parser) interfacetype() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("interfacetype")()
}
p.want(LINTERFACE)
p.want('{')
var l []*Node
for p.tok != EOF && p.tok != '}' {
l = append(l, p.interfacedcl())
if !p.osemi('}') {
break
}
}
p.want('}')
t := Nod(OTINTER, nil, nil)
t.List.Set(l)
return t
}
// Function stuff.
// All in one place to show how crappy it all is.
func (p *parser) xfndcl() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("xfndcl")()
}
p.want(LFUNC)
f := p.fndcl(p.pragma&Nointerface != 0)
body := p.fnbody()
if f == nil {
return nil
}
f.Nbody.Set(body)
f.Noescape = p.pragma&Noescape != 0
if f.Noescape && len(body) != 0 {
Yyerror("can only use //go:noescape with external func implementations")
}
f.Func.Pragma = p.pragma
f.Func.Endlineno = lineno
funcbody(f)
return f
}
// FunctionDecl = "func" FunctionName ( Function | Signature ) .
// FunctionName = identifier .
// Function = Signature FunctionBody .
// MethodDecl = "func" Receiver MethodName ( Function | Signature ) .
// Receiver = Parameters .
func (p *parser) fndcl(nointerface bool) *Node {
if trace && Debug['x'] != 0 {
defer p.trace("fndcl")()
}
switch p.tok {
case LNAME, '@', '?':
// sym '(' oarg_type_list_ocomma ')' fnres
name := p.sym()
params := p.param_list()
result := p.fnres()
params = checkarglist(params, 1)
if name.Name == "init" {
name = renameinit()
if len(params) != 0 || len(result) != 0 {
Yyerror("func init must have no arguments and no return values")
}
}
if localpkg.Name == "main" && name.Name == "main" {
if len(params) != 0 || len(result) != 0 {
Yyerror("func main must have no arguments and no return values")
}
}
t := Nod(OTFUNC, nil, nil)
t.List.Set(params)
t.Rlist.Set(result)
f := Nod(ODCLFUNC, nil, nil)
f.Func.Nname = newfuncname(name)
f.Func.Nname.Name.Defn = f
f.Func.Nname.Name.Param.Ntype = t // TODO: check if nname already has an ntype
declare(f.Func.Nname, PFUNC)
funchdr(f)
return f
case '(':
// '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres
rparam := p.param_list()
name := p.sym()
params := p.param_list()
result := p.fnres()
rparam = checkarglist(rparam, 0)
params = checkarglist(params, 1)
if len(rparam) == 0 {
Yyerror("method has no receiver")
return nil
}
if len(rparam) > 1 {
Yyerror("method has multiple receivers")
return nil
}
rcvr := rparam[0]
if rcvr.Op != ODCLFIELD {
Yyerror("bad receiver in method")
return nil
}
t := Nod(OTFUNC, rcvr, nil)
t.List.Set(params)
t.Rlist.Set(result)
f := Nod(ODCLFUNC, nil, nil)
f.Func.Shortname = newfuncname(name)
f.Func.Nname = methodname1(f.Func.Shortname, rcvr.Right)
f.Func.Nname.Name.Defn = f
f.Func.Nname.Name.Param.Ntype = t
f.Func.Nname.Nointerface = nointerface
declare(f.Func.Nname, PFUNC)
funchdr(f)
return f
default:
p.syntax_error("expecting name or (")
p.advance('{', ';')
return nil
}
}
func (p *parser) hidden_fndcl() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_fndcl")()
}
switch p.tok {
default:
// hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres
s1 := p.hidden_pkg_importsym()
p.want('(')
s3 := p.ohidden_funarg_list()
p.want(')')
s5 := p.ohidden_funres()
s := s1
t := functype(nil, s3, s5)
importsym(s, ONAME)
if s.Def != nil && s.Def.Op == ONAME {
if Eqtype(t, s.Def.Type) {
dclcontext = PDISCARD // since we skip funchdr below
return nil
}
Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", s, s.Def.Type, t)
}
ss := newfuncname(s)
ss.Type = t
declare(ss, PFUNC)
funchdr(ss)
return ss
case '(':
// '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres
p.next()
s2 := p.hidden_funarg_list()
p.want(')')
s4 := p.sym()
p.want('(')
s6 := p.ohidden_funarg_list()
p.want(')')
s8 := p.ohidden_funres()
ss := methodname1(newname(s4), s2[0].Right)
ss.Type = functype(s2[0], s6, s8)
checkwidth(ss.Type)
addmethod(s4, ss.Type, p.structpkg, false, false)
funchdr(ss)
// inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
// (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled
// out by typecheck's lookdot as this $$.ttype. So by providing
// this back link here we avoid special casing there.
ss.Type.Nname = ss
return ss
}
}
// FunctionBody = Block .
func (p *parser) fnbody() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("fnbody")()
}
if p.got('{') {
p.fnest++
body := p.stmt_list()
p.fnest--
p.want('}')
if body == nil {
body = []*Node{Nod(OEMPTY, nil, nil)}
}
return body
}
return nil
}
// Result = Parameters | Type .
func (p *parser) fnres() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("fnres")()
}
if p.tok == '(' {
result := p.param_list()
return checkarglist(result, 0)
}
if result := p.try_ntype(); result != nil {
return []*Node{Nod(ODCLFIELD, nil, result)}
}
return nil
}
// Declaration = ConstDecl | TypeDecl | VarDecl .
// TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
func (p *parser) xdcl_list() (l []*Node) {
if trace && Debug['x'] != 0 {
defer p.trace("xdcl_list")()
}
for p.tok != EOF {
switch p.tok {
case LVAR, LCONST, LTYPE:
l = append(l, p.common_dcl()...)
case LFUNC:
l = append(l, p.xfndcl())
default:
if p.tok == '{' && len(l) != 0 && l[len(l)-1].Op == ODCLFUNC && l[len(l)-1].Nbody.Len() == 0 {
// opening { of function declaration on next line
p.syntax_error("unexpected semicolon or newline before {")
} else {
p.syntax_error("non-declaration statement outside function body")
}
p.advance(LVAR, LCONST, LTYPE, LFUNC)
continue
}
if nsyntaxerrors == 0 {
testdclstack()
}
// Reset p.pragma BEFORE advancing to the next token (consuming ';')
// since comments before may set pragmas for the next function decl.
p.pragma = 0
if p.tok != EOF && !p.got(';') {
p.syntax_error("after top level declaration")
p.advance(LVAR, LCONST, LTYPE, LFUNC)
}
}
return
}
// FieldDecl = (IdentifierList Type | AnonymousField) [ Tag ] .
// AnonymousField = [ "*" ] TypeName .
// Tag = string_lit .
func (p *parser) structdcl() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("structdcl")()
}
var sym *Sym
switch p.tok {
case LNAME:
sym = p.sym_
p.next()
if sym == nil {
panic("unreachable") // we must have a sym for LNAME
}
if p.tok == '.' || p.tok == LLITERAL || p.tok == ';' || p.tok == '}' {
// embed oliteral
field := p.embed(sym)
tag := p.oliteral()
field.SetVal(tag)
return []*Node{field}
}
// LNAME belongs to first *Sym of new_name_list
//
// during imports, unqualified non-exported identifiers are from builtinpkg
if importpkg != nil && !exportname(sym.Name) {
sym = Pkglookup(sym.Name, builtinpkg)
if sym == nil {
p.import_error()
}
}
fallthrough
case '@', '?':
// new_name_list ntype oliteral
fields := p.new_name_list(sym)
typ := p.ntype()
tag := p.oliteral()
if len(fields) == 0 || fields[0].Sym.Name == "?" {
// ? symbol, during import
n := typ
if n.Op == OIND {
n = n.Left
}
n = embedded(n.Sym, importpkg)
n.Right = typ
n.SetVal(tag)
return []*Node{n}
}
for i, n := range fields {
fields[i] = Nod(ODCLFIELD, n, typ)
fields[i].SetVal(tag)
}
return fields
case '(':
p.next()
if p.got('*') {
// '(' '*' embed ')' oliteral
field := p.embed(nil)
p.want(')')
tag := p.oliteral()
field.Right = Nod(OIND, field.Right, nil)
field.SetVal(tag)
Yyerror("cannot parenthesize embedded type")
return []*Node{field}
} else {
// '(' embed ')' oliteral
field := p.embed(nil)
p.want(')')
tag := p.oliteral()
field.SetVal(tag)
Yyerror("cannot parenthesize embedded type")
return []*Node{field}
}
case '*':
p.next()
if p.got('(') {
// '*' '(' embed ')' oliteral
field := p.embed(nil)
p.want(')')
tag := p.oliteral()
field.Right = Nod(OIND, field.Right, nil)
field.SetVal(tag)
Yyerror("cannot parenthesize embedded type")
return []*Node{field}
} else {
// '*' embed oliteral
field := p.embed(nil)
tag := p.oliteral()
field.Right = Nod(OIND, field.Right, nil)
field.SetVal(tag)
return []*Node{field}
}
default:
p.syntax_error("expecting field name or embedded type")
p.advance(';', '}')
return nil
}
}
func (p *parser) oliteral() (v Val) {
if p.tok == LLITERAL {
v = p.val
p.next()
}
return
}
func (p *parser) packname(name *Sym) *Sym {
if trace && Debug['x'] != 0 {
defer p.trace("embed")()
}
if name != nil {
// LNAME was already consumed and is coming in as name
} else if p.tok == LNAME {
name = p.sym_
p.next()
} else {
p.syntax_error("expecting name")
p.advance('.', ';', '}')
name = new(Sym)
}
if p.got('.') {
// LNAME '.' sym
s := p.sym()
var pkg *Pkg
if name.Def == nil || name.Def.Op != OPACK {
Yyerror("%v is not a package", name)
pkg = localpkg
} else {
name.Def.Used = true
pkg = name.Def.Name.Pkg
}
return restrictlookup(s.Name, pkg)
}
// LNAME
if n := oldname(name); n.Name != nil && n.Name.Pack != nil {
n.Name.Pack.Used = true
}
return name
}
func (p *parser) embed(sym *Sym) *Node {
if trace && Debug['x'] != 0 {
defer p.trace("embed")()
}
pkgname := p.packname(sym)
return embedded(pkgname, localpkg)
}
// MethodSpec = MethodName Signature | InterfaceTypeName .
// MethodName = identifier .
// InterfaceTypeName = TypeName .
func (p *parser) interfacedcl() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("interfacedcl")()
}
switch p.tok {
case LNAME:
sym := p.sym_
p.next()
// accept potential name list but complain
hasNameList := false
for p.got(',') {
p.sym()
hasNameList = true
}
if hasNameList {
p.syntax_error("name list not allowed in interface type")
// already progressed, no need to advance
}
if p.tok != '(' {
// packname
pname := p.packname(sym)
return Nod(ODCLFIELD, nil, oldname(pname))
}
// newname indcl
mname := newname(sym)
sig := p.indcl()
meth := Nod(ODCLFIELD, mname, sig)
ifacedcl(meth)
return meth
case '@', '?':
// newname indcl
// We arrive here when parsing an interface type declared inside
// an exported and inlineable function and the interface declares
// unexported methods (which are then package-qualified).
//
// Since the compiler always flattens embedded interfaces, we
// will never see an embedded package-qualified interface in export
// data; i.e., when we reach here we know it must be a method.
//
// See also issue 14164.
mname := newname(p.sym())
sig := p.indcl()
meth := Nod(ODCLFIELD, mname, sig)
ifacedcl(meth)
return meth
case '(':
p.next()
pname := p.packname(nil)
p.want(')')
n := Nod(ODCLFIELD, nil, oldname(pname))
Yyerror("cannot parenthesize embedded type")
return n
default:
p.syntax_error("")
p.advance(';', '}')
return nil
}
}
// MethodSpec = MethodName Signature .
// MethodName = identifier .
func (p *parser) indcl() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("indcl")()
}
params := p.param_list()
result := p.fnres()
// without func keyword
params = checkarglist(params, 1)
t := Nod(OTFUNC, fakethis(), nil)
t.List.Set(params)
t.Rlist.Set(result)
return t
}
// ParameterDecl = [ IdentifierList ] [ "..." ] Type .
func (p *parser) arg_type() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("arg_type")()
}
switch p.tok {
case LNAME, '@', '?':
name := p.sym()
switch p.tok {
case LCOMM, LFUNC, '[', LCHAN, LMAP, LSTRUCT, LINTERFACE, '*', LNAME, '@', '?', '(':
// sym name_or_type
typ := p.ntype()
nn := Nod(ONONAME, nil, nil)
nn.Sym = name
return Nod(OKEY, nn, typ)
case LDDD:
// sym dotdotdot
typ := p.dotdotdot()
nn := Nod(ONONAME, nil, nil)
nn.Sym = name
return Nod(OKEY, nn, typ)
default:
// name_or_type
name := mkname(name)
// from dotname
if p.got('.') {
return p.new_dotname(name)
}
return name
}
case LDDD:
// dotdotdot
return p.dotdotdot()
case LCOMM, LFUNC, '[', LCHAN, LMAP, LSTRUCT, LINTERFACE, '*', '(':
// name_or_type
return p.ntype()
default:
p.syntax_error("expecting )")
p.advance(',', ')')
return nil
}
}
// Parameters = "(" [ ParameterList [ "," ] ] ")" .
// ParameterList = ParameterDecl { "," ParameterDecl } .
func (p *parser) param_list() (l []*Node) {
if trace && Debug['x'] != 0 {
defer p.trace("param_list")()
}
p.want('(')
for p.tok != EOF && p.tok != ')' {
l = append(l, p.arg_type())
if !p.ocomma(')') {
break
}
}
p.want(')')
return
}
var missing_stmt = Nod(OXXX, nil, nil)
// Statement =
// Declaration | LabeledStmt | SimpleStmt |
// GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
// FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
// DeferStmt .
//
// stmt may return missing_stmt.
func (p *parser) stmt() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("stmt")()
}
switch p.tok {
case '{':
return p.compound_stmt()
case LVAR, LCONST, LTYPE:
return liststmt(p.common_dcl())
case LNAME, '@', '?', LLITERAL, LFUNC, '(', // operands
'[', LSTRUCT, LMAP, LCHAN, LINTERFACE, // composite types
'+', '-', '*', '&', '^', '~', LCOMM, '!': // unary operators
return p.simple_stmt(true, false)
case LFOR:
return p.for_stmt()
case LSWITCH:
return p.switch_stmt()
case LSELECT:
return p.select_stmt()
case LIF:
return p.if_stmt()
case LFALL:
p.next()
// will be converted to OFALL
stmt := Nod(OXFALL, nil, nil)
stmt.Xoffset = int64(block)
return stmt
case LBREAK:
p.next()
return Nod(OBREAK, p.onew_name(), nil)
case LCONTINUE:
p.next()
return Nod(OCONTINUE, p.onew_name(), nil)
case LGO:
p.next()
return Nod(OPROC, p.pseudocall(), nil)
case LDEFER:
p.next()
return Nod(ODEFER, p.pseudocall(), nil)
case LGOTO:
p.next()
stmt := Nod(OGOTO, p.new_name(p.sym()), nil)
stmt.Sym = dclstack // context, for goto restrictions
return stmt
case LRETURN:
p.next()
var results []*Node
if p.tok != ';' && p.tok != '}' {
results = p.expr_list()
}
stmt := Nod(ORETURN, nil, nil)
stmt.List.Set(results)
if stmt.List.Len() == 0 && Curfn != nil {
for _, ln := range Curfn.Func.Dcl {
if ln.Class == PPARAM {
continue
}
if ln.Class != PPARAMOUT {
break
}
if ln.Sym.Def != ln {
Yyerror("%s is shadowed during return", ln.Sym.Name)
}
}
}
return stmt
case ';':
return nil
default:
return missing_stmt
}
}
// StatementList = { Statement ";" } .
func (p *parser) stmt_list() (l []*Node) {
if trace && Debug['x'] != 0 {
defer p.trace("stmt_list")()
}
for p.tok != EOF && p.tok != '}' && p.tok != LCASE && p.tok != LDEFAULT {
s := p.stmt()
if s == missing_stmt {
break
}
if s == nil {
} else if s.Op == OBLOCK && s.Ninit.Len() == 0 {
l = append(l, s.List.Slice()...)
} else {
l = append(l, s)
}
// customized version of osemi:
// ';' is optional before a closing ')' or '}'
if p.tok == ')' || p.tok == '}' {
continue
}
if !p.got(';') {
p.syntax_error("at end of statement")
p.advance(';', '}')
}
}
return
}
// IdentifierList = identifier { "," identifier } .
//
// If first != nil we have the first symbol already.
func (p *parser) new_name_list(first *Sym) []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("new_name_list")()
}
if first == nil {
first = p.sym() // may still be nil
}
var l []*Node
n := p.new_name(first)
if n != nil {
l = append(l, n)
}
for p.got(',') {
n = p.new_name(p.sym())
if n != nil {
l = append(l, n)
}
}
return l
}
// IdentifierList = identifier { "," identifier } .
func (p *parser) dcl_name_list() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("dcl_name_list")()
}
s := []*Node{p.dcl_name()}
for p.got(',') {
s = append(s, p.dcl_name())
}
return s
}
// ExpressionList = Expression { "," Expression } .
func (p *parser) expr_list() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("expr_list")()
}
l := []*Node{p.expr()}
for p.got(',') {
l = append(l, p.expr())
}
return l
}
// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
func (p *parser) arg_list() (l []*Node, ddd bool) {
if trace && Debug['x'] != 0 {
defer p.trace("arg_list")()
}
p.want('(')
p.xnest++
for p.tok != EOF && p.tok != ')' && !ddd {
l = append(l, p.expr()) // expr_or_type
ddd = p.got(LDDD)
if !p.ocomma(')') {
break
}
}
p.xnest--
p.want(')')
return
}
// osemi parses an optional semicolon.
func (p *parser) osemi(follow int32) bool {
switch p.tok {
case ';':
p.next()
return true
case ')', '}':
// semicolon is optional before ) or }
return true
}
p.syntax_error("expecting semicolon, newline, or " + tokstring(follow))
p.advance(follow)
return false
}
// ocomma parses an optional comma.
func (p *parser) ocomma(follow int32) bool {
switch p.tok {
case ',':
p.next()
return true
case ')', '}':
// comma is optional before ) or }
return true
}
p.syntax_error("expecting comma or " + tokstring(follow))
p.advance(follow)
return false
}
// ----------------------------------------------------------------------------
// Importing packages
func (p *parser) import_error() {
p.syntax_error("in export data of imported package")
p.next()
}
// The methods below reflect a 1:1 translation of the original (and now defunct)
// go.y yacc productions. They could be simplified significantly and also use better
// variable names. However, we will be able to delete them once we enable the
// new export format by default, so it's not worth the effort (issue 13241).
func (p *parser) hidden_importsym() *Sym {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_importsym")()
}
p.want('@')
var s2 Val
if p.tok == LLITERAL {
s2 = p.val
p.next()
} else {
p.import_error()
}
p.want('.')
switch p.tok {
case LNAME:
s4 := p.sym_
p.next()
var p *Pkg
if s2.U.(string) == "" {
p = importpkg
} else {
if isbadimport(s2.U.(string)) {
errorexit()
}
p = mkpkg(s2.U.(string))
}
return Pkglookup(s4.Name, p)
case '?':
p.next()
var p *Pkg
if s2.U.(string) == "" {
p = importpkg
} else {
if isbadimport(s2.U.(string)) {
errorexit()
}
p = mkpkg(s2.U.(string))
}
return Pkglookup("?", p)
default:
p.import_error()
return nil
}
}
func (p *parser) ohidden_funarg_list() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("ohidden_funarg_list")()
}
var ss []*Node
if p.tok != ')' {
ss = p.hidden_funarg_list()
}
return ss
}
func (p *parser) ohidden_structdcl_list() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("ohidden_structdcl_list")()
}
var ss []*Node
if p.tok != '}' {
ss = p.hidden_structdcl_list()
}
return ss
}
func (p *parser) ohidden_interfacedcl_list() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("ohidden_interfacedcl_list")()
}
var ss []*Node
if p.tok != '}' {
ss = p.hidden_interfacedcl_list()
}
return ss
}
// import syntax from package header
func (p *parser) hidden_import() {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_import")()
}
switch p.tok {
case LIMPORT:
// LIMPORT LNAME LLITERAL ';'
p.next()
var s2 *Sym
if p.tok == LNAME {
s2 = p.sym_
p.next()
} else {
p.import_error()
}
var s3 Val
if p.tok == LLITERAL {
s3 = p.val
p.next()
} else {
p.import_error()
}
p.want(';')
importimport(s2, s3.U.(string))
case LVAR:
// LVAR hidden_pkg_importsym hidden_type ';'
p.next()
s2 := p.hidden_pkg_importsym()
s3 := p.hidden_type()
p.want(';')
importvar(s2, s3)
case LCONST:
// LCONST hidden_pkg_importsym '=' hidden_constant ';'
// LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'
p.next()
s2 := p.hidden_pkg_importsym()
var s3 *Type = Types[TIDEAL]
if p.tok != '=' {
s3 = p.hidden_type()
}
p.want('=')
s4 := p.hidden_constant()
p.want(';')
importconst(s2, s3, s4)
case LTYPE:
// LTYPE hidden_pkgtype hidden_type ';'
p.next()
s2 := p.hidden_pkgtype()
s3 := p.hidden_type()
p.want(';')
importtype(s2, s3)
case LFUNC:
// LFUNC hidden_fndcl fnbody ';'
p.next()
s2 := p.hidden_fndcl()
s3 := p.fnbody()
p.want(';')
if s2 == nil {
dclcontext = PEXTERN // since we skip the funcbody below
return
}
s2.Func.Inl.Set(s3)
funcbody(s2)
importlist = append(importlist, s2)
if Debug['E'] > 0 {
fmt.Printf("import [%q] func %v \n", importpkg.Path, s2)
if Debug['m'] > 2 && len(s2.Func.Inl.Slice()) != 0 {
fmt.Printf("inl body:%v\n", s2.Func.Inl)
}
}
default:
p.import_error()
}
}
func (p *parser) hidden_pkg_importsym() *Sym {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_pkg_importsym")()
}
s := p.hidden_importsym()
p.structpkg = s.Pkg
return s
}
func (p *parser) hidden_pkgtype() *Type {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_pkgtype")()
}
s1 := p.hidden_pkg_importsym()
ss := pkgtype(s1)
importsym(s1, OTYPE)
return ss
}
// ----------------------------------------------------------------------------
// Importing types
func (p *parser) hidden_type() *Type {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_type")()
}
switch p.tok {
default:
return p.hidden_type_misc()
case LCOMM:
return p.hidden_type_recv_chan()
case LFUNC:
return p.hidden_type_func()
}
}
func (p *parser) hidden_type_non_recv_chan() *Type {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_type_non_recv_chan")()
}
switch p.tok {
default:
return p.hidden_type_misc()
case LFUNC:
return p.hidden_type_func()
}
}
func (p *parser) hidden_type_misc() *Type {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_type_misc")()
}
switch p.tok {
case '@':
// hidden_importsym
s1 := p.hidden_importsym()
return pkgtype(s1)
case LNAME:
// LNAME
s1 := p.sym_
p.next()
// predefined name like uint8
s1 = Pkglookup(s1.Name, builtinpkg)
if s1.Def == nil || s1.Def.Op != OTYPE {
Yyerror("%s is not a type", s1.Name)
return nil
} else {
return s1.Def.Type
}
case '[':
// '[' ']' hidden_type
// '[' LLITERAL ']' hidden_type
p.next()
var s2 *Node
if p.tok == LLITERAL {
s2 = nodlit(p.val)
p.next()
}
p.want(']')
s4 := p.hidden_type()
return aindex(s2, s4)
case LMAP:
// LMAP '[' hidden_type ']' hidden_type
p.next()
p.want('[')
s3 := p.hidden_type()
p.want(']')
s5 := p.hidden_type()
return maptype(s3, s5)
case LSTRUCT:
// LSTRUCT '{' ohidden_structdcl_list '}'
p.next()
p.want('{')
s3 := p.ohidden_structdcl_list()
p.want('}')
return tostruct(s3)
case LINTERFACE:
// LINTERFACE '{' ohidden_interfacedcl_list '}'
p.next()
p.want('{')
s3 := p.ohidden_interfacedcl_list()
p.want('}')
return tointerface(s3)
case '*':
// '*' hidden_type
p.next()
s2 := p.hidden_type()
return Ptrto(s2)
case LCHAN:
p.next()
switch p.tok {
default:
// LCHAN hidden_type_non_recv_chan
s2 := p.hidden_type_non_recv_chan()
ss := typ(TCHAN)
ss.Type = s2
ss.Chan = Cboth
return ss
case '(':
// LCHAN '(' hidden_type_recv_chan ')'
p.next()
s3 := p.hidden_type_recv_chan()
p.want(')')
ss := typ(TCHAN)
ss.Type = s3
ss.Chan = Cboth
return ss
case LCOMM:
// LCHAN hidden_type
p.next()
s3 := p.hidden_type()
ss := typ(TCHAN)
ss.Type = s3
ss.Chan = Csend
return ss
}
default:
p.import_error()
return nil
}
}
func (p *parser) hidden_type_recv_chan() *Type {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_type_recv_chan")()
}
p.want(LCOMM)
p.want(LCHAN)
s3 := p.hidden_type()
ss := typ(TCHAN)
ss.Type = s3
ss.Chan = Crecv
return ss
}
func (p *parser) hidden_type_func() *Type {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_type_func")()
}
p.want(LFUNC)
p.want('(')
s3 := p.ohidden_funarg_list()
p.want(')')
s5 := p.ohidden_funres()
return functype(nil, s3, s5)
}
func (p *parser) hidden_funarg() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_funarg")()
}
s1 := p.sym()
switch p.tok {
default:
s2 := p.hidden_type()
s3 := p.oliteral()
ss := Nod(ODCLFIELD, nil, typenod(s2))
if s1 != nil {
ss.Left = newname(s1)
}
ss.SetVal(s3)
return ss
case LDDD:
p.next()
s3 := p.hidden_type()
s4 := p.oliteral()
var t *Type
t = typ(TARRAY)
t.Bound = -1
t.Type = s3
ss := Nod(ODCLFIELD, nil, typenod(t))
if s1 != nil {
ss.Left = newname(s1)
}
ss.Isddd = true
ss.SetVal(s4)
return ss
}
}
func (p *parser) hidden_structdcl() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_structdcl")()
}
s1 := p.sym()
s2 := p.hidden_type()
s3 := p.oliteral()
var s *Sym
var pkg *Pkg
var ss *Node
if s1 != nil && s1.Name != "?" {
ss = Nod(ODCLFIELD, newname(s1), typenod(s2))
ss.SetVal(s3)
} else {
s = s2.Sym
if s == nil && Isptr[s2.Etype] {
s = s2.Type.Sym
}
pkg = importpkg
if s1 != nil {
pkg = s1.Pkg
}
ss = embedded(s, pkg)
ss.Right = typenod(s2)
ss.SetVal(s3)
}
return ss
}
func (p *parser) hidden_interfacedcl() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_interfacedcl")()
}
// The original (now defunct) grammar in go.y accepted both a method
// or an (embedded) type:
//
// hidden_interfacedcl:
// sym '(' ohidden_funarg_list ')' ohidden_funres
// {
// $$ = Nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
// }
// | hidden_type
// {
// $$ = Nod(ODCLFIELD, nil, typenod($1));
// }
//
// But the current textual export code only exports (inlined) methods,
// even if the methods came from embedded interfaces. Furthermore, in
// the original grammar, hidden_type may also start with a sym (LNAME
// or '@'), complicating matters further. Since we never have embedded
// types, only parse methods here.
s1 := p.sym()
p.want('(')
s3 := p.ohidden_funarg_list()
p.want(')')
s5 := p.ohidden_funres()
return Nod(ODCLFIELD, newname(s1), typenod(functype(fakethis(), s3, s5)))
}
func (p *parser) ohidden_funres() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("ohidden_funres")()
}
switch p.tok {
default:
return nil
case '(', '@', LNAME, '[', LMAP, LSTRUCT, LINTERFACE, '*', LCHAN, LCOMM, LFUNC:
return p.hidden_funres()
}
}
func (p *parser) hidden_funres() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_funres")()
}
switch p.tok {
case '(':
p.next()
s2 := p.ohidden_funarg_list()
p.want(')')
return s2
default:
s1 := p.hidden_type()
return []*Node{Nod(ODCLFIELD, nil, typenod(s1))}
}
}
// ----------------------------------------------------------------------------
// Importing constants
func (p *parser) hidden_literal() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_literal")()
}
switch p.tok {
case LLITERAL:
ss := nodlit(p.val)
p.next()
return ss
case '-':
p.next()
if p.tok == LLITERAL {
ss := nodlit(p.val)
p.next()
switch ss.Val().Ctype() {
case CTINT, CTRUNE:
mpnegfix(ss.Val().U.(*Mpint))
break
case CTFLT:
mpnegflt(ss.Val().U.(*Mpflt))
break
case CTCPLX:
mpnegflt(&ss.Val().U.(*Mpcplx).Real)
mpnegflt(&ss.Val().U.(*Mpcplx).Imag)
break
default:
Yyerror("bad negated constant")
}
return ss
} else {
p.import_error()
return nil
}
case LNAME, '@', '?':
s1 := p.sym()
ss := oldname(Pkglookup(s1.Name, builtinpkg))
if ss.Op != OLITERAL {
Yyerror("bad constant %v", ss.Sym)
}
return ss
default:
p.import_error()
return nil
}
}
func (p *parser) hidden_constant() *Node {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_constant")()
}
switch p.tok {
default:
return p.hidden_literal()
case '(':
p.next()
s2 := p.hidden_literal()
p.want('+')
s4 := p.hidden_literal()
p.want(')')
if s2.Val().Ctype() == CTRUNE && s4.Val().Ctype() == CTINT {
ss := s2
mpaddfixfix(s2.Val().U.(*Mpint), s4.Val().U.(*Mpint), 0)
return ss
}
s4.Val().U.(*Mpcplx).Real = s4.Val().U.(*Mpcplx).Imag
Mpmovecflt(&s4.Val().U.(*Mpcplx).Imag, 0.0)
return nodcplxlit(s2.Val(), s4.Val())
}
}
func (p *parser) hidden_import_list() {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_import_list")()
}
for p.tok != '$' {
p.hidden_import()
}
}
func (p *parser) hidden_funarg_list() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_funarg_list")()
}
s1 := p.hidden_funarg()
ss := []*Node{s1}
for p.got(',') {
s3 := p.hidden_funarg()
ss = append(ss, s3)
}
return ss
}
func (p *parser) hidden_structdcl_list() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_structdcl_list")()
}
s1 := p.hidden_structdcl()
ss := []*Node{s1}
for p.got(';') {
s3 := p.hidden_structdcl()
ss = append(ss, s3)
}
return ss
}
func (p *parser) hidden_interfacedcl_list() []*Node {
if trace && Debug['x'] != 0 {
defer p.trace("hidden_interfacedcl_list")()
}
s1 := p.hidden_interfacedcl()
ss := []*Node{s1}
for p.got(';') {
s3 := p.hidden_interfacedcl()
ss = append(ss, s3)
}
return ss
}