github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/compile/internal/gc/bimport.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Binary package import.
     6  // Based loosely on x/tools/go/importer.
     7  
     8  package gc
     9  
    10  import (
    11  	"bufio"
    12  	"cmd/compile/internal/big"
    13  	"encoding/binary"
    14  	"fmt"
    15  )
    16  
    17  // The overall structure of Import is symmetric to Export: For each
    18  // export method in bexport.go there is a matching and symmetric method
    19  // in bimport.go. Changing the export format requires making symmetric
    20  // changes to bimport.go and bexport.go.
    21  
    22  type importer struct {
    23  	in       *bufio.Reader
    24  	buf      []byte   // for reading strings
    25  	bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib
    26  	pkgList  []*Pkg
    27  	typList  []*Type
    28  	inlined  []*Node // functions with pending inlined function bodies
    29  
    30  	// debugging support
    31  	debugFormat bool
    32  	read        int // bytes read
    33  }
    34  
    35  // Import populates importpkg from the serialized package data.
    36  func Import(in *bufio.Reader) {
    37  	p := importer{in: in}
    38  	p.buf = p.bufarray[:]
    39  
    40  	// read low-level encoding format
    41  	switch format := p.byte(); format {
    42  	case 'c':
    43  		// compact format - nothing to do
    44  	case 'd':
    45  		p.debugFormat = true
    46  	default:
    47  		Fatalf("importer: invalid encoding format in export data: got %q; want 'c' or 'd'", format)
    48  	}
    49  
    50  	// --- generic export data ---
    51  
    52  	if v := p.string(); v != exportVersion {
    53  		Fatalf("importer: unknown export data version: %s", v)
    54  	}
    55  
    56  	// populate typList with predeclared "known" types
    57  	p.typList = append(p.typList, predeclared()...)
    58  
    59  	// read package data
    60  	p.pkg()
    61  	if p.pkgList[0] != importpkg {
    62  		Fatalf("importer: imported package not found in pkgList[0]")
    63  	}
    64  
    65  	// read compiler-specific flags
    66  	importpkg.Safe = p.string() == "safe"
    67  
    68  	// defer some type-checking until all types are read in completely
    69  	// (parser.go:import_package)
    70  	tcok := typecheckok
    71  	typecheckok = true
    72  	defercheckwidth()
    73  
    74  	// read objects
    75  
    76  	// Phase 1
    77  	objcount := 0
    78  	for {
    79  		tag := p.tagOrIndex()
    80  		if tag == endTag {
    81  			break
    82  		}
    83  		p.obj(tag)
    84  		objcount++
    85  	}
    86  
    87  	// self-verification
    88  	if count := p.int(); count != objcount {
    89  		Fatalf("importer: got %d objects; want %d", objcount, count)
    90  	}
    91  
    92  	// --- compiler-specific export data ---
    93  
    94  	// Phase 2
    95  	objcount = 0
    96  	for {
    97  		tag := p.tagOrIndex()
    98  		if tag == endTag {
    99  			break
   100  		}
   101  		p.obj(tag)
   102  		objcount++
   103  	}
   104  
   105  	// self-verification
   106  	if count := p.int(); count != objcount {
   107  		Fatalf("importer: got %d objects; want %d", objcount, count)
   108  	}
   109  
   110  	// read inlined functions bodies
   111  	if dclcontext != PEXTERN {
   112  		Fatalf("importer: unexpected context %d", dclcontext)
   113  	}
   114  
   115  	bcount := p.int() // consistency check only
   116  	if bcount != len(p.inlined) {
   117  		Fatalf("importer: expected %d inlined function bodies; got %d", bcount, len(p.inlined))
   118  	}
   119  	for _, f := range p.inlined {
   120  		if Funcdepth != 0 {
   121  			Fatalf("importer: unexpected Funcdepth %d", Funcdepth)
   122  		}
   123  		if f != nil {
   124  			// function body not yet imported - read body and set it
   125  			funchdr(f)
   126  			f.Func.Inl.Set(p.stmtList())
   127  			funcbody(f)
   128  		} else {
   129  			// function already imported - read body but discard declarations
   130  			dclcontext = PDISCARD // throw away any declarations
   131  			p.stmtList()
   132  			dclcontext = PEXTERN
   133  		}
   134  	}
   135  
   136  	if dclcontext != PEXTERN {
   137  		Fatalf("importer: unexpected context %d", dclcontext)
   138  	}
   139  
   140  	// --- end of export data ---
   141  
   142  	typecheckok = tcok
   143  	resumecheckwidth()
   144  
   145  	testdclstack() // debugging only
   146  }
   147  
   148  func (p *importer) pkg() *Pkg {
   149  	// if the package was seen before, i is its index (>= 0)
   150  	i := p.tagOrIndex()
   151  	if i >= 0 {
   152  		return p.pkgList[i]
   153  	}
   154  
   155  	// otherwise, i is the package tag (< 0)
   156  	if i != packageTag {
   157  		Fatalf("importer: expected package tag, found tag = %d", i)
   158  	}
   159  
   160  	// read package data
   161  	name := p.string()
   162  	path := p.string()
   163  
   164  	// we should never see an empty package name
   165  	if name == "" {
   166  		Fatalf("importer: empty package name in import")
   167  	}
   168  
   169  	// we should never see a bad import path
   170  	if isbadimport(path) {
   171  		Fatalf("importer: bad path in import: %q", path)
   172  	}
   173  
   174  	// an empty path denotes the package we are currently importing
   175  	pkg := importpkg
   176  	if path != "" {
   177  		pkg = mkpkg(path)
   178  	}
   179  	if pkg.Name == "" {
   180  		pkg.Name = name
   181  	} else if pkg.Name != name {
   182  		Fatalf("importer: conflicting names %s and %s for package %q", pkg.Name, name, path)
   183  	}
   184  	p.pkgList = append(p.pkgList, pkg)
   185  
   186  	return pkg
   187  }
   188  
   189  func idealType(typ *Type) *Type {
   190  	if typ.IsUntyped() {
   191  		// canonicalize ideal types
   192  		typ = Types[TIDEAL]
   193  	}
   194  	return typ
   195  }
   196  
   197  func (p *importer) obj(tag int) {
   198  	switch tag {
   199  	case constTag:
   200  		sym := p.qualifiedName()
   201  		typ := p.typ()
   202  		val := p.value(typ)
   203  		importconst(sym, idealType(typ), nodlit(val))
   204  
   205  	case typeTag:
   206  		p.typ()
   207  
   208  	case varTag:
   209  		sym := p.qualifiedName()
   210  		typ := p.typ()
   211  		importvar(sym, typ)
   212  
   213  	case funcTag:
   214  		sym := p.qualifiedName()
   215  		params := p.paramList()
   216  		result := p.paramList()
   217  		inl := p.int()
   218  
   219  		sig := functype(nil, params, result)
   220  		importsym(sym, ONAME)
   221  		if sym.Def != nil && sym.Def.Op == ONAME {
   222  			if Eqtype(sig, sym.Def.Type) {
   223  				// function was imported before (via another import)
   224  				dclcontext = PDISCARD // since we skip funchdr below
   225  			} else {
   226  				Fatalf("importer: inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, sig)
   227  			}
   228  		}
   229  
   230  		var n *Node
   231  		if dclcontext != PDISCARD {
   232  			n = newfuncname(sym)
   233  			n.Type = sig
   234  			declare(n, PFUNC)
   235  			if inl < 0 {
   236  				funchdr(n)
   237  			}
   238  		}
   239  
   240  		if inl >= 0 {
   241  			// function has inlined body - collect for later
   242  			if inl != len(p.inlined) {
   243  				Fatalf("importer: inlined index = %d; want %d", inl, len(p.inlined))
   244  			}
   245  			p.inlined = append(p.inlined, n)
   246  		}
   247  
   248  		// parser.go:hidden_import
   249  		if dclcontext == PDISCARD {
   250  			dclcontext = PEXTERN // since we skip the funcbody below
   251  			break
   252  		}
   253  
   254  		if inl < 0 {
   255  			funcbody(n)
   256  		}
   257  		importlist = append(importlist, n) // TODO(gri) may only be needed for inlineable functions
   258  
   259  		if Debug['E'] > 0 {
   260  			fmt.Printf("import [%q] func %v \n", importpkg.Path, n)
   261  			if Debug['m'] > 2 && len(n.Func.Inl.Slice()) != 0 {
   262  				fmt.Printf("inl body: %v\n", n.Func.Inl)
   263  			}
   264  		}
   265  
   266  	default:
   267  		Fatalf("importer: unexpected object tag")
   268  	}
   269  }
   270  
   271  func (p *importer) newtyp(etype EType) *Type {
   272  	t := typ(etype)
   273  	p.typList = append(p.typList, t)
   274  	return t
   275  }
   276  
   277  func (p *importer) typ() *Type {
   278  	// if the type was seen before, i is its index (>= 0)
   279  	i := p.tagOrIndex()
   280  	if i >= 0 {
   281  		return p.typList[i]
   282  	}
   283  
   284  	// otherwise, i is the type tag (< 0)
   285  	var t *Type
   286  	switch i {
   287  	case namedTag:
   288  		// parser.go:hidden_importsym
   289  		tsym := p.qualifiedName()
   290  
   291  		// parser.go:hidden_pkgtype
   292  		t = pkgtype(tsym)
   293  		p.typList = append(p.typList, t)
   294  
   295  		// read underlying type
   296  		// parser.go:hidden_type
   297  		t0 := p.typ()
   298  		importtype(t, t0) // parser.go:hidden_import
   299  
   300  		// interfaces don't have associated methods
   301  		if t0.IsInterface() {
   302  			break
   303  		}
   304  
   305  		// set correct import context (since p.typ() may be called
   306  		// while importing the body of an inlined function)
   307  		savedContext := dclcontext
   308  		dclcontext = PEXTERN
   309  
   310  		// read associated methods
   311  		for i := p.int(); i > 0; i-- {
   312  			// parser.go:hidden_fndcl
   313  
   314  			sym := p.fieldSym()
   315  
   316  			recv := p.paramList() // TODO(gri) do we need a full param list for the receiver?
   317  			params := p.paramList()
   318  			result := p.paramList()
   319  			inl := p.int()
   320  
   321  			n := methodname1(newname(sym), recv[0].Right)
   322  			n.Type = functype(recv[0], params, result)
   323  			checkwidth(n.Type)
   324  			addmethod(sym, n.Type, tsym.Pkg, false, false)
   325  			if inl < 0 {
   326  				funchdr(n)
   327  			}
   328  
   329  			if inl >= 0 {
   330  				// method has inlined body - collect for later
   331  				if inl != len(p.inlined) {
   332  					Fatalf("importer: inlined index = %d; want %d", inl, len(p.inlined))
   333  				}
   334  				p.inlined = append(p.inlined, n)
   335  			}
   336  
   337  			// (comment from parser.go)
   338  			// inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
   339  			// (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled
   340  			// out by typecheck's lookdot as this $$.ttype. So by providing
   341  			// this back link here we avoid special casing there.
   342  			n.Type.SetNname(n)
   343  
   344  			// parser.go:hidden_import
   345  			if inl < 0 {
   346  				funcbody(n)
   347  			}
   348  			importlist = append(importlist, n) // TODO(gri) may only be needed for inlineable functions
   349  
   350  			if Debug['E'] > 0 {
   351  				fmt.Printf("import [%q] meth %v \n", importpkg.Path, n)
   352  				if Debug['m'] > 2 && len(n.Func.Inl.Slice()) != 0 {
   353  					fmt.Printf("inl body: %v\n", n.Func.Inl)
   354  				}
   355  			}
   356  		}
   357  
   358  		dclcontext = savedContext
   359  
   360  	case arrayTag, sliceTag:
   361  		t = p.newtyp(TARRAY)
   362  		if i == arrayTag {
   363  			t.SetNumElem(p.int64())
   364  		} else {
   365  			t.SetNumElem(sliceBound)
   366  		}
   367  		t.Type = p.typ()
   368  
   369  	case dddTag:
   370  		t = p.newtyp(TDDDFIELD)
   371  		t.Type = p.typ()
   372  
   373  	case structTag:
   374  		t = p.newtyp(TSTRUCT)
   375  		tostruct0(t, p.fieldList())
   376  
   377  	case pointerTag:
   378  		t = p.newtyp(Tptr)
   379  		t.Type = p.typ()
   380  
   381  	case signatureTag:
   382  		t = p.newtyp(TFUNC)
   383  		params := p.paramList()
   384  		result := p.paramList()
   385  		functype0(t, nil, params, result)
   386  
   387  	case interfaceTag:
   388  		t = p.newtyp(TINTER)
   389  		if p.int() != 0 {
   390  			Fatalf("importer: unexpected embedded interface")
   391  		}
   392  		tointerface0(t, p.methodList())
   393  
   394  	case mapTag:
   395  		t = p.newtyp(TMAP)
   396  		t.Down = p.typ() // key
   397  		t.Type = p.typ() // val
   398  
   399  	case chanTag:
   400  		t = p.newtyp(TCHAN)
   401  		t.Chan = ChanDir(p.int())
   402  		t.Type = p.typ()
   403  
   404  	default:
   405  		Fatalf("importer: unexpected type (tag = %d)", i)
   406  	}
   407  
   408  	if t == nil {
   409  		Fatalf("importer: nil type (type tag = %d)", i)
   410  	}
   411  
   412  	return t
   413  }
   414  
   415  func (p *importer) qualifiedName() *Sym {
   416  	name := p.string()
   417  	pkg := p.pkg()
   418  	return pkg.Lookup(name)
   419  }
   420  
   421  // parser.go:hidden_structdcl_list
   422  func (p *importer) fieldList() []*Node {
   423  	i := p.int()
   424  	if i == 0 {
   425  		return nil
   426  	}
   427  	n := make([]*Node, i)
   428  	for i := range n {
   429  		n[i] = p.field()
   430  	}
   431  	return n
   432  }
   433  
   434  // parser.go:hidden_structdcl
   435  func (p *importer) field() *Node {
   436  	sym := p.fieldName()
   437  	typ := p.typ()
   438  	note := p.note()
   439  
   440  	var n *Node
   441  	if sym.Name != "" {
   442  		n = Nod(ODCLFIELD, newname(sym), typenod(typ))
   443  	} else {
   444  		// anonymous field - typ must be T or *T and T must be a type name
   445  		s := typ.Sym
   446  		if s == nil && typ.IsPtr() {
   447  			s = typ.Type.Sym // deref
   448  		}
   449  		pkg := importpkg
   450  		if sym != nil {
   451  			pkg = sym.Pkg
   452  		}
   453  		n = embedded(s, pkg)
   454  		n.Right = typenod(typ)
   455  	}
   456  	n.SetVal(note)
   457  
   458  	return n
   459  }
   460  
   461  func (p *importer) note() (v Val) {
   462  	if s := p.string(); s != "" {
   463  		v.U = s
   464  	}
   465  	return
   466  }
   467  
   468  // parser.go:hidden_interfacedcl_list
   469  func (p *importer) methodList() []*Node {
   470  	i := p.int()
   471  	if i == 0 {
   472  		return nil
   473  	}
   474  	n := make([]*Node, i)
   475  	for i := range n {
   476  		n[i] = p.method()
   477  	}
   478  	return n
   479  }
   480  
   481  // parser.go:hidden_interfacedcl
   482  func (p *importer) method() *Node {
   483  	sym := p.fieldName()
   484  	params := p.paramList()
   485  	result := p.paramList()
   486  	return Nod(ODCLFIELD, newname(sym), typenod(functype(fakethis(), params, result)))
   487  }
   488  
   489  // parser.go:sym,hidden_importsym
   490  func (p *importer) fieldName() *Sym {
   491  	name := p.string()
   492  	pkg := localpkg
   493  	if name == "_" {
   494  		// During imports, unqualified non-exported identifiers are from builtinpkg
   495  		// (see parser.go:sym). The binary exporter only exports blank as a non-exported
   496  		// identifier without qualification.
   497  		pkg = localpkg
   498  	} else if name == "?" || name != "" && !exportname(name) {
   499  		if name == "?" {
   500  			name = ""
   501  		}
   502  		pkg = p.pkg()
   503  	}
   504  	return pkg.Lookup(name)
   505  }
   506  
   507  // parser.go:ohidden_funarg_list
   508  func (p *importer) paramList() []*Node {
   509  	i := p.int()
   510  	if i == 0 {
   511  		return nil
   512  	}
   513  	// negative length indicates unnamed parameters
   514  	named := true
   515  	if i < 0 {
   516  		i = -i
   517  		named = false
   518  	}
   519  	// i > 0
   520  	n := make([]*Node, i)
   521  	for i := range n {
   522  		n[i] = p.param(named)
   523  	}
   524  	return n
   525  }
   526  
   527  // parser.go:hidden_funarg
   528  func (p *importer) param(named bool) *Node {
   529  	typ := p.typ()
   530  
   531  	isddd := false
   532  	if typ.Etype == TDDDFIELD {
   533  		// TDDDFIELD indicates wrapped ... slice type
   534  		typ = typSlice(typ.Wrapped())
   535  		isddd = true
   536  	}
   537  
   538  	n := Nod(ODCLFIELD, nil, typenod(typ))
   539  	n.Isddd = isddd
   540  
   541  	if named {
   542  		name := p.string()
   543  		if name == "" {
   544  			Fatalf("importer: expected named parameter")
   545  		}
   546  		// TODO(gri) Supply function/method package rather than
   547  		// encoding the package for each parameter repeatedly.
   548  		pkg := p.pkg()
   549  		n.Left = newname(pkg.Lookup(name))
   550  	}
   551  
   552  	// TODO(gri) This is compiler-specific (escape info).
   553  	// Move into compiler-specific section eventually?
   554  	n.SetVal(p.note())
   555  
   556  	return n
   557  }
   558  
   559  func (p *importer) value(typ *Type) (x Val) {
   560  	switch tag := p.tagOrIndex(); tag {
   561  	case falseTag:
   562  		x.U = false
   563  
   564  	case trueTag:
   565  		x.U = true
   566  
   567  	case int64Tag:
   568  		u := new(Mpint)
   569  		u.SetInt64(p.int64())
   570  		u.Rune = typ == idealrune
   571  		x.U = u
   572  
   573  	case floatTag:
   574  		f := newMpflt()
   575  		p.float(f)
   576  		if typ == idealint || typ.IsInteger() {
   577  			// uncommon case: large int encoded as float
   578  			u := new(Mpint)
   579  			u.SetFloat(f)
   580  			x.U = u
   581  			break
   582  		}
   583  		x.U = f
   584  
   585  	case complexTag:
   586  		u := new(Mpcplx)
   587  		p.float(&u.Real)
   588  		p.float(&u.Imag)
   589  		x.U = u
   590  
   591  	case stringTag:
   592  		x.U = p.string()
   593  
   594  	case unknownTag:
   595  		Fatalf("importer: unknown constant (importing package with errors)")
   596  
   597  	case nilTag:
   598  		x.U = new(NilVal)
   599  
   600  	default:
   601  		Fatalf("importer: unexpected value tag %d", tag)
   602  	}
   603  
   604  	// verify ideal type
   605  	if typ.IsUntyped() && untype(x.Ctype()) != typ {
   606  		Fatalf("importer: value %v and type %v don't match", x, typ)
   607  	}
   608  
   609  	return
   610  }
   611  
   612  func (p *importer) float(x *Mpflt) {
   613  	sign := p.int()
   614  	if sign == 0 {
   615  		x.SetFloat64(0)
   616  		return
   617  	}
   618  
   619  	exp := p.int()
   620  	mant := new(big.Int).SetBytes([]byte(p.string()))
   621  
   622  	m := x.Val.SetInt(mant)
   623  	m.SetMantExp(m, exp-mant.BitLen())
   624  	if sign < 0 {
   625  		m.Neg(m)
   626  	}
   627  }
   628  
   629  // ----------------------------------------------------------------------------
   630  // Inlined function bodies
   631  
   632  // Approach: Read nodes and use them to create/declare the same data structures
   633  // as done originally by the (hidden) parser by closely following the parser's
   634  // original code. In other words, "parsing" the import data (which happens to
   635  // be encoded in binary rather textual form) is the best way at the moment to
   636  // re-establish the syntax tree's invariants. At some future point we might be
   637  // able to avoid this round-about way and create the rewritten nodes directly,
   638  // possibly avoiding a lot of duplicate work (name resolution, type checking).
   639  
   640  func (p *importer) stmtList() []*Node {
   641  	var list []*Node
   642  	for {
   643  		n := p.node()
   644  		if n == nil {
   645  			break
   646  		}
   647  		// OBLOCK nodes may be created when importing ODCL nodes - unpack them
   648  		if n.Op == OBLOCK {
   649  			list = append(list, n.List.Slice()...)
   650  		} else {
   651  			list = append(list, n)
   652  		}
   653  	}
   654  	return list
   655  }
   656  
   657  func (p *importer) exprList() []*Node {
   658  	var list []*Node
   659  	for {
   660  		n := p.expr()
   661  		if n == nil {
   662  			break
   663  		}
   664  		list = append(list, n)
   665  	}
   666  	return list
   667  }
   668  
   669  func (p *importer) elemList() []*Node {
   670  	c := p.int()
   671  	list := make([]*Node, c)
   672  	for i := range list {
   673  		list[i] = Nod(OKEY, mkname(p.fieldSym()), p.expr())
   674  	}
   675  	return list
   676  }
   677  
   678  func (p *importer) expr() *Node {
   679  	n := p.node()
   680  	if n != nil && n.Op == OBLOCK {
   681  		Fatalf("unexpected block node: %v", n)
   682  	}
   683  	return n
   684  }
   685  
   686  // TODO(gri) split into expr and stmt
   687  func (p *importer) node() *Node {
   688  	switch op := p.op(); op {
   689  	// expressions
   690  	// case OPAREN:
   691  	// 	unreachable - unpacked by exporter
   692  
   693  	// case ODDDARG:
   694  	//	unimplemented
   695  
   696  	// case OREGISTER:
   697  	//	unimplemented
   698  
   699  	case OLITERAL:
   700  		typ := p.typ()
   701  		n := nodlit(p.value(typ))
   702  		if !typ.IsUntyped() {
   703  			conv := Nod(OCALL, typenod(typ), nil)
   704  			conv.List.Set1(n)
   705  			n = conv
   706  		}
   707  		return n
   708  
   709  	case ONAME:
   710  		if p.bool() {
   711  			// "_"
   712  			// TODO(gri) avoid repeated "_" lookup
   713  			return mkname(Pkglookup("_", localpkg))
   714  		}
   715  		return NodSym(OXDOT, typenod(p.typ()), p.fieldSym())
   716  
   717  	case OPACK, ONONAME:
   718  		return mkname(p.sym())
   719  
   720  	case OTYPE:
   721  		if p.bool() {
   722  			return mkname(p.sym())
   723  		}
   724  		return typenod(p.typ())
   725  
   726  	// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
   727  	//      unreachable - should have been resolved by typechecking
   728  
   729  	// case OCLOSURE:
   730  	//	unimplemented
   731  
   732  	// case OCOMPLIT:
   733  	//	unimplemented
   734  
   735  	case OPTRLIT:
   736  		n := p.expr()
   737  		if !p.bool() /* !implicit, i.e. '&' operator*/ {
   738  			if n.Op == OCOMPLIT {
   739  				// Special case for &T{...}: turn into (*T){...}.
   740  				n.Right = Nod(OIND, n.Right, nil)
   741  				n.Right.Implicit = true
   742  			} else {
   743  				n = Nod(OADDR, n, nil)
   744  			}
   745  		}
   746  		return n
   747  
   748  	case OSTRUCTLIT:
   749  		n := Nod(OCOMPLIT, nil, nil)
   750  		if !p.bool() {
   751  			n.Right = typenod(p.typ())
   752  		}
   753  		n.List.Set(p.elemList())
   754  		return n
   755  
   756  	case OARRAYLIT, OMAPLIT:
   757  		n := Nod(OCOMPLIT, nil, nil)
   758  		if !p.bool() {
   759  			n.Right = typenod(p.typ())
   760  		}
   761  		n.List.Set(p.exprList())
   762  		return n
   763  
   764  	case OKEY:
   765  		left, right := p.exprsOrNil()
   766  		return Nod(OKEY, left, right)
   767  
   768  	// case OCALLPART:
   769  	//	unimplemented
   770  
   771  	// case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
   772  	// 	unreachable - mapped to case OXDOT below by exporter
   773  
   774  	case OXDOT:
   775  		// see parser.new_dotname
   776  		obj := p.expr()
   777  		sel := p.fieldSym()
   778  		if obj.Op == OPACK {
   779  			s := restrictlookup(sel.Name, obj.Name.Pkg)
   780  			obj.Used = true
   781  			return oldname(s)
   782  		}
   783  		return NodSym(OXDOT, obj, sel)
   784  
   785  	// case ODOTTYPE, ODOTTYPE2:
   786  	// 	unreachable - mapped to case ODOTTYPE below by exporter
   787  
   788  	case ODOTTYPE:
   789  		n := Nod(ODOTTYPE, p.expr(), nil)
   790  		if p.bool() {
   791  			n.Right = p.expr()
   792  		} else {
   793  			n.Right = typenod(p.typ())
   794  		}
   795  		return n
   796  
   797  	// case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
   798  	// 	unreachable - mapped to cases below by exporter
   799  
   800  	case OINDEX, OSLICE, OSLICE3:
   801  		return Nod(op, p.expr(), p.expr())
   802  
   803  	case OCOPY, OCOMPLEX:
   804  		n := builtinCall(op)
   805  		n.List.Set([]*Node{p.expr(), p.expr()})
   806  		return n
   807  
   808  	// case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
   809  	// 	unreachable - mapped to OCONV case below by exporter
   810  
   811  	case OCONV:
   812  		n := Nod(OCALL, typenod(p.typ()), nil)
   813  		if p.bool() {
   814  			n.List.Set1(p.expr())
   815  		} else {
   816  			n.List.Set(p.exprList())
   817  		}
   818  		return n
   819  
   820  	case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
   821  		n := builtinCall(op)
   822  		if p.bool() {
   823  			n.List.Set1(p.expr())
   824  		} else {
   825  			n.List.Set(p.exprList())
   826  			n.Isddd = p.bool()
   827  		}
   828  		return n
   829  
   830  	// case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
   831  	// 	unreachable - mapped to OCALL case below by exporter
   832  
   833  	case OCALL:
   834  		n := Nod(OCALL, p.expr(), nil)
   835  		n.List.Set(p.exprList())
   836  		n.Isddd = p.bool()
   837  		return n
   838  
   839  	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
   840  		n := builtinCall(OMAKE)
   841  		n.List.Append(typenod(p.typ()))
   842  		n.List.Append(p.exprList()...)
   843  		return n
   844  
   845  	// unary expressions
   846  	case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV:
   847  		return Nod(op, p.expr(), nil)
   848  
   849  	// binary expressions
   850  	case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT,
   851  		OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR:
   852  		return Nod(op, p.expr(), p.expr())
   853  
   854  	case OADDSTR:
   855  		list := p.exprList()
   856  		x := list[0]
   857  		for _, y := range list[1:] {
   858  			x = Nod(OADD, x, y)
   859  		}
   860  		return x
   861  
   862  	// case OCMPSTR, OCMPIFACE:
   863  	// 	unreachable - mapped to std comparison operators by exporter
   864  
   865  	case ODCLCONST:
   866  		// TODO(gri) these should not be exported in the first place
   867  		return Nod(OEMPTY, nil, nil)
   868  
   869  	// --------------------------------------------------------------------
   870  	// statements
   871  	case ODCL:
   872  		var lhs *Node
   873  		if p.bool() {
   874  			lhs = p.expr()
   875  		} else {
   876  			lhs = dclname(p.sym())
   877  		}
   878  		// TODO(gri) avoid list created here!
   879  		return liststmt(variter([]*Node{lhs}, typenod(p.typ()), nil))
   880  
   881  	// case ODCLFIELD:
   882  	//	unimplemented
   883  
   884  	case OAS, OASWB:
   885  		if p.bool() {
   886  			lhs := p.expr()
   887  			rhs := p.expr()
   888  			return Nod(OAS, lhs, rhs)
   889  		}
   890  		// TODO(gri) we should not have emitted anything here
   891  		return Nod(OEMPTY, nil, nil)
   892  
   893  	case OASOP:
   894  		n := Nod(OASOP, nil, nil)
   895  		n.Etype = EType(p.int())
   896  		n.Left = p.expr()
   897  		if !p.bool() {
   898  			n.Right = Nodintconst(1)
   899  			n.Implicit = true
   900  		} else {
   901  			n.Right = p.expr()
   902  		}
   903  		return n
   904  
   905  	case OAS2:
   906  		lhs := p.exprList()
   907  		rhs := p.exprList()
   908  		n := Nod(OAS2, nil, nil)
   909  		n.List.Set(lhs)
   910  		n.Rlist.Set(rhs)
   911  		return n
   912  
   913  	case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
   914  		n := Nod(OAS2, nil, nil)
   915  		n.List.Set(p.exprList())
   916  		n.Rlist.Set(p.exprList())
   917  		return n
   918  
   919  	case ORETURN:
   920  		n := Nod(ORETURN, nil, nil)
   921  		n.List.Set(p.exprList())
   922  		return n
   923  
   924  	// case ORETJMP:
   925  	// 	unreachable - generated by compiler for trampolin routines (not exported)
   926  
   927  	case OPROC, ODEFER:
   928  		return Nod(op, p.expr(), nil)
   929  
   930  	case OIF:
   931  		markdcl()
   932  		n := Nod(OIF, nil, nil)
   933  		n.Ninit.Set(p.stmtList())
   934  		n.Left = p.expr()
   935  		n.Nbody.Set(p.stmtList())
   936  		n.Rlist.Set(p.stmtList())
   937  		popdcl()
   938  		return n
   939  
   940  	case OFOR:
   941  		markdcl()
   942  		n := Nod(OFOR, nil, nil)
   943  		n.Ninit.Set(p.stmtList())
   944  		n.Left, n.Right = p.exprsOrNil()
   945  		n.Nbody.Set(p.stmtList())
   946  		popdcl()
   947  		return n
   948  
   949  	case ORANGE:
   950  		markdcl()
   951  		n := Nod(ORANGE, nil, nil)
   952  		n.List.Set(p.stmtList())
   953  		n.Right = p.expr()
   954  		n.Nbody.Set(p.stmtList())
   955  		popdcl()
   956  		return n
   957  
   958  	case OSELECT, OSWITCH:
   959  		markdcl()
   960  		n := Nod(op, nil, nil)
   961  		n.Ninit.Set(p.stmtList())
   962  		n.Left, _ = p.exprsOrNil()
   963  		n.List.Set(p.stmtList())
   964  		popdcl()
   965  		return n
   966  
   967  	case OCASE, OXCASE:
   968  		markdcl()
   969  		n := Nod(OXCASE, nil, nil)
   970  		n.List.Set(p.exprList())
   971  		// TODO(gri) eventually we must declare variables for type switch
   972  		// statements (type switch statements are not yet exported)
   973  		n.Nbody.Set(p.stmtList())
   974  		popdcl()
   975  		return n
   976  
   977  	case OBREAK, OCONTINUE, OGOTO, OFALL, OXFALL:
   978  		if op == OFALL {
   979  			op = OXFALL
   980  		}
   981  		left, _ := p.exprsOrNil()
   982  		return Nod(op, left, nil)
   983  
   984  	// case OEMPTY:
   985  	// 	unreachable - not emitted by exporter
   986  
   987  	case OLABEL:
   988  		n := Nod(OLABEL, p.expr(), nil)
   989  		n.Left.Sym = dclstack // context, for goto restrictions
   990  		return n
   991  
   992  	case OEND:
   993  		return nil
   994  
   995  	default:
   996  		Fatalf("importer: %s (%d) node not yet supported", opnames[op], op)
   997  		panic("unreachable") // satisfy compiler
   998  	}
   999  }
  1000  
  1001  func builtinCall(op Op) *Node {
  1002  	return Nod(OCALL, mkname(builtinpkg.Lookup(goopnames[op])), nil)
  1003  }
  1004  
  1005  func (p *importer) exprsOrNil() (a, b *Node) {
  1006  	ab := p.int()
  1007  	if ab&1 != 0 {
  1008  		a = p.expr()
  1009  	}
  1010  	if ab&2 != 0 {
  1011  		b = p.expr()
  1012  	}
  1013  	return
  1014  }
  1015  
  1016  func (p *importer) fieldSym() *Sym {
  1017  	name := p.string()
  1018  	pkg := localpkg
  1019  	if !exportname(name) {
  1020  		pkg = p.pkg()
  1021  	}
  1022  	return pkg.Lookup(name)
  1023  }
  1024  
  1025  func (p *importer) sym() *Sym {
  1026  	name := p.string()
  1027  	pkg := localpkg
  1028  	if name != "_" {
  1029  		pkg = p.pkg()
  1030  	}
  1031  	return pkg.Lookup(name)
  1032  }
  1033  
  1034  func (p *importer) bool() bool {
  1035  	return p.int() != 0
  1036  }
  1037  
  1038  func (p *importer) op() Op {
  1039  	return Op(p.int())
  1040  }
  1041  
  1042  // ----------------------------------------------------------------------------
  1043  // Low-level decoders
  1044  
  1045  func (p *importer) tagOrIndex() int {
  1046  	if p.debugFormat {
  1047  		p.marker('t')
  1048  	}
  1049  
  1050  	return int(p.rawInt64())
  1051  }
  1052  
  1053  func (p *importer) int() int {
  1054  	x := p.int64()
  1055  	if int64(int(x)) != x {
  1056  		Fatalf("importer: exported integer too large")
  1057  	}
  1058  	return int(x)
  1059  }
  1060  
  1061  func (p *importer) int64() int64 {
  1062  	if p.debugFormat {
  1063  		p.marker('i')
  1064  	}
  1065  
  1066  	return p.rawInt64()
  1067  }
  1068  
  1069  func (p *importer) string() string {
  1070  	if p.debugFormat {
  1071  		p.marker('s')
  1072  	}
  1073  
  1074  	// TODO(gri) should we intern strings here?
  1075  
  1076  	if n := int(p.rawInt64()); n > 0 {
  1077  		if cap(p.buf) < n {
  1078  			p.buf = make([]byte, n)
  1079  		} else {
  1080  			p.buf = p.buf[:n]
  1081  		}
  1082  		for i := range p.buf {
  1083  			p.buf[i] = p.byte()
  1084  		}
  1085  		return string(p.buf)
  1086  	}
  1087  
  1088  	return ""
  1089  }
  1090  
  1091  func (p *importer) marker(want byte) {
  1092  	if got := p.byte(); got != want {
  1093  		Fatalf("importer: incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
  1094  	}
  1095  
  1096  	pos := p.read
  1097  	if n := int(p.rawInt64()); n != pos {
  1098  		Fatalf("importer: incorrect position: got %d; want %d", n, pos)
  1099  	}
  1100  }
  1101  
  1102  // rawInt64 should only be used by low-level decoders
  1103  func (p *importer) rawInt64() int64 {
  1104  	i, err := binary.ReadVarint(p)
  1105  	if err != nil {
  1106  		Fatalf("importer: read error: %v", err)
  1107  	}
  1108  	return i
  1109  }
  1110  
  1111  // needed for binary.ReadVarint in rawInt64
  1112  func (p *importer) ReadByte() (byte, error) {
  1113  	return p.byte(), nil
  1114  }
  1115  
  1116  // byte is the bottleneck interface for reading from p.in.
  1117  // It unescapes '|' 'S' to '$' and '|' '|' to '|'.
  1118  func (p *importer) byte() byte {
  1119  	c, err := p.in.ReadByte()
  1120  	p.read++
  1121  	if err != nil {
  1122  		Fatalf("importer: read error: %v", err)
  1123  	}
  1124  	if c == '|' {
  1125  		c, err = p.in.ReadByte()
  1126  		p.read++
  1127  		if err != nil {
  1128  			Fatalf("importer: read error: %v", err)
  1129  		}
  1130  		switch c {
  1131  		case 'S':
  1132  			c = '$'
  1133  		case '|':
  1134  			// nothing to do
  1135  		default:
  1136  			Fatalf("importer: unexpected escape sequence in export data")
  1137  		}
  1138  	}
  1139  	return c
  1140  }