// 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.

// This file is a copy of $GOROOT/src/go/internal/gcimporter/bimport.go.

package gcimporter

import (
	
	
	
	
	
	
	
	
	
	
	
)

type importer struct {
	imports    map[string]*types.Package
	data       []byte
	importpath string
	buf        []byte // for reading strings
	version    int    // export format version

	// object lists
	strList       []string           // in order of appearance
	pathList      []string           // in order of appearance
	pkgList       []*types.Package   // in order of appearance
	typList       []types.Type       // in order of appearance
	interfaceList []*types.Interface // for delayed completion only
	trackAllTypes bool

	// position encoding
	posInfoFormat bool
	prevFile      string
	prevLine      int
	fake          fakeFileSet

	// debugging support
	debugFormat bool
	read        int // bytes read
}

// BImportData imports a package from the serialized package data
// and returns the number of bytes consumed and a reference to the package.
// If the export data version is not recognized or the format is otherwise
// compromised, an error is returned.
func ( *token.FileSet,  map[string]*types.Package,  []byte,  string) ( int,  *types.Package,  error) {
	// catch panics and return them as errors
	const  = 6
	 := -1 // unknown version
	defer func() {
		if  := recover();  != nil {
			// Return a (possibly nil or incomplete) package unchanged (see #16088).
			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{""}, // empty string is mapped to 0
		pathList:   []string{""}, // empty string is mapped to 0
		fake: fakeFileSet{
			fset:  ,
			files: make(map[string]*fileInfo),
		},
	}
	defer .fake.setLines() // set lines for files in fset

	// read version info
	var  string
	if  := .rawByte();  == 'c' ||  == 'd' {
		// Go1.7 encoding; first byte encodes low-level
		// encoding format (compact vs debug).
		// For backward-compatibility only (avoid problems with
		// old installed packages). Newly compiled packages use
		// the extensible format string.
		// TODO(gri) Remove this support eventually; after Go1.8.
		if  == 'd' {
			.debugFormat = true
		}
		.trackAllTypes = .rawByte() == 'a'
		.posInfoFormat = .int() != 0
		 = .string()
		if  == "v1" {
			 = 0
		}
	} else {
		// Go1.8 extensible encoding
		// read version string and extract version number (ignore anything after the version number)
		 = .rawStringln()
		if  := strings.SplitN(, " ", 3); len() >= 2 && [0] == "version" {
			if ,  := strconv.Atoi([1]);  == nil &&  > 0 {
				 = 
			}
		}
	}
	.version = 

	// read version specific flags - extend as necessary
	switch .version {
	// case currentVersion:
	// 	...
	//	fallthrough
	case , 5, 4, 3, 2, 1:
		.debugFormat = .rawStringln(.rawByte()) == "debug"
		.trackAllTypes = .int() != 0
		.posInfoFormat = .int() != 0
	case 0:
		// Go1.7 encoding format - nothing to do here
	default:
		errorf("unknown bexport format version %d (%q)", .version, )
	}

	// --- generic export data ---

	// populate typList with predeclared "known" types
	.typList = append(.typList, predeclared()...)

	// read package data
	 = .pkg()

	// read objects of phase 1 only (see cmd/compile/internal/gc/bexport.go)
	 := 0
	for {
		 := .tagOrIndex()
		if  == endTag {
			break
		}
		.obj()
		++
	}

	// self-verification
	if  := .int();  !=  {
		errorf("got %d objects; want %d", , )
	}

	// ignore compiler-specific import data

	// complete interfaces
	// TODO(gri) re-investigate if we still need to do this in a delayed fashion
	for ,  := range .interfaceList {
		.Complete()
	}

	// record all referenced packages as imports
	 := append(([]*types.Package)(nil), .pkgList[1:]...)
	sort.Sort(byPath())
	.SetImports()

	// package was imported completely and without errors
	.MarkComplete()

	return .read, , nil
}

func ( string,  ...interface{}) {
	panic(fmt.Sprintf(, ...))
}

func ( *importer) () *types.Package {
	// if the package was seen before, i is its index (>= 0)
	 := .tagOrIndex()
	if  >= 0 {
		return .pkgList[]
	}

	// otherwise, i is the package tag (< 0)
	if  != packageTag {
		errorf("unexpected package tag %d version %d", , .version)
	}

	// read package data
	 := .string()
	var  string
	if .version >= 5 {
		 = .path()
	} else {
		 = .string()
	}
	if .version >= 6 {
		.int() // package height; unused by go/types
	}

	// we should never see an empty package name
	if  == "" {
		errorf("empty package name in import")
	}

	// an empty path denotes the package we are currently importing;
	// it must be the first package we see
	if ( == "") != (len(.pkgList) == 0) {
		errorf("package path %q for pkg index %d", , len(.pkgList))
	}

	// if the package was imported before, use that one; otherwise create a new one
	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 
}

// objTag returns the tag value for each object kind.
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)", , ) // panics
		panic("unreachable")
	}
}

func (,  types.Object) bool {
	// Because unnamed types are not canonicalized, we cannot simply compare types for
	// (pointer) identity.
	// Ideally we'd check equality of constant values as well, but this is good enough.
	return objTag() == objTag() && types.Identical(.Type(), .Type())
}

func ( *importer) ( types.Object) {
	 := .Pkg()
	if  := .Scope().Insert();  != nil {
		// This can only trigger if we import a (non-type) object a second time.
		// Excluding type aliases, this cannot happen because 1) we only import a package
		// once; and b) we ignore compiler-specific export data which may contain
		// functions whose inlined function bodies refer to other functions that
		// were already imported.
		// However, type aliases require reexporting the original type, so we need
		// to allow it (see also the comment in cmd/compile/internal/gc/bimport.go,
		// method importer.obj, switch case importing functions).
		// TODO(gri) review/update this comment once the gc compiler handles type aliases.
		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:
		// TODO(gri) verify type alias hookup is correct
		 := .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 // see cmd/compile/internal/gc/bexport.go

func ( *importer) () token.Pos {
	if !.posInfoFormat {
		return token.NoPos
	}

	 := .prevFile
	 := .prevLine
	 := .int()
	 += 
	if .version >= 5 {
		if  == deltaNewFile {
			if  := .int();  >= 0 {
				// file changed
				 = .path()
				 = 
			}
		}
	} else {
		if  == 0 {
			if  := .int();  >= 0 {
				// file changed
				 = .prevFile[:] + .string()
				 = .int()
			}
		}
	}
	.prevFile = 
	.prevLine = 

	return .fake.pos(, , 0)
}

// Synthesize a token.Pos
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 {
	// TODO(mdempsky): Make use of column.

	// Since we don't know the set of needed file positions, we reserve maxlines
	// positions per file. We delay calling token.File.SetLines until all
	// positions have been calculated (by way of fakeFileSet.setLines), so that
	// we can avoid setting unnecessary lines. See also golang/go#46586.
	 := .files[]
	if  == nil {
		 = &fileInfo{file: .fset.AddFile(, -1, maxlines)}
		.files[] = 
	}
	if  > maxlines {
		 = 1
	}
	if  > .lastline {
		.lastline = 
	}

	// Return a fake position assuming that f.file consists only of newlines.
	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, )
}

// A dddSlice is a types.Type representing ...T parameters.
// It only appears for parameter types and does not escape
// the importer.
type dddSlice struct {
	elem types.Type
}

func ( *dddSlice) () types.Type { return  }
func ( *dddSlice) () string         { return "..." + .elem.String() }

// parent is the package which declared the type; parent == nil means
// the package currently imported. The parent package is needed for
// exported struct fields and interface methods which don't contain
// explicit package information in the export data.
//
// A non-nil tname is used as the "owner" of the result type; i.e.,
// the result type is the underlying type of tname. tname is used
// to give interface methods a named receiver type where possible.
func ( *importer) ( *types.Package,  *types.Named) types.Type {
	// if the type was seen before, i is its index (>= 0)
	 := .tagOrIndex()
	if  >= 0 {
		return .typList[]
	}

	// otherwise, i is the type tag (< 0)
	switch  {
	case namedTag:
		// read type object
		 := .pos()
		,  := .qualifiedName()
		 := .Scope()
		 := .Lookup()

		// if the object doesn't exist yet, create and insert it
		if  == nil {
			 = types.NewTypeName(, , , nil)
			.Insert()
		}

		if ,  := .(*types.TypeName); ! {
			errorf("pkg = %s, name = %s => %s", , , )
		}

		// associate new named type with obj if it doesn't exist yet
		 := types.NewNamed(.(*types.TypeName), nil, nil)

		// but record the existing type, if any
		 := .Type().(*types.Named) // tname is either t0 or the existing type
		.record()

		// read underlying type
		.SetUnderlying(.(, ))

		// interfaces don't have associated methods
		if types.IsInterface() {
			return 
		}

		// read associated methods
		for  := .int();  > 0; -- {
			// TODO(gri) replace this with something closer to fieldName
			 := .pos()
			 := .string()
			if !exported() {
				.pkg()
			}

			,  := .paramList() // TODO(gri) do we need a full param list for the receiver?
			,  := .paramList()
			,  := .paramList()
			.int() // go:nointerface pragma - discarded

			 := 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:
		// Create a dummy entry in the type list. This is safe because we
		// cannot expect the interface type to appear in a cycle, as any
		// such cycle must contain a named type which would have been
		// first defined earlier.
		// TODO(gri) Is this still true now that we have type aliases?
		// See issue #23225.
		 := 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", ) // panics
		panic("unreachable")
	}
}

func ( int) types.ChanDir {
	// tag values must match the constants in cmd/compile/internal/gc/go.go
	switch  {
	case 1 /* Crecv */ :
		return types.RecvOnly
	case 2 /* Csend */ :
		return types.SendOnly
	case 3 /* Cboth */ :
		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  == "" {
		// anonymous field - typ must be T or *T and T must be a type name
		switch typ := deref().(type) {
		case *types.Basic: // basic types are named types
			 = nil // // objects defined in Universe scope have no package
			 = .Name()
		case *types.Named:
			 = .Obj().Name()
		default:
			errorf("named base type expected")
		}
		 = true
	} else if  {
		// anonymous field: we have an explicit name because it's an alias
		 = 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()
	// If we don't have a baseType, use a nil receiver.
	// A receiver using the actual interface type (which
	// we don't know yet) will be filled in when we call
	// types.Interface.Complete.
	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 {
		// use the imported package instead
		 = .pkgList[0]
	}
	if .version == 0 &&  == "_" {
		// version 0 didn't export a package for _ fields
		return
	}
	switch  {
	case "":
		// 1) field name matches base type name and is exported: nothing to do
	case "?":
		// 2) field name matches base type name and is not exported: need package
		 = ""
		 = .pkg()
	case "@":
		// 3) field name doesn't match type name (alias)
		 = .string()
		 = true
		fallthrough
	default:
		if !exported() {
			 = .pkg()
		}
	}
	return
}

func ( *importer) () (*types.Tuple, bool) {
	 := .int()
	if  == 0 {
		return nil, false
	}
	// negative length indicates unnamed parameters
	 := true
	if  < 0 {
		 = -
		 = false
	}
	// n > 0
	 := 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 {
			 = [:] // cut off gc-specific parameter numbering
		}
	}

	// read and discard compiler-specific info
	.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", ) // panics
		panic("unreachable")
	}
}

func ( *importer) () constant.Value {
	 := .int()
	if  == 0 {
		return constant.MakeInt64(0)
	}

	 := .int()
	 := []byte(.string()) // big endian

	// remove leading 0's if any
	for len() > 0 && [0] == 0 {
		 = [1:]
	}

	// convert to little endian
	// TODO(gri) go/constant should have a more direct conversion function
	//           (e.g., once it supports a big.Float based implementation)
	for ,  := 0, len()-1;  < ; ,  = +1, -1 {
		[], [] = [], []
	}

	// adjust exponent (constant.MakeFromBytes creates an integer value,
	// but mant represents the mantissa bits such that 0.5 <= mant < 1.0)
	 -= 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 
}

// ----------------------------------------------------------------------------
// Low-level decoders

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')
	}
	// if the path was seen before, i is its index (>= 0)
	// (the empty string is at index 0)
	 := .rawInt64()
	if  >= 0 {
		return .pathList[]
	}
	// otherwise, i is the negative path length (< 0)
	 := make([]string, -)
	for  := range  {
		[] = .string()
	}
	 := strings.Join(, "/")
	.pathList = append(.pathList, )
	return 
}

func ( *importer) () string {
	if .debugFormat {
		.marker('s')
	}
	// if the string was seen before, i is its index (>= 0)
	// (the empty string is at index 0)
	 := .rawInt64()
	if  >= 0 {
		return .strList[]
	}
	// otherwise, i is the negative string length (< 0)
	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", , )
	}
}

// rawInt64 should only be used by low-level decoders.
func ( *importer) () int64 {
	,  := binary.ReadVarint()
	if  != nil {
		errorf("read error: %v", )
	}
	return 
}

// rawStringln should only be used to read the initial version string.
func ( *importer) ( byte) string {
	.buf = .buf[:0]
	for  != '\n' {
		.buf = append(.buf, )
		 = .rawByte()
	}
	return string(.buf)
}

// needed for binary.ReadVarint in rawInt64
func ( *importer) () (byte, error) {
	return .rawByte(), nil
}

// byte is the bottleneck interface for reading p.data.
// It unescapes '|' 'S' to '$' and '|' '|' to '|'.
// rawByte should only be used by low-level decoders.
func ( *importer) () byte {
	 := .data[0]
	 := 1
	if  == '|' {
		 = .data[1]
		 = 2
		switch  {
		case 'S':
			 = '$'
		case '|':
			// nothing to do
		default:
			errorf("unexpected escape sequence in export data")
		}
	}
	.data = .data[:]
	.read += 
	return 

}

// ----------------------------------------------------------------------------
// Export format

// Tags. Must be < 0.
const (
	// Objects
	packageTag = -(iota + 1)
	constTag
	typeTag
	varTag
	funcTag
	endTag

	// Types
	namedTag
	arrayTag
	sliceTag
	dddTag
	structTag
	pointerTag
	signatureTag
	interfaceTag
	mapTag
	chanTag

	// Values
	falseTag
	trueTag
	int64Tag
	floatTag
	fractionTag // not used by gc
	complexTag
	stringTag
	nilTag     // only used by gc (appears in exported inlined function bodies)
	unknownTag // not used by gc (only appears in packages with errors)

	// Type aliases
	aliasTag
)

var predeclOnce sync.Once
var predecl []types.Type // initialized lazily

func () []types.Type {
	predeclOnce.Do(func() {
		// initialize lazily to be sure that all
		// elements have been initialized before
		predecl = []types.Type{ // basic types
			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],

			// basic type aliases
			types.Universe.Lookup("byte").Type(),
			types.Universe.Lookup("rune").Type(),

			// error
			types.Universe.Lookup("error").Type(),

			// untyped types
			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],

			// package unsafe
			types.Typ[types.UnsafePointer],

			// invalid type
			types.Typ[types.Invalid], // only appears in packages with errors

			// used internally by gc; never used by this package or in .a files
			anyType{},
		}
		predecl = append(predecl, additionalPredeclared()...)
	})
	return predecl
}

type anyType struct{}

func ( anyType) () types.Type { return  }
func ( anyType) () string         { return "any" }