2015-08-13 19:05:37 -07:00
|
|
|
// Copyright 2015 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
// Binary package import.
|
|
|
|
|
// Based loosely on x/tools/go/importer.
|
|
|
|
|
|
|
|
|
|
package gc
|
|
|
|
|
|
|
|
|
|
import (
|
2016-03-11 13:39:20 -05:00
|
|
|
"bufio"
|
2015-08-13 19:05:37 -07:00
|
|
|
"cmd/compile/internal/big"
|
|
|
|
|
"encoding/binary"
|
2015-10-22 18:56:45 -07:00
|
|
|
"fmt"
|
2015-08-13 19:05:37 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// The overall structure of Import is symmetric to Export: For each
|
|
|
|
|
// export method in bexport.go there is a matching and symmetric method
|
|
|
|
|
// in bimport.go. Changing the export format requires making symmetric
|
|
|
|
|
// changes to bimport.go and bexport.go.
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
type importer struct {
|
|
|
|
|
in *bufio.Reader
|
|
|
|
|
buf []byte // for reading strings
|
|
|
|
|
bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib
|
|
|
|
|
pkgList []*Pkg
|
|
|
|
|
typList []*Type
|
|
|
|
|
inlined []*Node // functions with pending inlined function bodies
|
|
|
|
|
|
|
|
|
|
// debugging support
|
|
|
|
|
debugFormat bool
|
|
|
|
|
read int // bytes read
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
// Import populates importpkg from the serialized package data.
|
2016-03-11 13:39:20 -05:00
|
|
|
func Import(in *bufio.Reader) {
|
2015-08-13 19:05:37 -07:00
|
|
|
p := importer{in: in}
|
|
|
|
|
p.buf = p.bufarray[:]
|
|
|
|
|
|
|
|
|
|
// read low-level encoding format
|
|
|
|
|
switch format := p.byte(); format {
|
|
|
|
|
case 'c':
|
|
|
|
|
// compact format - nothing to do
|
|
|
|
|
case 'd':
|
|
|
|
|
p.debugFormat = true
|
|
|
|
|
default:
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: invalid encoding format in export data: got %q; want 'c' or 'd'", format)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- generic export data ---
|
|
|
|
|
|
|
|
|
|
if v := p.string(); v != exportVersion {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: unknown export data version: %s", v)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// populate typList with predeclared "known" types
|
|
|
|
|
p.typList = append(p.typList, predeclared()...)
|
|
|
|
|
|
|
|
|
|
// read package data
|
|
|
|
|
p.pkg()
|
|
|
|
|
if p.pkgList[0] != importpkg {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: imported package not found in pkgList[0]")
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read compiler-specific flags
|
|
|
|
|
importpkg.Safe = p.string() == "safe"
|
|
|
|
|
|
|
|
|
|
// defer some type-checking until all types are read in completely
|
2016-03-08 18:57:19 +00:00
|
|
|
// (parser.go:import_package)
|
2015-08-13 19:05:37 -07:00
|
|
|
tcok := typecheckok
|
|
|
|
|
typecheckok = true
|
|
|
|
|
defercheckwidth()
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// read objects
|
2015-08-13 19:05:37 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// Phase 1
|
|
|
|
|
objcount := 0
|
|
|
|
|
for {
|
|
|
|
|
tag := p.tagOrIndex()
|
|
|
|
|
if tag == endTag {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
p.obj(tag)
|
|
|
|
|
objcount++
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// self-verification
|
|
|
|
|
if count := p.int(); count != objcount {
|
|
|
|
|
Fatalf("importer: got %d objects; want %d", objcount, count)
|
|
|
|
|
}
|
2015-08-13 19:05:37 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// --- compiler-specific export data ---
|
2015-08-13 19:05:37 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// Phase 2
|
|
|
|
|
objcount = 0
|
|
|
|
|
for {
|
|
|
|
|
tag := p.tagOrIndex()
|
|
|
|
|
if tag == endTag {
|
|
|
|
|
break
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
2016-03-18 17:21:32 -07:00
|
|
|
p.obj(tag)
|
|
|
|
|
objcount++
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// self-verification
|
|
|
|
|
if count := p.int(); count != objcount {
|
|
|
|
|
Fatalf("importer: got %d objects; want %d", objcount, count)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
2015-10-22 18:56:45 -07:00
|
|
|
// read inlined functions bodies
|
2016-03-18 17:21:32 -07:00
|
|
|
if dclcontext != PEXTERN {
|
|
|
|
|
Fatalf("importer: unexpected context %d", dclcontext)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bcount := p.int() // consistency check only
|
|
|
|
|
if bcount != len(p.inlined) {
|
|
|
|
|
Fatalf("importer: expected %d inlined function bodies; got %d", bcount, len(p.inlined))
|
|
|
|
|
}
|
|
|
|
|
for _, f := range p.inlined {
|
|
|
|
|
if Funcdepth != 0 {
|
|
|
|
|
Fatalf("importer: unexpected Funcdepth %d", Funcdepth)
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
2016-03-18 17:21:32 -07:00
|
|
|
if f != nil {
|
|
|
|
|
// function body not yet imported - read body and set it
|
|
|
|
|
funchdr(f)
|
|
|
|
|
f.Func.Inl.Set(p.stmtList())
|
|
|
|
|
funcbody(f)
|
|
|
|
|
} else {
|
|
|
|
|
// function already imported - read body but discard declarations
|
|
|
|
|
dclcontext = PDISCARD // throw away any declarations
|
|
|
|
|
p.stmtList()
|
|
|
|
|
dclcontext = PEXTERN
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if dclcontext != PEXTERN {
|
|
|
|
|
Fatalf("importer: unexpected context %d", dclcontext)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- end of export data ---
|
|
|
|
|
|
|
|
|
|
typecheckok = tcok
|
|
|
|
|
resumecheckwidth()
|
|
|
|
|
|
|
|
|
|
testdclstack() // debugging only
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) pkg() *Pkg {
|
|
|
|
|
// if the package was seen before, i is its index (>= 0)
|
|
|
|
|
i := p.tagOrIndex()
|
|
|
|
|
if i >= 0 {
|
|
|
|
|
return p.pkgList[i]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// otherwise, i is the package tag (< 0)
|
|
|
|
|
if i != packageTag {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: expected package tag, found tag = %d", i)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read package data
|
|
|
|
|
name := p.string()
|
|
|
|
|
path := p.string()
|
|
|
|
|
|
|
|
|
|
// we should never see an empty package name
|
|
|
|
|
if name == "" {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: empty package name in import")
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we should never see a bad import path
|
|
|
|
|
if isbadimport(path) {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: bad path in import: %q", path)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// an empty path denotes the package we are currently importing
|
|
|
|
|
pkg := importpkg
|
|
|
|
|
if path != "" {
|
|
|
|
|
pkg = mkpkg(path)
|
|
|
|
|
}
|
|
|
|
|
if pkg.Name == "" {
|
|
|
|
|
pkg.Name = name
|
|
|
|
|
} else if pkg.Name != name {
|
2016-03-18 17:21:32 -07:00
|
|
|
Fatalf("importer: conflicting names %s and %s for package %q", pkg.Name, name, path)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
p.pkgList = append(p.pkgList, pkg)
|
|
|
|
|
|
|
|
|
|
return pkg
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
func idealType(typ *Type) *Type {
|
|
|
|
|
if typ.IsUntyped() {
|
|
|
|
|
// canonicalize ideal types
|
|
|
|
|
typ = Types[TIDEAL]
|
|
|
|
|
}
|
|
|
|
|
return typ
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) obj(tag int) {
|
|
|
|
|
switch tag {
|
|
|
|
|
case constTag:
|
|
|
|
|
sym := p.qualifiedName()
|
|
|
|
|
typ := p.typ()
|
|
|
|
|
val := p.value(typ)
|
|
|
|
|
importconst(sym, idealType(typ), nodlit(val))
|
|
|
|
|
|
|
|
|
|
case typeTag:
|
|
|
|
|
p.typ()
|
|
|
|
|
|
|
|
|
|
case varTag:
|
|
|
|
|
sym := p.qualifiedName()
|
|
|
|
|
typ := p.typ()
|
|
|
|
|
importvar(sym, typ)
|
|
|
|
|
|
|
|
|
|
case funcTag:
|
|
|
|
|
sym := p.qualifiedName()
|
|
|
|
|
params := p.paramList()
|
|
|
|
|
result := p.paramList()
|
|
|
|
|
inl := p.int()
|
|
|
|
|
|
|
|
|
|
sig := functype(nil, params, result)
|
|
|
|
|
importsym(sym, ONAME)
|
|
|
|
|
if sym.Def != nil && sym.Def.Op == ONAME {
|
|
|
|
|
if Eqtype(sig, sym.Def.Type) {
|
|
|
|
|
// function was imported before (via another import)
|
|
|
|
|
dclcontext = PDISCARD // since we skip funchdr below
|
|
|
|
|
} else {
|
|
|
|
|
Fatalf("importer: inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, sig)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var n *Node
|
|
|
|
|
if dclcontext != PDISCARD {
|
|
|
|
|
n = newfuncname(sym)
|
|
|
|
|
n.Type = sig
|
|
|
|
|
declare(n, PFUNC)
|
|
|
|
|
if inl < 0 {
|
|
|
|
|
funchdr(n)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if inl >= 0 {
|
|
|
|
|
// function has inlined body - collect for later
|
|
|
|
|
if inl != len(p.inlined) {
|
|
|
|
|
Fatalf("importer: inlined index = %d; want %d", inl, len(p.inlined))
|
|
|
|
|
}
|
|
|
|
|
p.inlined = append(p.inlined, n)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// parser.go:hidden_import
|
|
|
|
|
if dclcontext == PDISCARD {
|
|
|
|
|
dclcontext = PEXTERN // since we skip the funcbody below
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if inl < 0 {
|
|
|
|
|
funcbody(n)
|
|
|
|
|
}
|
|
|
|
|
importlist = append(importlist, n) // TODO(gri) may only be needed for inlineable functions
|
|
|
|
|
|
|
|
|
|
if Debug['E'] > 0 {
|
|
|
|
|
fmt.Printf("import [%q] func %v \n", importpkg.Path, n)
|
|
|
|
|
if Debug['m'] > 2 && len(n.Func.Inl.Slice()) != 0 {
|
|
|
|
|
fmt.Printf("inl body: %v\n", n.Func.Inl)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
Fatalf("importer: unexpected object tag")
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
func (p *importer) newtyp(etype EType) *Type {
|
2015-08-13 19:05:37 -07:00
|
|
|
t := typ(etype)
|
|
|
|
|
p.typList = append(p.typList, t)
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) typ() *Type {
|
|
|
|
|
// if the type was seen before, i is its index (>= 0)
|
|
|
|
|
i := p.tagOrIndex()
|
|
|
|
|
if i >= 0 {
|
|
|
|
|
return p.typList[i]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// otherwise, i is the type tag (< 0)
|
|
|
|
|
var t *Type
|
|
|
|
|
switch i {
|
|
|
|
|
case namedTag:
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_importsym
|
2015-08-13 19:05:37 -07:00
|
|
|
tsym := p.qualifiedName()
|
|
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_pkgtype
|
2015-08-13 19:05:37 -07:00
|
|
|
t = pkgtype(tsym)
|
|
|
|
|
p.typList = append(p.typList, t)
|
|
|
|
|
|
|
|
|
|
// read underlying type
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_type
|
2015-08-13 19:05:37 -07:00
|
|
|
t0 := p.typ()
|
2016-03-08 18:57:19 +00:00
|
|
|
importtype(t, t0) // parser.go:hidden_import
|
2015-08-13 19:05:37 -07:00
|
|
|
|
|
|
|
|
// interfaces don't have associated methods
|
2016-03-30 14:56:08 -07:00
|
|
|
if t0.IsInterface() {
|
2015-08-13 19:05:37 -07:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// set correct import context (since p.typ() may be called
|
|
|
|
|
// while importing the body of an inlined function)
|
|
|
|
|
savedContext := dclcontext
|
|
|
|
|
dclcontext = PEXTERN
|
|
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
// read associated methods
|
|
|
|
|
for i := p.int(); i > 0; i-- {
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_fndcl
|
2016-03-18 17:21:32 -07:00
|
|
|
|
|
|
|
|
sym := p.fieldSym()
|
|
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
recv := p.paramList() // TODO(gri) do we need a full param list for the receiver?
|
|
|
|
|
params := p.paramList()
|
|
|
|
|
result := p.paramList()
|
2015-10-22 18:56:45 -07:00
|
|
|
inl := p.int()
|
2015-08-13 19:05:37 -07:00
|
|
|
|
2016-03-08 10:26:20 -08:00
|
|
|
n := methodname1(newname(sym), recv[0].Right)
|
|
|
|
|
n.Type = functype(recv[0], params, result)
|
2015-08-13 19:05:37 -07:00
|
|
|
checkwidth(n.Type)
|
2016-03-11 17:12:31 -08:00
|
|
|
addmethod(sym, n.Type, tsym.Pkg, false, false)
|
2016-03-18 17:21:32 -07:00
|
|
|
if inl < 0 {
|
|
|
|
|
funchdr(n)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if inl >= 0 {
|
|
|
|
|
// method has inlined body - collect for later
|
|
|
|
|
if inl != len(p.inlined) {
|
|
|
|
|
Fatalf("importer: inlined index = %d; want %d", inl, len(p.inlined))
|
|
|
|
|
}
|
|
|
|
|
p.inlined = append(p.inlined, n)
|
|
|
|
|
}
|
2015-08-13 19:05:37 -07:00
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// (comment from parser.go)
|
2015-08-13 19:05:37 -07:00
|
|
|
// 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
|
2016-03-01 23:21:55 +00:00
|
|
|
// out by typecheck's lookdot as this $$.ttype. So by providing
|
2015-08-13 19:05:37 -07:00
|
|
|
// this back link here we avoid special casing there.
|
2016-03-30 16:59:53 -07:00
|
|
|
n.Type.SetNname(n)
|
2015-08-13 19:05:37 -07:00
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_import
|
2016-03-18 17:21:32 -07:00
|
|
|
if inl < 0 {
|
|
|
|
|
funcbody(n)
|
|
|
|
|
}
|
|
|
|
|
importlist = append(importlist, n) // TODO(gri) may only be needed for inlineable functions
|
|
|
|
|
|
|
|
|
|
if Debug['E'] > 0 {
|
|
|
|
|
fmt.Printf("import [%q] meth %v \n", importpkg.Path, n)
|
|
|
|
|
if Debug['m'] > 2 && len(n.Func.Inl.Slice()) != 0 {
|
|
|
|
|
fmt.Printf("inl body: %v\n", n.Func.Inl)
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
|
|
|
|
}
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
dclcontext = savedContext
|
|
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
case arrayTag, sliceTag:
|
|
|
|
|
t = p.newtyp(TARRAY)
|
2016-04-01 20:11:30 -07:00
|
|
|
var bound int64
|
2015-08-13 19:05:37 -07:00
|
|
|
if i == arrayTag {
|
2016-04-01 20:11:30 -07:00
|
|
|
bound = p.int64()
|
|
|
|
|
}
|
|
|
|
|
elem := p.typ()
|
|
|
|
|
if i == arrayTag {
|
|
|
|
|
t.Extra = &ArrayType{Elem: elem, Bound: bound}
|
2016-03-31 15:18:39 -07:00
|
|
|
} else {
|
2016-04-01 20:11:30 -07:00
|
|
|
t.Extra = SliceType{Elem: elem}
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case dddTag:
|
2016-03-27 12:30:16 -07:00
|
|
|
t = p.newtyp(TDDDFIELD)
|
2016-04-01 20:11:30 -07:00
|
|
|
t.Extra = DDDFieldType{T: p.typ()}
|
2015-08-13 19:05:37 -07:00
|
|
|
|
|
|
|
|
case structTag:
|
|
|
|
|
t = p.newtyp(TSTRUCT)
|
|
|
|
|
tostruct0(t, p.fieldList())
|
|
|
|
|
|
|
|
|
|
case pointerTag:
|
|
|
|
|
t = p.newtyp(Tptr)
|
2016-04-01 20:11:30 -07:00
|
|
|
t.Extra = PtrType{Elem: p.typ()}
|
2015-08-13 19:05:37 -07:00
|
|
|
|
|
|
|
|
case signatureTag:
|
|
|
|
|
t = p.newtyp(TFUNC)
|
|
|
|
|
params := p.paramList()
|
|
|
|
|
result := p.paramList()
|
|
|
|
|
functype0(t, nil, params, result)
|
|
|
|
|
|
|
|
|
|
case interfaceTag:
|
|
|
|
|
t = p.newtyp(TINTER)
|
|
|
|
|
if p.int() != 0 {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: unexpected embedded interface")
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
tointerface0(t, p.methodList())
|
|
|
|
|
|
|
|
|
|
case mapTag:
|
|
|
|
|
t = p.newtyp(TMAP)
|
2016-04-01 20:11:30 -07:00
|
|
|
mt := t.MapType()
|
|
|
|
|
mt.Key = p.typ()
|
|
|
|
|
mt.Val = p.typ()
|
2015-08-13 19:05:37 -07:00
|
|
|
|
|
|
|
|
case chanTag:
|
|
|
|
|
t = p.newtyp(TCHAN)
|
2016-04-01 20:11:30 -07:00
|
|
|
ct := t.ChanType()
|
|
|
|
|
ct.Dir = ChanDir(p.int())
|
|
|
|
|
ct.Elem = p.typ()
|
2015-08-13 19:05:37 -07:00
|
|
|
|
|
|
|
|
default:
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: unexpected type (tag = %d)", i)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t == nil {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: nil type (type tag = %d)", i)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) qualifiedName() *Sym {
|
|
|
|
|
name := p.string()
|
|
|
|
|
pkg := p.pkg()
|
|
|
|
|
return pkg.Lookup(name)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_structdcl_list
|
2016-03-08 10:26:20 -08:00
|
|
|
func (p *importer) fieldList() []*Node {
|
2015-08-13 19:05:37 -07:00
|
|
|
i := p.int()
|
|
|
|
|
if i == 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2016-03-08 21:53:33 +01:00
|
|
|
n := make([]*Node, i)
|
|
|
|
|
for i := range n {
|
|
|
|
|
n[i] = p.field()
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_structdcl
|
2015-08-13 19:05:37 -07:00
|
|
|
func (p *importer) field() *Node {
|
|
|
|
|
sym := p.fieldName()
|
|
|
|
|
typ := p.typ()
|
|
|
|
|
note := p.note()
|
|
|
|
|
|
|
|
|
|
var n *Node
|
|
|
|
|
if sym.Name != "" {
|
|
|
|
|
n = Nod(ODCLFIELD, newname(sym), typenod(typ))
|
|
|
|
|
} else {
|
|
|
|
|
// anonymous field - typ must be T or *T and T must be a type name
|
|
|
|
|
s := typ.Sym
|
2016-03-30 15:09:25 -07:00
|
|
|
if s == nil && typ.IsPtr() {
|
2016-04-01 20:11:30 -07:00
|
|
|
s = typ.Elem().Sym // deref
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
pkg := importpkg
|
|
|
|
|
if sym != nil {
|
|
|
|
|
pkg = sym.Pkg
|
|
|
|
|
}
|
|
|
|
|
n = embedded(s, pkg)
|
|
|
|
|
n.Right = typenod(typ)
|
|
|
|
|
}
|
|
|
|
|
n.SetVal(note)
|
|
|
|
|
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) note() (v Val) {
|
|
|
|
|
if s := p.string(); s != "" {
|
|
|
|
|
v.U = s
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_interfacedcl_list
|
2016-03-08 10:26:20 -08:00
|
|
|
func (p *importer) methodList() []*Node {
|
2015-08-13 19:05:37 -07:00
|
|
|
i := p.int()
|
|
|
|
|
if i == 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2016-03-08 21:53:33 +01:00
|
|
|
n := make([]*Node, i)
|
|
|
|
|
for i := range n {
|
|
|
|
|
n[i] = p.method()
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_interfacedcl
|
2015-08-13 19:05:37 -07:00
|
|
|
func (p *importer) method() *Node {
|
|
|
|
|
sym := p.fieldName()
|
|
|
|
|
params := p.paramList()
|
|
|
|
|
result := p.paramList()
|
|
|
|
|
return Nod(ODCLFIELD, newname(sym), typenod(functype(fakethis(), params, result)))
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:sym,hidden_importsym
|
2015-08-13 19:05:37 -07:00
|
|
|
func (p *importer) fieldName() *Sym {
|
|
|
|
|
name := p.string()
|
|
|
|
|
pkg := localpkg
|
|
|
|
|
if name == "_" {
|
|
|
|
|
// During imports, unqualified non-exported identifiers are from builtinpkg
|
2016-03-08 18:57:19 +00:00
|
|
|
// (see parser.go:sym). The binary exporter only exports blank as a non-exported
|
2015-08-13 19:05:37 -07:00
|
|
|
// identifier without qualification.
|
2016-03-18 17:21:32 -07:00
|
|
|
pkg = localpkg
|
2015-08-13 19:05:37 -07:00
|
|
|
} else if name == "?" || name != "" && !exportname(name) {
|
|
|
|
|
if name == "?" {
|
|
|
|
|
name = ""
|
|
|
|
|
}
|
|
|
|
|
pkg = p.pkg()
|
|
|
|
|
}
|
|
|
|
|
return pkg.Lookup(name)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:ohidden_funarg_list
|
2016-03-08 10:26:20 -08:00
|
|
|
func (p *importer) paramList() []*Node {
|
2015-08-13 19:05:37 -07:00
|
|
|
i := p.int()
|
|
|
|
|
if i == 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
// negative length indicates unnamed parameters
|
|
|
|
|
named := true
|
|
|
|
|
if i < 0 {
|
|
|
|
|
i = -i
|
|
|
|
|
named = false
|
|
|
|
|
}
|
|
|
|
|
// i > 0
|
2016-03-08 21:53:33 +01:00
|
|
|
n := make([]*Node, i)
|
|
|
|
|
for i := range n {
|
|
|
|
|
n[i] = p.param(named)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_funarg
|
2015-08-13 19:05:37 -07:00
|
|
|
func (p *importer) param(named bool) *Node {
|
|
|
|
|
typ := p.typ()
|
|
|
|
|
|
|
|
|
|
isddd := false
|
2016-03-27 12:30:16 -07:00
|
|
|
if typ.Etype == TDDDFIELD {
|
2016-03-31 15:18:39 -07:00
|
|
|
// TDDDFIELD indicates wrapped ... slice type
|
2016-04-01 20:11:30 -07:00
|
|
|
typ = typSlice(typ.DDDField())
|
2015-08-13 19:05:37 -07:00
|
|
|
isddd = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n := Nod(ODCLFIELD, nil, typenod(typ))
|
|
|
|
|
n.Isddd = isddd
|
|
|
|
|
|
|
|
|
|
if named {
|
|
|
|
|
name := p.string()
|
|
|
|
|
if name == "" {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: expected named parameter")
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
2016-03-18 17:21:32 -07:00
|
|
|
// TODO(gri) Supply function/method package rather than
|
|
|
|
|
// encoding the package for each parameter repeatedly.
|
|
|
|
|
pkg := p.pkg()
|
|
|
|
|
n.Left = newname(pkg.Lookup(name))
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO(gri) This is compiler-specific (escape info).
|
|
|
|
|
// Move into compiler-specific section eventually?
|
|
|
|
|
n.SetVal(p.note())
|
|
|
|
|
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) value(typ *Type) (x Val) {
|
|
|
|
|
switch tag := p.tagOrIndex(); tag {
|
|
|
|
|
case falseTag:
|
|
|
|
|
x.U = false
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
case trueTag:
|
|
|
|
|
x.U = true
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
case int64Tag:
|
|
|
|
|
u := new(Mpint)
|
2016-03-20 13:55:42 -07:00
|
|
|
u.SetInt64(p.int64())
|
2015-08-13 19:05:37 -07:00
|
|
|
u.Rune = typ == idealrune
|
|
|
|
|
x.U = u
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
case floatTag:
|
|
|
|
|
f := newMpflt()
|
|
|
|
|
p.float(f)
|
2016-03-30 15:09:25 -07:00
|
|
|
if typ == idealint || typ.IsInteger() {
|
2015-08-13 19:05:37 -07:00
|
|
|
// uncommon case: large int encoded as float
|
|
|
|
|
u := new(Mpint)
|
2016-03-20 13:55:42 -07:00
|
|
|
u.SetFloat(f)
|
2015-08-13 19:05:37 -07:00
|
|
|
x.U = u
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
x.U = f
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
case complexTag:
|
|
|
|
|
u := new(Mpcplx)
|
|
|
|
|
p.float(&u.Real)
|
|
|
|
|
p.float(&u.Imag)
|
|
|
|
|
x.U = u
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
case stringTag:
|
|
|
|
|
x.U = p.string()
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 11:13:24 -04:00
|
|
|
case unknownTag:
|
|
|
|
|
Fatalf("importer: unknown constant (importing package with errors)")
|
|
|
|
|
|
2015-10-22 18:56:45 -07:00
|
|
|
case nilTag:
|
|
|
|
|
x.U = new(NilVal)
|
|
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
default:
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: unexpected value tag %d", tag)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// verify ideal type
|
2016-04-01 13:36:24 -07:00
|
|
|
if typ.IsUntyped() && untype(x.Ctype()) != typ {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: value %v and type %v don't match", x, typ)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) float(x *Mpflt) {
|
|
|
|
|
sign := p.int()
|
|
|
|
|
if sign == 0 {
|
2016-03-20 13:55:42 -07:00
|
|
|
x.SetFloat64(0)
|
2015-08-13 19:05:37 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
exp := p.int()
|
|
|
|
|
mant := new(big.Int).SetBytes([]byte(p.string()))
|
|
|
|
|
|
|
|
|
|
m := x.Val.SetInt(mant)
|
|
|
|
|
m.SetMantExp(m, exp-mant.BitLen())
|
|
|
|
|
if sign < 0 {
|
|
|
|
|
m.Neg(m)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// Inlined function bodies
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// 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).
|
|
|
|
|
|
|
|
|
|
func (p *importer) stmtList() []*Node {
|
|
|
|
|
var list []*Node
|
|
|
|
|
for {
|
|
|
|
|
n := p.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 (p *importer) exprList() []*Node {
|
|
|
|
|
var list []*Node
|
|
|
|
|
for {
|
|
|
|
|
n := p.expr()
|
|
|
|
|
if n == nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
list = append(list, n)
|
|
|
|
|
}
|
2016-03-11 13:40:01 -08:00
|
|
|
return list
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
func (p *importer) elemList() []*Node {
|
2016-03-03 14:11:17 -08:00
|
|
|
c := p.int()
|
2016-03-18 17:21:32 -07:00
|
|
|
list := make([]*Node, c)
|
|
|
|
|
for i := range list {
|
|
|
|
|
list[i] = Nod(OKEY, mkname(p.fieldSym()), p.expr())
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
2016-03-18 17:21:32 -07:00
|
|
|
return list
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) expr() *Node {
|
|
|
|
|
n := p.node()
|
|
|
|
|
if n != nil && n.Op == OBLOCK {
|
|
|
|
|
Fatalf("unexpected block node: %v", n)
|
|
|
|
|
}
|
|
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// TODO(gri) split into expr and stmt
|
2015-10-22 18:56:45 -07:00
|
|
|
func (p *importer) node() *Node {
|
2016-03-18 17:21:32 -07:00
|
|
|
switch op := p.op(); op {
|
|
|
|
|
// expressions
|
|
|
|
|
// case OPAREN:
|
|
|
|
|
// unreachable - unpacked by exporter
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// case ODDDARG:
|
|
|
|
|
// unimplemented
|
|
|
|
|
|
|
|
|
|
// case OREGISTER:
|
|
|
|
|
// unimplemented
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OLITERAL:
|
|
|
|
|
typ := p.typ()
|
2016-03-18 17:21:32 -07:00
|
|
|
n := nodlit(p.value(typ))
|
|
|
|
|
if !typ.IsUntyped() {
|
|
|
|
|
conv := Nod(OCALL, typenod(typ), nil)
|
|
|
|
|
conv.List.Set1(n)
|
|
|
|
|
n = conv
|
|
|
|
|
}
|
|
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
case ONAME:
|
2015-10-22 18:56:45 -07:00
|
|
|
if p.bool() {
|
2016-03-18 17:21:32 -07:00
|
|
|
// "_"
|
|
|
|
|
// TODO(gri) avoid repeated "_" lookup
|
|
|
|
|
return mkname(Pkglookup("_", localpkg))
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
2016-03-18 17:21:32 -07:00
|
|
|
return NodSym(OXDOT, typenod(p.typ()), p.fieldSym())
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
case OPACK, ONONAME:
|
|
|
|
|
return mkname(p.sym())
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
case OTYPE:
|
|
|
|
|
if p.bool() {
|
|
|
|
|
return mkname(p.sym())
|
|
|
|
|
}
|
|
|
|
|
return typenod(p.typ())
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
|
|
|
|
|
// unreachable - should have been resolved by typechecking
|
|
|
|
|
|
|
|
|
|
// case OCLOSURE:
|
|
|
|
|
// unimplemented
|
|
|
|
|
|
|
|
|
|
// case OCOMPLIT:
|
|
|
|
|
// unimplemented
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OPTRLIT:
|
2016-03-18 17:21:32 -07:00
|
|
|
n := p.expr()
|
|
|
|
|
if !p.bool() /* !implicit, i.e. '&' operator*/ {
|
|
|
|
|
if n.Op == OCOMPLIT {
|
|
|
|
|
// Special case for &T{...}: turn into (*T){...}.
|
|
|
|
|
n.Right = Nod(OIND, n.Right, nil)
|
|
|
|
|
n.Right.Implicit = true
|
|
|
|
|
} else {
|
|
|
|
|
n = Nod(OADDR, n, nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OSTRUCTLIT:
|
2016-03-18 17:21:32 -07:00
|
|
|
n := Nod(OCOMPLIT, nil, nil)
|
|
|
|
|
if !p.bool() {
|
|
|
|
|
n.Right = typenod(p.typ())
|
|
|
|
|
}
|
|
|
|
|
n.List.Set(p.elemList())
|
|
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OARRAYLIT, OMAPLIT:
|
2016-03-18 17:21:32 -07:00
|
|
|
n := Nod(OCOMPLIT, nil, nil)
|
|
|
|
|
if !p.bool() {
|
|
|
|
|
n.Right = typenod(p.typ())
|
|
|
|
|
}
|
|
|
|
|
n.List.Set(p.exprList())
|
|
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OKEY:
|
2016-03-18 17:21:32 -07:00
|
|
|
left, right := p.exprsOrNil()
|
|
|
|
|
return Nod(OKEY, left, right)
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// case OCALLPART:
|
|
|
|
|
// unimplemented
|
|
|
|
|
|
|
|
|
|
// case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
|
|
|
|
|
// unreachable - mapped to case OXDOT below by exporter
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
case OXDOT:
|
2015-10-22 18:56:45 -07:00
|
|
|
// see parser.new_dotname
|
2016-03-18 17:21:32 -07:00
|
|
|
obj := p.expr()
|
|
|
|
|
sel := p.fieldSym()
|
2015-10-22 18:56:45 -07:00
|
|
|
if obj.Op == OPACK {
|
|
|
|
|
s := restrictlookup(sel.Name, obj.Name.Pkg)
|
|
|
|
|
obj.Used = true
|
|
|
|
|
return oldname(s)
|
|
|
|
|
}
|
cmd/compile: change ODOT and friends to use Sym, not Right
The Node type ODOT and its variants all represent a selector, with a
simple name to the right of the dot. Before this change this was
represented by using an ONAME Node in the Right field. This ONAME node
served no useful purpose. This CL changes these Node types to store the
symbol in the Sym field instead, thus not requiring allocating a Node
for each selector.
When compiling x/tools/go/types this CL eliminates nearly 5000 calls to
newname and reduces the total number of Nodes allocated by about 6.6%.
It seems to cut compilation time by 1 to 2 percent.
Getting this right was somewhat subtle, and I added two dubious changes
to produce the exact same output as before. One is to ishairy in
inl.go: the ONAME node increased the cost of ODOT and friends by 1, and
I retained that, although really ODOT is not more expensive than any
other node. The other is to varexpr in walk.go: because the ONAME in
the Right field of an ODOT has no class, varexpr would always return
false for an ODOT, although in fact for some ODOT's it seemingly ought
to return true; I added an && false for now. I will send separate CLs,
that will break toolstash -cmp, to clean these up.
This CL passes toolstash -cmp.
Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80
Reviewed-on: https://go-review.googlesource.com/20890
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-03-18 16:52:30 -07:00
|
|
|
return NodSym(OXDOT, obj, sel)
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// case ODOTTYPE, ODOTTYPE2:
|
|
|
|
|
// unreachable - mapped to case ODOTTYPE below by exporter
|
|
|
|
|
|
|
|
|
|
case ODOTTYPE:
|
|
|
|
|
n := Nod(ODOTTYPE, p.expr(), nil)
|
2015-10-22 18:56:45 -07:00
|
|
|
if p.bool() {
|
2016-03-18 17:21:32 -07:00
|
|
|
n.Right = p.expr()
|
2015-10-22 18:56:45 -07:00
|
|
|
} else {
|
2016-03-18 17:21:32 -07:00
|
|
|
n.Right = typenod(p.typ())
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
2016-03-18 17:21:32 -07:00
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
|
|
|
|
|
// unreachable - mapped to cases below by exporter
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
case OINDEX, OSLICE, OSLICE3:
|
|
|
|
|
return Nod(op, p.expr(), p.expr())
|
|
|
|
|
|
|
|
|
|
case OCOPY, OCOMPLEX:
|
|
|
|
|
n := builtinCall(op)
|
|
|
|
|
n.List.Set([]*Node{p.expr(), p.expr()})
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
// case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
|
|
|
|
|
// unreachable - mapped to OCONV case below by exporter
|
|
|
|
|
|
|
|
|
|
case OCONV:
|
|
|
|
|
n := Nod(OCALL, typenod(p.typ()), nil)
|
|
|
|
|
if p.bool() {
|
|
|
|
|
n.List.Set1(p.expr())
|
|
|
|
|
} else {
|
|
|
|
|
n.List.Set(p.exprList())
|
|
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
|
|
|
|
|
n := builtinCall(op)
|
|
|
|
|
if p.bool() {
|
|
|
|
|
n.List.Set1(p.expr())
|
|
|
|
|
} else {
|
|
|
|
|
n.List.Set(p.exprList())
|
|
|
|
|
n.Isddd = p.bool()
|
|
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
// case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
|
|
|
|
|
// unreachable - mapped to OCALL case below by exporter
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
case OCALL:
|
|
|
|
|
n := Nod(OCALL, p.expr(), nil)
|
|
|
|
|
n.List.Set(p.exprList())
|
2015-10-22 18:56:45 -07:00
|
|
|
n.Isddd = p.bool()
|
2016-03-18 17:21:32 -07:00
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
case OMAKEMAP, OMAKECHAN, OMAKESLICE:
|
|
|
|
|
n := builtinCall(OMAKE)
|
|
|
|
|
n.List.Append(typenod(p.typ()))
|
|
|
|
|
n.List.Append(p.exprList()...)
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
// unary expressions
|
|
|
|
|
case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV:
|
|
|
|
|
return Nod(op, p.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 Nod(op, p.expr(), p.expr())
|
|
|
|
|
|
|
|
|
|
case OADDSTR:
|
|
|
|
|
list := p.exprList()
|
|
|
|
|
x := list[0]
|
|
|
|
|
for _, y := range list[1:] {
|
|
|
|
|
x = Nod(OADD, x, y)
|
|
|
|
|
}
|
|
|
|
|
return x
|
|
|
|
|
|
|
|
|
|
// case OCMPSTR, OCMPIFACE:
|
|
|
|
|
// unreachable - mapped to std comparison operators by exporter
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
case ODCLCONST:
|
|
|
|
|
// TODO(gri) these should not be exported in the first place
|
|
|
|
|
return Nod(OEMPTY, nil, nil)
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// --------------------------------------------------------------------
|
2015-10-22 18:56:45 -07:00
|
|
|
// statements
|
|
|
|
|
case ODCL:
|
2016-03-18 17:21:32 -07:00
|
|
|
var lhs *Node
|
|
|
|
|
if p.bool() {
|
|
|
|
|
lhs = p.expr()
|
|
|
|
|
} else {
|
|
|
|
|
lhs = dclname(p.sym())
|
|
|
|
|
}
|
|
|
|
|
// TODO(gri) avoid list created here!
|
|
|
|
|
return liststmt(variter([]*Node{lhs}, typenod(p.typ()), nil))
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// case ODCLFIELD:
|
|
|
|
|
// unimplemented
|
|
|
|
|
|
|
|
|
|
case OAS, OASWB:
|
|
|
|
|
if p.bool() {
|
|
|
|
|
lhs := p.expr()
|
|
|
|
|
rhs := p.expr()
|
|
|
|
|
return Nod(OAS, lhs, rhs)
|
|
|
|
|
}
|
|
|
|
|
// TODO(gri) we should not have emitted anything here
|
|
|
|
|
return Nod(OEMPTY, nil, nil)
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OASOP:
|
2016-03-18 17:21:32 -07:00
|
|
|
n := Nod(OASOP, nil, nil)
|
2015-10-22 18:56:45 -07:00
|
|
|
n.Etype = EType(p.int())
|
2016-03-18 17:21:32 -07:00
|
|
|
n.Left = p.expr()
|
|
|
|
|
if !p.bool() {
|
|
|
|
|
n.Right = Nodintconst(1)
|
|
|
|
|
n.Implicit = true
|
|
|
|
|
} else {
|
|
|
|
|
n.Right = p.expr()
|
|
|
|
|
}
|
|
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
case OAS2:
|
|
|
|
|
lhs := p.exprList()
|
|
|
|
|
rhs := p.exprList()
|
|
|
|
|
n := Nod(OAS2, nil, nil)
|
|
|
|
|
n.List.Set(lhs)
|
|
|
|
|
n.Rlist.Set(rhs)
|
|
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
|
2016-03-18 17:21:32 -07:00
|
|
|
n := Nod(OAS2, nil, nil)
|
|
|
|
|
n.List.Set(p.exprList())
|
|
|
|
|
n.Rlist.Set(p.exprList())
|
|
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case ORETURN:
|
2016-03-18 17:21:32 -07:00
|
|
|
n := Nod(ORETURN, nil, nil)
|
|
|
|
|
n.List.Set(p.exprList())
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
// case ORETJMP:
|
|
|
|
|
// unreachable - generated by compiler for trampolin routines (not exported)
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OPROC, ODEFER:
|
2016-03-18 17:21:32 -07:00
|
|
|
return Nod(op, p.expr(), nil)
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OIF:
|
2016-03-18 17:21:32 -07:00
|
|
|
markdcl()
|
|
|
|
|
n := Nod(OIF, nil, nil)
|
|
|
|
|
n.Ninit.Set(p.stmtList())
|
|
|
|
|
n.Left = p.expr()
|
|
|
|
|
n.Nbody.Set(p.stmtList())
|
|
|
|
|
n.Rlist.Set(p.stmtList())
|
|
|
|
|
popdcl()
|
|
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OFOR:
|
2016-03-18 17:21:32 -07:00
|
|
|
markdcl()
|
|
|
|
|
n := Nod(OFOR, nil, nil)
|
|
|
|
|
n.Ninit.Set(p.stmtList())
|
|
|
|
|
n.Left, n.Right = p.exprsOrNil()
|
|
|
|
|
n.Nbody.Set(p.stmtList())
|
|
|
|
|
popdcl()
|
|
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case ORANGE:
|
2016-03-18 17:21:32 -07:00
|
|
|
markdcl()
|
|
|
|
|
n := Nod(ORANGE, nil, nil)
|
|
|
|
|
n.List.Set(p.stmtList())
|
|
|
|
|
n.Right = p.expr()
|
|
|
|
|
n.Nbody.Set(p.stmtList())
|
|
|
|
|
popdcl()
|
|
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OSELECT, OSWITCH:
|
2016-03-18 17:21:32 -07:00
|
|
|
markdcl()
|
|
|
|
|
n := Nod(op, nil, nil)
|
|
|
|
|
n.Ninit.Set(p.stmtList())
|
|
|
|
|
n.Left, _ = p.exprsOrNil()
|
|
|
|
|
n.List.Set(p.stmtList())
|
|
|
|
|
popdcl()
|
|
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OCASE, OXCASE:
|
2016-03-18 17:21:32 -07:00
|
|
|
markdcl()
|
|
|
|
|
n := Nod(OXCASE, nil, nil)
|
|
|
|
|
n.List.Set(p.exprList())
|
|
|
|
|
// TODO(gri) eventually we must declare variables for type switch
|
|
|
|
|
// statements (type switch statements are not yet exported)
|
|
|
|
|
n.Nbody.Set(p.stmtList())
|
|
|
|
|
popdcl()
|
|
|
|
|
return n
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OBREAK, OCONTINUE, OGOTO, OFALL, OXFALL:
|
2016-03-18 17:21:32 -07:00
|
|
|
if op == OFALL {
|
|
|
|
|
op = OXFALL
|
|
|
|
|
}
|
|
|
|
|
left, _ := p.exprsOrNil()
|
|
|
|
|
return Nod(op, left, nil)
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// case OEMPTY:
|
|
|
|
|
// unreachable - not emitted by exporter
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OLABEL:
|
2016-03-18 17:21:32 -07:00
|
|
|
n := Nod(OLABEL, p.expr(), nil)
|
|
|
|
|
n.Left.Sym = dclstack // context, for goto restrictions
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
case OEND:
|
|
|
|
|
return nil
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
default:
|
2016-03-18 17:21:32 -07:00
|
|
|
Fatalf("importer: %s (%d) node not yet supported", opnames[op], op)
|
|
|
|
|
panic("unreachable") // satisfy compiler
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
2016-03-18 17:21:32 -07:00
|
|
|
}
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
func builtinCall(op Op) *Node {
|
|
|
|
|
return Nod(OCALL, mkname(builtinpkg.Lookup(goopnames[op])), nil)
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
func (p *importer) exprsOrNil() (a, b *Node) {
|
2015-10-22 18:56:45 -07:00
|
|
|
ab := p.int()
|
|
|
|
|
if ab&1 != 0 {
|
2016-03-18 17:21:32 -07:00
|
|
|
a = p.expr()
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
|
|
|
|
if ab&2 != 0 {
|
2016-03-18 17:21:32 -07:00
|
|
|
b = p.expr()
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
2015-10-22 18:56:45 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
func (p *importer) fieldSym() *Sym {
|
|
|
|
|
name := p.string()
|
|
|
|
|
pkg := localpkg
|
|
|
|
|
if !exportname(name) {
|
|
|
|
|
pkg = p.pkg()
|
|
|
|
|
}
|
|
|
|
|
return pkg.Lookup(name)
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-22 18:56:45 -07:00
|
|
|
func (p *importer) sym() *Sym {
|
2016-03-18 17:21:32 -07:00
|
|
|
name := p.string()
|
|
|
|
|
pkg := localpkg
|
|
|
|
|
if name != "_" {
|
|
|
|
|
pkg = p.pkg()
|
|
|
|
|
}
|
|
|
|
|
return pkg.Lookup(name)
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) bool() bool {
|
|
|
|
|
return p.int() != 0
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
2015-10-22 18:56:45 -07:00
|
|
|
func (p *importer) op() Op {
|
|
|
|
|
return Op(p.int())
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// Low-level decoders
|
|
|
|
|
|
|
|
|
|
func (p *importer) tagOrIndex() int {
|
|
|
|
|
if p.debugFormat {
|
|
|
|
|
p.marker('t')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return int(p.rawInt64())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) int() int {
|
|
|
|
|
x := p.int64()
|
|
|
|
|
if int64(int(x)) != x {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: exported integer too large")
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
return int(x)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) int64() int64 {
|
|
|
|
|
if p.debugFormat {
|
|
|
|
|
p.marker('i')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return p.rawInt64()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) string() string {
|
|
|
|
|
if p.debugFormat {
|
|
|
|
|
p.marker('s')
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
// TODO(gri) should we intern strings here?
|
|
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
if n := int(p.rawInt64()); n > 0 {
|
|
|
|
|
if cap(p.buf) < n {
|
|
|
|
|
p.buf = make([]byte, n)
|
|
|
|
|
} else {
|
|
|
|
|
p.buf = p.buf[:n]
|
|
|
|
|
}
|
2016-03-08 21:53:33 +01:00
|
|
|
for i := range p.buf {
|
2015-10-23 16:01:09 -07:00
|
|
|
p.buf[i] = p.byte()
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
return string(p.buf)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) marker(want byte) {
|
|
|
|
|
if got := p.byte(); got != want {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos := p.read
|
|
|
|
|
if n := int(p.rawInt64()); n != pos {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: incorrect position: got %d; want %d", n, pos)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// rawInt64 should only be used by low-level decoders
|
|
|
|
|
func (p *importer) rawInt64() int64 {
|
|
|
|
|
i, err := binary.ReadVarint(p)
|
|
|
|
|
if err != nil {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: read error: %v", err)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
return i
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// needed for binary.ReadVarint in rawInt64
|
|
|
|
|
func (p *importer) ReadByte() (byte, error) {
|
|
|
|
|
return p.byte(), nil
|
|
|
|
|
}
|
2015-10-23 16:01:09 -07:00
|
|
|
|
|
|
|
|
// byte is the bottleneck interface for reading from p.in.
|
|
|
|
|
// It unescapes '|' 'S' to '$' and '|' '|' to '|'.
|
|
|
|
|
func (p *importer) byte() byte {
|
2016-03-11 13:39:20 -05:00
|
|
|
c, err := p.in.ReadByte()
|
2015-10-23 16:01:09 -07:00
|
|
|
p.read++
|
2016-03-11 13:39:20 -05:00
|
|
|
if err != nil {
|
|
|
|
|
Fatalf("importer: read error: %v", err)
|
2015-10-23 16:01:09 -07:00
|
|
|
}
|
|
|
|
|
if c == '|' {
|
2016-03-11 13:39:20 -05:00
|
|
|
c, err = p.in.ReadByte()
|
2015-10-23 16:01:09 -07:00
|
|
|
p.read++
|
2016-03-11 13:39:20 -05:00
|
|
|
if err != nil {
|
|
|
|
|
Fatalf("importer: read error: %v", err)
|
2015-10-23 16:01:09 -07:00
|
|
|
}
|
|
|
|
|
switch c {
|
|
|
|
|
case 'S':
|
|
|
|
|
c = '$'
|
|
|
|
|
case '|':
|
|
|
|
|
// nothing to do
|
|
|
|
|
default:
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: unexpected escape sequence in export data")
|
2015-10-23 16:01:09 -07:00
|
|
|
}
|
|
|
|
|
}
|
2016-03-11 13:39:20 -05:00
|
|
|
return c
|
2015-10-23 16:01:09 -07:00
|
|
|
}
|