github.com/champo/mobile@v0.0.0-20190107162257-dc0771356504/bind/gen.go (about) 1 // Copyright 2015 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 bind 6 7 import ( 8 "bytes" 9 "fmt" 10 "go/ast" 11 "go/token" 12 "go/types" 13 "io" 14 "regexp" 15 "strings" 16 "unicode" 17 "unicode/utf8" 18 ) 19 20 type ( 21 ErrorList []error 22 23 // varMode describes the lifetime of an argument or 24 // return value. Modes are used to guide the conversion 25 // of string and byte slice values accross the language 26 // barrier. The same conversion mode must be used for 27 // both the conversion before a foreign call and the 28 // corresponding conversion after the call. 29 // See the mode* constants for a description of 30 // each mode. 31 varMode int 32 ) 33 34 const ( 35 // modeTransient are for function arguments that 36 // are not used after the function returns. 37 // Transient byte slices don't need copying 38 // when passed accross the language barrier. 39 modeTransient varMode = iota 40 // modeRetained are for returned values and for function 41 // arguments that are used after the function returns. 42 // Retained byte slices need an intermediate copy. 43 modeRetained 44 ) 45 46 func (list ErrorList) Error() string { 47 buf := new(bytes.Buffer) 48 for i, err := range list { 49 if i > 0 { 50 buf.WriteRune('\n') 51 } 52 io.WriteString(buf, err.Error()) 53 } 54 return buf.String() 55 } 56 57 // interfaceInfo comes from Init and collects the auxillary information 58 // needed to generate bindings for an exported Go interface in a bound 59 // package. 60 type interfaceInfo struct { 61 obj *types.TypeName 62 t *types.Interface 63 summary ifaceSummary 64 } 65 66 // structInfo comes from Init and collects the auxillary information 67 // needed to generate bindings for an exported Go struct in a bound 68 // package. 69 type structInfo struct { 70 obj *types.TypeName 71 t *types.Struct 72 } 73 74 // Generator contains the common Go package information 75 // needed for the specific Go, Java, ObjC generators. 76 // 77 // After setting Printer, Fset, AllPkg, Pkg, the Init 78 // method is used to initialize the auxiliary information 79 // about the package to be generated, Pkg. 80 type Generator struct { 81 *Printer 82 Fset *token.FileSet 83 AllPkg []*types.Package 84 Files []*ast.File 85 Pkg *types.Package 86 err ErrorList 87 88 // fields set by init. 89 pkgName string 90 pkgPrefix string 91 funcs []*types.Func 92 constants []*types.Const 93 vars []*types.Var 94 95 interfaces []interfaceInfo 96 structs []structInfo 97 otherNames []*types.TypeName 98 // allIntf contains interfaces from all bound packages. 99 allIntf []interfaceInfo 100 101 docs pkgDocs 102 } 103 104 // A pkgDocs maps the name of each exported package-level declaration to its extracted documentation. 105 type pkgDocs map[string]*pkgDoc 106 107 type pkgDoc struct { 108 doc string 109 // Struct or interface fields and methods. 110 members map[string]string 111 } 112 113 // pkgPrefix returns a prefix that disambiguates symbol names for binding 114 // multiple packages. 115 // 116 // TODO(elias.naur): Avoid (and test) name clashes from multiple packages 117 // with the same name. Perhaps use the index from the order the package is 118 // generated. 119 func pkgPrefix(pkg *types.Package) string { 120 // The error type has no package 121 if pkg == nil { 122 return "" 123 } 124 return pkg.Name() 125 } 126 127 func (g *Generator) Init() { 128 if g.Pkg != nil { 129 g.pkgName = g.Pkg.Name() 130 } 131 g.pkgPrefix = pkgPrefix(g.Pkg) 132 133 if g.Pkg != nil { 134 g.parseDocs() 135 scope := g.Pkg.Scope() 136 hasExported := false 137 for _, name := range scope.Names() { 138 obj := scope.Lookup(name) 139 if !obj.Exported() { 140 continue 141 } 142 hasExported = true 143 switch obj := obj.(type) { 144 case *types.Func: 145 if isCallable(obj) { 146 g.funcs = append(g.funcs, obj) 147 } 148 case *types.TypeName: 149 named := obj.Type().(*types.Named) 150 switch t := named.Underlying().(type) { 151 case *types.Struct: 152 g.structs = append(g.structs, structInfo{obj, t}) 153 case *types.Interface: 154 g.interfaces = append(g.interfaces, interfaceInfo{obj, t, makeIfaceSummary(t)}) 155 default: 156 g.otherNames = append(g.otherNames, obj) 157 } 158 case *types.Const: 159 g.constants = append(g.constants, obj) 160 case *types.Var: 161 g.vars = append(g.vars, obj) 162 default: 163 g.errorf("unsupported exported type for %s: %T", obj.Name(), obj) 164 } 165 } 166 if !hasExported { 167 g.errorf("no exported names in the package %q", g.Pkg.Path()) 168 } 169 } else { 170 // Bind the single supported type from the universe scope, error. 171 errType := types.Universe.Lookup("error").(*types.TypeName) 172 t := errType.Type().Underlying().(*types.Interface) 173 g.interfaces = append(g.interfaces, interfaceInfo{errType, t, makeIfaceSummary(t)}) 174 } 175 for _, p := range g.AllPkg { 176 scope := p.Scope() 177 for _, name := range scope.Names() { 178 obj := scope.Lookup(name) 179 if !obj.Exported() { 180 continue 181 } 182 if obj, ok := obj.(*types.TypeName); ok { 183 named := obj.Type().(*types.Named) 184 if t, ok := named.Underlying().(*types.Interface); ok { 185 g.allIntf = append(g.allIntf, interfaceInfo{obj, t, makeIfaceSummary(t)}) 186 } 187 } 188 } 189 } 190 } 191 192 // parseDocs extracts documentation from a package in a form useful for lookups. 193 func (g *Generator) parseDocs() { 194 d := make(pkgDocs) 195 for _, f := range g.Files { 196 for _, decl := range f.Decls { 197 switch decl := decl.(type) { 198 case *ast.GenDecl: 199 for _, spec := range decl.Specs { 200 switch spec := spec.(type) { 201 case *ast.TypeSpec: 202 d.addType(spec, decl.Doc) 203 case *ast.ValueSpec: 204 d.addValue(spec, decl.Doc) 205 } 206 } 207 case *ast.FuncDecl: 208 d.addFunc(decl) 209 } 210 } 211 } 212 g.docs = d 213 } 214 215 func (d pkgDocs) addValue(t *ast.ValueSpec, outerDoc *ast.CommentGroup) { 216 for _, n := range t.Names { 217 if !ast.IsExported(n.Name) { 218 continue 219 } 220 doc := t.Doc 221 if doc == nil { 222 doc = outerDoc 223 } 224 if doc != nil { 225 d[n.Name] = &pkgDoc{doc: doc.Text()} 226 } 227 } 228 } 229 230 func (d pkgDocs) addFunc(f *ast.FuncDecl) { 231 doc := f.Doc 232 if doc == nil { 233 return 234 } 235 fn := f.Name.Name 236 if !ast.IsExported(fn) { 237 return 238 } 239 if r := f.Recv; r != nil { 240 // f is a method. 241 n := typeName(r.List[0].Type) 242 pd, exists := d[n] 243 if !exists { 244 pd = &pkgDoc{members: make(map[string]string)} 245 d[n] = pd 246 } 247 pd.members[fn] = doc.Text() 248 } else { 249 // f is a function. 250 d[fn] = &pkgDoc{doc: doc.Text()} 251 } 252 } 253 254 func (d pkgDocs) addType(t *ast.TypeSpec, outerDoc *ast.CommentGroup) { 255 if !ast.IsExported(t.Name.Name) { 256 return 257 } 258 doc := t.Doc 259 if doc == nil { 260 doc = outerDoc 261 } 262 pd := d[t.Name.Name] 263 pd = &pkgDoc{members: make(map[string]string)} 264 d[t.Name.Name] = pd 265 if doc != nil { 266 pd.doc = doc.Text() 267 } 268 var fields *ast.FieldList 269 switch t := t.Type.(type) { 270 case *ast.StructType: 271 fields = t.Fields 272 case *ast.InterfaceType: 273 fields = t.Methods 274 } 275 if fields != nil { 276 for _, field := range fields.List { 277 if field.Doc != nil { 278 if field.Names == nil { 279 // Anonymous field. Extract name from its type. 280 if n := typeName(field.Type); ast.IsExported(n) { 281 pd.members[n] = field.Doc.Text() 282 } 283 } 284 for _, n := range field.Names { 285 if ast.IsExported(n.Name) { 286 pd.members[n.Name] = field.Doc.Text() 287 } 288 } 289 } 290 } 291 } 292 } 293 294 // typeName returns the type name T for expressions on the 295 // T, *T, **T (etc.) form. 296 func typeName(t ast.Expr) string { 297 switch t := t.(type) { 298 case *ast.StarExpr: 299 return typeName(t.X) 300 case *ast.Ident: 301 return t.Name 302 case *ast.SelectorExpr: 303 return t.Sel.Name 304 default: 305 return "" 306 } 307 } 308 309 func (d *pkgDoc) Doc() string { 310 if d == nil { 311 return "" 312 } 313 return d.doc 314 } 315 316 func (d *pkgDoc) Member(n string) string { 317 if d == nil { 318 return "" 319 } 320 return d.members[n] 321 } 322 323 // constructorType returns the type T for a function of the forms: 324 // 325 // func NewT...(...) *T 326 // func NewT...(...) (*T, error) 327 func (g *Generator) constructorType(f *types.Func) *types.TypeName { 328 sig := f.Type().(*types.Signature) 329 res := sig.Results() 330 if res.Len() != 1 && !(res.Len() == 2 && isErrorType(res.At(1).Type())) { 331 return nil 332 } 333 rt := res.At(0).Type() 334 pt, ok := rt.(*types.Pointer) 335 if !ok { 336 return nil 337 } 338 nt, ok := pt.Elem().(*types.Named) 339 if !ok { 340 return nil 341 } 342 obj := nt.Obj() 343 if !strings.HasPrefix(f.Name(), "New"+obj.Name()) { 344 return nil 345 } 346 return obj 347 } 348 349 func toCFlag(v bool) int { 350 if v { 351 return 1 352 } 353 return 0 354 } 355 356 func (g *Generator) errorf(format string, args ...interface{}) { 357 g.err = append(g.err, fmt.Errorf(format, args...)) 358 } 359 360 // cgoType returns the name of a Cgo type suitable for converting a value of 361 // the given type. 362 func (g *Generator) cgoType(t types.Type) string { 363 switch t := t.(type) { 364 case *types.Basic: 365 switch t.Kind() { 366 case types.Bool, types.UntypedBool: 367 return "char" 368 case types.Int: 369 return "nint" 370 case types.Int8: 371 return "int8_t" 372 case types.Int16: 373 return "int16_t" 374 case types.Int32, types.UntypedRune: // types.Rune 375 return "int32_t" 376 case types.Int64, types.UntypedInt: 377 return "int64_t" 378 case types.Uint8: // types.Byte 379 return "uint8_t" 380 // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: 381 case types.Float32: 382 return "float" 383 case types.Float64, types.UntypedFloat: 384 return "double" 385 case types.String: 386 return "nstring" 387 default: 388 g.errorf("unsupported basic type: %s", t) 389 } 390 case *types.Slice: 391 switch e := t.Elem().(type) { 392 case *types.Basic: 393 switch e.Kind() { 394 case types.Uint8: // Byte. 395 return "nbyteslice" 396 default: 397 g.errorf("unsupported slice type: %s", t) 398 } 399 default: 400 g.errorf("unsupported slice type: %s", t) 401 } 402 case *types.Pointer: 403 if _, ok := t.Elem().(*types.Named); ok { 404 return g.cgoType(t.Elem()) 405 } 406 g.errorf("unsupported pointer to type: %s", t) 407 case *types.Named: 408 return "int32_t" 409 default: 410 g.errorf("unsupported type: %s", t) 411 } 412 return "TODO" 413 } 414 415 func (g *Generator) genInterfaceMethodSignature(m *types.Func, iName string, header bool, g_paramName func(*types.Tuple, int) string) { 416 sig := m.Type().(*types.Signature) 417 params := sig.Params() 418 res := sig.Results() 419 420 if res.Len() == 0 { 421 g.Printf("void ") 422 } else { 423 if res.Len() == 1 { 424 g.Printf("%s ", g.cgoType(res.At(0).Type())) 425 } else { 426 if header { 427 g.Printf("typedef struct cproxy%s_%s_%s_return {\n", g.pkgPrefix, iName, m.Name()) 428 g.Indent() 429 for i := 0; i < res.Len(); i++ { 430 t := res.At(i).Type() 431 g.Printf("%s r%d;\n", g.cgoType(t), i) 432 } 433 g.Outdent() 434 g.Printf("} cproxy%s_%s_%s_return;\n", g.pkgPrefix, iName, m.Name()) 435 } 436 g.Printf("struct cproxy%s_%s_%s_return ", g.pkgPrefix, iName, m.Name()) 437 } 438 } 439 g.Printf("cproxy%s_%s_%s(int32_t refnum", g.pkgPrefix, iName, m.Name()) 440 for i := 0; i < params.Len(); i++ { 441 t := params.At(i).Type() 442 g.Printf(", %s %s", g.cgoType(t), g_paramName(params, i)) 443 } 444 g.Printf(")") 445 if header { 446 g.Printf(";\n") 447 } else { 448 g.Printf(" {\n") 449 } 450 } 451 452 func (g *Generator) validPkg(pkg *types.Package) bool { 453 for _, p := range g.AllPkg { 454 if p == pkg { 455 return true 456 } 457 } 458 return false 459 } 460 461 // isSigSupported reports whether the generators can handle a given 462 // function signature. 463 func (g *Generator) isSigSupported(t types.Type) bool { 464 sig := t.(*types.Signature) 465 params := sig.Params() 466 for i := 0; i < params.Len(); i++ { 467 if !g.isSupported(params.At(i).Type()) { 468 return false 469 } 470 } 471 res := sig.Results() 472 for i := 0; i < res.Len(); i++ { 473 if !g.isSupported(res.At(i).Type()) { 474 return false 475 } 476 } 477 return true 478 } 479 480 // isSupported reports whether the generators can handle the type. 481 func (g *Generator) isSupported(t types.Type) bool { 482 if isErrorType(t) || isWrapperType(t) { 483 return true 484 } 485 switch t := t.(type) { 486 case *types.Basic: 487 switch t.Kind() { 488 case types.Bool, types.UntypedBool, 489 types.Int, 490 types.Int8, types.Uint8, // types.Byte 491 types.Int16, 492 types.Int32, types.UntypedRune, // types.Rune 493 types.Int64, types.UntypedInt, 494 types.Float32, 495 types.Float64, types.UntypedFloat, 496 types.String, types.UntypedString: 497 return true 498 } 499 return false 500 case *types.Slice: 501 switch e := t.Elem().(type) { 502 case *types.Basic: 503 return e.Kind() == types.Uint8 504 } 505 case *types.Pointer: 506 switch t := t.Elem().(type) { 507 case *types.Named: 508 return g.validPkg(t.Obj().Pkg()) 509 } 510 case *types.Named: 511 switch t.Underlying().(type) { 512 case *types.Interface, *types.Pointer: 513 return g.validPkg(t.Obj().Pkg()) 514 } 515 } 516 return false 517 } 518 519 var paramRE = regexp.MustCompile(`^p[0-9]*$`) 520 521 // basicParamName replaces incompatible name with a p0-pN name. 522 // Missing names, or existing names of the form p[0-9] are incompatible. 523 func basicParamName(params *types.Tuple, pos int) string { 524 name := params.At(pos).Name() 525 if name == "" || name[0] == '_' || paramRE.MatchString(name) { 526 name = fmt.Sprintf("p%d", pos) 527 } 528 return name 529 } 530 531 func lowerFirst(s string) string { 532 if s == "" { 533 return "" 534 } 535 536 var conv []rune 537 for len(s) > 0 { 538 r, n := utf8.DecodeRuneInString(s) 539 if !unicode.IsUpper(r) { 540 if l := len(conv); l > 1 { 541 conv[l-1] = unicode.ToUpper(conv[l-1]) 542 } 543 return string(conv) + s 544 } 545 conv = append(conv, unicode.ToLower(r)) 546 s = s[n:] 547 } 548 return string(conv) 549 } 550 551 // newNameSanitizer returns a functions that replaces all dashes and dots 552 // with underscores, as well as avoiding reserved words by suffixing such 553 // identifiers with underscores. 554 func newNameSanitizer(res []string) func(s string) string { 555 reserved := make(map[string]bool) 556 for _, word := range res { 557 reserved[word] = true 558 } 559 symbols := strings.NewReplacer( 560 "-", "_", 561 ".", "_", 562 ) 563 return func(s string) string { 564 if reserved[s] { 565 return s + "_" 566 } 567 return symbols.Replace(s) 568 } 569 }