blob: f151719922041ca2b6de3c1c544802c311246c5f [file] [log] [blame]
// 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 ""
}