diff options
Diffstat (limited to 'src/cmd/compile/internal/gc/iimport.go')
-rw-r--r-- | src/cmd/compile/internal/gc/iimport.go | 1117 |
1 files changed, 1117 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go new file mode 100644 index 0000000..c0114d0 --- /dev/null +++ b/src/cmd/compile/internal/gc/iimport.go @@ -0,0 +1,1117 @@ +// Copyright 2018 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. + +// Indexed package import. +// See iexport.go for the export data format. + +package gc + +import ( + "cmd/compile/internal/types" + "cmd/internal/bio" + "cmd/internal/goobj" + "cmd/internal/obj" + "cmd/internal/src" + "encoding/binary" + "fmt" + "io" + "math/big" + "os" + "strings" +) + +// An iimporterAndOffset identifies an importer and an offset within +// its data section. +type iimporterAndOffset struct { + p *iimporter + off uint64 +} + +var ( + // declImporter maps from imported identifiers to an importer + // and offset where that identifier's declaration can be read. + declImporter = map[*types.Sym]iimporterAndOffset{} + + // inlineImporter is like declImporter, but for inline bodies + // for function and method symbols. + inlineImporter = map[*types.Sym]iimporterAndOffset{} +) + +func expandDecl(n *Node) { + if n.Op != ONONAME { + return + } + + r := importReaderFor(n, declImporter) + if r == nil { + // Can happen if user tries to reference an undeclared name. + return + } + + r.doDecl(n) +} + +func expandInline(fn *Node) { + if fn.Func.Inl.Body != nil { + return + } + + r := importReaderFor(fn, inlineImporter) + if r == nil { + Fatalf("missing import reader for %v", fn) + } + + r.doInline(fn) +} + +func importReaderFor(n *Node, importers map[*types.Sym]iimporterAndOffset) *importReader { + x, ok := importers[n.Sym] + if !ok { + return nil + } + + return x.p.newReader(x.off, n.Sym.Pkg) +} + +type intReader struct { + *bio.Reader + pkg *types.Pkg +} + +func (r *intReader) int64() int64 { + i, err := binary.ReadVarint(r.Reader) + if err != nil { + yyerror("import %q: read error: %v", r.pkg.Path, err) + errorexit() + } + return i +} + +func (r *intReader) uint64() uint64 { + i, err := binary.ReadUvarint(r.Reader) + if err != nil { + yyerror("import %q: read error: %v", r.pkg.Path, err) + errorexit() + } + return i +} + +func iimport(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintType) { + ir := &intReader{in, pkg} + + version := ir.uint64() + if version != iexportVersion { + yyerror("import %q: unknown export format version %d", pkg.Path, version) + errorexit() + } + + sLen := ir.uint64() + dLen := ir.uint64() + + // Map string (and data) section into memory as a single large + // string. This reduces heap fragmentation and allows + // returning individual substrings very efficiently. + data, err := mapFile(in.File(), in.Offset(), int64(sLen+dLen)) + if err != nil { + yyerror("import %q: mapping input: %v", pkg.Path, err) + errorexit() + } + stringData := data[:sLen] + declData := data[sLen:] + + in.MustSeek(int64(sLen+dLen), os.SEEK_CUR) + + p := &iimporter{ + ipkg: pkg, + + pkgCache: map[uint64]*types.Pkg{}, + posBaseCache: map[uint64]*src.PosBase{}, + typCache: map[uint64]*types.Type{}, + + stringData: stringData, + declData: declData, + } + + for i, pt := range predeclared() { + p.typCache[uint64(i)] = pt + } + + // Declaration index. + for nPkgs := ir.uint64(); nPkgs > 0; nPkgs-- { + pkg := p.pkgAt(ir.uint64()) + pkgName := p.stringAt(ir.uint64()) + pkgHeight := int(ir.uint64()) + if pkg.Name == "" { + pkg.Name = pkgName + pkg.Height = pkgHeight + numImport[pkgName]++ + + // TODO(mdempsky): This belongs somewhere else. + pkg.Lookup("_").Def = asTypesNode(nblank) + } else { + if pkg.Name != pkgName { + Fatalf("conflicting package names %v and %v for path %q", pkg.Name, pkgName, pkg.Path) + } + if pkg.Height != pkgHeight { + Fatalf("conflicting package heights %v and %v for path %q", pkg.Height, pkgHeight, pkg.Path) + } + } + + for nSyms := ir.uint64(); nSyms > 0; nSyms-- { + s := pkg.Lookup(p.stringAt(ir.uint64())) + off := ir.uint64() + + if _, ok := declImporter[s]; ok { + continue + } + declImporter[s] = iimporterAndOffset{p, off} + + // Create stub declaration. If used, this will + // be overwritten by expandDecl. + if s.Def != nil { + Fatalf("unexpected definition for %v: %v", s, asNode(s.Def)) + } + s.Def = asTypesNode(npos(src.NoXPos, dclname(s))) + } + } + + // Inline body index. + for nPkgs := ir.uint64(); nPkgs > 0; nPkgs-- { + pkg := p.pkgAt(ir.uint64()) + + for nSyms := ir.uint64(); nSyms > 0; nSyms-- { + s := pkg.Lookup(p.stringAt(ir.uint64())) + off := ir.uint64() + + if _, ok := inlineImporter[s]; ok { + continue + } + inlineImporter[s] = iimporterAndOffset{p, off} + } + } + + // Fingerprint. + _, err = io.ReadFull(in, fingerprint[:]) + if err != nil { + yyerror("import %s: error reading fingerprint", pkg.Path) + errorexit() + } + return fingerprint +} + +type iimporter struct { + ipkg *types.Pkg + + pkgCache map[uint64]*types.Pkg + posBaseCache map[uint64]*src.PosBase + typCache map[uint64]*types.Type + + stringData string + declData string +} + +func (p *iimporter) stringAt(off uint64) string { + var x [binary.MaxVarintLen64]byte + n := copy(x[:], p.stringData[off:]) + + slen, n := binary.Uvarint(x[:n]) + if n <= 0 { + Fatalf("varint failed") + } + spos := off + uint64(n) + return p.stringData[spos : spos+slen] +} + +func (p *iimporter) posBaseAt(off uint64) *src.PosBase { + if posBase, ok := p.posBaseCache[off]; ok { + return posBase + } + + file := p.stringAt(off) + posBase := src.NewFileBase(file, file) + p.posBaseCache[off] = posBase + return posBase +} + +func (p *iimporter) pkgAt(off uint64) *types.Pkg { + if pkg, ok := p.pkgCache[off]; ok { + return pkg + } + + pkg := p.ipkg + if pkgPath := p.stringAt(off); pkgPath != "" { + pkg = types.NewPkg(pkgPath, "") + } + p.pkgCache[off] = pkg + return pkg +} + +// An importReader keeps state for reading an individual imported +// object (declaration or inline body). +type importReader struct { + strings.Reader + p *iimporter + + currPkg *types.Pkg + prevBase *src.PosBase + prevLine int64 + prevColumn int64 +} + +func (p *iimporter) newReader(off uint64, pkg *types.Pkg) *importReader { + r := &importReader{ + p: p, + currPkg: pkg, + } + // (*strings.Reader).Reset wasn't added until Go 1.7, and we + // need to build with Go 1.4. + r.Reader = *strings.NewReader(p.declData[off:]) + return r +} + +func (r *importReader) string() string { return r.p.stringAt(r.uint64()) } +func (r *importReader) posBase() *src.PosBase { return r.p.posBaseAt(r.uint64()) } +func (r *importReader) pkg() *types.Pkg { return r.p.pkgAt(r.uint64()) } + +func (r *importReader) setPkg() { + r.currPkg = r.pkg() +} + +func (r *importReader) doDecl(n *Node) { + if n.Op != ONONAME { + Fatalf("doDecl: unexpected Op for %v: %v", n.Sym, n.Op) + } + + tag := r.byte() + pos := r.pos() + + switch tag { + case 'A': + typ := r.typ() + + importalias(r.p.ipkg, pos, n.Sym, typ) + + case 'C': + typ, val := r.value() + + importconst(r.p.ipkg, pos, n.Sym, typ, val) + + case 'F': + typ := r.signature(nil) + + importfunc(r.p.ipkg, pos, n.Sym, typ) + r.funcExt(n) + + case 'T': + // Types can be recursive. We need to setup a stub + // declaration before recursing. + t := importtype(r.p.ipkg, pos, n.Sym) + + // We also need to defer width calculations until + // after the underlying type has been assigned. + defercheckwidth() + underlying := r.typ() + setUnderlying(t, underlying) + resumecheckwidth() + + if underlying.IsInterface() { + r.typeExt(t) + break + } + + ms := make([]*types.Field, r.uint64()) + for i := range ms { + mpos := r.pos() + msym := r.ident() + recv := r.param() + mtyp := r.signature(recv) + + f := types.NewField() + f.Pos = mpos + f.Sym = msym + f.Type = mtyp + ms[i] = f + + m := newfuncnamel(mpos, methodSym(recv.Type, msym)) + m.Type = mtyp + m.SetClass(PFUNC) + // methodSym already marked m.Sym as a function. + + // (comment from parser.go) + // 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. + mtyp.SetNname(asTypesNode(m)) + } + t.Methods().Set(ms) + + r.typeExt(t) + for _, m := range ms { + r.methExt(m) + } + + case 'V': + typ := r.typ() + + importvar(r.p.ipkg, pos, n.Sym, typ) + r.varExt(n) + + default: + Fatalf("unexpected tag: %v", tag) + } +} + +func (p *importReader) value() (typ *types.Type, v Val) { + typ = p.typ() + + switch constTypeOf(typ) { + case CTNIL: + v.U = &NilVal{} + case CTBOOL: + v.U = p.bool() + case CTSTR: + v.U = p.string() + case CTINT: + x := new(Mpint) + x.Rune = typ == types.UntypedRune + p.mpint(&x.Val, typ) + v.U = x + case CTFLT: + x := newMpflt() + p.float(x, typ) + v.U = x + case CTCPLX: + x := newMpcmplx() + p.float(&x.Real, typ) + p.float(&x.Imag, typ) + v.U = x + } + return +} + +func (p *importReader) mpint(x *big.Int, typ *types.Type) { + signed, maxBytes := intSize(typ) + + maxSmall := 256 - maxBytes + if signed { + maxSmall = 256 - 2*maxBytes + } + if maxBytes == 1 { + maxSmall = 256 + } + + n, _ := p.ReadByte() + if uint(n) < maxSmall { + v := int64(n) + if signed { + v >>= 1 + if n&1 != 0 { + v = ^v + } + } + x.SetInt64(v) + return + } + + v := -n + if signed { + v = -(n &^ 1) >> 1 + } + if v < 1 || uint(v) > maxBytes { + Fatalf("weird decoding: %v, %v => %v", n, signed, v) + } + b := make([]byte, v) + p.Read(b) + x.SetBytes(b) + if signed && n&1 != 0 { + x.Neg(x) + } +} + +func (p *importReader) float(x *Mpflt, typ *types.Type) { + var mant big.Int + p.mpint(&mant, typ) + m := x.Val.SetInt(&mant) + if m.Sign() == 0 { + return + } + m.SetMantExp(m, int(p.int64())) +} + +func (r *importReader) ident() *types.Sym { + name := r.string() + if name == "" { + return nil + } + pkg := r.currPkg + if types.IsExported(name) { + pkg = localpkg + } + return pkg.Lookup(name) +} + +func (r *importReader) qualifiedIdent() *types.Sym { + name := r.string() + pkg := r.pkg() + return pkg.Lookup(name) +} + +func (r *importReader) pos() src.XPos { + delta := r.int64() + r.prevColumn += delta >> 1 + if delta&1 != 0 { + delta = r.int64() + r.prevLine += delta >> 1 + if delta&1 != 0 { + r.prevBase = r.posBase() + } + } + + if (r.prevBase == nil || r.prevBase.AbsFilename() == "") && r.prevLine == 0 && r.prevColumn == 0 { + // TODO(mdempsky): Remove once we reliably write + // position information for all nodes. + return src.NoXPos + } + + if r.prevBase == nil { + Fatalf("missing posbase") + } + pos := src.MakePos(r.prevBase, uint(r.prevLine), uint(r.prevColumn)) + return Ctxt.PosTable.XPos(pos) +} + +func (r *importReader) typ() *types.Type { + return r.p.typAt(r.uint64()) +} + +func (p *iimporter) typAt(off uint64) *types.Type { + t, ok := p.typCache[off] + if !ok { + if off < predeclReserved { + Fatalf("predeclared type missing from cache: %d", off) + } + t = p.newReader(off-predeclReserved, nil).typ1() + p.typCache[off] = t + } + return t +} + +func (r *importReader) typ1() *types.Type { + switch k := r.kind(); k { + default: + Fatalf("unexpected kind tag in %q: %v", r.p.ipkg.Path, k) + return nil + + case definedType: + // We might be called from within doInline, in which + // case Sym.Def can point to declared parameters + // instead of the top-level types. Also, we don't + // support inlining functions with local defined + // types. Therefore, this must be a package-scope + // type. + n := asNode(r.qualifiedIdent().PkgDef()) + if n.Op == ONONAME { + expandDecl(n) + } + if n.Op != OTYPE { + Fatalf("expected OTYPE, got %v: %v, %v", n.Op, n.Sym, n) + } + return n.Type + case pointerType: + return types.NewPtr(r.typ()) + case sliceType: + return types.NewSlice(r.typ()) + case arrayType: + n := r.uint64() + return types.NewArray(r.typ(), int64(n)) + case chanType: + dir := types.ChanDir(r.uint64()) + return types.NewChan(r.typ(), dir) + case mapType: + return types.NewMap(r.typ(), r.typ()) + + case signatureType: + r.setPkg() + return r.signature(nil) + + case structType: + r.setPkg() + + fs := make([]*types.Field, r.uint64()) + for i := range fs { + pos := r.pos() + sym := r.ident() + typ := r.typ() + emb := r.bool() + note := r.string() + + f := types.NewField() + f.Pos = pos + f.Sym = sym + f.Type = typ + if emb { + f.Embedded = 1 + } + f.Note = note + fs[i] = f + } + + t := types.New(TSTRUCT) + t.SetPkg(r.currPkg) + t.SetFields(fs) + return t + + case interfaceType: + r.setPkg() + + embeddeds := make([]*types.Field, r.uint64()) + for i := range embeddeds { + pos := r.pos() + typ := r.typ() + + f := types.NewField() + f.Pos = pos + f.Type = typ + embeddeds[i] = f + } + + methods := make([]*types.Field, r.uint64()) + for i := range methods { + pos := r.pos() + sym := r.ident() + typ := r.signature(fakeRecvField()) + + f := types.NewField() + f.Pos = pos + f.Sym = sym + f.Type = typ + methods[i] = f + } + + t := types.New(TINTER) + t.SetPkg(r.currPkg) + t.SetInterface(append(embeddeds, methods...)) + + // Ensure we expand the interface in the frontend (#25055). + checkwidth(t) + return t + } +} + +func (r *importReader) kind() itag { + return itag(r.uint64()) +} + +func (r *importReader) signature(recv *types.Field) *types.Type { + params := r.paramList() + results := r.paramList() + if n := len(params); n > 0 { + params[n-1].SetIsDDD(r.bool()) + } + t := functypefield(recv, params, results) + t.SetPkg(r.currPkg) + return t +} + +func (r *importReader) paramList() []*types.Field { + fs := make([]*types.Field, r.uint64()) + for i := range fs { + fs[i] = r.param() + } + return fs +} + +func (r *importReader) param() *types.Field { + f := types.NewField() + f.Pos = r.pos() + f.Sym = r.ident() + f.Type = r.typ() + return f +} + +func (r *importReader) bool() bool { + return r.uint64() != 0 +} + +func (r *importReader) int64() int64 { + n, err := binary.ReadVarint(r) + if err != nil { + Fatalf("readVarint: %v", err) + } + return n +} + +func (r *importReader) uint64() uint64 { + n, err := binary.ReadUvarint(r) + if err != nil { + Fatalf("readVarint: %v", err) + } + return n +} + +func (r *importReader) byte() byte { + x, err := r.ReadByte() + if err != nil { + Fatalf("declReader.ReadByte: %v", err) + } + return x +} + +// Compiler-specific extensions. + +func (r *importReader) varExt(n *Node) { + r.linkname(n.Sym) + r.symIdx(n.Sym) +} + +func (r *importReader) funcExt(n *Node) { + r.linkname(n.Sym) + r.symIdx(n.Sym) + + // Escape analysis. + for _, fs := range &types.RecvsParams { + for _, f := range fs(n.Type).FieldSlice() { + f.Note = r.string() + } + } + + // Inline body. + if u := r.uint64(); u > 0 { + n.Func.Inl = &Inline{ + Cost: int32(u - 1), + } + n.Func.Endlineno = r.pos() + } +} + +func (r *importReader) methExt(m *types.Field) { + if r.bool() { + m.SetNointerface(true) + } + r.funcExt(asNode(m.Type.Nname())) +} + +func (r *importReader) linkname(s *types.Sym) { + s.Linkname = r.string() +} + +func (r *importReader) symIdx(s *types.Sym) { + lsym := s.Linksym() + idx := int32(r.int64()) + if idx != -1 { + if s.Linkname != "" { + Fatalf("bad index for linknamed symbol: %v %d\n", lsym, idx) + } + lsym.SymIdx = idx + lsym.Set(obj.AttrIndexed, true) + } +} + +func (r *importReader) typeExt(t *types.Type) { + t.SetNotInHeap(r.bool()) + i, pi := r.int64(), r.int64() + if i != -1 && pi != -1 { + typeSymIdx[t] = [2]int64{i, pi} + } +} + +// Map imported type T to the index of type descriptor symbols of T and *T, +// so we can use index to reference the symbol. +var typeSymIdx = make(map[*types.Type][2]int64) + +func (r *importReader) doInline(n *Node) { + if len(n.Func.Inl.Body) != 0 { + Fatalf("%v already has inline body", n) + } + + funchdr(n) + body := r.stmtList() + funcbody() + if body == nil { + // + // Make sure empty body is not interpreted as + // no inlineable body (see also parser.fnbody) + // (not doing so can cause significant performance + // degradation due to unnecessary calls to empty + // functions). + body = []*Node{} + } + n.Func.Inl.Body = body + + importlist = append(importlist, n) + + if Debug.E > 0 && Debug.m > 2 { + if Debug.m > 3 { + fmt.Printf("inl body for %v %#v: %+v\n", n, n.Type, asNodes(n.Func.Inl.Body)) + } else { + fmt.Printf("inl body for %v %#v: %v\n", n, n.Type, asNodes(n.Func.Inl.Body)) + } + } +} + +// ---------------------------------------------------------------------------- +// Inlined function bodies + +// Approach: Read nodes and use them to create/declare the same data structures +// as done originally by the (hidden) parser by closely following the parser's +// original code. In other words, "parsing" the import data (which happens to +// be encoded in binary rather textual form) is the best way at the moment to +// re-establish the syntax tree's invariants. At some future point we might be +// able to avoid this round-about way and create the rewritten nodes directly, +// possibly avoiding a lot of duplicate work (name resolution, type checking). +// +// Refined nodes (e.g., ODOTPTR as a refinement of OXDOT) are exported as their +// unrefined nodes (since this is what the importer uses). The respective case +// entries are unreachable in the importer. + +func (r *importReader) stmtList() []*Node { + var list []*Node + for { + n := r.node() + if n == nil { + break + } + // OBLOCK nodes may be created when importing ODCL nodes - unpack them + if n.Op == OBLOCK { + list = append(list, n.List.Slice()...) + } else { + list = append(list, n) + } + + } + return list +} + +func (r *importReader) caseList(sw *Node) []*Node { + namedTypeSwitch := sw.Op == OSWITCH && sw.Left != nil && sw.Left.Op == OTYPESW && sw.Left.Left != nil + + cases := make([]*Node, r.uint64()) + for i := range cases { + cas := nodl(r.pos(), OCASE, nil, nil) + cas.List.Set(r.stmtList()) + if namedTypeSwitch { + // Note: per-case variables will have distinct, dotted + // names after import. That's okay: swt.go only needs + // Sym for diagnostics anyway. + caseVar := newnamel(cas.Pos, r.ident()) + declare(caseVar, dclcontext) + cas.Rlist.Set1(caseVar) + caseVar.Name.Defn = sw.Left + } + cas.Nbody.Set(r.stmtList()) + cases[i] = cas + } + return cases +} + +func (r *importReader) exprList() []*Node { + var list []*Node + for { + n := r.expr() + if n == nil { + break + } + list = append(list, n) + } + return list +} + +func (r *importReader) expr() *Node { + n := r.node() + if n != nil && n.Op == OBLOCK { + Fatalf("unexpected block node: %v", n) + } + return n +} + +// TODO(gri) split into expr and stmt +func (r *importReader) node() *Node { + switch op := r.op(); op { + // expressions + // case OPAREN: + // unreachable - unpacked by exporter + + case OLITERAL: + pos := r.pos() + typ, val := r.value() + + n := npos(pos, nodlit(val)) + n.Type = typ + return n + + case ONONAME: + return mkname(r.qualifiedIdent()) + + case ONAME: + return mkname(r.ident()) + + // case OPACK, ONONAME: + // unreachable - should have been resolved by typechecking + + case OTYPE: + return typenod(r.typ()) + + case OTYPESW: + n := nodl(r.pos(), OTYPESW, nil, nil) + if s := r.ident(); s != nil { + n.Left = npos(n.Pos, newnoname(s)) + } + n.Right, _ = r.exprsOrNil() + return n + + // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC: + // unreachable - should have been resolved by typechecking + + // case OCLOSURE: + // unimplemented + + // case OPTRLIT: + // unreachable - mapped to case OADDR below by exporter + + case OSTRUCTLIT: + // TODO(mdempsky): Export position information for OSTRUCTKEY nodes. + savedlineno := lineno + lineno = r.pos() + n := nodl(lineno, OCOMPLIT, nil, typenod(r.typ())) + n.List.Set(r.elemList()) // special handling of field names + lineno = savedlineno + return n + + // case OARRAYLIT, OSLICELIT, OMAPLIT: + // unreachable - mapped to case OCOMPLIT below by exporter + + case OCOMPLIT: + n := nodl(r.pos(), OCOMPLIT, nil, typenod(r.typ())) + n.List.Set(r.exprList()) + return n + + case OKEY: + pos := r.pos() + left, right := r.exprsOrNil() + return nodl(pos, OKEY, left, right) + + // case OSTRUCTKEY: + // unreachable - handled in case OSTRUCTLIT by elemList + + // case OCALLPART: + // unreachable - mapped to case OXDOT below by exporter + + // case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH: + // unreachable - mapped to case OXDOT below by exporter + + case OXDOT: + // see parser.new_dotname + return npos(r.pos(), nodSym(OXDOT, r.expr(), r.ident())) + + // case ODOTTYPE, ODOTTYPE2: + // unreachable - mapped to case ODOTTYPE below by exporter + + case ODOTTYPE: + n := nodl(r.pos(), ODOTTYPE, r.expr(), nil) + n.Type = r.typ() + return n + + // case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR: + // unreachable - mapped to cases below by exporter + + case OINDEX: + return nodl(r.pos(), op, r.expr(), r.expr()) + + case OSLICE, OSLICE3: + n := nodl(r.pos(), op, r.expr(), nil) + low, high := r.exprsOrNil() + var max *Node + if n.Op.IsSlice3() { + max = r.expr() + } + n.SetSliceBounds(low, high, max) + return n + + // case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR: + // unreachable - mapped to OCONV case below by exporter + + case OCONV: + n := nodl(r.pos(), OCONV, r.expr(), nil) + n.Type = r.typ() + return n + + case OCOPY, OCOMPLEX, OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN: + n := npos(r.pos(), builtinCall(op)) + n.List.Set(r.exprList()) + if op == OAPPEND { + n.SetIsDDD(r.bool()) + } + return n + + // case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG: + // unreachable - mapped to OCALL case below by exporter + + case OCALL: + n := nodl(r.pos(), OCALL, nil, nil) + n.Ninit.Set(r.stmtList()) + n.Left = r.expr() + n.List.Set(r.exprList()) + n.SetIsDDD(r.bool()) + return n + + case OMAKEMAP, OMAKECHAN, OMAKESLICE: + n := npos(r.pos(), builtinCall(OMAKE)) + n.List.Append(typenod(r.typ())) + n.List.Append(r.exprList()...) + return n + + // unary expressions + case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV: + return nodl(r.pos(), op, r.expr(), nil) + + // binary expressions + case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT, + OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR: + return nodl(r.pos(), op, r.expr(), r.expr()) + + case OADDSTR: + pos := r.pos() + list := r.exprList() + x := npos(pos, list[0]) + for _, y := range list[1:] { + x = nodl(pos, OADD, x, y) + } + return x + + // -------------------------------------------------------------------- + // statements + case ODCL: + pos := r.pos() + lhs := npos(pos, dclname(r.ident())) + typ := typenod(r.typ()) + return npos(pos, liststmt(variter([]*Node{lhs}, typ, nil))) // TODO(gri) avoid list creation + + // case ODCLFIELD: + // unimplemented + + // case OAS, OASWB: + // unreachable - mapped to OAS case below by exporter + + case OAS: + return nodl(r.pos(), OAS, r.expr(), r.expr()) + + case OASOP: + n := nodl(r.pos(), OASOP, nil, nil) + n.SetSubOp(r.op()) + n.Left = r.expr() + if !r.bool() { + n.Right = nodintconst(1) + n.SetImplicit(true) + } else { + n.Right = r.expr() + } + return n + + // case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: + // unreachable - mapped to OAS2 case below by exporter + + case OAS2: + n := nodl(r.pos(), OAS2, nil, nil) + n.List.Set(r.exprList()) + n.Rlist.Set(r.exprList()) + return n + + case ORETURN: + n := nodl(r.pos(), ORETURN, nil, nil) + n.List.Set(r.exprList()) + return n + + // case ORETJMP: + // unreachable - generated by compiler for trampolin routines (not exported) + + case OGO, ODEFER: + return nodl(r.pos(), op, r.expr(), nil) + + case OIF: + n := nodl(r.pos(), OIF, nil, nil) + n.Ninit.Set(r.stmtList()) + n.Left = r.expr() + n.Nbody.Set(r.stmtList()) + n.Rlist.Set(r.stmtList()) + return n + + case OFOR: + n := nodl(r.pos(), OFOR, nil, nil) + n.Ninit.Set(r.stmtList()) + n.Left, n.Right = r.exprsOrNil() + n.Nbody.Set(r.stmtList()) + return n + + case ORANGE: + n := nodl(r.pos(), ORANGE, nil, nil) + n.List.Set(r.stmtList()) + n.Right = r.expr() + n.Nbody.Set(r.stmtList()) + return n + + case OSELECT, OSWITCH: + n := nodl(r.pos(), op, nil, nil) + n.Ninit.Set(r.stmtList()) + n.Left, _ = r.exprsOrNil() + n.List.Set(r.caseList(n)) + return n + + // case OCASE: + // handled by caseList + + case OFALL: + n := nodl(r.pos(), OFALL, nil, nil) + return n + + case OBREAK, OCONTINUE: + pos := r.pos() + left, _ := r.exprsOrNil() + if left != nil { + left = newname(left.Sym) + } + return nodl(pos, op, left, nil) + + // case OEMPTY: + // unreachable - not emitted by exporter + + case OGOTO, OLABEL: + n := nodl(r.pos(), op, nil, nil) + n.Sym = lookup(r.string()) + return n + + case OEND: + return nil + + default: + Fatalf("cannot import %v (%d) node\n"+ + "\t==> please file an issue and assign to gri@", op, int(op)) + panic("unreachable") // satisfy compiler + } +} + +func (r *importReader) op() Op { + return Op(r.uint64()) +} + +func (r *importReader) elemList() []*Node { + c := r.uint64() + list := make([]*Node, c) + for i := range list { + s := r.ident() + list[i] = nodSym(OSTRUCTKEY, r.expr(), s) + } + return list +} + +func (r *importReader) exprsOrNil() (a, b *Node) { + ab := r.uint64() + if ab&1 != 0 { + a = r.expr() + } + if ab&2 != 0 { + b = r.node() + } + return +} |