| // Copyright 2014 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. |
| |
| package main |
| |
| import ( |
| "go/ast" |
| "go/build" |
| "go/parser" |
| "go/scanner" |
| "go/token" |
| "go/types" |
| "io" |
| "os" |
| "path/filepath" |
| "unicode" |
| "unicode/utf8" |
| |
| "golang.org/x/mobile/bind" |
| "golang.org/x/mobile/internal/loader" |
| ) |
| |
| func genPkg(pkg *build.Package) { |
| files := parseFiles(pkg.Dir, pkg.GoFiles) |
| if len(files) == 0 { |
| return // some error has been reported |
| } |
| |
| conf := loader.Config{ |
| Fset: fset, |
| AllowErrors: true, |
| } |
| conf.TypeChecker.IgnoreFuncBodies = true |
| conf.TypeChecker.FakeImportC = true |
| conf.TypeChecker.DisableUnusedImportCheck = true |
| var tcErrs []error |
| conf.TypeChecker.Error = func(err error) { |
| tcErrs = append(tcErrs, err) |
| } |
| conf.CreateFromFiles(pkg.ImportPath, files...) |
| program, err := conf.Load() |
| if err != nil { |
| for _, err := range tcErrs { |
| errorf("%v", err) |
| } |
| errorf("%v", err) |
| return |
| } |
| p := program.Created[0].Pkg |
| |
| fname := defaultFileName(*lang, p) |
| switch *lang { |
| case "java": |
| w, closer := writer(fname, p) |
| processErr(bind.GenJava(w, fset, p, *javaPkg)) |
| closer() |
| case "go": |
| w, closer := writer(fname, p) |
| processErr(bind.GenGo(w, fset, p)) |
| closer() |
| case "objc": |
| if fname == "" { |
| processErr(bind.GenObjc(os.Stdout, fset, p, *prefix, true)) |
| processErr(bind.GenObjc(os.Stdout, fset, p, *prefix, false)) |
| } else { |
| hname := fname[:len(fname)-2] + ".h" |
| w, closer := writer(hname, p) |
| processErr(bind.GenObjc(w, fset, p, *prefix, true)) |
| closer() |
| w, closer = writer(fname, p) |
| processErr(bind.GenObjc(w, fset, p, *prefix, false)) |
| closer() |
| } |
| default: |
| errorf("unknown target language: %q", *lang) |
| } |
| } |
| |
| func processErr(err error) { |
| if err != nil { |
| if list, _ := err.(bind.ErrorList); len(list) > 0 { |
| for _, err := range list { |
| errorf("%v", err) |
| } |
| } else { |
| errorf("%v", err) |
| } |
| } |
| } |
| |
| var fset = token.NewFileSet() |
| |
| func parseFiles(dir string, filenames []string) []*ast.File { |
| var files []*ast.File |
| hasErr := false |
| for _, filename := range filenames { |
| path := filepath.Join(dir, filename) |
| file, err := parser.ParseFile(fset, path, nil, parser.AllErrors) |
| if err != nil { |
| hasErr = true |
| if list, _ := err.(scanner.ErrorList); len(list) > 0 { |
| for _, err := range list { |
| errorf("%v", err) |
| } |
| } else { |
| errorf("%v", err) |
| } |
| } |
| files = append(files, file) |
| } |
| if hasErr { |
| return nil |
| } |
| return files |
| } |
| |
| func writer(fname string, pkg *types.Package) (w io.Writer, closer func()) { |
| if fname == "" { |
| return os.Stdout, func() { return } |
| } |
| |
| dir := filepath.Dir(fname) |
| if err := os.MkdirAll(dir, 0755); err != nil { |
| errorf("invalid output dir: %v", err) |
| os.Exit(exitStatus) |
| } |
| |
| f, err := os.Create(fname) |
| if err != nil { |
| errorf("invalid output dir: %v", err) |
| os.Exit(exitStatus) |
| } |
| closer = func() { |
| if err := f.Close(); err != nil { |
| errorf("error in closing output file: %v", err) |
| } |
| } |
| return f, closer |
| } |
| |
| func defaultFileName(lang string, pkg *types.Package) string { |
| if *outdir == "" { |
| return "" |
| } |
| |
| switch lang { |
| case "java": |
| firstRune, size := utf8.DecodeRuneInString(pkg.Name()) |
| className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:] |
| return filepath.Join(*outdir, className+".java") |
| case "go": |
| return filepath.Join(*outdir, "go_"+pkg.Name()+".go") |
| case "objc": |
| firstRune, size := utf8.DecodeRuneInString(pkg.Name()) |
| className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:] |
| return filepath.Join(*outdir, "Go"+className+".m") |
| } |
| errorf("unknown target language: %q", lang) |
| os.Exit(exitStatus) |
| return "" |
| } |