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 }