[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/export.go b/src/cmd/internal/gc/export.go
new file mode 100644
index 0000000..5b34fe2
--- /dev/null
+++ b/src/cmd/internal/gc/export.go
@@ -0,0 +1,596 @@
+// 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"
+	"sort"
+	"unicode"
+	"unicode/utf8"
+)
+
+var asmlist *NodeList
+
+// Mark n's symbol as exported
+func exportsym(n *Node) {
+	if n == nil || n.Sym == nil {
+		return
+	}
+	if n.Sym.Flags&(SymExport|SymPackage) != 0 {
+		if n.Sym.Flags&SymPackage != 0 {
+			Yyerror("export/package mismatch: %v", Sconv(n.Sym, 0))
+		}
+		return
+	}
+
+	n.Sym.Flags |= SymExport
+
+	if Debug['E'] != 0 {
+		fmt.Printf("export symbol %v\n", Sconv(n.Sym, 0))
+	}
+	exportlist = list(exportlist, n)
+}
+
+func exportname(s string) bool {
+	if s[0] < utf8.RuneSelf {
+		return 'A' <= s[0] && s[0] <= 'Z'
+	}
+	r, _ := utf8.DecodeRuneInString(s)
+	return unicode.IsUpper(r)
+}
+
+func initname(s string) int {
+	return bool2int(s == "init")
+}
+
+// exportedsym reports whether a symbol will be visible
+// to files that import our package.
+func exportedsym(sym *Sym) int {
+	// Builtins are visible everywhere.
+	if sym.Pkg == builtinpkg || sym.Origpkg == builtinpkg {
+		return 1
+	}
+
+	return bool2int(sym.Pkg == localpkg && exportname(sym.Name))
+}
+
+func autoexport(n *Node, ctxt int) {
+	if n == nil || n.Sym == nil {
+		return
+	}
+	if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
+		return
+	}
+	if n.Ntype != nil && n.Ntype.Op == OTFUNC && n.Ntype.Left != nil { // method
+		return
+	}
+
+	// -A is for cmd/gc/mkbuiltin script, so export everything
+	if Debug['A'] != 0 || exportname(n.Sym.Name) || initname(n.Sym.Name) != 0 {
+		exportsym(n)
+	}
+	if asmhdr != "" && n.Sym.Pkg == localpkg && !(n.Sym.Flags&SymAsm != 0) {
+		n.Sym.Flags |= SymAsm
+		asmlist = list(asmlist, n)
+	}
+}
+
+func dumppkg(p *Pkg) {
+	var suffix string
+
+	if p == nil || p == localpkg || p.Exported != 0 || p == builtinpkg {
+		return
+	}
+	p.Exported = 1
+	suffix = ""
+	if !(p.Direct != 0) {
+		suffix = " // indirect"
+	}
+	fmt.Fprintf(bout, "\timport %s \"%v\"%s\n", p.Name, Zconv(p.Path, 0), suffix)
+}
+
+// Look for anything we need for the inline body
+func reexportdeplist(ll *NodeList) {
+	for ; ll != nil; ll = ll.Next {
+		reexportdep(ll.N)
+	}
+}
+
+func reexportdep(n *Node) {
+	var t *Type
+
+	if !(n != nil) {
+		return
+	}
+
+	//print("reexportdep %+hN\n", n);
+	switch n.Op {
+	case ONAME:
+		switch n.Class &^ PHEAP {
+		// methods will be printed along with their type
+		// nodes for T.Method expressions
+		case PFUNC:
+			if n.Left != nil && n.Left.Op == OTYPE {
+				break
+			}
+
+			// nodes for method calls.
+			if !(n.Type != nil) || n.Type.Thistuple > 0 {
+				break
+			}
+			fallthrough
+
+			// fallthrough
+		case PEXTERN:
+			if n.Sym != nil && !(exportedsym(n.Sym) != 0) {
+				if Debug['E'] != 0 {
+					fmt.Printf("reexport name %v\n", Sconv(n.Sym, 0))
+				}
+				exportlist = list(exportlist, n)
+			}
+		}
+
+		// Local variables in the bodies need their type.
+	case ODCL:
+		t = n.Left.Type
+
+		if t != Types[t.Etype] && t != idealbool && t != idealstring {
+			if Isptr[t.Etype] != 0 {
+				t = t.Type
+			}
+			if t != nil && t.Sym != nil && t.Sym.Def != nil && !(exportedsym(t.Sym) != 0) {
+				if Debug['E'] != 0 {
+					fmt.Printf("reexport type %v from declaration\n", Sconv(t.Sym, 0))
+				}
+				exportlist = list(exportlist, t.Sym.Def)
+			}
+		}
+
+	case OLITERAL:
+		t = n.Type
+		if t != Types[n.Type.Etype] && t != idealbool && t != idealstring {
+			if Isptr[t.Etype] != 0 {
+				t = t.Type
+			}
+			if t != nil && t.Sym != nil && t.Sym.Def != nil && !(exportedsym(t.Sym) != 0) {
+				if Debug['E'] != 0 {
+					fmt.Printf("reexport literal type %v\n", Sconv(t.Sym, 0))
+				}
+				exportlist = list(exportlist, t.Sym.Def)
+			}
+		}
+		fallthrough
+
+		// fallthrough
+	case OTYPE:
+		if n.Sym != nil && !(exportedsym(n.Sym) != 0) {
+			if Debug['E'] != 0 {
+				fmt.Printf("reexport literal/type %v\n", Sconv(n.Sym, 0))
+			}
+			exportlist = list(exportlist, n)
+		}
+
+		// for operations that need a type when rendered, put the type on the export list.
+	case OCONV,
+		OCONVIFACE,
+		OCONVNOP,
+		ORUNESTR,
+		OARRAYBYTESTR,
+		OARRAYRUNESTR,
+		OSTRARRAYBYTE,
+		OSTRARRAYRUNE,
+		ODOTTYPE,
+		ODOTTYPE2,
+		OSTRUCTLIT,
+		OARRAYLIT,
+		OPTRLIT,
+		OMAKEMAP,
+		OMAKESLICE,
+		OMAKECHAN:
+		t = n.Type
+
+		if !(t.Sym != nil) && t.Type != nil {
+			t = t.Type
+		}
+		if t != nil && t.Sym != nil && t.Sym.Def != nil && !(exportedsym(t.Sym) != 0) {
+			if Debug['E'] != 0 {
+				fmt.Printf("reexport type for expression %v\n", Sconv(t.Sym, 0))
+			}
+			exportlist = list(exportlist, t.Sym.Def)
+		}
+	}
+
+	reexportdep(n.Left)
+	reexportdep(n.Right)
+	reexportdeplist(n.List)
+	reexportdeplist(n.Rlist)
+	reexportdeplist(n.Ninit)
+	reexportdep(n.Ntest)
+	reexportdep(n.Nincr)
+	reexportdeplist(n.Nbody)
+	reexportdeplist(n.Nelse)
+}
+
+func dumpexportconst(s *Sym) {
+	var n *Node
+	var t *Type
+
+	n = s.Def
+	typecheck(&n, Erv)
+	if n == nil || n.Op != OLITERAL {
+		Fatal("dumpexportconst: oconst nil: %v", Sconv(s, 0))
+	}
+
+	t = n.Type // may or may not be specified
+	dumpexporttype(t)
+
+	if t != nil && !(isideal(t) != 0) {
+		fmt.Fprintf(bout, "\tconst %v %v = %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp), Vconv(&n.Val, obj.FmtSharp))
+	} else {
+		fmt.Fprintf(bout, "\tconst %v = %v\n", Sconv(s, obj.FmtSharp), Vconv(&n.Val, obj.FmtSharp))
+	}
+}
+
+func dumpexportvar(s *Sym) {
+	var n *Node
+	var t *Type
+
+	n = s.Def
+	typecheck(&n, Erv|Ecall)
+	if n == nil || n.Type == nil {
+		Yyerror("variable exported but not defined: %v", Sconv(s, 0))
+		return
+	}
+
+	t = n.Type
+	dumpexporttype(t)
+
+	if t.Etype == TFUNC && n.Class == PFUNC {
+		if n.Inl != nil {
+			// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
+			// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
+			if Debug['l'] < 2 {
+				typecheckinl(n)
+			}
+
+			// NOTE: The space after %#S here is necessary for ld's export data parser.
+			fmt.Fprintf(bout, "\tfunc %v %v { %v }\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp), Hconv(n.Inl, obj.FmtSharp))
+
+			reexportdeplist(n.Inl)
+		} else {
+			fmt.Fprintf(bout, "\tfunc %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp))
+		}
+	} else {
+		fmt.Fprintf(bout, "\tvar %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp))
+	}
+}
+
+type methodbyname []*Type
+
+func (x methodbyname) Len() int {
+	return len(x)
+}
+
+func (x methodbyname) Swap(i, j int) {
+	x[i], x[j] = x[j], x[i]
+}
+
+func (x methodbyname) Less(i, j int) bool {
+	var a *Type
+	var b *Type
+
+	a = x[i]
+	b = x[j]
+	return stringsCompare(a.Sym.Name, b.Sym.Name) < 0
+}
+
+func dumpexporttype(t *Type) {
+	var f *Type
+	var m []*Type
+	var i int
+	var n int
+
+	if t == nil {
+		return
+	}
+	if t.Printed != 0 || t == Types[t.Etype] || t == bytetype || t == runetype || t == errortype {
+		return
+	}
+	t.Printed = 1
+
+	if t.Sym != nil && t.Etype != TFIELD {
+		dumppkg(t.Sym.Pkg)
+	}
+
+	dumpexporttype(t.Type)
+	dumpexporttype(t.Down)
+
+	if t.Sym == nil || t.Etype == TFIELD {
+		return
+	}
+
+	n = 0
+	for f = t.Method; f != nil; f = f.Down {
+		dumpexporttype(f)
+		n++
+	}
+
+	m = make([]*Type, n)
+	i = 0
+	for f = t.Method; f != nil; f = f.Down {
+		m[i] = f
+		i++
+	}
+	sort.Sort(methodbyname(m[:n]))
+
+	fmt.Fprintf(bout, "\ttype %v %v\n", Sconv(t.Sym, obj.FmtSharp), Tconv(t, obj.FmtSharp|obj.FmtLong))
+	for i = 0; i < n; i++ {
+		f = m[i]
+		if f.Nointerface != 0 {
+			fmt.Fprintf(bout, "\t//go:nointerface\n")
+		}
+		if f.Type.Nname != nil && f.Type.Nname.Inl != nil { // nname was set by caninl
+
+			// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
+			// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
+			if Debug['l'] < 2 {
+				typecheckinl(f.Type.Nname)
+			}
+			fmt.Fprintf(bout, "\tfunc (%v) %v %v { %v }\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp), Hconv(f.Type.Nname.Inl, obj.FmtSharp))
+			reexportdeplist(f.Type.Nname.Inl)
+		} else {
+			fmt.Fprintf(bout, "\tfunc (%v) %v %v\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp))
+		}
+	}
+}
+
+func dumpsym(s *Sym) {
+	if s.Flags&SymExported != 0 {
+		return
+	}
+	s.Flags |= SymExported
+
+	if s.Def == nil {
+		Yyerror("unknown export symbol: %v", Sconv(s, 0))
+		return
+	}
+
+	//	print("dumpsym %O %+S\n", s->def->op, s);
+	dumppkg(s.Pkg)
+
+	switch s.Def.Op {
+	default:
+		Yyerror("unexpected export symbol: %v %v", Oconv(int(s.Def.Op), 0), Sconv(s, 0))
+
+	case OLITERAL:
+		dumpexportconst(s)
+
+	case OTYPE:
+		if s.Def.Type.Etype == TFORW {
+			Yyerror("export of incomplete type %v", Sconv(s, 0))
+		} else {
+			dumpexporttype(s.Def.Type)
+		}
+
+	case ONAME:
+		dumpexportvar(s)
+	}
+}
+
+func dumpexport() {
+	var l *NodeList
+	var i int32
+	var lno int32
+	var p *Pkg
+
+	lno = lineno
+
+	fmt.Fprintf(bout, "\n$$\npackage %s", localpkg.Name)
+	if safemode != 0 {
+		fmt.Fprintf(bout, " safe")
+	}
+	fmt.Fprintf(bout, "\n")
+
+	for i = 0; i < int32(len(phash)); i++ {
+		for p = phash[i]; p != nil; p = p.Link {
+			if p.Direct != 0 {
+				dumppkg(p)
+			}
+		}
+	}
+
+	for l = exportlist; l != nil; l = l.Next {
+		lineno = l.N.Lineno
+		dumpsym(l.N.Sym)
+	}
+
+	fmt.Fprintf(bout, "\n$$\n")
+	lineno = lno
+}
+
+/*
+ * import
+ */
+
+/*
+ * return the sym for ss, which should match lexical
+ */
+func importsym(s *Sym, op int) *Sym {
+	var pkgstr string
+
+	if s.Def != nil && int(s.Def.Op) != op {
+		pkgstr = fmt.Sprintf("during import \"%v\"", Zconv(importpkg.Path, 0))
+		redeclare(s, pkgstr)
+	}
+
+	// mark the symbol so it is not reexported
+	if s.Def == nil {
+		if exportname(s.Name) || initname(s.Name) != 0 {
+			s.Flags |= SymExport
+		} else {
+			s.Flags |= SymPackage // package scope
+		}
+	}
+
+	return s
+}
+
+/*
+ * return the type pkg.name, forward declaring if needed
+ */
+func pkgtype(s *Sym) *Type {
+	var t *Type
+
+	importsym(s, OTYPE)
+	if s.Def == nil || s.Def.Op != OTYPE {
+		t = typ(TFORW)
+		t.Sym = s
+		s.Def = typenod(t)
+	}
+
+	if s.Def.Type == nil {
+		Yyerror("pkgtype %v", Sconv(s, 0))
+	}
+	return s.Def.Type
+}
+
+func importimport(s *Sym, z *Strlit) {
+	// Informational: record package name
+	// associated with import path, for use in
+	// human-readable messages.
+	var p *Pkg
+
+	if isbadimport(z) {
+		errorexit()
+	}
+	p = mkpkg(z)
+	if p.Name == "" {
+		p.Name = s.Name
+		Pkglookup(s.Name, nil).Npkg++
+	} else if p.Name != s.Name {
+		Yyerror("conflicting names %s and %s for package \"%v\"", p.Name, s.Name, Zconv(p.Path, 0))
+	}
+
+	if !(incannedimport != 0) && myimportpath != "" && z.S == myimportpath {
+		Yyerror("import \"%v\": package depends on \"%v\" (import cycle)", Zconv(importpkg.Path, 0), Zconv(z, 0))
+		errorexit()
+	}
+}
+
+func importconst(s *Sym, t *Type, n *Node) {
+	var n1 *Node
+
+	importsym(s, OLITERAL)
+	Convlit(&n, t)
+
+	if s.Def != nil { // TODO: check if already the same.
+		return
+	}
+
+	if n.Op != OLITERAL {
+		Yyerror("expression must be a constant")
+		return
+	}
+
+	if n.Sym != nil {
+		n1 = Nod(OXXX, nil, nil)
+		*n1 = *n
+		n = n1
+	}
+
+	n.Orig = newname(s)
+	n.Sym = s
+	declare(n, PEXTERN)
+
+	if Debug['E'] != 0 {
+		fmt.Printf("import const %v\n", Sconv(s, 0))
+	}
+}
+
+func importvar(s *Sym, t *Type) {
+	var n *Node
+
+	importsym(s, ONAME)
+	if s.Def != nil && s.Def.Op == ONAME {
+		if Eqtype(t, s.Def.Type) {
+			return
+		}
+		Yyerror("inconsistent definition for var %v during import\n\t%v (in \"%v\")\n\t%v (in \"%v\")", Sconv(s, 0), Tconv(s.Def.Type, 0), Zconv(s.Importdef.Path, 0), Tconv(t, 0), Zconv(importpkg.Path, 0))
+	}
+
+	n = newname(s)
+	s.Importdef = importpkg
+	n.Type = t
+	declare(n, PEXTERN)
+
+	if Debug['E'] != 0 {
+		fmt.Printf("import var %v %v\n", Sconv(s, 0), Tconv(t, obj.FmtLong))
+	}
+}
+
+func importtype(pt *Type, t *Type) {
+	var n *Node
+
+	// override declaration in unsafe.go for Pointer.
+	// there is no way in Go code to define unsafe.Pointer
+	// so we have to supply it.
+	if incannedimport != 0 && importpkg.Name == "unsafe" && pt.Nod.Sym.Name == "Pointer" {
+		t = Types[TUNSAFEPTR]
+	}
+
+	if pt.Etype == TFORW {
+		n = pt.Nod
+		copytype(pt.Nod, t)
+		pt.Nod = n // unzero nod
+		pt.Sym.Importdef = importpkg
+		pt.Sym.Lastlineno = int32(parserline())
+		declare(n, PEXTERN)
+		checkwidth(pt)
+	} else if !Eqtype(pt.Orig, t) {
+		Yyerror("inconsistent definition for type %v during import\n\t%v (in \"%v\")\n\t%v (in \"%v\")", Sconv(pt.Sym, 0), Tconv(pt, obj.FmtLong), Zconv(pt.Sym.Importdef.Path, 0), Tconv(t, obj.FmtLong), Zconv(importpkg.Path, 0))
+	}
+
+	if Debug['E'] != 0 {
+		fmt.Printf("import type %v %v\n", Tconv(pt, 0), Tconv(t, obj.FmtLong))
+	}
+}
+
+func dumpasmhdr() {
+	var b *obj.Biobuf
+	var l *NodeList
+	var n *Node
+	var t *Type
+
+	b, err := obj.Bopenw(asmhdr)
+	if err != nil {
+		Fatal("%v", err)
+	}
+	fmt.Fprintf(b, "// generated by %cg -asmhdr from package %s\n\n", Thearch.Thechar, localpkg.Name)
+	for l = asmlist; l != nil; l = l.Next {
+		n = l.N
+		if isblanksym(n.Sym) {
+			continue
+		}
+		switch n.Op {
+		case OLITERAL:
+			fmt.Fprintf(b, "#define const_%s %v\n", n.Sym.Name, Vconv(&n.Val, obj.FmtSharp))
+
+		case OTYPE:
+			t = n.Type
+			if t.Etype != TSTRUCT || t.Map != nil || t.Funarg != 0 {
+				break
+			}
+			fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width))
+			for t = t.Type; t != nil; t = t.Down {
+				if !isblanksym(t.Sym) {
+					fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Width))
+				}
+			}
+		}
+	}
+
+	obj.Bterm(b)
+}