//!+ func PrintSkeleton(pkg *types.Package, ifacename, concname string) error { obj := pkg.Scope().Lookup(ifacename) if obj == nil { return fmt.Errorf("%s.%s not found", pkg.Path(), ifacename) } if _, ok := obj.(*types.TypeName); !ok { return fmt.Errorf("%v is not a named type", obj) } iface, ok := obj.Type().Underlying().(*types.Interface) if !ok { return fmt.Errorf("type %v is a %T, not an interface", obj, obj.Type().Underlying()) } // Use first letter of type name as receiver parameter. if !isValidIdentifier(concname) { return fmt.Errorf("invalid concrete type name: %q", concname) } r, _ := utf8.DecodeRuneInString(concname) fmt.Printf("// *%s implements %s.%s.\n", concname, pkg.Path(), ifacename) fmt.Printf("type %s struct{}\n", concname) mset := types.NewMethodSet(iface) for i := 0; i < mset.Len(); i++ { meth := mset.At(i).Obj() sig := types.TypeString(meth.Type(), (*types.Package).Name) fmt.Printf("func (%c *%s) %s%s {\n\tpanic(\"unimplemented\")\n}\n", r, concname, meth.Name(), strings.TrimPrefix(sig, "func")) } return nil }
func (c *converter) convertPackage(v *gotypes.Package) *types.Package { if v == nil { return nil } if v, ok := c.converted[v]; ok { return v.(*types.Package) } ret := types.NewPackage(v.Path(), v.Name()) if c.ret == nil { c.ret = ret } c.converted[v] = ret var imports []*types.Package for _, imported := range v.Imports() { imports = append(imports, c.convertPackage(imported)) } ret.SetImports(imports) c.convertScope(ret.Scope(), v.Scope()) for _, iface := range c.ifaces { iface.Complete() } return ret }
func (b *binder) GenGo(pkg *types.Package, allPkg []*types.Package, outdir string) error { pkgName := "go_" pkgPath := "" if pkg != nil { pkgName += pkg.Name() pkgPath = pkg.Path() } goFile := filepath.Join(outdir, pkgName+"main.go") generate := func(w io.Writer) error { if buildX { printcmd("gobind -lang=go -outdir=%s %s", outdir, pkgPath) } if buildN { return nil } conf := &bind.GeneratorConfig{ Writer: w, Fset: b.fset, Pkg: pkg, AllPkg: allPkg, } return bind.GenGo(conf) } if err := writeFile(goFile, generate); err != nil { return err } return nil }
func (p *exporter) pkg(pkg *types.Package, emptypath bool) { if pkg == nil { log.Fatalf("gcimporter: unexpected nil pkg") } // if we saw the package before, write its index (>= 0) if i, ok := p.pkgIndex[pkg]; ok { p.index('P', i) return } // otherwise, remember the package, write the package tag (< 0) and package data if trace { p.tracef("P%d = { ", len(p.pkgIndex)) defer p.tracef("} ") } p.pkgIndex[pkg] = len(p.pkgIndex) p.tag(packageTag) p.string(pkg.Name()) if emptypath { p.string("") } else { p.string(pkg.Path()) } }
// pkgName retuns the package name and adds the package to the list of // imports. func (g *goGen) pkgName(pkg *types.Package) string { // The error type has no package if pkg == nil { return "" } g.imports[pkg.Path()] = struct{}{} return pkg.Name() + "." }
func (b *binder) GenObjc(pkg *types.Package, allPkg []*types.Package, outdir string) (string, error) { const bindPrefixDefault = "Go" if bindPrefix == "" { bindPrefix = bindPrefixDefault } name := strings.Title(pkg.Name()) bindOption := "-lang=objc" if bindPrefix != bindPrefixDefault { bindOption += " -prefix=" + bindPrefix } fileBase := bindPrefix + name mfile := filepath.Join(outdir, fileBase+".m") hfile := filepath.Join(outdir, fileBase+".h") gohfile := filepath.Join(outdir, pkg.Name()+".h") conf := &bind.GeneratorConfig{ Fset: b.fset, Pkg: pkg, AllPkg: allPkg, } generate := func(w io.Writer) error { if buildX { printcmd("gobind %s -outdir=%s %s", bindOption, outdir, pkg.Path()) } if buildN { return nil } conf.Writer = w return bind.GenObjc(conf, bindPrefix, bind.ObjcM) } if err := writeFile(mfile, generate); err != nil { return "", err } generate = func(w io.Writer) error { if buildN { return nil } conf.Writer = w return bind.GenObjc(conf, bindPrefix, bind.ObjcH) } if err := writeFile(hfile, generate); err != nil { return "", err } generate = func(w io.Writer) error { if buildN { return nil } conf.Writer = w return bind.GenObjc(conf, bindPrefix, bind.ObjcGoH) } if err := writeFile(gohfile, generate); err != nil { return "", err } return fileBase, nil }
func (c *funcContext) pkgVar(pkg *types.Package) string { if pkg == c.p.Pkg { return "$pkg" } pkgVar, found := c.p.pkgVars[pkg.Path()] if !found { pkgVar = fmt.Sprintf(`$packages["%s"]`, pkg.Path()) } return pkgVar }
func pkgFirstElem(p *types.Package) string { if p == nil { return "" } path := p.Path() idx := strings.Index(path, "/") if idx == -1 { return "" } return path[:idx] }
// export emits the exported package features. func (w *Walker) export(pkg *types.Package) { if *verbose { log.Println(pkg) } pop := w.pushScope("pkg " + pkg.Path()) w.current = pkg scope := pkg.Scope() for _, name := range scope.Names() { if ast.IsExported(name) { w.emitObj(scope.Lookup(name)) } } pop() }
func (r *renamer) checkExport(id *ast.Ident, pkg *types.Package, from types.Object) bool { // Reject cross-package references if r.to is unexported. // (Such references may be qualified identifiers or field/method // selections.) if !ast.IsExported(r.to) && pkg != from.Pkg() { r.errorf(from.Pos(), "renaming this %s %q to %q would make it unexported", objectKind(from), from.Name(), r.to) r.errorf(id.Pos(), "\tbreaking references from packages such as %q", pkg.Path()) return false } return true }
func (b *binder) GenJava(pkg *types.Package, allPkg []*types.Package, outdir, javadir string) error { className := strings.Title(pkg.Name()) javaFile := filepath.Join(javadir, className+".java") cFile := filepath.Join(outdir, "java_"+pkg.Name()+".c") hFile := filepath.Join(outdir, pkg.Name()+".h") bindOption := "-lang=java" if bindJavaPkg != "" { bindOption += " -javapkg=" + bindJavaPkg } conf := &bind.GeneratorConfig{ Fset: b.fset, Pkg: pkg, AllPkg: allPkg, } generate := func(w io.Writer) error { if buildX { printcmd("gobind %s -outdir=%s %s", bindOption, javadir, pkg.Path()) } if buildN { return nil } conf.Writer = w return bind.GenJava(conf, bindJavaPkg, bind.Java) } if err := writeFile(javaFile, generate); err != nil { return err } generate = func(w io.Writer) error { if buildN { return nil } conf.Writer = w return bind.GenJava(conf, bindJavaPkg, bind.JavaC) } if err := writeFile(cFile, generate); err != nil { return err } generate = func(w io.Writer) error { if buildN { return nil } conf.Writer = w return bind.GenJava(conf, bindJavaPkg, bind.JavaH) } return writeFile(hFile, generate) }
func (b *binder) GenObjc(pkg *types.Package, outdir string) (string, error) { const bindPrefixDefault = "Go" if bindPrefix == "" { bindPrefix = bindPrefixDefault } name := strings.Title(pkg.Name()) bindOption := "-lang=objc" if bindPrefix != bindPrefixDefault { bindOption += " -prefix=" + bindPrefix } fileBase := bindPrefix + name mfile := filepath.Join(outdir, fileBase+".m") hfile := filepath.Join(outdir, fileBase+".h") generate := func(w io.Writer) error { if buildX { printcmd("gobind %s -outdir=%s %s", bindOption, outdir, pkg.Path()) } if buildN { return nil } return bind.GenObjc(w, b.fset, pkg, bindPrefix, false) } if err := writeFile(mfile, generate); err != nil { return "", err } generate = func(w io.Writer) error { if buildN { return nil } return bind.GenObjc(w, b.fset, pkg, bindPrefix, true) } if err := writeFile(hfile, generate); err != nil { return "", err } objcPkg, err := ctx.Import("golang.org/x/mobile/bind/objc", "", build.FindOnly) if err != nil { return "", err } if err := copyFile(filepath.Join(outdir, "seq.h"), filepath.Join(objcPkg.Dir, "seq.h")); err != nil { return "", err } return fileBase, nil }
func (b *binder) GenGo(pkg *types.Package, outdir string) error { pkgName := "go_" + pkg.Name() outdir = filepath.Join(outdir, pkgName) goFile := filepath.Join(outdir, pkgName+"main.go") generate := func(w io.Writer) error { if buildX { printcmd("gobind -lang=go -outdir=%s %s", outdir, pkg.Path()) } if buildN { return nil } return bind.GenGo(w, b.fset, pkg) } if err := writeFile(goFile, generate); err != nil { return err } return nil }
// BuildPackage builds an SSA program with IR for a single package. // // It populates pkg by type-checking the specified file ASTs. All // dependencies are loaded using the importer specified by tc, which // typically loads compiler export data; SSA code cannot be built for // those packages. BuildPackage then constructs an ssa.Program with all // dependency packages created, and builds and returns the SSA package // corresponding to pkg. // // The caller must have set pkg.Path() to the import path. // // The operation fails if there were any type-checking or import errors. // // See ../ssa/example_test.go for an example. // func BuildPackage(tc *types.Config, fset *token.FileSet, pkg *types.Package, files []*ast.File, mode ssa.BuilderMode) (*ssa.Package, *types.Info, error) { if fset == nil { panic("no token.FileSet") } if pkg.Path() == "" { panic("package has no import path") } info := &types.Info{ Types: make(map[ast.Expr]types.TypeAndValue), Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), Implicits: make(map[ast.Node]types.Object), Scopes: make(map[ast.Node]*types.Scope), Selections: make(map[*ast.SelectorExpr]*types.Selection), } if err := types.NewChecker(tc, fset, pkg, info).Files(files); err != nil { return nil, nil, err } prog := ssa.NewProgram(fset, mode) // Create SSA packages for all imports. // Order is not significant. created := make(map[*types.Package]bool) var createAll func(pkgs []*types.Package) createAll = func(pkgs []*types.Package) { for _, p := range pkgs { if !created[p] { created[p] = true prog.CreatePackage(p, nil, nil, true) createAll(p.Imports()) } } } createAll(pkg.Imports()) // Create and build the primary package. ssapkg := prog.CreatePackage(pkg, files, info, false) ssapkg.Build() return ssapkg, info, nil }
func (b *binder) GenJava(pkg *types.Package, outdir string) error { className := strings.Title(pkg.Name()) javaFile := filepath.Join(outdir, className+".java") bindOption := "-lang=java" if bindJavaPkg != "" { bindOption += " -javapkg=" + bindJavaPkg } generate := func(w io.Writer) error { if buildX { printcmd("gobind %s -outdir=%s %s", bindOption, outdir, pkg.Path()) } if buildN { return nil } return bind.GenJava(w, b.fset, pkg, bindJavaPkg) } if err := writeFile(javaFile, generate); err != nil { return err } return nil }
func findFromObjects(iprog *loader.Program, spec *spec) ([]types.Object, error) { if spec.filename != "" { return findFromObjectsInFile(iprog, spec) } // Search for objects defined in specified package. // TODO(adonovan): the iprog.ImportMap has an entry {"main": ...} // for main packages, even though that's not an import path. // Seems like a bug. // // pkg := iprog.ImportMap[spec.pkg] // if pkg == nil { // return fmt.Errorf("cannot find package %s", spec.pkg) // can't happen? // } // info := iprog.AllPackages[pkg] // Workaround: lookup by value. var info *loader.PackageInfo var pkg *types.Package for pkg, info = range iprog.AllPackages { if pkg.Path() == spec.pkg { break } } if info == nil { return nil, fmt.Errorf("package %q was not loaded", spec.pkg) } objects, err := findObjects(info, spec) if err != nil { return nil, err } if len(objects) > 1 { // ambiguous "*" scope query return nil, ambiguityError(iprog.Fset, objects) } return objects, nil }
func (p *exporter) pkg(pkg *types.Package) { if trace { p.tracef("package { ") defer p.tracef("} ") } if pkg == nil { panic("unexpected nil pkg") } // if the package was seen before, write its index (>= 0) if i, ok := p.pkgIndex[pkg]; ok { p.int(i) return } p.pkgIndex[pkg] = len(p.pkgIndex) // otherwise, write the package tag (< 0) and package data p.int(packageTag) p.string(pkg.Name()) p.string(pkg.Path()) }
func describePackage(qpos *queryPos, path []ast.Node) (*describePackageResult, error) { var description string var pkg *types.Package switch n := path[0].(type) { case *ast.ImportSpec: var obj types.Object if n.Name != nil { obj = qpos.info.Defs[n.Name] } else { obj = qpos.info.Implicits[n] } pkgname, _ := obj.(*types.PkgName) if pkgname == nil { return nil, fmt.Errorf("can't import package %s", n.Path.Value) } pkg = pkgname.Imported() description = fmt.Sprintf("import of package %q", pkg.Path()) case *ast.Ident: if _, isDef := path[1].(*ast.File); isDef { // e.g. package id pkg = qpos.info.Pkg description = fmt.Sprintf("definition of package %q", pkg.Path()) } else { // e.g. import id "..." // or id.F() pkg = qpos.info.ObjectOf(n).(*types.PkgName).Imported() description = fmt.Sprintf("reference to package %q", pkg.Path()) } default: // Unreachable? return nil, fmt.Errorf("unexpected AST for package: %T", n) } var members []*describeMember // NB: "unsafe" has no types.Package if pkg != nil { // Enumerate the accessible package members // in lexicographic order. for _, name := range pkg.Scope().Names() { if pkg == qpos.info.Pkg || ast.IsExported(name) { mem := pkg.Scope().Lookup(name) var methods []*types.Selection if mem, ok := mem.(*types.TypeName); ok { methods = accessibleMethods(mem.Type(), qpos.info.Pkg) } members = append(members, &describeMember{ mem, methods, }) } } } return &describePackageResult{qpos.fset, path[0], description, pkg, members}, nil }
func IsJsPackage(pkg *types.Package) bool { return pkg != nil && pkg.Path() == "github.com/gopherjs/gopherjs/js" }
func IsJsPackage(pkg *types.Package) bool { return pkg != nil && (pkg.Path() == "github.com/gopherjs/gopherjs/js" || strings.HasSuffix(pkg.Path(), "/vendor/github.com/gopherjs/gopherjs/js")) }
// Transform applies the transformation to the specified parsed file, // whose type information is supplied in info, and returns the number // of replacements that were made. // // It mutates the AST in place (the identity of the root node is // unchanged), and may add nodes for which no type information is // available in info. // // Derived from rewriteFile in $GOROOT/src/cmd/gofmt/rewrite.go. // func (tr *Transformer) Transform(info *types.Info, pkg *types.Package, file *ast.File) int { if !tr.seenInfos[info] { tr.seenInfos[info] = true mergeTypeInfo(tr.info, info) } tr.currentPkg = pkg tr.nsubsts = 0 if tr.verbose { fmt.Fprintf(os.Stderr, "before: %s\n", astString(tr.fset, tr.before)) fmt.Fprintf(os.Stderr, "after: %s\n", astString(tr.fset, tr.after)) } var f func(rv reflect.Value) reflect.Value f = func(rv reflect.Value) reflect.Value { // don't bother if val is invalid to start with if !rv.IsValid() { return reflect.Value{} } rv = apply(f, rv) e := rvToExpr(rv) if e != nil { savedEnv := tr.env tr.env = make(map[string]ast.Expr) // inefficient! Use a slice of k/v pairs if tr.matchExpr(tr.before, e) { if tr.verbose { fmt.Fprintf(os.Stderr, "%s matches %s", astString(tr.fset, tr.before), astString(tr.fset, e)) if len(tr.env) > 0 { fmt.Fprintf(os.Stderr, " with:") for name, ast := range tr.env { fmt.Fprintf(os.Stderr, " %s->%s", name, astString(tr.fset, ast)) } } fmt.Fprintf(os.Stderr, "\n") } tr.nsubsts++ // Clone the replacement tree, performing parameter substitution. // We update all positions to n.Pos() to aid comment placement. rv = tr.subst(tr.env, reflect.ValueOf(tr.after), reflect.ValueOf(e.Pos())) } tr.env = savedEnv } return rv } file2 := apply(f, reflect.ValueOf(file)).Interface().(*ast.File) // By construction, the root node is unchanged. if file != file2 { panic("BUG") } // Add any necessary imports. // TODO(adonovan): remove no-longer needed imports too. if tr.nsubsts > 0 { pkgs := make(map[string]*types.Package) for obj := range tr.importedObjs { pkgs[obj.Pkg().Path()] = obj.Pkg() } for _, imp := range file.Imports { path, _ := strconv.Unquote(imp.Path.Value) delete(pkgs, path) } delete(pkgs, pkg.Path()) // don't import self // NB: AddImport may completely replace the AST! // It thus renders info and tr.info no longer relevant to file. var paths []string for path := range pkgs { paths = append(paths, path) } sort.Strings(paths) for _, path := range paths { astutil.AddImport(tr.fset, file, path) } } tr.currentPkg = nil return tr.nsubsts }
func (b *binder) GenJava(pkg *types.Package, allPkg []*types.Package, classes []*java.Class, outdir, androidDir string) error { jpkgname := bind.JavaPkgName(bindJavaPkg, pkg) javadir := filepath.Join(androidDir, strings.Replace(jpkgname, ".", "/", -1)) var className string pkgName := "" pkgPath := "" javaPkg := "" if pkg != nil { className = strings.Title(pkg.Name()) pkgName = pkg.Name() pkgPath = pkg.Path() javaPkg = bindJavaPkg } else { pkgName = "universe" className = "Universe" } javaFile := filepath.Join(javadir, className+".java") cFile := filepath.Join(outdir, "java_"+pkgName+".c") hFile := filepath.Join(outdir, pkgName+".h") bindOption := "-lang=java" if javaPkg != "" { bindOption += " -javapkg=" + javaPkg } var buf bytes.Buffer g := &bind.JavaGen{ JavaPkg: javaPkg, Generator: &bind.Generator{ Printer: &bind.Printer{Buf: &buf, IndentEach: []byte(" ")}, Fset: b.fset, AllPkg: allPkg, Pkg: pkg, }, } g.Init(classes) generate := func(w io.Writer) error { if buildX { printcmd("gobind %s -outdir=%s %s", bindOption, javadir, pkgPath) } if buildN { return nil } buf.Reset() if err := g.GenJava(); err != nil { return err } _, err := io.Copy(w, &buf) return err } if err := writeFile(javaFile, generate); err != nil { return err } for i, name := range g.ClassNames() { generate := func(w io.Writer) error { if buildN { return nil } buf.Reset() if err := g.GenClass(i); err != nil { return err } _, err := io.Copy(w, &buf) return err } classFile := filepath.Join(javadir, name+".java") if err := writeFile(classFile, generate); err != nil { return err } } generate = func(w io.Writer) error { if buildN { return nil } buf.Reset() if err := g.GenC(); err != nil { return err } _, err := io.Copy(w, &buf) return err } if err := writeFile(cFile, generate); err != nil { return err } generate = func(w io.Writer) error { if buildN { return nil } buf.Reset() if err := g.GenH(); err != nil { return err } _, err := io.Copy(w, &buf) return err } return writeFile(hFile, generate) }
func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) { // collect objects by kind var ( consts []*types.Const typem []*types.Named // non-interface types with methods typez []*types.TypeName // interfaces or types without methods vars []*types.Var funcs []*types.Func builtins []*types.Builtin methods = make(map[*types.Named][]*types.Selection) // method sets for named types ) scope := pkg.Scope() for _, name := range scope.Names() { obj := scope.Lookup(name) if obj.Exported() { // collect top-level exported and possibly filtered objects if filter == nil || filter(obj) { switch obj := obj.(type) { case *types.Const: consts = append(consts, obj) case *types.TypeName: // group into types with methods and types without if named, m := methodsFor(obj); named != nil { typem = append(typem, named) methods[named] = m } else { typez = append(typez, obj) } case *types.Var: vars = append(vars, obj) case *types.Func: funcs = append(funcs, obj) case *types.Builtin: // for unsafe.Sizeof, etc. builtins = append(builtins, obj) } } } else if filter == nil { // no filtering: collect top-level unexported types with methods if obj, _ := obj.(*types.TypeName); obj != nil { // see case *types.TypeName above if named, m := methodsFor(obj); named != nil { typem = append(typem, named) methods[named] = m } } } } p.printf("package %s // %q\n", pkg.Name(), pkg.Path()) p.printDecl("const", len(consts), func() { for _, obj := range consts { p.printObj(obj) p.print("\n") } }) p.printDecl("var", len(vars), func() { for _, obj := range vars { p.printObj(obj) p.print("\n") } }) p.printDecl("type", len(typez), func() { for _, obj := range typez { p.printf("%s ", obj.Name()) p.writeType(p.pkg, obj.Type().Underlying()) p.print("\n") } }) // non-interface types with methods for _, named := range typem { first := true if obj := named.Obj(); obj.Exported() { if first { p.print("\n") first = false } p.printf("type %s ", obj.Name()) p.writeType(p.pkg, named.Underlying()) p.print("\n") } for _, m := range methods[named] { if obj := m.Obj(); obj.Exported() { if first { p.print("\n") first = false } p.printFunc(m.Recv(), obj.(*types.Func)) p.print("\n") } } } if len(funcs) > 0 { p.print("\n") for _, obj := range funcs { p.printFunc(nil, obj) p.print("\n") } } // TODO(gri) better handling of builtins (package unsafe only) if len(builtins) > 0 { p.print("\n") for _, obj := range builtins { p.printf("func %s() // builtin\n", obj.Name()) } } p.print("\n") }
func (b *binder) GenObjc(pkg *types.Package, allPkg []*types.Package, outdir string, wrappers []*objc.Named) (string, error) { const bindPrefixDefault = "Go" if bindPrefix == "" || pkg == nil { bindPrefix = bindPrefixDefault } pkgName := "" pkgPath := "" if pkg != nil { pkgName = pkg.Name() pkgPath = pkg.Path() } else { pkgName = "universe" } bindOption := "-lang=objc" if bindPrefix != bindPrefixDefault { bindOption += " -prefix=" + bindPrefix } fileBase := bindPrefix + strings.Title(pkgName) mfile := filepath.Join(outdir, fileBase+".m") hfile := filepath.Join(outdir, fileBase+".h") gohfile := filepath.Join(outdir, pkgName+".h") var buf bytes.Buffer g := &bind.ObjcGen{ Generator: &bind.Generator{ Printer: &bind.Printer{Buf: &buf, IndentEach: []byte("\t")}, Fset: b.fset, AllPkg: allPkg, Pkg: pkg, }, Prefix: bindPrefix, } g.Init(wrappers) generate := func(w io.Writer) error { if buildX { printcmd("gobind %s -outdir=%s %s", bindOption, outdir, pkgPath) } if buildN { return nil } buf.Reset() if err := g.GenM(); err != nil { return err } _, err := io.Copy(w, &buf) return err } if err := writeFile(mfile, generate); err != nil { return "", err } generate = func(w io.Writer) error { if buildN { return nil } buf.Reset() if err := g.GenH(); err != nil { return err } _, err := io.Copy(w, &buf) return err } if err := writeFile(hfile, generate); err != nil { return "", err } generate = func(w io.Writer) error { if buildN { return nil } buf.Reset() if err := g.GenGoH(); err != nil { return err } _, err := io.Copy(w, &buf) return err } if err := writeFile(gohfile, generate); err != nil { return "", err } return fileBase, nil }
// pkgName retuns the package name and adds the package to the list of // imports. func (g *goGen) pkgName(pkg *types.Package) string { g.imports[pkg.Path()] = struct{}{} return pkg.Name() }