| package ssa |
| |
| // This file defines an implementation of the types.Importer interface |
| // (func) that loads the transitive closure of dependencies of a |
| // "main" package. |
| |
| import ( |
| "go/ast" |
| "go/build" |
| "go/parser" |
| "go/token" |
| "os" |
| "path/filepath" |
| |
| "code.google.com/p/go.exp/go/types" |
| ) |
| |
| // Prototype of a function that locates, reads and parses a set of |
| // source files given an import path. |
| // |
| // fset is the fileset to which the ASTs should be added. |
| // path is the imported path, e.g. "sync/atomic". |
| // |
| // On success, the function returns files, the set of ASTs produced, |
| // or the first error encountered. |
| // |
| type SourceLoader func(fset *token.FileSet, path string) (files []*ast.File, err error) |
| |
| // doImport loads the typechecker package identified by path |
| // Implements the types.Importer prototype. |
| // |
| func (b *Builder) doImport(imports map[string]*types.Package, path string) (typkg *types.Package, err error) { |
| // Package unsafe is handled specially, and has no ssa.Package. |
| if path == "unsafe" { |
| return types.Unsafe, nil |
| } |
| |
| if pkg := b.Prog.Packages[path]; pkg != nil { |
| typkg = pkg.Types |
| imports[path] = typkg |
| return // positive cache hit |
| } |
| |
| if err = b.importErrs[path]; err != nil { |
| return // negative cache hit |
| } |
| var files []*ast.File |
| if b.mode&UseGCImporter != 0 { |
| typkg, err = types.GcImport(imports, path) |
| } else { |
| files, err = b.loader(b.Prog.Files, path) |
| if err == nil { |
| typkg, err = b.typechecker.Check(b.Prog.Files, files) |
| } |
| } |
| if err != nil { |
| // Cache failure |
| b.importErrs[path] = err |
| return nil, err |
| } |
| |
| // Cache success |
| imports[path] = typkg // cache for just this package. |
| b.Prog.Packages[path] = b.createPackageImpl(typkg, path, files) // cache across all packages |
| |
| return typkg, nil |
| } |
| |
| // GorootLoader is an implementation of the SourceLoader function |
| // prototype that loads and parses Go source files from the package |
| // directory beneath $GOROOT/src/pkg. |
| // |
| // TODO(adonovan): get rsc and adg (go/build owners) to review this. |
| // |
| func GorootLoader(fset *token.FileSet, path string) (files []*ast.File, err error) { |
| // TODO(adonovan): fix: Do we need cwd? Shouldn't ImportDir(path) / $GOROOT suffice? |
| srcDir, err := os.Getwd() |
| if err != nil { |
| return // serious misconfiguration |
| } |
| bp, err := build.Import(path, srcDir, 0) |
| if err != nil { |
| return // import failed |
| } |
| files, err = ParseFiles(fset, bp.Dir, bp.GoFiles...) |
| if err != nil { |
| return nil, err |
| } |
| return |
| } |
| |
| // ParseFiles parses the Go source files files within directory dir |
| // and returns their ASTs, or the first parse error if any. |
| // |
| // This utility function is provided to facilitate implementing a |
| // SourceLoader. |
| // |
| func ParseFiles(fset *token.FileSet, dir string, files ...string) (parsed []*ast.File, err error) { |
| for _, file := range files { |
| var f *ast.File |
| if !filepath.IsAbs(file) { |
| file = filepath.Join(dir, file) |
| } |
| f, err = parser.ParseFile(fset, file, nil, parser.DeclarationErrors) |
| if err != nil { |
| return // parsing failed |
| } |
| parsed = append(parsed, f) |
| } |
| return |
| } |