package gcimporter
import (
)
type importer struct {
imports map[string]*types.Package
data []byte
importpath string
buf []byte
version int
strList []string
pathList []string
pkgList []*types.Package
typList []types.Type
interfaceList []*types.Interface
trackAllTypes bool
posInfoFormat bool
prevFile string
prevLine int
fake fakeFileSet
debugFormat bool
read int
}
func ( *token.FileSet, map[string]*types.Package, []byte, string) ( int, *types.Package, error) {
const = 6
:= -1
defer func() {
if := recover(); != nil {
if > {
= fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", , )
} else {
= fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", , )
}
}
}()
:= importer{
imports: ,
data: ,
importpath: ,
version: ,
strList: []string{""},
pathList: []string{""},
fake: fakeFileSet{
fset: ,
files: make(map[string]*fileInfo),
},
}
defer .fake.setLines()
var string
if := .rawByte(); == 'c' || == 'd' {
if == 'd' {
.debugFormat = true
}
.trackAllTypes = .rawByte() == 'a'
.posInfoFormat = .int() != 0
= .string()
if == "v1" {
= 0
}
} else {
= .rawStringln()
if := strings.SplitN(, " ", 3); len() >= 2 && [0] == "version" {
if , := strconv.Atoi([1]); == nil && > 0 {
=
}
}
}
.version =
switch .version {
case , 5, 4, 3, 2, 1:
.debugFormat = .rawStringln(.rawByte()) == "debug"
.trackAllTypes = .int() != 0
.posInfoFormat = .int() != 0
case 0:
default:
errorf("unknown bexport format version %d (%q)", .version, )
}
.typList = append(.typList, predeclared()...)
= .pkg()
:= 0
for {
:= .tagOrIndex()
if == endTag {
break
}
.obj()
++
}
if := .int(); != {
errorf("got %d objects; want %d", , )
}
for , := range .interfaceList {
.Complete()
}
:= append(([]*types.Package)(nil), .pkgList[1:]...)
sort.Sort(byPath())
.SetImports()
.MarkComplete()
return .read, , nil
}
func ( string, ...interface{}) {
panic(fmt.Sprintf(, ...))
}
func ( *importer) () *types.Package {
:= .tagOrIndex()
if >= 0 {
return .pkgList[]
}
if != packageTag {
errorf("unexpected package tag %d version %d", , .version)
}
:= .string()
var string
if .version >= 5 {
= .path()
} else {
= .string()
}
if .version >= 6 {
.int()
}
if == "" {
errorf("empty package name in import")
}
if ( == "") != (len(.pkgList) == 0) {
errorf("package path %q for pkg index %d", , len(.pkgList))
}
if == "" {
= .importpath
}
:= .imports[]
if == nil {
= types.NewPackage(, )
.imports[] =
} else if .Name() != {
errorf("conflicting names %s and %s for package %q", .Name(), , )
}
.pkgList = append(.pkgList, )
return
}
func ( types.Object) int {
switch .(type) {
case *types.Const:
return constTag
case *types.TypeName:
return typeTag
case *types.Var:
return varTag
case *types.Func:
return funcTag
default:
errorf("unexpected object: %v (%T)", , )
panic("unreachable")
}
}
func (, types.Object) bool {
return objTag() == objTag() && types.Identical(.Type(), .Type())
}
func ( *importer) ( types.Object) {
:= .Pkg()
if := .Scope().Insert(); != nil {
if !sameObj(, ) {
errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", , )
}
}
}
func ( *importer) ( int) {
switch {
case constTag:
:= .pos()
, := .qualifiedName()
:= .typ(nil, nil)
:= .value()
.declare(types.NewConst(, , , , ))
case aliasTag:
:= .pos()
, := .qualifiedName()
:= .typ(nil, nil)
.declare(types.NewTypeName(, , , ))
case typeTag:
.typ(nil, nil)
case varTag:
:= .pos()
, := .qualifiedName()
:= .typ(nil, nil)
.declare(types.NewVar(, , , ))
case funcTag:
:= .pos()
, := .qualifiedName()
, := .paramList()
, := .paramList()
:= types.NewSignature(nil, , , )
.declare(types.NewFunc(, , , ))
default:
errorf("unexpected object tag %d", )
}
}
const deltaNewFile = -64
func ( *importer) () token.Pos {
if !.posInfoFormat {
return token.NoPos
}
:= .prevFile
:= .prevLine
:= .int()
+=
if .version >= 5 {
if == deltaNewFile {
if := .int(); >= 0 {
= .path()
=
}
}
} else {
if == 0 {
if := .int(); >= 0 {
= .prevFile[:] + .string()
= .int()
}
}
}
.prevFile =
.prevLine =
return .fake.pos(, , 0)
}
type fakeFileSet struct {
fset *token.FileSet
files map[string]*fileInfo
}
type fileInfo struct {
file *token.File
lastline int
}
const maxlines = 64 * 1024
func ( *fakeFileSet) ( string, , int) token.Pos {
:= .files[]
if == nil {
= &fileInfo{file: .fset.AddFile(, -1, maxlines)}
.files[] =
}
if > maxlines {
= 1
}
if > .lastline {
.lastline =
}
return token.Pos(.file.Base() + - 1)
}
func ( *fakeFileSet) () {
fakeLinesOnce.Do(func() {
fakeLines = make([]int, maxlines)
for := range fakeLines {
fakeLines[] =
}
})
for , := range .files {
.file.SetLines(fakeLines[:.lastline])
}
}
var (
fakeLines []int
fakeLinesOnce sync.Once
)
func ( *importer) () ( *types.Package, string) {
= .string()
= .pkg()
return
}
func ( *importer) ( types.Type) {
.typList = append(.typList, )
}
type dddSlice struct {
elem types.Type
}
func ( *dddSlice) () types.Type { return }
func ( *dddSlice) () string { return "..." + .elem.String() }
func ( *importer) ( *types.Package, *types.Named) types.Type {
:= .tagOrIndex()
if >= 0 {
return .typList[]
}
switch {
case namedTag:
:= .pos()
, := .qualifiedName()
:= .Scope()
:= .Lookup()
if == nil {
= types.NewTypeName(, , , nil)
.Insert()
}
if , := .(*types.TypeName); ! {
errorf("pkg = %s, name = %s => %s", , , )
}
:= types.NewNamed(.(*types.TypeName), nil, nil)
:= .Type().(*types.Named)
.record()
.SetUnderlying(.(, ))
if types.IsInterface() {
return
}
for := .int(); > 0; -- {
:= .pos()
:= .string()
if !exported() {
.pkg()
}
, := .paramList()
, := .paramList()
, := .paramList()
.int()
:= types.NewSignature(.At(0), , , )
.AddMethod(types.NewFunc(, , , ))
}
return
case arrayTag:
:= new(types.Array)
if .trackAllTypes {
.record()
}
:= .int64()
* = *types.NewArray(.(, nil), )
return
case sliceTag:
:= new(types.Slice)
if .trackAllTypes {
.record()
}
* = *types.NewSlice(.(, nil))
return
case dddTag:
:= new(dddSlice)
if .trackAllTypes {
.record()
}
.elem = .(, nil)
return
case structTag:
:= new(types.Struct)
if .trackAllTypes {
.record()
}
* = *types.NewStruct(.fieldList())
return
case pointerTag:
:= new(types.Pointer)
if .trackAllTypes {
.record()
}
* = *types.NewPointer(.(, nil))
return
case signatureTag:
:= new(types.Signature)
if .trackAllTypes {
.record()
}
, := .paramList()
, := .paramList()
* = *types.NewSignature(nil, , , )
return
case interfaceTag:
:= len(.typList)
if .trackAllTypes {
.record(nil)
}
var []types.Type
for := .int(); > 0; -- {
.pos()
= append(, .(, nil))
}
:= newInterface(.methodList(, ), )
.interfaceList = append(.interfaceList, )
if .trackAllTypes {
.typList[] =
}
return
case mapTag:
:= new(types.Map)
if .trackAllTypes {
.record()
}
:= .(, nil)
:= .(, nil)
* = *types.NewMap(, )
return
case chanTag:
:= new(types.Chan)
if .trackAllTypes {
.record()
}
:= chanDir(.int())
:= .(, nil)
* = *types.NewChan(, )
return
default:
errorf("unexpected type tag %d", )
panic("unreachable")
}
}
func ( int) types.ChanDir {
switch {
case 1 :
return types.RecvOnly
case 2 :
return types.SendOnly
case 3 :
return types.SendRecv
default:
errorf("unexpected channel dir %d", )
return 0
}
}
func ( *importer) ( *types.Package) ( []*types.Var, []string) {
if := .int(); > 0 {
= make([]*types.Var, )
= make([]string, )
for := range {
[], [] = .field()
}
}
return
}
func ( *importer) ( *types.Package) (*types.Var, string) {
:= .pos()
, , := .fieldName()
:= .typ(, nil)
:= .string()
:= false
if == "" {
switch typ := deref().(type) {
case *types.Basic:
= nil
= .Name()
case *types.Named:
= .Obj().Name()
default:
errorf("named base type expected")
}
= true
} else if {
= true
}
return types.NewField(, , , , ),
}
func ( *importer) ( *types.Package, *types.Named) ( []*types.Func) {
if := .int(); > 0 {
= make([]*types.Func, )
for := range {
[] = .method(, )
}
}
return
}
func ( *importer) ( *types.Package, *types.Named) *types.Func {
:= .pos()
, , := .fieldName()
var *types.Var
if != nil {
= types.NewVar(token.NoPos, , "", )
}
, := .paramList()
, := .paramList()
:= types.NewSignature(, , , )
return types.NewFunc(, , , )
}
func ( *importer) ( *types.Package) ( *types.Package, string, bool) {
= .string()
=
if == nil {
= .pkgList[0]
}
if .version == 0 && == "_" {
return
}
switch {
case "":
case "?":
= ""
= .pkg()
case "@":
= .string()
= true
fallthrough
default:
if !exported() {
= .pkg()
}
}
return
}
func ( *importer) () (*types.Tuple, bool) {
:= .int()
if == 0 {
return nil, false
}
:= true
if < 0 {
= -
= false
}
:= make([]*types.Var, )
:= false
for := range {
[], = .param()
}
return types.NewTuple(...),
}
func ( *importer) ( bool) (*types.Var, bool) {
:= .typ(nil, nil)
, := .(*dddSlice)
if {
= types.NewSlice(.elem)
}
var *types.Package
var string
if {
= .string()
if == "" {
errorf("expected named parameter")
}
if != "_" {
= .pkg()
}
if := strings.Index(, "ยท"); > 0 {
= [:]
}
}
.string()
return types.NewVar(token.NoPos, , , ),
}
func ( string) bool {
, := utf8.DecodeRuneInString()
return unicode.IsUpper()
}
func ( *importer) () constant.Value {
switch := .tagOrIndex(); {
case falseTag:
return constant.MakeBool(false)
case trueTag:
return constant.MakeBool(true)
case int64Tag:
return constant.MakeInt64(.int64())
case floatTag:
return .float()
case complexTag:
:= .float()
:= .float()
return constant.BinaryOp(, token.ADD, constant.MakeImag())
case stringTag:
return constant.MakeString(.string())
case unknownTag:
return constant.MakeUnknown()
default:
errorf("unexpected value tag %d", )
panic("unreachable")
}
}
func ( *importer) () constant.Value {
:= .int()
if == 0 {
return constant.MakeInt64(0)
}
:= .int()
:= []byte(.string())
for len() > 0 && [0] == 0 {
= [1:]
}
for , := 0, len()-1; < ; , = +1, -1 {
[], [] = [], []
}
-= len() << 3
if len() > 0 {
for := [len()-1]; &0x80 == 0; <<= 1 {
++
}
}
:= constant.MakeFromBytes()
switch {
case < 0:
:= constant.Shift(constant.MakeInt64(1), token.SHL, uint(-))
= constant.BinaryOp(, token.QUO, )
case > 0:
= constant.Shift(, token.SHL, uint())
}
if < 0 {
= constant.UnaryOp(token.SUB, , 0)
}
return
}
func ( *importer) () int {
if .debugFormat {
.marker('t')
}
return int(.rawInt64())
}
func ( *importer) () int {
:= .int64()
if int64(int()) != {
errorf("exported integer too large")
}
return int()
}
func ( *importer) () int64 {
if .debugFormat {
.marker('i')
}
return .rawInt64()
}
func ( *importer) () string {
if .debugFormat {
.marker('p')
}
:= .rawInt64()
if >= 0 {
return .pathList[]
}
:= make([]string, -)
for := range {
[] = .string()
}
:= strings.Join(, "/")
.pathList = append(.pathList, )
return
}
func ( *importer) () string {
if .debugFormat {
.marker('s')
}
:= .rawInt64()
if >= 0 {
return .strList[]
}
if := int(-); <= cap(.buf) {
.buf = .buf[:]
} else {
.buf = make([]byte, )
}
for := range .buf {
.buf[] = .rawByte()
}
:= string(.buf)
.strList = append(.strList, )
return
}
func ( *importer) ( byte) {
if := .rawByte(); != {
errorf("incorrect marker: got %c; want %c (pos = %d)", , , .read)
}
:= .read
if := int(.rawInt64()); != {
errorf("incorrect position: got %d; want %d", , )
}
}
func ( *importer) () int64 {
, := binary.ReadVarint()
if != nil {
errorf("read error: %v", )
}
return
}
func ( *importer) ( byte) string {
.buf = .buf[:0]
for != '\n' {
.buf = append(.buf, )
= .rawByte()
}
return string(.buf)
}
func ( *importer) () (byte, error) {
return .rawByte(), nil
}
func ( *importer) () byte {
:= .data[0]
:= 1
if == '|' {
= .data[1]
= 2
switch {
case 'S':
= '$'
case '|':
default:
errorf("unexpected escape sequence in export data")
}
}
.data = .data[:]
.read +=
return
}
const (
packageTag = -(iota + 1)
constTag
typeTag
varTag
funcTag
endTag
namedTag
arrayTag
sliceTag
dddTag
structTag
pointerTag
signatureTag
interfaceTag
mapTag
chanTag
falseTag
trueTag
int64Tag
floatTag
fractionTag
complexTag
stringTag
nilTag
unknownTag
aliasTag
)
var predeclOnce sync.Once
var predecl []types.Type
func () []types.Type {
predeclOnce.Do(func() {
predecl = []types.Type{
types.Typ[types.Bool],
types.Typ[types.Int],
types.Typ[types.Int8],
types.Typ[types.Int16],
types.Typ[types.Int32],
types.Typ[types.Int64],
types.Typ[types.Uint],
types.Typ[types.Uint8],
types.Typ[types.Uint16],
types.Typ[types.Uint32],
types.Typ[types.Uint64],
types.Typ[types.Uintptr],
types.Typ[types.Float32],
types.Typ[types.Float64],
types.Typ[types.Complex64],
types.Typ[types.Complex128],
types.Typ[types.String],
types.Universe.Lookup("byte").Type(),
types.Universe.Lookup("rune").Type(),
types.Universe.Lookup("error").Type(),
types.Typ[types.UntypedBool],
types.Typ[types.UntypedInt],
types.Typ[types.UntypedRune],
types.Typ[types.UntypedFloat],
types.Typ[types.UntypedComplex],
types.Typ[types.UntypedString],
types.Typ[types.UntypedNil],
types.Typ[types.UnsafePointer],
types.Typ[types.Invalid],
anyType{},
}
predecl = append(predecl, additionalPredeclared()...)
})
return predecl
}
type anyType struct{}
func ( anyType) () types.Type { return }
func ( anyType) () string { return "any" }