[dev.cc] cmd/internal/gc, cmd/new6g etc: convert from cmd/gc, cmd/6g etc
First draft of converted Go compiler, using rsc.io/c2go rev 83d795a.
Change-Id: I29f4c7010de07d2ff1947bbca9865879d83c32c3
Reviewed-on: https://go-review.googlesource.com/4851
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/src/cmd/internal/gc/dcl.go b/src/cmd/internal/gc/dcl.go
new file mode 100644
index 0000000..0aeb587
--- /dev/null
+++ b/src/cmd/internal/gc/dcl.go
@@ -0,0 +1,1565 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/internal/obj"
+ "fmt"
+ "strings"
+)
+
+func dflag() int {
+ if !(Debug['d'] != 0) {
+ return 0
+ }
+ if Debug['y'] != 0 {
+ return 1
+ }
+ if incannedimport != 0 {
+ return 0
+ }
+ return 1
+}
+
+/*
+ * declaration stack & operations
+ */
+func dcopy(a *Sym, b *Sym) {
+ a.Pkg = b.Pkg
+ a.Name = b.Name
+ a.Def = b.Def
+ a.Block = b.Block
+ a.Lastlineno = b.Lastlineno
+}
+
+func push() *Sym {
+ var d *Sym
+
+ d = new(Sym)
+ d.Lastlineno = lineno
+ d.Link = dclstack
+ dclstack = d
+ return d
+}
+
+func pushdcl(s *Sym) *Sym {
+ var d *Sym
+
+ d = push()
+ dcopy(d, s)
+ if dflag() != 0 {
+ fmt.Printf("\t%v push %v %p\n", Ctxt.Line(int(lineno)), Sconv(s, 0), s.Def)
+ }
+ return d
+}
+
+func popdcl() {
+ var d *Sym
+ var s *Sym
+ var lno int
+
+ // if(dflag())
+ // print("revert\n");
+
+ for d = dclstack; d != nil; d = d.Link {
+ if d.Name == "" {
+ break
+ }
+ s = Pkglookup(d.Name, d.Pkg)
+ lno = int(s.Lastlineno)
+ dcopy(s, d)
+ d.Lastlineno = int32(lno)
+ if dflag() != 0 {
+ fmt.Printf("\t%v pop %v %p\n", Ctxt.Line(int(lineno)), Sconv(s, 0), s.Def)
+ }
+ }
+
+ if d == nil {
+ Fatal("popdcl: no mark")
+ }
+ dclstack = d.Link
+ block = d.Block
+}
+
+func poptodcl() {
+ // pop the old marker and push a new one
+ // (cannot reuse the existing one)
+ // because we use the markers to identify blocks
+ // for the goto restriction checks.
+ popdcl()
+
+ markdcl()
+}
+
+func markdcl() {
+ var d *Sym
+
+ d = push()
+ d.Name = "" // used as a mark in fifo
+ d.Block = block
+
+ blockgen++
+ block = blockgen
+}
+
+// if(dflag())
+// print("markdcl\n");
+func dumpdcl(st string) {
+ var s *Sym
+ var d *Sym
+ var i int
+
+ i = 0
+ for d = dclstack; d != nil; d = d.Link {
+ i++
+ fmt.Printf(" %.2d %p", i, d)
+ if d.Name == "" {
+ fmt.Printf("\n")
+ continue
+ }
+
+ fmt.Printf(" '%s'", d.Name)
+ s = Pkglookup(d.Name, d.Pkg)
+ fmt.Printf(" %v\n", Sconv(s, 0))
+ }
+}
+
+func testdclstack() {
+ var d *Sym
+
+ for d = dclstack; d != nil; d = d.Link {
+ if d.Name == "" {
+ if nerrors != 0 {
+ errorexit()
+ }
+ Yyerror("mark left on the stack")
+ continue
+ }
+ }
+}
+
+func redeclare(s *Sym, where string) {
+ var pkgstr *Strlit
+ var line1 int
+ var line2 int
+
+ if s.Lastlineno == 0 {
+ var tmp *Strlit
+ if s.Origpkg != nil {
+ tmp = s.Origpkg.Path
+ } else {
+ tmp = s.Pkg.Path
+ }
+ pkgstr = tmp
+ Yyerror("%v redeclared %s\n"+"\tprevious declaration during import \"%v\"", Sconv(s, 0), where, Zconv(pkgstr, 0))
+ } else {
+ line1 = parserline()
+ line2 = int(s.Lastlineno)
+
+ // When an import and a declaration collide in separate files,
+ // present the import as the "redeclared", because the declaration
+ // is visible where the import is, but not vice versa.
+ // See issue 4510.
+ if s.Def == nil {
+ line2 = line1
+ line1 = int(s.Lastlineno)
+ }
+
+ yyerrorl(int(line1), "%v redeclared %s\n"+"\tprevious declaration at %v", Sconv(s, 0), where, Ctxt.Line(line2))
+ }
+}
+
+var vargen int
+
+/*
+ * declare individual names - var, typ, const
+ */
+
+var declare_typegen int
+
+func declare(n *Node, ctxt int) {
+ var s *Sym
+ var gen int
+
+ if ctxt == PDISCARD {
+ return
+ }
+
+ if isblank(n) {
+ return
+ }
+
+ n.Lineno = int32(parserline())
+ s = n.Sym
+
+ // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
+ if importpkg == nil && !(typecheckok != 0) && s.Pkg != localpkg {
+ Yyerror("cannot declare name %v", Sconv(s, 0))
+ }
+
+ if ctxt == PEXTERN && s.Name == "init" {
+ Yyerror("cannot declare init - must be func", s)
+ }
+
+ gen = 0
+ if ctxt == PEXTERN {
+ externdcl = list(externdcl, n)
+ if dflag() != 0 {
+ fmt.Printf("\t%v global decl %v %p\n", Ctxt.Line(int(lineno)), Sconv(s, 0), n)
+ }
+ } else {
+ if Curfn == nil && ctxt == PAUTO {
+ Fatal("automatic outside function")
+ }
+ if Curfn != nil {
+ Curfn.Dcl = list(Curfn.Dcl, n)
+ }
+ if n.Op == OTYPE {
+ declare_typegen++
+ gen = declare_typegen
+ } else if n.Op == ONAME && ctxt == PAUTO && !strings.Contains(s.Name, "·") {
+ vargen++
+ gen = vargen
+ }
+ pushdcl(s)
+ n.Curfn = Curfn
+ }
+
+ if ctxt == PAUTO {
+ n.Xoffset = 0
+ }
+
+ if s.Block == block {
+ // functype will print errors about duplicate function arguments.
+ // Don't repeat the error here.
+ if ctxt != PPARAM && ctxt != PPARAMOUT {
+ redeclare(s, "in this block")
+ }
+ }
+
+ s.Block = block
+ s.Lastlineno = int32(parserline())
+ s.Def = n
+ n.Vargen = int32(gen)
+ n.Funcdepth = Funcdepth
+ n.Class = uint8(ctxt)
+
+ autoexport(n, ctxt)
+}
+
+func addvar(n *Node, t *Type, ctxt int) {
+ if n == nil || n.Sym == nil || (n.Op != ONAME && n.Op != ONONAME) || t == nil {
+ Fatal("addvar: n=%v t=%v nil", Nconv(n, 0), Tconv(t, 0))
+ }
+
+ n.Op = ONAME
+ declare(n, ctxt)
+ n.Type = t
+}
+
+/*
+ * declare variables from grammar
+ * new_name_list (type | [type] = expr_list)
+ */
+func variter(vl *NodeList, t *Node, el *NodeList) *NodeList {
+ var doexpr int
+ var v *Node
+ var e *Node
+ var as2 *Node
+ var init *NodeList
+
+ init = nil
+ doexpr = bool2int(el != nil)
+
+ if count(el) == 1 && count(vl) > 1 {
+ e = el.N
+ as2 = Nod(OAS2, nil, nil)
+ as2.List = vl
+ as2.Rlist = list1(e)
+ for ; vl != nil; vl = vl.Next {
+ v = vl.N
+ v.Op = ONAME
+ declare(v, dclcontext)
+ v.Ntype = t
+ v.Defn = as2
+ if Funcdepth > 0 {
+ init = list(init, Nod(ODCL, v, nil))
+ }
+ }
+
+ return list(init, as2)
+ }
+
+ for ; vl != nil; vl = vl.Next {
+ if doexpr != 0 {
+ if el == nil {
+ Yyerror("missing expression in var declaration")
+ break
+ }
+
+ e = el.N
+ el = el.Next
+ } else {
+ e = nil
+ }
+
+ v = vl.N
+ v.Op = ONAME
+ declare(v, dclcontext)
+ v.Ntype = t
+
+ if e != nil || Funcdepth > 0 || isblank(v) {
+ if Funcdepth > 0 {
+ init = list(init, Nod(ODCL, v, nil))
+ }
+ e = Nod(OAS, v, e)
+ init = list(init, e)
+ if e.Right != nil {
+ v.Defn = e
+ }
+ }
+ }
+
+ if el != nil {
+ Yyerror("extra expression in var declaration")
+ }
+ return init
+}
+
+/*
+ * declare constants from grammar
+ * new_name_list [[type] = expr_list]
+ */
+func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList {
+ var v *Node
+ var c *Node
+ var vv *NodeList
+
+ vv = nil
+ if cl == nil {
+ if t != nil {
+ Yyerror("const declaration cannot have type without expression")
+ }
+ cl = lastconst
+ t = lasttype
+ } else {
+ lastconst = cl
+ lasttype = t
+ }
+
+ cl = listtreecopy(cl)
+
+ for ; vl != nil; vl = vl.Next {
+ if cl == nil {
+ Yyerror("missing value in const declaration")
+ break
+ }
+
+ c = cl.N
+ cl = cl.Next
+
+ v = vl.N
+ v.Op = OLITERAL
+ declare(v, dclcontext)
+
+ v.Ntype = t
+ v.Defn = c
+
+ vv = list(vv, Nod(ODCLCONST, v, nil))
+ }
+
+ if cl != nil {
+ Yyerror("extra expression in const declaration")
+ }
+ iota_ += 1
+ return vv
+}
+
+/*
+ * this generates a new name node,
+ * typically for labels or other one-off names.
+ */
+func newname(s *Sym) *Node {
+ var n *Node
+
+ if s == nil {
+ Fatal("newname nil")
+ }
+
+ n = Nod(ONAME, nil, nil)
+ n.Sym = s
+ n.Type = nil
+ n.Addable = 1
+ n.Ullman = 1
+ n.Xoffset = 0
+ return n
+}
+
+/*
+ * this generates a new name node for a name
+ * being declared.
+ */
+func dclname(s *Sym) *Node {
+ var n *Node
+
+ n = newname(s)
+ n.Op = ONONAME // caller will correct it
+ return n
+}
+
+func typenod(t *Type) *Node {
+ // if we copied another type with *t = *u
+ // then t->nod might be out of date, so
+ // check t->nod->type too
+ if t.Nod == nil || t.Nod.Type != t {
+ t.Nod = Nod(OTYPE, nil, nil)
+ t.Nod.Type = t
+ t.Nod.Sym = t.Sym
+ }
+
+ return t.Nod
+}
+
+/*
+ * this will return an old name
+ * that has already been pushed on the
+ * declaration list. a diagnostic is
+ * generated if no name has been defined.
+ */
+func oldname(s *Sym) *Node {
+ var n *Node
+ var c *Node
+
+ n = s.Def
+ if n == nil {
+ // maybe a top-level name will come along
+ // to give this a definition later.
+ // walkdef will check s->def again once
+ // all the input source has been processed.
+ n = newname(s)
+
+ n.Op = ONONAME
+ n.Iota = iota_ // save current iota value in const declarations
+ }
+
+ if Curfn != nil && n.Funcdepth > 0 && n.Funcdepth != Funcdepth && n.Op == ONAME {
+ // inner func is referring to var in outer func.
+ //
+ // TODO(rsc): If there is an outer variable x and we
+ // are parsing x := 5 inside the closure, until we get to
+ // the := it looks like a reference to the outer x so we'll
+ // make x a closure variable unnecessarily.
+ if n.Closure == nil || n.Closure.Funcdepth != Funcdepth {
+ // create new closure var.
+ c = Nod(ONAME, nil, nil)
+
+ c.Sym = s
+ c.Class = PPARAMREF
+ c.Isddd = n.Isddd
+ c.Defn = n
+ c.Addable = 0
+ c.Ullman = 2
+ c.Funcdepth = Funcdepth
+ c.Outer = n.Closure
+ n.Closure = c
+ c.Closure = n
+ c.Xoffset = 0
+ Curfn.Cvars = list(Curfn.Cvars, c)
+ }
+
+ // return ref to closure var, not original
+ return n.Closure
+ }
+
+ return n
+}
+
+/*
+ * := declarations
+ */
+func colasname(n *Node) int {
+ switch n.Op {
+ case ONAME,
+ ONONAME,
+ OPACK,
+ OTYPE,
+ OLITERAL:
+ return bool2int(n.Sym != nil)
+ }
+
+ return 0
+}
+
+func colasdefn(left *NodeList, defn *Node) {
+ var nnew int
+ var nerr int
+ var l *NodeList
+ var n *Node
+
+ for l = left; l != nil; l = l.Next {
+ if l.N.Sym != nil {
+ l.N.Sym.Flags |= SymUniq
+ }
+ }
+
+ nnew = 0
+ nerr = 0
+ for l = left; l != nil; l = l.Next {
+ n = l.N
+ if isblank(n) {
+ continue
+ }
+ if !(colasname(n) != 0) {
+ yyerrorl(int(defn.Lineno), "non-name %v on left side of :=", Nconv(n, 0))
+ nerr++
+ continue
+ }
+
+ if n.Sym.Flags&SymUniq == 0 {
+ yyerrorl(int(defn.Lineno), "%v repeated on left side of :=", Sconv(n.Sym, 0))
+ n.Diag++
+ nerr++
+ continue
+ }
+
+ n.Sym.Flags &^= SymUniq
+ if n.Sym.Block == block {
+ continue
+ }
+
+ nnew++
+ n = newname(n.Sym)
+ declare(n, dclcontext)
+ n.Defn = defn
+ defn.Ninit = list(defn.Ninit, Nod(ODCL, n, nil))
+ l.N = n
+ }
+
+ if nnew == 0 && nerr == 0 {
+ yyerrorl(int(defn.Lineno), "no new variables on left side of :=")
+ }
+}
+
+func colas(left *NodeList, right *NodeList, lno int32) *Node {
+ var as *Node
+
+ as = Nod(OAS2, nil, nil)
+ as.List = left
+ as.Rlist = right
+ as.Colas = 1
+ as.Lineno = lno
+ colasdefn(left, as)
+
+ // make the tree prettier; not necessary
+ if count(left) == 1 && count(right) == 1 {
+ as.Left = as.List.N
+ as.Right = as.Rlist.N
+ as.List = nil
+ as.Rlist = nil
+ as.Op = OAS
+ }
+
+ return as
+}
+
+/*
+ * declare the arguments in an
+ * interface field declaration.
+ */
+func ifacedcl(n *Node) {
+ if n.Op != ODCLFIELD || n.Right == nil {
+ Fatal("ifacedcl")
+ }
+
+ if isblank(n.Left) {
+ Yyerror("methods must have a unique non-blank name")
+ }
+
+ dclcontext = PPARAM
+ markdcl()
+ Funcdepth++
+ n.Outer = Curfn
+ Curfn = n
+ funcargs(n.Right)
+
+ // funcbody is normally called after the parser has
+ // seen the body of a function but since an interface
+ // field declaration does not have a body, we must
+ // call it now to pop the current declaration context.
+ dclcontext = PAUTO
+
+ funcbody(n)
+}
+
+/*
+ * declare the function proper
+ * and declare the arguments.
+ * called in extern-declaration context
+ * returns in auto-declaration context.
+ */
+func funchdr(n *Node) {
+ // change the declaration context from extern to auto
+ if Funcdepth == 0 && dclcontext != PEXTERN {
+ Fatal("funchdr: dclcontext")
+ }
+
+ dclcontext = PAUTO
+ markdcl()
+ Funcdepth++
+
+ n.Outer = Curfn
+ Curfn = n
+
+ if n.Nname != nil {
+ funcargs(n.Nname.Ntype)
+ } else if n.Ntype != nil {
+ funcargs(n.Ntype)
+ } else {
+ funcargs2(n.Type)
+ }
+}
+
+func funcargs(nt *Node) {
+ var n *Node
+ var nn *Node
+ var l *NodeList
+ var gen int
+
+ if nt.Op != OTFUNC {
+ Fatal("funcargs %v", Oconv(int(nt.Op), 0))
+ }
+
+ // re-start the variable generation number
+ // we want to use small numbers for the return variables,
+ // so let them have the chunk starting at 1.
+ vargen = count(nt.Rlist)
+
+ // declare the receiver and in arguments.
+ // no n->defn because type checking of func header
+ // will not fill in the types until later
+ if nt.Left != nil {
+ n = nt.Left
+ if n.Op != ODCLFIELD {
+ Fatal("funcargs receiver %v", Oconv(int(n.Op), 0))
+ }
+ if n.Left != nil {
+ n.Left.Op = ONAME
+ n.Left.Ntype = n.Right
+ declare(n.Left, PPARAM)
+ if dclcontext == PAUTO {
+ vargen++
+ n.Left.Vargen = int32(vargen)
+ }
+ }
+ }
+
+ for l = nt.List; l != nil; l = l.Next {
+ n = l.N
+ if n.Op != ODCLFIELD {
+ Fatal("funcargs in %v", Oconv(int(n.Op), 0))
+ }
+ if n.Left != nil {
+ n.Left.Op = ONAME
+ n.Left.Ntype = n.Right
+ declare(n.Left, PPARAM)
+ if dclcontext == PAUTO {
+ vargen++
+ n.Left.Vargen = int32(vargen)
+ }
+ }
+ }
+
+ // declare the out arguments.
+ gen = count(nt.List)
+ var i int = 0
+ for l = nt.Rlist; l != nil; l = l.Next {
+ n = l.N
+
+ if n.Op != ODCLFIELD {
+ Fatal("funcargs out %v", Oconv(int(n.Op), 0))
+ }
+
+ if n.Left == nil {
+ // Name so that escape analysis can track it. ~r stands for 'result'.
+ namebuf = fmt.Sprintf("~r%d", gen)
+ gen++
+
+ n.Left = newname(Lookup(namebuf))
+ }
+
+ // TODO: n->left->missing = 1;
+ n.Left.Op = ONAME
+
+ if isblank(n.Left) {
+ // Give it a name so we can assign to it during return. ~b stands for 'blank'.
+ // The name must be different from ~r above because if you have
+ // func f() (_ int)
+ // func g() int
+ // f is allowed to use a plain 'return' with no arguments, while g is not.
+ // So the two cases must be distinguished.
+ // We do not record a pointer to the original node (n->orig).
+ // Having multiple names causes too much confusion in later passes.
+ nn = Nod(OXXX, nil, nil)
+
+ *nn = *n.Left
+ nn.Orig = nn
+ namebuf = fmt.Sprintf("~b%d", gen)
+ gen++
+ nn.Sym = Lookup(namebuf)
+ n.Left = nn
+ }
+
+ n.Left.Ntype = n.Right
+ declare(n.Left, PPARAMOUT)
+ if dclcontext == PAUTO {
+ i++
+ n.Left.Vargen = int32(i)
+ }
+ }
+}
+
+/*
+ * Same as funcargs, except run over an already constructed TFUNC.
+ * This happens during import, where the hidden_fndcl rule has
+ * used functype directly to parse the function's type.
+ */
+func funcargs2(t *Type) {
+ var ft *Type
+ var n *Node
+
+ if t.Etype != TFUNC {
+ Fatal("funcargs2 %v", Tconv(t, 0))
+ }
+
+ if t.Thistuple != 0 {
+ for ft = getthisx(t).Type; ft != nil; ft = ft.Down {
+ if !(ft.Nname != nil) || !(ft.Nname.Sym != nil) {
+ continue
+ }
+ n = ft.Nname // no need for newname(ft->nname->sym)
+ n.Type = ft.Type
+ declare(n, PPARAM)
+ }
+ }
+
+ if t.Intuple != 0 {
+ for ft = getinargx(t).Type; ft != nil; ft = ft.Down {
+ if !(ft.Nname != nil) || !(ft.Nname.Sym != nil) {
+ continue
+ }
+ n = ft.Nname
+ n.Type = ft.Type
+ declare(n, PPARAM)
+ }
+ }
+
+ if t.Outtuple != 0 {
+ for ft = getoutargx(t).Type; ft != nil; ft = ft.Down {
+ if !(ft.Nname != nil) || !(ft.Nname.Sym != nil) {
+ continue
+ }
+ n = ft.Nname
+ n.Type = ft.Type
+ declare(n, PPARAMOUT)
+ }
+ }
+}
+
+/*
+ * finish the body.
+ * called in auto-declaration context.
+ * returns in extern-declaration context.
+ */
+func funcbody(n *Node) {
+ // change the declaration context from auto to extern
+ if dclcontext != PAUTO {
+ Fatal("funcbody: dclcontext")
+ }
+ popdcl()
+ Funcdepth--
+ Curfn = n.Outer
+ n.Outer = nil
+ if Funcdepth == 0 {
+ dclcontext = PEXTERN
+ }
+}
+
+/*
+ * new type being defined with name s.
+ */
+func typedcl0(s *Sym) *Node {
+ var n *Node
+
+ n = newname(s)
+ n.Op = OTYPE
+ declare(n, dclcontext)
+ return n
+}
+
+/*
+ * node n, which was returned by typedcl0
+ * is being declared to have uncompiled type t.
+ * return the ODCLTYPE node to use.
+ */
+func typedcl1(n *Node, t *Node, local int) *Node {
+ n.Ntype = t
+ n.Local = uint8(local)
+ return Nod(ODCLTYPE, n, nil)
+}
+
+/*
+ * structs, functions, and methods.
+ * they don't belong here, but where do they belong?
+ */
+func checkembeddedtype(t *Type) {
+ if t == nil {
+ return
+ }
+
+ if t.Sym == nil && Isptr[t.Etype] != 0 {
+ t = t.Type
+ if t.Etype == TINTER {
+ Yyerror("embedded type cannot be a pointer to interface")
+ }
+ }
+
+ if Isptr[t.Etype] != 0 {
+ Yyerror("embedded type cannot be a pointer")
+ } else if t.Etype == TFORW && t.Embedlineno == 0 {
+ t.Embedlineno = lineno
+ }
+}
+
+func structfield(n *Node) *Type {
+ var f *Type
+ var lno int
+
+ lno = int(lineno)
+ lineno = n.Lineno
+
+ if n.Op != ODCLFIELD {
+ Fatal("structfield: oops %v\n", Nconv(n, 0))
+ }
+
+ f = typ(TFIELD)
+ f.Isddd = n.Isddd
+
+ if n.Right != nil {
+ typecheck(&n.Right, Etype)
+ n.Type = n.Right.Type
+ if n.Left != nil {
+ n.Left.Type = n.Type
+ }
+ if n.Embedded != 0 {
+ checkembeddedtype(n.Type)
+ }
+ }
+
+ n.Right = nil
+
+ f.Type = n.Type
+ if f.Type == nil {
+ f.Broke = 1
+ }
+
+ switch n.Val.Ctype {
+ case CTSTR:
+ f.Note = n.Val.U.Sval
+
+ default:
+ Yyerror("field annotation must be string")
+ fallthrough
+
+ // fallthrough
+ case CTxxx:
+ f.Note = nil
+ }
+
+ if n.Left != nil && n.Left.Op == ONAME {
+ f.Nname = n.Left
+ f.Embedded = n.Embedded
+ f.Sym = f.Nname.Sym
+ }
+
+ lineno = int32(lno)
+ return f
+}
+
+var uniqgen uint32
+
+func checkdupfields(t *Type, what string) {
+ var lno int
+
+ lno = int(lineno)
+
+ for ; t != nil; t = t.Down {
+ if t.Sym != nil && t.Nname != nil && !isblank(t.Nname) {
+ if t.Sym.Uniqgen == uniqgen {
+ lineno = t.Nname.Lineno
+ Yyerror("duplicate %s %s", what, t.Sym.Name)
+ } else {
+ t.Sym.Uniqgen = uniqgen
+ }
+ }
+ }
+
+ lineno = int32(lno)
+}
+
+/*
+ * convert a parsed id/type list into
+ * a type for struct/interface/arglist
+ */
+func tostruct(l *NodeList) *Type {
+ var t *Type
+ var f *Type
+ var tp **Type
+ t = typ(TSTRUCT)
+
+ for tp = &t.Type; l != nil; l = l.Next {
+ f = structfield(l.N)
+
+ *tp = f
+ tp = &f.Down
+ }
+
+ for f = t.Type; f != nil && !(t.Broke != 0); f = f.Down {
+ if f.Broke != 0 {
+ t.Broke = 1
+ }
+ }
+
+ uniqgen++
+ checkdupfields(t.Type, "field")
+
+ if !(t.Broke != 0) {
+ checkwidth(t)
+ }
+
+ return t
+}
+
+func tofunargs(l *NodeList) *Type {
+ var t *Type
+ var f *Type
+ var tp **Type
+
+ t = typ(TSTRUCT)
+ t.Funarg = 1
+
+ for tp = &t.Type; l != nil; l = l.Next {
+ f = structfield(l.N)
+ f.Funarg = 1
+
+ // esc.c needs to find f given a PPARAM to add the tag.
+ if l.N.Left != nil && l.N.Left.Class == PPARAM {
+ l.N.Left.Paramfld = f
+ }
+
+ *tp = f
+ tp = &f.Down
+ }
+
+ for f = t.Type; f != nil && !(t.Broke != 0); f = f.Down {
+ if f.Broke != 0 {
+ t.Broke = 1
+ }
+ }
+
+ return t
+}
+
+func interfacefield(n *Node) *Type {
+ var f *Type
+ var lno int
+
+ lno = int(lineno)
+ lineno = n.Lineno
+
+ if n.Op != ODCLFIELD {
+ Fatal("interfacefield: oops %v\n", Nconv(n, 0))
+ }
+
+ if n.Val.Ctype != CTxxx {
+ Yyerror("interface method cannot have annotation")
+ }
+
+ f = typ(TFIELD)
+ f.Isddd = n.Isddd
+
+ if n.Right != nil {
+ if n.Left != nil {
+ // queue resolution of method type for later.
+ // right now all we need is the name list.
+ // avoids cycles for recursive interface types.
+ n.Type = typ(TINTERMETH)
+
+ n.Type.Nname = n.Right
+ n.Left.Type = n.Type
+ queuemethod(n)
+
+ if n.Left.Op == ONAME {
+ f.Nname = n.Left
+ f.Embedded = n.Embedded
+ f.Sym = f.Nname.Sym
+ }
+ } else {
+ typecheck(&n.Right, Etype)
+ n.Type = n.Right.Type
+
+ if n.Embedded != 0 {
+ checkembeddedtype(n.Type)
+ }
+
+ if n.Type != nil {
+ switch n.Type.Etype {
+ case TINTER:
+ break
+
+ case TFORW:
+ Yyerror("interface type loop involving %v", Tconv(n.Type, 0))
+ f.Broke = 1
+
+ default:
+ Yyerror("interface contains embedded non-interface %v", Tconv(n.Type, 0))
+ f.Broke = 1
+ }
+ }
+ }
+ }
+
+ n.Right = nil
+
+ f.Type = n.Type
+ if f.Type == nil {
+ f.Broke = 1
+ }
+
+ lineno = int32(lno)
+ return f
+}
+
+func tointerface(l *NodeList) *Type {
+ var t *Type
+ var f *Type
+ var tp **Type
+ var t1 *Type
+
+ t = typ(TINTER)
+
+ tp = &t.Type
+ for ; l != nil; l = l.Next {
+ f = interfacefield(l.N)
+
+ if l.N.Left == nil && f.Type.Etype == TINTER {
+ // embedded interface, inline methods
+ for t1 = f.Type.Type; t1 != nil; t1 = t1.Down {
+ f = typ(TFIELD)
+ f.Type = t1.Type
+ f.Broke = t1.Broke
+ f.Sym = t1.Sym
+ if f.Sym != nil {
+ f.Nname = newname(f.Sym)
+ }
+ *tp = f
+ tp = &f.Down
+ }
+ } else {
+ *tp = f
+ tp = &f.Down
+ }
+ }
+
+ for f = t.Type; f != nil && !(t.Broke != 0); f = f.Down {
+ if f.Broke != 0 {
+ t.Broke = 1
+ }
+ }
+
+ uniqgen++
+ checkdupfields(t.Type, "method")
+ t = sortinter(t)
+ checkwidth(t)
+
+ return t
+}
+
+func embedded(s *Sym, pkg *Pkg) *Node {
+ var n *Node
+ var name string
+ const (
+ CenterDot = 0xB7
+ )
+ // Names sometimes have disambiguation junk
+ // appended after a center dot. Discard it when
+ // making the name for the embedded struct field.
+ name = s.Name
+
+ if i := strings.Index(s.Name, string(CenterDot)); i >= 0 {
+ name = s.Name[:i]
+ }
+
+ if exportname(name) {
+ n = newname(Lookup(name))
+ } else if s.Pkg == builtinpkg {
+ // The name of embedded builtins belongs to pkg.
+ n = newname(Pkglookup(name, pkg))
+ } else {
+ n = newname(Pkglookup(name, s.Pkg))
+ }
+ n = Nod(ODCLFIELD, n, oldname(s))
+ n.Embedded = 1
+ return n
+}
+
+/*
+ * check that the list of declarations is either all anonymous or all named
+ */
+func findtype(l *NodeList) *Node {
+ for ; l != nil; l = l.Next {
+ if l.N.Op == OKEY {
+ return l.N.Right
+ }
+ }
+ return nil
+}
+
+func checkarglist(all *NodeList, input int) *NodeList {
+ var named int
+ var n *Node
+ var t *Node
+ var nextt *Node
+ var l *NodeList
+
+ named = 0
+ for l = all; l != nil; l = l.Next {
+ if l.N.Op == OKEY {
+ named = 1
+ break
+ }
+ }
+
+ if named != 0 {
+ n = nil
+ for l = all; l != nil; l = l.Next {
+ n = l.N
+ if n.Op != OKEY && n.Sym == nil {
+ Yyerror("mixed named and unnamed function parameters")
+ break
+ }
+ }
+
+ if l == nil && n != nil && n.Op != OKEY {
+ Yyerror("final function parameter must have type")
+ }
+ }
+
+ nextt = nil
+ for l = all; l != nil; l = l.Next {
+ // can cache result from findtype to avoid
+ // quadratic behavior here, but unlikely to matter.
+ n = l.N
+
+ if named != 0 {
+ if n.Op == OKEY {
+ t = n.Right
+ n = n.Left
+ nextt = nil
+ } else {
+ if nextt == nil {
+ nextt = findtype(l)
+ }
+ t = nextt
+ }
+ } else {
+ t = n
+ n = nil
+ }
+
+ // during import l->n->op is OKEY, but l->n->left->sym == S
+ // means it was a '?', not that it was
+ // a lone type This doesn't matter for the exported
+ // declarations, which are parsed by rules that don't
+ // use checkargs, but can happen for func literals in
+ // the inline bodies.
+ // TODO(rsc) this can go when typefmt case TFIELD in exportmode fmt.c prints _ instead of ?
+ if importpkg != nil && n.Sym == nil {
+ n = nil
+ }
+
+ if n != nil && n.Sym == nil {
+ t = n
+ n = nil
+ }
+
+ if n != nil {
+ n = newname(n.Sym)
+ }
+ n = Nod(ODCLFIELD, n, t)
+ if n.Right != nil && n.Right.Op == ODDD {
+ if !(input != 0) {
+ Yyerror("cannot use ... in output argument list")
+ } else if l.Next != nil {
+ Yyerror("can only use ... as final argument in list")
+ }
+ n.Right.Op = OTARRAY
+ n.Right.Right = n.Right.Left
+ n.Right.Left = nil
+ n.Isddd = 1
+ if n.Left != nil {
+ n.Left.Isddd = 1
+ }
+ }
+
+ l.N = n
+ }
+
+ return all
+}
+
+func fakethis() *Node {
+ var n *Node
+
+ n = Nod(ODCLFIELD, nil, typenod(Ptrto(typ(TSTRUCT))))
+ return n
+}
+
+/*
+ * Is this field a method on an interface?
+ * Those methods have an anonymous
+ * *struct{} as the receiver.
+ * (See fakethis above.)
+ */
+func isifacemethod(f *Type) int {
+ var rcvr *Type
+ var t *Type
+
+ rcvr = getthisx(f).Type
+ if rcvr.Sym != nil {
+ return 0
+ }
+ t = rcvr.Type
+ if !(Isptr[t.Etype] != 0) {
+ return 0
+ }
+ t = t.Type
+ if t.Sym != nil || t.Etype != TSTRUCT || t.Type != nil {
+ return 0
+ }
+ return 1
+}
+
+/*
+ * turn a parsed function declaration
+ * into a type
+ */
+func functype(this *Node, in *NodeList, out *NodeList) *Type {
+ var t *Type
+ var rcvr *NodeList
+ var s *Sym
+
+ t = typ(TFUNC)
+
+ rcvr = nil
+ if this != nil {
+ rcvr = list1(this)
+ }
+ t.Type = tofunargs(rcvr)
+ t.Type.Down = tofunargs(out)
+ t.Type.Down.Down = tofunargs(in)
+
+ uniqgen++
+ checkdupfields(t.Type.Type, "argument")
+ checkdupfields(t.Type.Down.Type, "argument")
+ checkdupfields(t.Type.Down.Down.Type, "argument")
+
+ if t.Type.Broke != 0 || t.Type.Down.Broke != 0 || t.Type.Down.Down.Broke != 0 {
+ t.Broke = 1
+ }
+
+ if this != nil {
+ t.Thistuple = 1
+ }
+ t.Outtuple = count(out)
+ t.Intuple = count(in)
+ t.Outnamed = 0
+ if t.Outtuple > 0 && out.N.Left != nil && out.N.Left.Orig != nil {
+ s = out.N.Left.Orig.Sym
+ if s != nil && (s.Name[0] != '~' || s.Name[1] != 'r') { // ~r%d is the name invented for an unnamed result
+ t.Outnamed = 1
+ }
+ }
+
+ return t
+}
+
+var methodsym_toppkg *Pkg
+
+func methodsym(nsym *Sym, t0 *Type, iface int) *Sym {
+ var s *Sym
+ var p string
+ var t *Type
+ var suffix string
+ var spkg *Pkg
+
+ t = t0
+ if t == nil {
+ goto bad
+ }
+ s = t.Sym
+ if s == nil && Isptr[t.Etype] != 0 {
+ t = t.Type
+ if t == nil {
+ goto bad
+ }
+ s = t.Sym
+ }
+
+ spkg = nil
+ if s != nil {
+ spkg = s.Pkg
+ }
+
+ // if t0 == *t and t0 has a sym,
+ // we want to see *t, not t0, in the method name.
+ if t != t0 && t0.Sym != nil {
+ t0 = Ptrto(t)
+ }
+
+ suffix = ""
+ if iface != 0 {
+ dowidth(t0)
+ if t0.Width < Types[Tptr].Width {
+ suffix = "·i"
+ }
+ }
+
+ if (spkg == nil || nsym.Pkg != spkg) && !exportname(nsym.Name) {
+ if t0.Sym == nil && Isptr[t0.Etype] != 0 {
+ p = fmt.Sprintf("(%v).%s.%s%s", Tconv(t0, obj.FmtLeft|obj.FmtShort), nsym.Pkg.Prefix, nsym.Name, suffix)
+ } else {
+ p = fmt.Sprintf("%v.%s.%s%s", Tconv(t0, obj.FmtLeft|obj.FmtShort), nsym.Pkg.Prefix, nsym.Name, suffix)
+ }
+ } else {
+ if t0.Sym == nil && Isptr[t0.Etype] != 0 {
+ p = fmt.Sprintf("(%v).%s%s", Tconv(t0, obj.FmtLeft|obj.FmtShort), nsym.Name, suffix)
+ } else {
+ p = fmt.Sprintf("%v.%s%s", Tconv(t0, obj.FmtLeft|obj.FmtShort), nsym.Name, suffix)
+ }
+ }
+
+ if spkg == nil {
+ if methodsym_toppkg == nil {
+ methodsym_toppkg = mkpkg(newstrlit("go"))
+ }
+ spkg = methodsym_toppkg
+ }
+
+ s = Pkglookup(p, spkg)
+
+ return s
+
+bad:
+ Yyerror("illegal receiver type: %v", Tconv(t0, 0))
+ return nil
+}
+
+func methodname(n *Node, t *Type) *Node {
+ var s *Sym
+
+ s = methodsym(n.Sym, t, 0)
+ if s == nil {
+ return n
+ }
+ return newname(s)
+}
+
+func methodname1(n *Node, t *Node) *Node {
+ var star string
+ var p string
+
+ star = ""
+ if t.Op == OIND {
+ star = "*"
+ t = t.Left
+ }
+
+ if t.Sym == nil || isblank(n) {
+ return newname(n.Sym)
+ }
+
+ if star != "" {
+ p = fmt.Sprintf("(%s%v).%v", star, Sconv(t.Sym, 0), Sconv(n.Sym, 0))
+ } else {
+ p = fmt.Sprintf("%v.%v", Sconv(t.Sym, 0), Sconv(n.Sym, 0))
+ }
+
+ if exportname(t.Sym.Name) {
+ n = newname(Lookup(p))
+ } else {
+ n = newname(Pkglookup(p, t.Sym.Pkg))
+ }
+
+ return n
+}
+
+/*
+ * add a method, declared as a function,
+ * n is fieldname, pa is base type, t is function type
+ */
+func addmethod(sf *Sym, t *Type, local bool, nointerface bool) {
+ var f *Type
+ var d *Type
+ var pa *Type
+ var n *Node
+
+ // get field sym
+ if sf == nil {
+ Fatal("no method symbol")
+ }
+
+ // get parent type sym
+ pa = getthisx(t).Type // ptr to this structure
+ if pa == nil {
+ Yyerror("missing receiver")
+ return
+ }
+
+ pa = pa.Type
+ f = methtype(pa, 1)
+ if f == nil {
+ t = pa
+ if t == nil { // rely on typecheck having complained before
+ return
+ }
+ if t != nil {
+ if Isptr[t.Etype] != 0 {
+ if t.Sym != nil {
+ Yyerror("invalid receiver type %v (%v is a pointer type)", Tconv(pa, 0), Tconv(t, 0))
+ return
+ }
+
+ t = t.Type
+ }
+
+ if t.Broke != 0 { // rely on typecheck having complained before
+ return
+ }
+ if t.Sym == nil {
+ Yyerror("invalid receiver type %v (%v is an unnamed type)", Tconv(pa, 0), Tconv(t, 0))
+ return
+ }
+
+ if Isptr[t.Etype] != 0 {
+ Yyerror("invalid receiver type %v (%v is a pointer type)", Tconv(pa, 0), Tconv(t, 0))
+ return
+ }
+
+ if t.Etype == TINTER {
+ Yyerror("invalid receiver type %v (%v is an interface type)", Tconv(pa, 0), Tconv(t, 0))
+ return
+ }
+ }
+
+ // Should have picked off all the reasons above,
+ // but just in case, fall back to generic error.
+ Yyerror("invalid receiver type %v (%v / %v)", Tconv(pa, 0), Tconv(pa, obj.FmtLong), Tconv(t, obj.FmtLong))
+
+ return
+ }
+
+ pa = f
+ if pa.Etype == TSTRUCT {
+ for f = pa.Type; f != nil; f = f.Down {
+ if f.Sym == sf {
+ Yyerror("type %v has both field and method named %v", Tconv(pa, 0), Sconv(sf, 0))
+ return
+ }
+ }
+ }
+
+ if local && !(pa.Local != 0) {
+ // defining method on non-local type.
+ Yyerror("cannot define new methods on non-local type %v", Tconv(pa, 0))
+
+ return
+ }
+
+ n = Nod(ODCLFIELD, newname(sf), nil)
+ n.Type = t
+
+ d = nil // last found
+ for f = pa.Method; f != nil; f = f.Down {
+ d = f
+ if f.Etype != TFIELD {
+ Fatal("addmethod: not TFIELD: %v", Tconv(f, obj.FmtLong))
+ }
+ if sf.Name != f.Sym.Name {
+ continue
+ }
+ if !Eqtype(t, f.Type) {
+ Yyerror("method redeclared: %v.%v\n\t%v\n\t%v", Tconv(pa, 0), Sconv(sf, 0), Tconv(f.Type, 0), Tconv(t, 0))
+ }
+ return
+ }
+
+ f = structfield(n)
+ f.Nointerface = uint8(bool2int(nointerface))
+
+ // during import unexported method names should be in the type's package
+ if importpkg != nil && f.Sym != nil && !exportname(f.Sym.Name) && f.Sym.Pkg != structpkg {
+ Fatal("imported method name %v in wrong package %s\n", Sconv(f.Sym, obj.FmtSign), structpkg.Name)
+ }
+
+ if d == nil {
+ pa.Method = f
+ } else {
+ d.Down = f
+ }
+ return
+}
+
+func funccompile(n *Node) {
+ Stksize = BADWIDTH
+ Maxarg = 0
+
+ if n.Type == nil {
+ if nerrors == 0 {
+ Fatal("funccompile missing type")
+ }
+ return
+ }
+
+ // assign parameter offsets
+ checkwidth(n.Type)
+
+ if Curfn != nil {
+ Fatal("funccompile %v inside %v", Sconv(n.Nname.Sym, 0), Sconv(Curfn.Nname.Sym, 0))
+ }
+
+ Stksize = 0
+ dclcontext = PAUTO
+ Funcdepth = n.Funcdepth + 1
+ compile(n)
+ Curfn = nil
+ Funcdepth = 0
+ dclcontext = PEXTERN
+}
+
+func funcsym(s *Sym) *Sym {
+ var p string
+ var s1 *Sym
+
+ p = fmt.Sprintf("%s·f", s.Name)
+ s1 = Pkglookup(p, s.Pkg)
+
+ if s1.Def == nil {
+ s1.Def = newname(s1)
+ s1.Def.Shortname = newname(s)
+ funcsyms = list(funcsyms, s1.Def)
+ }
+
+ return s1
+}