github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/cmd/gobind/gen.go (about)

     1  // Copyright 2014 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"go/ast"
     9  	"go/build"
    10  	"go/parser"
    11  	"go/scanner"
    12  	"go/token"
    13  	"go/types"
    14  	"io"
    15  	"os"
    16  	"path/filepath"
    17  	"unicode"
    18  	"unicode/utf8"
    19  
    20  	"github.com/c-darwin/mobile/bind"
    21  	"github.com/c-darwin/mobile/internal/loader"
    22  )
    23  
    24  func genPkg(pkg *build.Package) {
    25  	files := parseFiles(pkg.Dir, pkg.GoFiles)
    26  	if len(files) == 0 {
    27  		return // some error has been reported
    28  	}
    29  
    30  	conf := loader.Config{
    31  		Fset:        fset,
    32  		AllowErrors: true,
    33  	}
    34  	conf.TypeChecker.IgnoreFuncBodies = true
    35  	conf.TypeChecker.FakeImportC = true
    36  	conf.TypeChecker.DisableUnusedImportCheck = true
    37  	var tcErrs []error
    38  	conf.TypeChecker.Error = func(err error) {
    39  		tcErrs = append(tcErrs, err)
    40  	}
    41  	conf.CreateFromFiles(pkg.ImportPath, files...)
    42  	program, err := conf.Load()
    43  	if err != nil {
    44  		for _, err := range tcErrs {
    45  			errorf("%v", err)
    46  		}
    47  		errorf("%v", err)
    48  		return
    49  	}
    50  	p := program.Created[0].Pkg
    51  
    52  	fname := defaultFileName(*lang, p)
    53  	switch *lang {
    54  	case "java":
    55  		w, closer := writer(fname, p)
    56  		processErr(bind.GenJava(w, fset, p))
    57  		closer()
    58  	case "go":
    59  		w, closer := writer(fname, p)
    60  		processErr(bind.GenGo(w, fset, p))
    61  		closer()
    62  	case "objc":
    63  		if fname == "" {
    64  			processErr(bind.GenObjc(os.Stdout, fset, p, true))
    65  			processErr(bind.GenObjc(os.Stdout, fset, p, false))
    66  		} else {
    67  			hname := fname[:len(fname)-2] + ".h"
    68  			w, closer := writer(hname, p)
    69  			processErr(bind.GenObjc(w, fset, p, true))
    70  			closer()
    71  			w, closer = writer(fname, p)
    72  			processErr(bind.GenObjc(w, fset, p, false))
    73  			closer()
    74  		}
    75  	default:
    76  		errorf("unknown target language: %q", *lang)
    77  	}
    78  }
    79  
    80  func processErr(err error) {
    81  	if err != nil {
    82  		if list, _ := err.(bind.ErrorList); len(list) > 0 {
    83  			for _, err := range list {
    84  				errorf("%v", err)
    85  			}
    86  		} else {
    87  			errorf("%v", err)
    88  		}
    89  	}
    90  }
    91  
    92  var fset = token.NewFileSet()
    93  
    94  func parseFiles(dir string, filenames []string) []*ast.File {
    95  	var files []*ast.File
    96  	hasErr := false
    97  	for _, filename := range filenames {
    98  		path := filepath.Join(dir, filename)
    99  		file, err := parser.ParseFile(fset, path, nil, parser.AllErrors)
   100  		if err != nil {
   101  			hasErr = true
   102  			if list, _ := err.(scanner.ErrorList); len(list) > 0 {
   103  				for _, err := range list {
   104  					errorf("%v", err)
   105  				}
   106  			} else {
   107  				errorf("%v", err)
   108  			}
   109  		}
   110  		files = append(files, file)
   111  	}
   112  	if hasErr {
   113  		return nil
   114  	}
   115  	return files
   116  }
   117  
   118  func writer(fname string, pkg *types.Package) (w io.Writer, closer func()) {
   119  	if fname == "" {
   120  		return os.Stdout, func() { return }
   121  	}
   122  
   123  	dir := filepath.Dir(fname)
   124  	if err := os.MkdirAll(dir, 0755); err != nil {
   125  		errorf("invalid output dir: %v", err)
   126  		os.Exit(exitStatus)
   127  	}
   128  
   129  	f, err := os.Create(fname)
   130  	if err != nil {
   131  		errorf("invalid output dir: %v", err)
   132  		os.Exit(exitStatus)
   133  	}
   134  	closer = func() {
   135  		if err := f.Close(); err != nil {
   136  			errorf("error in closing output file: %v", err)
   137  		}
   138  	}
   139  	return f, closer
   140  }
   141  
   142  func defaultFileName(lang string, pkg *types.Package) string {
   143  	if *outdir == "" {
   144  		return ""
   145  	}
   146  
   147  	switch lang {
   148  	case "java":
   149  		firstRune, size := utf8.DecodeRuneInString(pkg.Name())
   150  		className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:]
   151  		return filepath.Join(*outdir, className+".java")
   152  	case "go":
   153  		return filepath.Join(*outdir, "go_"+pkg.Name()+".go")
   154  	case "objc":
   155  		firstRune, size := utf8.DecodeRuneInString(pkg.Name())
   156  		className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:]
   157  		return filepath.Join(*outdir, "Go"+className+".m")
   158  	}
   159  	errorf("unknown target language: %q", lang)
   160  	os.Exit(exitStatus)
   161  	return ""
   162  }