func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
	rootMap := make(map[string]int, len(roots))
	for i, root := range roots {
		rootMap[root] = i
	}
	ld.pkgs = make(map[string]*loaderPackage)
	var initial = make([]*loaderPackage, len(roots))
	for _, pkg := range list {
		rootIndex := -1
		if i, found := rootMap[pkg.ID]; found {
			rootIndex = i
		}
		lpkg := &loaderPackage{
			Package: pkg,
			needtypes: ld.Mode >= LoadAllSyntax ||
				ld.Mode >= LoadTypes && rootIndex >= 0,
			needsrc: ld.Mode >= LoadAllSyntax ||
				ld.Mode >= LoadSyntax && rootIndex >= 0 ||
				len(ld.Overlay) > 0 ||  
				pkg.ExportFile == "" && pkg.PkgPath != "unsafe",
		}
		ld.pkgs[lpkg.ID] = lpkg
		if rootIndex >= 0 {
			initial[rootIndex] = lpkg
			lpkg.initial = true
		}
	}
	for i, root := range roots {
		if initial[i] == nil {
			return nil, fmt.Errorf("root package %v is missing", root)
		}
	}
	const (
		white = 0  
		grey  = 1  
		black = 2  
	)
	var stack []*loaderPackage
	var visit func(lpkg *loaderPackage) bool
	var srcPkgs []*loaderPackage
	visit = func(lpkg *loaderPackage) bool {
		switch lpkg.color {
		case black:
			return lpkg.needsrc
		case grey:
			panic("internal error: grey node")
		}
		lpkg.color = grey
		stack = append(stack, lpkg)  
		stubs := lpkg.Imports        
		lpkg.Imports = make(map[string]*Package, len(stubs))
		for importPath, ipkg := range stubs {
			var importErr error
			imp := ld.pkgs[ipkg.ID]
			if imp == nil {
				importErr = fmt.Errorf("missing package: %q", ipkg.ID)
			} else if imp.color == grey {
				importErr = fmt.Errorf("import cycle: %s", stack)
			}
			if importErr != nil {
				if lpkg.importErrors == nil {
					lpkg.importErrors = make(map[string]error)
				}
				lpkg.importErrors[importPath] = importErr
				continue
			}
			if visit(imp) {
				lpkg.needsrc = true
			}
			lpkg.Imports[importPath] = imp.Package
		}
		if lpkg.needsrc {
			srcPkgs = append(srcPkgs, lpkg)
		}
		stack = stack[:len(stack)-1]  
		lpkg.color = black
		return lpkg.needsrc
	}
	if ld.Mode < LoadImports {
		for _, lpkg := range initial {
			lpkg.Imports = nil
		}
	} else {
		for _, lpkg := range initial {
			visit(lpkg)
		}
	}
	for _, lpkg := range srcPkgs {
		for _, ipkg := range lpkg.Imports {
			imp := ld.pkgs[ipkg.ID]
			imp.needtypes = true
		}
	}
	if ld.Mode >= LoadTypes {
		var wg sync.WaitGroup
		for _, lpkg := range initial {
			wg.Add(1)
			go func(lpkg *loaderPackage) {
				ld.loadRecursive(lpkg)
				wg.Done()
			}(lpkg)
		}
		wg.Wait()
	}
	result := make([]*Package, len(initial))
	for i, lpkg := range initial {
		result[i] = lpkg.Package
	}
	return result, nil
}
refine connects the supplied packages into a graph and then adds type and
and syntax information as requested by the LoadMode.
package packages
import (
	"context"
	"encoding/json"
	"fmt"
	"go/ast"
	"go/parser"
	"go/scanner"
	"go/token"
	"go/types"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"golang.org/x/tools/go/gcexportdata"
)
type LoadMode int
const (
	LoadFiles LoadMode = iota
	LoadImports
	LoadTypes
	LoadSyntax
	LoadAllSyntax
)
type Config struct {
	Mode LoadMode
	Context context.Context
	Dir string
	Env []string
	BuildFlags []string
	Fset *token.FileSet
	ParseFile func(fset *token.FileSet, filename string, src []byte) (*ast.File, error)
	Tests bool
	Overlay map[string][]byte
}
type driver func(cfg *Config, patterns ...string) (*driverResponse, error)
type driverResponse struct {
	Sizes *types.StdSizes
	Roots []string `json:",omitempty"`
	Packages []*Package
}
func Load(cfg *Config, patterns ...string) ([]*Package, error) {
	l := newLoader(cfg)
	response, err := defaultDriver(&l.Config, patterns...)
	if err != nil {
		return nil, err
	}
	l.sizes = response.Sizes
	return l.refine(response.Roots, response.Packages...)
}
func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
	driver := findExternalDriver(cfg)
	if driver == nil {
		driver = goListDriver
	}
	return driver(cfg, patterns...)
}
type Package struct {
	ID string
	Name string
	PkgPath string
	Errors []Error
	GoFiles []string
	CompiledGoFiles []string
	OtherFiles []string
	ExportFile string
	Imports map[string]*Package
	Types *types.Package
	Fset *token.FileSet
	IllTyped bool
	Syntax []*ast.File
	TypesInfo *types.Info
	TypesSizes types.Sizes
}
type Error struct {
	Pos  string  
	Msg  string
	Kind ErrorKind
}
type ErrorKind int
const (
	UnknownError ErrorKind = iota
	ListError
	ParseError
	TypeError
)
func (err Error) Error() string {
	pos := err.Pos
	if pos == "" {
		pos = "-"  
	}
	return pos + ": " + err.Msg
}
type flatPackage struct {
	ID              string
	Name            string            `json:",omitempty"`
	PkgPath         string            `json:",omitempty"`
	Errors          []Error           `json:",omitempty"`
	GoFiles         []string          `json:",omitempty"`
	CompiledGoFiles []string          `json:",omitempty"`
	OtherFiles      []string          `json:",omitempty"`
	ExportFile      string            `json:",omitempty"`
	Imports         map[string]string `json:",omitempty"`
}
func (p *Package) MarshalJSON() ([]byte, error) {
	flat := &flatPackage{
		ID:              p.ID,
		Name:            p.Name,
		PkgPath:         p.PkgPath,
		Errors:          p.Errors,
		GoFiles:         p.GoFiles,
		CompiledGoFiles: p.CompiledGoFiles,
		OtherFiles:      p.OtherFiles,
		ExportFile:      p.ExportFile,
	}
	if len(p.Imports) > 0 {
		flat.Imports = make(map[string]string, len(p.Imports))
		for path, ipkg := range p.Imports {
			flat.Imports[path] = ipkg.ID
		}
	}
	return json.Marshal(flat)
}
func (p *Package) UnmarshalJSON(b []byte) error {
	flat := &flatPackage{}
	if err := json.Unmarshal(b, &flat); err != nil {
		return err
	}
	*p = Package{
		ID:              flat.ID,
		Name:            flat.Name,
		PkgPath:         flat.PkgPath,
		Errors:          flat.Errors,
		GoFiles:         flat.GoFiles,
		CompiledGoFiles: flat.CompiledGoFiles,
		OtherFiles:      flat.OtherFiles,
		ExportFile:      flat.ExportFile,
	}
	if len(flat.Imports) > 0 {
		p.Imports = make(map[string]*Package, len(flat.Imports))
		for path, id := range flat.Imports {
			p.Imports[path] = &Package{ID: id}
		}
	}
	return nil
}
func (p *Package) String() string { return p.ID }
type loaderPackage struct {
	*Package
	importErrors map[string]error  
	loadOnce     sync.Once
	color        uint8  
	needsrc      bool   
	needtypes    bool   
	initial      bool   
}
type loader struct {
	pkgs map[string]*loaderPackage
	Config
	sizes    types.Sizes
	exportMu sync.Mutex  
}
func newLoader(cfg *Config) *loader {
	ld := &loader{}
	if cfg != nil {
		ld.Config = *cfg
	}
	if ld.Config.Env == nil {
		ld.Config.Env = os.Environ()
	}
	if ld.Context == nil {
		ld.Context = context.Background()
	}
	if ld.Dir == "" {
		if dir, err := os.Getwd(); err == nil {
			ld.Dir = dir
		}
	}
	if ld.Mode >= LoadTypes {
		if ld.Fset == nil {
			ld.Fset = token.NewFileSet()
		}
		if ld.ParseFile == nil {
			ld.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) {
				var isrc interface{}
				if src != nil {
					isrc = src
				}
				const mode = parser.AllErrors | parser.ParseComments
				return parser.ParseFile(fset, filename, isrc, mode)
			}
		}
	}
	return ld
}