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.
|
|
|
|
|
|
|
|
|
|
// 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()
|
|
|
|
|
|
|
|
|
|
// read consts
|
|
|
|
|
for i := p.int(); i > 0; i-- {
|
|
|
|
|
sym := p.localname()
|
|
|
|
|
typ := p.typ()
|
|
|
|
|
val := p.value(typ)
|
2015-10-22 18:56:45 -07:00
|
|
|
importconst(sym, idealType(typ), nodlit(val))
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read vars
|
|
|
|
|
for i := p.int(); i > 0; i-- {
|
|
|
|
|
sym := p.localname()
|
|
|
|
|
typ := p.typ()
|
|
|
|
|
importvar(sym, typ)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read funcs
|
|
|
|
|
for i := p.int(); i > 0; i-- {
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_fndcl
|
2015-08-13 19:05:37 -07:00
|
|
|
sym := p.localname()
|
2016-03-11 13:40:01 -08:00
|
|
|
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-11 13:40:01 -08:00
|
|
|
sig := functype(nil, params, result)
|
2015-08-13 19:05:37 -07:00
|
|
|
importsym(sym, ONAME)
|
2016-03-11 13:40:01 -08:00
|
|
|
if sym.Def != nil && sym.Def.Op == ONAME && !Eqtype(sig, sym.Def.Type) {
|
|
|
|
|
Fatalf("importer: inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, sig)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n := newfuncname(sym)
|
2016-03-11 13:40:01 -08:00
|
|
|
n.Type = sig
|
2015-08-13 19:05:37 -07:00
|
|
|
declare(n, PFUNC)
|
|
|
|
|
funchdr(n)
|
|
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_import
|
2016-02-27 14:31:33 -08:00
|
|
|
n.Func.Inl.Set(nil)
|
2015-10-22 18:56:45 -07:00
|
|
|
if inl >= 0 {
|
|
|
|
|
if inl != len(p.inlined) {
|
2016-03-11 13:40:01 -08:00
|
|
|
panic(fmt.Sprintf("inlined body list inconsistent: %d != %d", inl, len(p.inlined)))
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
|
|
|
|
p.inlined = append(p.inlined, n.Func)
|
|
|
|
|
}
|
2015-08-13 19:05:37 -07:00
|
|
|
funcbody(n)
|
|
|
|
|
importlist = append(importlist, n) // TODO(gri) do this only if body is inlineable?
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read types
|
|
|
|
|
for i := p.int(); i > 0; i-- {
|
|
|
|
|
// name is parsed as part of named type
|
|
|
|
|
p.typ()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- compiler-specific export data ---
|
|
|
|
|
|
2015-10-22 18:56:45 -07:00
|
|
|
// read inlined functions bodies
|
|
|
|
|
n := p.int()
|
|
|
|
|
for i := 0; i < n; i++ {
|
2016-03-11 13:40:01 -08:00
|
|
|
body := p.block()
|
2015-10-22 18:56:45 -07:00
|
|
|
const hookup = false // TODO(gri) enable and remove this condition
|
|
|
|
|
if hookup {
|
|
|
|
|
p.inlined[i].Inl.Set(body)
|
|
|
|
|
}
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- end of export data ---
|
|
|
|
|
|
|
|
|
|
typecheckok = tcok
|
|
|
|
|
resumecheckwidth()
|
|
|
|
|
|
|
|
|
|
testdclstack() // debugging only
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-22 18:56:45 -07:00
|
|
|
func idealType(typ *Type) *Type {
|
|
|
|
|
if isideal(typ) {
|
|
|
|
|
// canonicalize ideal types
|
|
|
|
|
typ = Types[TIDEAL]
|
|
|
|
|
}
|
|
|
|
|
return typ
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
type importer struct {
|
2016-03-11 13:39:20 -05:00
|
|
|
in *bufio.Reader
|
2015-08-13 19:05:37 -07:00
|
|
|
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
|
2015-10-22 18:56:45 -07:00
|
|
|
inlined []*Func
|
2015-08-13 19:05:37 -07:00
|
|
|
|
|
|
|
|
debugFormat bool
|
|
|
|
|
read int // bytes read
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: inconsistent package names: got %s; want %s (path = %s)", pkg.Name, name, path)
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
p.pkgList = append(p.pkgList, pkg)
|
|
|
|
|
|
|
|
|
|
return pkg
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) localname() *Sym {
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_importsym
|
2015-08-13 19:05:37 -07:00
|
|
|
name := p.string()
|
|
|
|
|
if name == "" {
|
2015-10-22 18:56:45 -07:00
|
|
|
Fatalf("importer: unexpected anonymous name")
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
|
|
|
|
return importpkg.Lookup(name)
|
|
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
importsym(tsym, OTYPE)
|
|
|
|
|
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
|
|
|
|
|
if t0.Etype == TINTER {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read associated methods
|
|
|
|
|
for i := p.int(); i > 0; i-- {
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_fndcl
|
2015-08-13 19:05:37 -07:00
|
|
|
name := p.string()
|
|
|
|
|
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
|
|
|
|
|
|
|
|
pkg := localpkg
|
|
|
|
|
if !exportname(name) {
|
|
|
|
|
pkg = tsym.Pkg
|
|
|
|
|
}
|
|
|
|
|
sym := pkg.Lookup(name)
|
|
|
|
|
|
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)
|
2015-08-13 19:05:37 -07:00
|
|
|
funchdr(n)
|
|
|
|
|
|
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.
|
|
|
|
|
n.Type.Nname = n
|
|
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:hidden_import
|
2016-02-27 14:31:33 -08:00
|
|
|
n.Func.Inl.Set(nil)
|
2015-10-22 18:56:45 -07:00
|
|
|
if inl >= 0 {
|
|
|
|
|
if inl != len(p.inlined) {
|
2016-03-11 13:40:01 -08:00
|
|
|
panic(fmt.Sprintf("inlined body list inconsistent: %d != %d", inl, len(p.inlined)))
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
|
|
|
|
p.inlined = append(p.inlined, n.Func)
|
|
|
|
|
}
|
2015-08-13 19:05:37 -07:00
|
|
|
funcbody(n)
|
|
|
|
|
importlist = append(importlist, n) // TODO(gri) do this only if body is inlineable?
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case arrayTag, sliceTag:
|
|
|
|
|
t = p.newtyp(TARRAY)
|
|
|
|
|
t.Bound = -1
|
|
|
|
|
if i == arrayTag {
|
|
|
|
|
t.Bound = p.int64()
|
|
|
|
|
}
|
|
|
|
|
t.Type = p.typ()
|
|
|
|
|
|
|
|
|
|
case dddTag:
|
|
|
|
|
t = p.newtyp(T_old_DARRAY)
|
|
|
|
|
t.Bound = -1
|
|
|
|
|
t.Type = p.typ()
|
|
|
|
|
|
|
|
|
|
case structTag:
|
|
|
|
|
t = p.newtyp(TSTRUCT)
|
|
|
|
|
tostruct0(t, p.fieldList())
|
|
|
|
|
|
|
|
|
|
case pointerTag:
|
|
|
|
|
t = p.newtyp(Tptr)
|
|
|
|
|
t.Type = p.typ()
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
t.Down = p.typ() // key
|
|
|
|
|
t.Type = p.typ() // val
|
|
|
|
|
|
|
|
|
|
case chanTag:
|
|
|
|
|
t = p.newtyp(TCHAN)
|
|
|
|
|
t.Chan = uint8(p.int())
|
|
|
|
|
t.Type = p.typ()
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
if s == nil && Isptr[typ.Etype] {
|
|
|
|
|
s = typ.Type.Sym // deref
|
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
|
pkg = builtinpkg
|
|
|
|
|
} 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
|
|
|
|
|
if typ.Etype == T_old_DARRAY {
|
|
|
|
|
// T_old_DARRAY indicates ... type
|
2016-03-09 15:32:57 -08:00
|
|
|
// TODO(mdempsky): Fix Type rekinding.
|
2015-08-13 19:05:37 -07:00
|
|
|
typ.Etype = TARRAY
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
// The parameter package doesn't matter; it's never consulted.
|
2016-03-08 18:57:19 +00:00
|
|
|
// We use the builtinpkg per parser.go:sym (line 1181).
|
2015-08-13 19:05:37 -07:00
|
|
|
n.Left = newname(builtinpkg.Lookup(name))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
if typ == idealint || Isint[typ.Etype] {
|
|
|
|
|
// 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
|
|
|
|
|
if isideal(typ) && 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-11 13:40:01 -08:00
|
|
|
func (p *importer) block() []*Node {
|
|
|
|
|
markdcl()
|
|
|
|
|
// TODO(gri) populate "scope" with function parameters so they can be found
|
|
|
|
|
// inside the function body
|
|
|
|
|
list := p.nodeList()
|
|
|
|
|
popdcl()
|
|
|
|
|
return list
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 18:57:19 +00:00
|
|
|
// parser.go:stmt_list
|
2016-03-03 14:11:17 -08:00
|
|
|
func (p *importer) nodeList() []*Node {
|
|
|
|
|
c := p.int()
|
2016-03-08 21:53:33 +01:00
|
|
|
s := make([]*Node, c)
|
|
|
|
|
for i := range s {
|
|
|
|
|
s[i] = p.node()
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
2016-03-03 14:11:17 -08:00
|
|
|
return s
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) node() *Node {
|
|
|
|
|
// TODO(gri) eventually we may need to allocate in each branch
|
|
|
|
|
n := Nod(p.op(), nil, nil)
|
|
|
|
|
|
|
|
|
|
switch n.Op {
|
|
|
|
|
// names
|
|
|
|
|
case ONAME, OPACK, ONONAME:
|
|
|
|
|
name := mkname(p.sym())
|
|
|
|
|
// TODO(gri) decide what to do here (this code throws away n)
|
|
|
|
|
/*
|
|
|
|
|
if name.Op != n.Op {
|
|
|
|
|
Fatalf("importer: got node op = %s; want %s", opnames[name.Op], opnames[n.Op])
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
n = name
|
|
|
|
|
|
|
|
|
|
case OTYPE:
|
|
|
|
|
if p.bool() {
|
|
|
|
|
n.Sym = p.sym()
|
|
|
|
|
} else {
|
|
|
|
|
n.Type = p.typ()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OLITERAL:
|
|
|
|
|
typ := p.typ()
|
|
|
|
|
n.Type = idealType(typ)
|
|
|
|
|
n.SetVal(p.value(typ))
|
|
|
|
|
|
|
|
|
|
// expressions
|
|
|
|
|
case OMAKEMAP, OMAKECHAN, OMAKESLICE:
|
|
|
|
|
if p.bool() {
|
2016-03-08 15:10:26 -08:00
|
|
|
n.List.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
|
|
|
|
n.Left, n.Right = p.nodesOrNil()
|
|
|
|
|
n.Type = p.typ()
|
|
|
|
|
|
|
|
|
|
case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV:
|
|
|
|
|
n.Left = p.node()
|
|
|
|
|
|
|
|
|
|
case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT,
|
|
|
|
|
OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND,
|
|
|
|
|
OSUB, OXOR:
|
|
|
|
|
n.Left = p.node()
|
|
|
|
|
n.Right = p.node()
|
|
|
|
|
|
|
|
|
|
case OADDSTR:
|
2016-03-08 15:10:26 -08:00
|
|
|
n.List.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OPTRLIT:
|
|
|
|
|
n.Left = p.node()
|
|
|
|
|
|
|
|
|
|
case OSTRUCTLIT:
|
|
|
|
|
n.Type = p.typ()
|
2016-03-08 15:10:26 -08:00
|
|
|
n.List.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
n.Implicit = p.bool()
|
|
|
|
|
|
|
|
|
|
case OARRAYLIT, OMAPLIT:
|
|
|
|
|
n.Type = p.typ()
|
2016-03-08 15:10:26 -08:00
|
|
|
n.List.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
n.Implicit = p.bool()
|
|
|
|
|
|
|
|
|
|
case OKEY:
|
|
|
|
|
n.Left, n.Right = p.nodesOrNil()
|
|
|
|
|
|
|
|
|
|
case OCOPY, OCOMPLEX:
|
|
|
|
|
n.Left = p.node()
|
|
|
|
|
n.Right = p.node()
|
|
|
|
|
|
|
|
|
|
case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
|
|
|
|
|
// n.Type = p.typ()
|
|
|
|
|
// if p.bool() {
|
|
|
|
|
// n.Left = p.node()
|
|
|
|
|
// } else {
|
2016-03-09 20:29:21 -08:00
|
|
|
// n.List.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
// }
|
|
|
|
|
x := Nod(OCALL, p.typ().Nod, nil)
|
|
|
|
|
if p.bool() {
|
2016-03-10 10:13:42 -08:00
|
|
|
x.List.Set1(p.node())
|
2015-10-22 18:56:45 -07:00
|
|
|
} else {
|
2016-03-08 15:10:26 -08:00
|
|
|
x.List.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
|
|
|
|
return x
|
|
|
|
|
|
|
|
|
|
case ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT:
|
|
|
|
|
// see parser.new_dotname
|
|
|
|
|
obj := p.node()
|
|
|
|
|
sel := p.sym()
|
|
|
|
|
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
|
|
|
|
|
|
|
|
case ODOTTYPE, ODOTTYPE2:
|
|
|
|
|
n.Left = p.node()
|
|
|
|
|
if p.bool() {
|
|
|
|
|
n.Right = p.node()
|
|
|
|
|
} else {
|
|
|
|
|
n.Type = p.typ()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
|
|
|
|
|
n.Left = p.node()
|
|
|
|
|
n.Right = p.node()
|
|
|
|
|
|
|
|
|
|
case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC,
|
|
|
|
|
ORECOVER, OPRINT, OPRINTN:
|
|
|
|
|
n.Left, _ = p.nodesOrNil()
|
2016-03-08 15:10:26 -08:00
|
|
|
n.List.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
n.Isddd = p.bool()
|
|
|
|
|
|
|
|
|
|
case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
|
|
|
|
|
n.Left = p.node()
|
2016-03-08 15:10:26 -08:00
|
|
|
n.List.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
n.Isddd = p.bool()
|
|
|
|
|
|
|
|
|
|
case OCMPSTR, OCMPIFACE:
|
|
|
|
|
n.Left = p.node()
|
|
|
|
|
n.Right = p.node()
|
|
|
|
|
n.Etype = EType(p.int())
|
|
|
|
|
|
|
|
|
|
case OPAREN:
|
|
|
|
|
n.Left = p.node()
|
|
|
|
|
|
|
|
|
|
// statements
|
|
|
|
|
case ODCL:
|
|
|
|
|
n.Left = p.node() // TODO(gri) compare with fmt code
|
|
|
|
|
n.Left.Type = p.typ()
|
|
|
|
|
|
|
|
|
|
case OAS:
|
|
|
|
|
n.Left, n.Right = p.nodesOrNil()
|
|
|
|
|
n.Colas = p.bool() // TODO(gri) what about complexinit?
|
|
|
|
|
|
|
|
|
|
case OASOP:
|
|
|
|
|
n.Left = p.node()
|
|
|
|
|
n.Right = p.node()
|
|
|
|
|
n.Etype = EType(p.int())
|
|
|
|
|
|
|
|
|
|
case OAS2, OASWB:
|
2016-03-08 15:10:26 -08:00
|
|
|
n.List.Set(p.nodeList())
|
|
|
|
|
n.Rlist.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
|
2016-03-08 15:10:26 -08:00
|
|
|
n.List.Set(p.nodeList())
|
|
|
|
|
n.Rlist.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case ORETURN:
|
2016-03-08 15:10:26 -08:00
|
|
|
n.List.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OPROC, ODEFER:
|
|
|
|
|
n.Left = p.node()
|
|
|
|
|
|
|
|
|
|
case OIF:
|
2016-03-08 15:10:26 -08:00
|
|
|
n.Ninit.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
n.Left = p.node()
|
2016-03-03 14:11:17 -08:00
|
|
|
n.Nbody.Set(p.nodeList())
|
2016-03-08 15:10:26 -08:00
|
|
|
n.Rlist.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OFOR:
|
2016-03-08 15:10:26 -08:00
|
|
|
n.Ninit.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
n.Left, n.Right = p.nodesOrNil()
|
2016-03-03 14:11:17 -08:00
|
|
|
n.Nbody.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case ORANGE:
|
|
|
|
|
if p.bool() {
|
2016-03-08 15:10:26 -08:00
|
|
|
n.List.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
|
|
|
|
n.Right = p.node()
|
2016-03-03 14:11:17 -08:00
|
|
|
n.Nbody.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OSELECT, OSWITCH:
|
2016-03-08 15:10:26 -08:00
|
|
|
n.Ninit.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
n.Left, _ = p.nodesOrNil()
|
2016-03-08 15:10:26 -08:00
|
|
|
n.List.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OCASE, OXCASE:
|
|
|
|
|
if p.bool() {
|
2016-03-08 15:10:26 -08:00
|
|
|
n.List.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
}
|
2016-03-03 14:11:17 -08:00
|
|
|
n.Nbody.Set(p.nodeList())
|
2015-10-22 18:56:45 -07:00
|
|
|
|
|
|
|
|
case OBREAK, OCONTINUE, OGOTO, OFALL, OXFALL:
|
|
|
|
|
n.Left, _ = p.nodesOrNil()
|
|
|
|
|
|
2016-03-16 18:44:17 -05:00
|
|
|
case OEMPTY, ODCLCONST:
|
2015-10-22 18:56:45 -07:00
|
|
|
// nothing to do
|
|
|
|
|
|
|
|
|
|
case OLABEL:
|
|
|
|
|
n.Left = p.node()
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
panic(fmt.Sprintf("importer: %s (%d) node not yet supported", opnames[n.Op], n.Op))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) nodesOrNil() (a, b *Node) {
|
|
|
|
|
ab := p.int()
|
|
|
|
|
if ab&1 != 0 {
|
|
|
|
|
a = p.node()
|
|
|
|
|
}
|
|
|
|
|
if ab&2 != 0 {
|
|
|
|
|
b = p.node()
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
2015-10-22 18:56:45 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importer) sym() *Sym {
|
|
|
|
|
return p.fieldName()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
}
|