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 {
|
2016-04-13 17:53:03 -07:00
|
|
|
in *bufio.Reader
|
|
|
|
|
buf []byte // reused for reading strings
|
2016-04-12 18:00:04 -07:00
|
|
|
|
2016-04-13 17:53:03 -07:00
|
|
|
// object lists, in order of deserialization
|
|
|
|
|
strList []string
|
|
|
|
|
pkgList []*Pkg
|
|
|
|
|
typList []*Type
|
|
|
|
|
funcList []*Node // nil entry means already declared
|
|
|
|
|
|
|
|
|
|
// position encoding
|
2016-04-22 14:50:20 -07:00
|
|
|
posInfoFormat bool
|
|
|
|
|
prevFile string
|
|
|
|
|
prevLine int
|
2016-03-18 17:21:32 -07:00
|
|
|
|
|
|
|
|
// 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) {
|
2016-04-13 17:53:03 -07:00
|
|
|
p := importer{
|
|
|
|
|
in: in,
|
|
|
|
|
strList: []string{""}, // empty string is mapped to 0
|
|
|
|
|
}
|
2015-08-13 19:05:37 -07:00
|
|
|
|
|
|
|
|
// read low-level encoding format
|
2016-04-13 17:53:03 -07:00
|
|
|
switch format := p.rawByte(); format {
|
2015-08-13 19:05:37 -07:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2016-04-22 14:50:20 -07:00
|
|
|
p.posInfoFormat = p.bool()
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
|
// 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-04-12 11:31:16 -07:00
|
|
|
// phase 1
|
2016-03-18 17:21:32 -07:00
|
|
|
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-04-12 11:31:16 -07:00
|
|
|
// read compiler-specific flags
|
|
|
|
|
importpkg.Safe = p.bool()
|
|
|
|
|
|
|
|
|
|
// phase 2
|
2016-03-18 17:21:32 -07:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2016-04-12 18:00:04 -07:00
|
|
|
// read inlineable functions bodies
|
2016-03-18 17:21:32 -07:00
|
|
|
if dclcontext != PEXTERN {
|
|
|
|
|
Fatalf("importer: unexpected context %d", dclcontext)
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-12 18:00:04 -07:00
|
|
|
objcount = 0
|
|
|
|
|
for i0 := -1; ; {
|
|
|
|
|
i := p.int() // index of function with inlineable body
|
|
|
|
|
if i < 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// don't process the same function twice
|
|
|
|
|
if i <= i0 {
|
|
|
|
|
Fatalf("importer: index not increasing: %d <= %d", i, i0)
|
|
|
|
|
}
|
|
|
|
|
i0 = i
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
if Funcdepth != 0 {
|
|
|
|
|
Fatalf("importer: unexpected Funcdepth %d", Funcdepth)
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
2016-04-12 18:00:04 -07:00
|
|
|
|
|
|
|
|
// Note: In the original code, funchdr and funcbody are called for
|
|
|
|
|
// all functions (that were not yet imported). Now, we are calling
|
|
|
|
|
// them only for functions with inlineable bodies. funchdr does
|
|
|
|
|
// parameter renaming which doesn't matter if we don't have a body.
|
|
|
|
|
|
|
|
|
|
if f := p.funcList[i]; f != nil {
|
|
|
|
|
// function not yet imported - read body and set it
|
2016-03-18 17:21:32 -07:00
|
|
|
funchdr(f)
|
2016-04-26 14:11:38 -07:00
|
|
|
body := p.stmtList()
|
|
|
|
|
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{Nod(OEMPTY, nil, nil)}
|
|
|
|
|
}
|
|
|
|
|
f.Func.Inl.Set(body)
|
2016-03-18 17:21:32 -07:00
|
|
|
funcbody(f)
|
|
|
|
|
} else {
|
|
|
|
|
// function already imported - read body but discard declarations
|
|
|
|
|
dclcontext = PDISCARD // throw away any declarations
|
|
|
|
|
p.stmtList()
|
|
|
|
|
dclcontext = PEXTERN
|
|
|
|
|
}
|
2016-04-12 18:00:04 -07:00
|
|
|
|
|
|
|
|
objcount++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// self-verification
|
|
|
|
|
if count := p.int(); count != objcount {
|
|
|
|
|
Fatalf("importer: got %d functions; want %d", objcount, count)
|
2016-03-18 17:21:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 == "" {
|
2016-05-02 17:03:36 -07:00
|
|
|
Fatalf("importer: empty package name for path %q", path)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we should never see a bad import path
|
|
|
|
|
if isbadimport(path) {
|
2016-05-02 17:03:36 -07:00
|
|
|
Fatalf("importer: bad package path %q for package %s", path, name)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
2016-04-12 21:58:44 -07:00
|
|
|
// an empty path denotes the package we are currently importing;
|
|
|
|
|
// it must be the first package we see
|
|
|
|
|
if (path == "") != (len(p.pkgList) == 0) {
|
|
|
|
|
panic(fmt.Sprintf("package path %q for pkg index %d", path, len(p.pkgList)))
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
pkg := importpkg
|
|
|
|
|
if path != "" {
|
|
|
|
|
pkg = mkpkg(path)
|
|
|
|
|
}
|
|
|
|
|
if pkg.Name == "" {
|
|
|
|
|
pkg.Name = name
|
|
|
|
|
} else if pkg.Name != name {
|
2016-05-02 17:03:36 -07:00
|
|
|
Fatalf("importer: conflicting package names %s and %s for path %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:
|
2016-04-13 17:53:03 -07:00
|
|
|
p.pos()
|
2016-03-18 17:21:32 -07:00
|
|
|
sym := p.qualifiedName()
|
|
|
|
|
typ := p.typ()
|
|
|
|
|
val := p.value(typ)
|
|
|
|
|
importconst(sym, idealType(typ), nodlit(val))
|
|
|
|
|
|
|
|
|
|
case typeTag:
|
|
|
|
|
p.typ()
|
|
|
|
|
|
|
|
|
|
case varTag:
|
2016-04-13 17:53:03 -07:00
|
|
|
p.pos()
|
2016-03-18 17:21:32 -07:00
|
|
|
sym := p.qualifiedName()
|
|
|
|
|
typ := p.typ()
|
|
|
|
|
importvar(sym, typ)
|
|
|
|
|
|
|
|
|
|
case funcTag:
|
2016-04-13 17:53:03 -07:00
|
|
|
p.pos()
|
2016-03-18 17:21:32 -07:00
|
|
|
sym := p.qualifiedName()
|
|
|
|
|
params := p.paramList()
|
|
|
|
|
result := p.paramList()
|
|
|
|
|
|
|
|
|
|
sig := functype(nil, params, result)
|
|
|
|
|
importsym(sym, ONAME)
|
|
|
|
|
if sym.Def != nil && sym.Def.Op == ONAME {
|
2016-04-12 18:00:04 -07:00
|
|
|
// function was imported before (via another import)
|
|
|
|
|
if !Eqtype(sig, sym.Def.Type) {
|
2016-03-18 17:21:32 -07:00
|
|
|
Fatalf("importer: inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, sig)
|
|
|
|
|
}
|
2016-04-12 18:00:04 -07:00
|
|
|
p.funcList = append(p.funcList, nil)
|
2016-03-18 17:21:32 -07:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-12 18:00:04 -07:00
|
|
|
n := newfuncname(sym)
|
|
|
|
|
n.Type = sig
|
|
|
|
|
declare(n, PFUNC)
|
|
|
|
|
p.funcList = append(p.funcList, n)
|
|
|
|
|
importlist = append(importlist, n)
|
2016-03-18 17:21:32 -07:00
|
|
|
|
|
|
|
|
if Debug['E'] > 0 {
|
|
|
|
|
fmt.Printf("import [%q] func %v \n", importpkg.Path, n)
|
2016-04-24 13:50:26 -07:00
|
|
|
if Debug['m'] > 2 && n.Func.Inl.Len() != 0 {
|
2016-03-18 17:21:32 -07:00
|
|
|
fmt.Printf("inl body: %v\n", n.Func.Inl)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
2016-04-12 11:31:16 -07:00
|
|
|
Fatalf("importer: unexpected object (tag = %d)", tag)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-13 17:53:03 -07:00
|
|
|
func (p *importer) pos() {
|
2016-04-22 14:50:20 -07:00
|
|
|
if !p.posInfoFormat {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-13 17:53:03 -07:00
|
|
|
file := p.prevFile
|
|
|
|
|
line := p.prevLine
|
|
|
|
|
if delta := p.int(); delta != 0 {
|
2016-04-28 12:43:12 -07:00
|
|
|
// line changed
|
2016-04-13 17:53:03 -07:00
|
|
|
line += delta
|
2016-04-28 12:43:12 -07:00
|
|
|
} else if n := p.int(); n >= 0 {
|
|
|
|
|
// file changed
|
|
|
|
|
file = p.prevFile[:n] + p.string()
|
2016-04-13 17:53:03 -07:00
|
|
|
p.prevFile = file
|
2016-04-28 12:43:12 -07:00
|
|
|
line = p.int()
|
2016-04-13 17:53:03 -07:00
|
|
|
}
|
|
|
|
|
p.prevLine = line
|
|
|
|
|
|
|
|
|
|
// TODO(gri) register new position
|
|
|
|
|
}
|
|
|
|
|
|
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
|
2016-04-13 17:53:03 -07:00
|
|
|
p.pos()
|
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
|
|
|
|
2016-04-13 17:53:03 -07:00
|
|
|
p.pos()
|
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()
|
|
|
|
|
|
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-04-12 18:00:04 -07:00
|
|
|
p.funcList = append(p.funcList, n)
|
|
|
|
|
importlist = append(importlist, 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-18 17:21:32 -07:00
|
|
|
if Debug['E'] > 0 {
|
|
|
|
|
fmt.Printf("import [%q] meth %v \n", importpkg.Path, n)
|
2016-04-24 13:50:26 -07:00
|
|
|
if Debug['m'] > 2 && n.Func.Inl.Len() != 0 {
|
2016-03-18 17:21:32 -07:00
|
|
|
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
|
|
|
|
|
|
2016-04-18 14:02:08 -07:00
|
|
|
case arrayTag:
|
2015-08-13 19:05:37 -07:00
|
|
|
t = p.newtyp(TARRAY)
|
2016-04-18 14:02:08 -07:00
|
|
|
bound := p.int64()
|
2016-04-01 20:11:30 -07:00
|
|
|
elem := p.typ()
|
2016-04-18 14:02:08 -07:00
|
|
|
t.Extra = &ArrayType{Elem: elem, Bound: bound}
|
|
|
|
|
|
|
|
|
|
case sliceTag:
|
|
|
|
|
t = p.newtyp(TSLICE)
|
|
|
|
|
elem := p.typ()
|
|
|
|
|
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-04-13 17:53:03 -07:00
|
|
|
func (p *importer) fieldList() (fields []*Node) {
|
|
|
|
|
if n := p.int(); n > 0 {
|
|
|
|
|
fields = make([]*Node, n)
|
|
|
|
|
for i := range fields {
|
|
|
|
|
fields[i] = p.field()
|
|
|
|
|
}
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
2016-04-13 17:53:03 -07:00
|
|
|
return
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
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 {
|
2016-04-13 17:53:03 -07:00
|
|
|
p.pos()
|
2015-08-13 19:05:37 -07:00
|
|
|
sym := p.fieldName()
|
|
|
|
|
typ := p.typ()
|
2016-04-25 13:24:48 -07:00
|
|
|
note := p.string()
|
2015-08-13 19:05:37 -07:00
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
}
|
2016-04-25 13:24:48 -07:00
|
|
|
n.SetVal(Val{U: note})
|
2015-08-13 19:05:37 -07:00
|
|
|
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_interfacedcl_list
|
2016-04-13 17:53:03 -07:00
|
|
|
func (p *importer) methodList() (methods []*Node) {
|
|
|
|
|
if n := p.int(); n > 0 {
|
|
|
|
|
methods = make([]*Node, n)
|
|
|
|
|
for i := range methods {
|
|
|
|
|
methods[i] = p.method()
|
|
|
|
|
}
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
2016-04-13 17:53:03 -07:00
|
|
|
return
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
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 {
|
2016-04-13 17:53:03 -07:00
|
|
|
p.pos()
|
2015-08-13 19:05:37 -07:00
|
|
|
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-05-02 17:03:36 -07:00
|
|
|
pkg = builtinpkg
|
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.
|
2016-05-02 17:03:36 -07:00
|
|
|
pkg := localpkg
|
|
|
|
|
if name != "_" {
|
|
|
|
|
pkg = p.pkg()
|
|
|
|
|
}
|
2016-03-18 17:21:32 -07:00
|
|
|
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?
|
2016-04-25 13:24:48 -07:00
|
|
|
n.SetVal(Val{U: p.string()})
|
2015-08-13 19:05:37 -07:00
|
|
|
|
|
|
|
|
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).
|
2016-04-13 13:17:30 -07:00
|
|
|
//
|
|
|
|
|
// 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.
|
2016-03-18 17:21:32 -07:00
|
|
|
|
|
|
|
|
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-04-21 11:55:33 -07:00
|
|
|
case OINDEX:
|
2016-03-18 17:21:32 -07:00
|
|
|
return Nod(op, p.expr(), p.expr())
|
|
|
|
|
|
2016-04-21 11:55:33 -07:00
|
|
|
case OSLICE, OSLICE3:
|
|
|
|
|
n := Nod(op, p.expr(), nil)
|
|
|
|
|
low, high := p.exprsOrNil()
|
|
|
|
|
var max *Node
|
|
|
|
|
if n.Op.IsSlice3() {
|
|
|
|
|
max = p.expr()
|
|
|
|
|
}
|
|
|
|
|
n.SetSliceBounds(low, high, max)
|
|
|
|
|
return n
|
|
|
|
|
|
2016-03-18 17:21:32 -07:00
|
|
|
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
|
|
|
|
|
|
2016-04-13 13:17:30 -07:00
|
|
|
// case OAS, OASWB:
|
|
|
|
|
// unreachable - mapped to OAS case below by exporter
|
|
|
|
|
|
|
|
|
|
case OAS:
|
|
|
|
|
return Nod(OAS, p.expr(), p.expr())
|
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-04-13 13:17:30 -07:00
|
|
|
// case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
|
|
|
|
|
// unreachable - mapped to OAS2 case below by exporter
|
2015-10-22 18:56:45 -07:00
|
|
|
|
2016-04-13 13:17:30 -07:00
|
|
|
case OAS2:
|
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
|
|
|
|
2016-04-13 13:17:30 -07:00
|
|
|
// case OCASE, OXCASE:
|
|
|
|
|
// unreachable - mapped to OXCASE case below by exporter
|
|
|
|
|
|
|
|
|
|
case 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
|
|
|
|
2016-04-13 13:17:30 -07:00
|
|
|
// case OFALL:
|
|
|
|
|
// unreachable - mapped to OXFALL case below by exporter
|
|
|
|
|
|
|
|
|
|
case OBREAK, OCONTINUE, OGOTO, OXFALL:
|
2016-03-18 17:21:32 -07:00
|
|
|
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-04-22 07:14:10 -07:00
|
|
|
Fatalf("importer: %s (%d) node not yet supported", op, op)
|
2016-03-18 17:21:32 -07:00
|
|
|
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 {
|
2016-04-13 17:53:03 -07:00
|
|
|
if debugFormat {
|
2015-08-13 19:05:37 -07:00
|
|
|
p.marker('s')
|
|
|
|
|
}
|
2016-04-13 17:53:03 -07:00
|
|
|
// if the string was seen before, i is its index (>= 0)
|
|
|
|
|
// (the empty string is at index 0)
|
|
|
|
|
i := p.rawInt64()
|
|
|
|
|
if i >= 0 {
|
|
|
|
|
return p.strList[i]
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
2016-04-13 17:53:03 -07:00
|
|
|
// otherwise, i is the negative string length (< 0)
|
|
|
|
|
if n := int(-i); n <= cap(p.buf) {
|
|
|
|
|
p.buf = p.buf[:n]
|
|
|
|
|
} else {
|
|
|
|
|
p.buf = make([]byte, n)
|
|
|
|
|
}
|
|
|
|
|
for i := range p.buf {
|
|
|
|
|
p.buf[i] = p.rawByte()
|
|
|
|
|
}
|
|
|
|
|
s := string(p.buf)
|
|
|
|
|
p.strList = append(p.strList, s)
|
|
|
|
|
return s
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) marker(want byte) {
|
2016-04-13 17:53:03 -07:00
|
|
|
if got := p.rawByte(); 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) {
|
2016-04-13 17:53:03 -07:00
|
|
|
return p.rawByte(), nil
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
2015-10-23 16:01:09 -07:00
|
|
|
|
2016-04-13 17:53:03 -07:00
|
|
|
// rawByte is the bottleneck interface for reading from p.in.
|
2015-10-23 16:01:09 -07:00
|
|
|
// It unescapes '|' 'S' to '$' and '|' '|' to '|'.
|
2016-04-13 17:53:03 -07:00
|
|
|
// rawByte should only be used by low-level decoders.
|
|
|
|
|
func (p *importer) rawByte() 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
|
|
|
}
|