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
2016-05-05 09:39:50 -07:00
// for delayed type verification
cmpList [ ] struct { pt , t * Type }
2016-04-13 17:53:03 -07:00
// 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
}
2016-05-05 09:39:50 -07:00
p . verifyTypes ( )
2015-08-13 19:05:37 -07:00
// --- end of export data ---
typecheckok = tcok
resumecheckwidth ( )
testdclstack ( ) // debugging only
}
2016-05-05 09:39:50 -07:00
func ( p * importer ) verifyTypes ( ) {
for _ , pair := range p . cmpList {
pt := pair . pt
t := pair . t
if ! Eqtype ( pt . Orig , t ) {
// TODO(gri) Is this a possible regular error (stale files)
// or can this only happen if export/import is flawed?
// (if the latter, change to Fatalf here)
Yyerror ( "inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)" , pt . Sym , Tconv ( pt , FmtLong ) , pt . Sym . Importdef . Path , Tconv ( t , FmtLong ) , importpkg . Path )
}
}
}
2015-08-13 19:05:37 -07:00
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
}
2016-05-05 09:39:50 -07:00
// This is like the function importtype but it delays the
// type identity check for types that have been seen already.
// importer.importtype and importtype and (export.go) need to
// remain in sync.
func ( p * importer ) importtype ( pt , t * Type ) {
// override declaration in unsafe.go for Pointer.
// there is no way in Go code to define unsafe.Pointer
// so we have to supply it.
if incannedimport != 0 && importpkg . Name == "unsafe" && pt . Nod . Sym . Name == "Pointer" {
t = Types [ TUNSAFEPTR ]
}
if pt . Etype == TFORW {
n := pt . Nod
copytype ( pt . Nod , t )
pt . Nod = n // unzero nod
pt . Sym . Importdef = importpkg
pt . Sym . Lastlineno = lineno
declare ( n , PEXTERN )
checkwidth ( pt )
} else {
// pt.Orig and t must be identical. Since t may not be
// fully set up yet, collect the types and verify identity
// later.
p . cmpList = append ( p . cmpList , struct { pt , t * Type } { pt , t } )
}
if Debug [ 'E' ] != 0 {
fmt . Printf ( "import type %v %v\n" , pt , Tconv ( t , FmtLong ) )
}
}
2015-08-13 19:05:37 -07:00
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-05-05 09:39:50 -07:00
p . 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-05-04 15:13:36 -07:00
if p . 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
}