github.com/F4RD1N/gomobile@v1.0.1/bind/gengo.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 bind 6 7 import ( 8 "bytes" 9 "fmt" 10 "go/types" 11 "strings" 12 ) 13 14 type goGen struct { 15 *Generator 16 17 // imports is the list of imports, in the form 18 // "the/package/path" 19 // 20 // or 21 // 22 // name "the/package/path" 23 // 24 // in case of duplicates. 25 imports []string 26 // The set of taken import names. 27 importNames map[string]struct{} 28 // importMap is a map from packages to their names. The name of a package is the last 29 // segment of its path, with duplicates resolved by appending a underscore and a unique 30 // number. 31 importMap map[*types.Package]string 32 } 33 34 const ( 35 goPreamble = gobindPreamble + `// Package main is an autogenerated binder stub for package %[1]s. 36 // 37 // autogenerated by gobind -lang=go %[2]s 38 package main 39 40 /* 41 #include <stdlib.h> 42 #include <stdint.h> 43 #include "seq.h" 44 #include "%[1]s.h" 45 46 */ 47 import "C" 48 49 ` 50 ) 51 52 func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) { 53 sig := o.Type().(*types.Signature) 54 params := sig.Params() 55 for i := 0; i < params.Len(); i++ { 56 p := params.At(i) 57 pn := "param_" + g.paramName(params, i) 58 g.genRead("_"+pn, pn, p.Type(), modeTransient) 59 } 60 61 res := sig.Results() 62 if res.Len() > 2 || res.Len() == 2 && !isErrorType(res.At(1).Type()) { 63 g.errorf("functions and methods must return either zero or one values, and optionally an error") 64 return 65 } 66 if res.Len() > 0 { 67 for i := 0; i < res.Len(); i++ { 68 if i > 0 { 69 g.Printf(", ") 70 } 71 g.Printf("res_%d", i) 72 } 73 g.Printf(" := ") 74 } 75 76 g.Printf("%s%s(", selectorLHS, o.Name()) 77 for i := 0; i < params.Len(); i++ { 78 if i > 0 { 79 g.Printf(", ") 80 } 81 g.Printf("_param_%s", g.paramName(params, i)) 82 } 83 g.Printf(")\n") 84 85 for i := 0; i < res.Len(); i++ { 86 pn := fmt.Sprintf("res_%d", i) 87 g.genWrite("_"+pn, pn, res.At(i).Type(), modeRetained) 88 } 89 if res.Len() > 0 { 90 g.Printf("return ") 91 for i := 0; i < res.Len(); i++ { 92 if i > 0 { 93 g.Printf(", ") 94 } 95 g.Printf("_res_%d", i) 96 } 97 g.Printf("\n") 98 } 99 } 100 101 func (g *goGen) genWrite(toVar, fromVar string, t types.Type, mode varMode) { 102 switch t := t.(type) { 103 case *types.Basic: 104 switch t.Kind() { 105 case types.String: 106 g.Printf("%s := encodeString(%s)\n", toVar, fromVar) 107 case types.Bool: 108 g.Printf("var %s C.%s = 0\n", toVar, g.cgoType(t)) 109 g.Printf("if %s { %s = 1 }\n", fromVar, toVar) 110 default: 111 g.Printf("%s := C.%s(%s)\n", toVar, g.cgoType(t), fromVar) 112 } 113 case *types.Slice: 114 switch e := t.Elem().(type) { 115 case *types.Basic: 116 switch e.Kind() { 117 case types.Uint8: // Byte. 118 g.Printf("%s := fromSlice(%s, %v)\n", toVar, fromVar, mode == modeRetained) 119 default: 120 g.errorf("unsupported type: %s", t) 121 } 122 default: 123 g.errorf("unsupported type: %s", t) 124 } 125 case *types.Pointer: 126 // TODO(crawshaw): test *int 127 // TODO(crawshaw): test **Generator 128 switch t := t.Elem().(type) { 129 case *types.Named: 130 g.genToRefNum(toVar, fromVar) 131 default: 132 g.errorf("unsupported type %s", t) 133 } 134 case *types.Named: 135 switch u := t.Underlying().(type) { 136 case *types.Interface, *types.Pointer: 137 g.genToRefNum(toVar, fromVar) 138 default: 139 g.errorf("unsupported, direct named type %s: %s", t, u) 140 } 141 default: 142 g.errorf("unsupported type %s", t) 143 } 144 } 145 146 // genToRefNum generates Go code for converting a variable to its refnum. 147 // Note that the nil-check cannot be lifted into seq.ToRefNum, because a nil 148 // struct pointer does not convert to a nil interface. 149 func (g *goGen) genToRefNum(toVar, fromVar string) { 150 g.Printf("var %s C.int32_t = _seq.NullRefNum\n", toVar) 151 g.Printf("if %s != nil {\n", fromVar) 152 g.Printf(" %s = C.int32_t(_seq.ToRefNum(%s))\n", toVar, fromVar) 153 g.Printf("}\n") 154 } 155 156 func (g *goGen) genFuncSignature(o *types.Func, objName string) { 157 g.Printf("//export proxy%s_%s_%s\n", g.pkgPrefix, objName, o.Name()) 158 g.Printf("func proxy%s_%s_%s(", g.pkgPrefix, objName, o.Name()) 159 if objName != "" { 160 g.Printf("refnum C.int32_t") 161 } 162 sig := o.Type().(*types.Signature) 163 params := sig.Params() 164 for i := 0; i < params.Len(); i++ { 165 if objName != "" || i > 0 { 166 g.Printf(", ") 167 } 168 p := params.At(i) 169 g.Printf("param_%s C.%s", g.paramName(params, i), g.cgoType(p.Type())) 170 } 171 g.Printf(") ") 172 res := sig.Results() 173 if res.Len() > 0 { 174 g.Printf("(") 175 for i := 0; i < res.Len(); i++ { 176 if i > 0 { 177 g.Printf(", ") 178 } 179 g.Printf("C.%s", g.cgoType(res.At(i).Type())) 180 } 181 g.Printf(") ") 182 } 183 g.Printf("{\n") 184 } 185 186 func (g *goGen) paramName(params *types.Tuple, pos int) string { 187 return basicParamName(params, pos) 188 } 189 190 func (g *goGen) genFunc(o *types.Func) { 191 if !g.isSigSupported(o.Type()) { 192 g.Printf("// skipped function %s with unsupported parameter or result types\n", o.Name()) 193 return 194 } 195 g.genFuncSignature(o, "") 196 g.Indent() 197 g.genFuncBody(o, g.pkgName(g.Pkg)) 198 g.Outdent() 199 g.Printf("}\n\n") 200 } 201 202 func (g *goGen) genStruct(obj *types.TypeName, T *types.Struct) { 203 fields := exportedFields(T) 204 methods := exportedMethodSet(types.NewPointer(obj.Type())) 205 206 for _, f := range fields { 207 if t := f.Type(); !g.isSupported(t) { 208 g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", obj.Name(), f.Name(), t) 209 continue 210 } 211 g.Printf("//export proxy%s_%s_%s_Set\n", g.pkgPrefix, obj.Name(), f.Name()) 212 g.Printf("func proxy%s_%s_%s_Set(refnum C.int32_t, v C.%s) {\n", g.pkgPrefix, obj.Name(), f.Name(), g.cgoType(f.Type())) 213 g.Indent() 214 g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") 215 g.genRead("_v", "v", f.Type(), modeRetained) 216 g.Printf("ref.Get().(*%s%s).%s = _v\n", g.pkgName(g.Pkg), obj.Name(), f.Name()) 217 g.Outdent() 218 g.Printf("}\n\n") 219 220 g.Printf("//export proxy%s_%s_%s_Get\n", g.pkgPrefix, obj.Name(), f.Name()) 221 g.Printf("func proxy%s_%s_%s_Get(refnum C.int32_t) C.%s {\n", g.pkgPrefix, obj.Name(), f.Name(), g.cgoType(f.Type())) 222 g.Indent() 223 g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") 224 g.Printf("v := ref.Get().(*%s%s).%s\n", g.pkgName(g.Pkg), obj.Name(), f.Name()) 225 g.genWrite("_v", "v", f.Type(), modeRetained) 226 g.Printf("return _v\n") 227 g.Outdent() 228 g.Printf("}\n\n") 229 } 230 231 for _, m := range methods { 232 if !g.isSigSupported(m.Type()) { 233 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) 234 continue 235 } 236 g.genFuncSignature(m, obj.Name()) 237 g.Indent() 238 g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") 239 g.Printf("v := ref.Get().(*%s%s)\n", g.pkgName(g.Pkg), obj.Name()) 240 g.genFuncBody(m, "v.") 241 g.Outdent() 242 g.Printf("}\n\n") 243 } 244 // Export constructor for ObjC and Java default no-arg constructors 245 g.Printf("//export new_%s_%s\n", g.Pkg.Name(), obj.Name()) 246 g.Printf("func new_%s_%s() C.int32_t {\n", g.Pkg.Name(), obj.Name()) 247 g.Indent() 248 g.Printf("return C.int32_t(_seq.ToRefNum(new(%s%s)))\n", g.pkgName(g.Pkg), obj.Name()) 249 g.Outdent() 250 g.Printf("}\n") 251 } 252 253 func (g *goGen) genVar(o *types.Var) { 254 if t := o.Type(); !g.isSupported(t) { 255 g.Printf("// skipped variable %s with unsupported type %s\n\n", o.Name(), t) 256 return 257 } 258 // TODO(hyangah): non-struct pointer types (*int), struct type. 259 260 v := fmt.Sprintf("%s%s", g.pkgName(g.Pkg), o.Name()) 261 262 // var I int 263 // 264 // func var_setI(v int) 265 g.Printf("//export var_set%s_%s\n", g.pkgPrefix, o.Name()) 266 g.Printf("func var_set%s_%s(v C.%s) {\n", g.pkgPrefix, o.Name(), g.cgoType(o.Type())) 267 g.Indent() 268 g.genRead("_v", "v", o.Type(), modeRetained) 269 g.Printf("%s = _v\n", v) 270 g.Outdent() 271 g.Printf("}\n") 272 273 // func var_getI() int 274 g.Printf("//export var_get%s_%s\n", g.pkgPrefix, o.Name()) 275 g.Printf("func var_get%s_%s() C.%s {\n", g.pkgPrefix, o.Name(), g.cgoType(o.Type())) 276 g.Indent() 277 g.Printf("v := %s\n", v) 278 g.genWrite("_v", "v", o.Type(), modeRetained) 279 g.Printf("return _v\n") 280 g.Outdent() 281 g.Printf("}\n") 282 } 283 284 func (g *goGen) genInterface(obj *types.TypeName) { 285 iface := obj.Type().(*types.Named).Underlying().(*types.Interface) 286 287 summary := makeIfaceSummary(iface) 288 289 // Define the entry points. 290 for _, m := range summary.callable { 291 if !g.isSigSupported(m.Type()) { 292 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) 293 continue 294 } 295 g.genFuncSignature(m, obj.Name()) 296 g.Indent() 297 g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") 298 g.Printf("v := ref.Get().(%s%s)\n", g.pkgName(g.Pkg), obj.Name()) 299 g.genFuncBody(m, "v.") 300 g.Outdent() 301 g.Printf("}\n\n") 302 } 303 304 // Define a proxy interface. 305 if !summary.implementable { 306 // The interface defines an unexported method or a method that 307 // uses an unexported type. We cannot generate a proxy object 308 // for such a type. 309 return 310 } 311 g.Printf("type proxy%s_%s _seq.Ref\n\n", g.pkgPrefix, obj.Name()) 312 313 g.Printf("func (p *proxy%s_%s) Bind_proxy_refnum__() int32 {\n", g.pkgPrefix, obj.Name()) 314 g.Indent() 315 g.Printf("return (*_seq.Ref)(p).Bind_IncNum()\n") 316 g.Outdent() 317 g.Printf("}\n\n") 318 319 for _, m := range summary.callable { 320 if !g.isSigSupported(m.Type()) { 321 g.Printf("// skipped method %s.%s with unsupported parameter or result types\n", obj.Name(), m.Name()) 322 continue 323 } 324 sig := m.Type().(*types.Signature) 325 params := sig.Params() 326 res := sig.Results() 327 328 if res.Len() > 2 || 329 (res.Len() == 2 && !isErrorType(res.At(1).Type())) { 330 g.errorf("functions and methods must return either zero or one value, and optionally an error: %s.%s", obj.Name(), m.Name()) 331 continue 332 } 333 334 g.Printf("func (p *proxy%s_%s) %s(", g.pkgPrefix, obj.Name(), m.Name()) 335 for i := 0; i < params.Len(); i++ { 336 if i > 0 { 337 g.Printf(", ") 338 } 339 g.Printf("param_%s %s", g.paramName(params, i), g.typeString(params.At(i).Type())) 340 } 341 g.Printf(") ") 342 343 if res.Len() == 1 { 344 g.Printf(g.typeString(res.At(0).Type())) 345 } else if res.Len() == 2 { 346 g.Printf("(%s, error)", g.typeString(res.At(0).Type())) 347 } 348 g.Printf(" {\n") 349 g.Indent() 350 351 for i := 0; i < params.Len(); i++ { 352 pn := "param_" + g.paramName(params, i) 353 g.genWrite("_"+pn, pn, params.At(i).Type(), modeTransient) 354 } 355 356 if res.Len() > 0 { 357 g.Printf("res := ") 358 } 359 g.Printf("C.cproxy%s_%s_%s(C.int32_t(p.Bind_proxy_refnum__())", g.pkgPrefix, obj.Name(), m.Name()) 360 for i := 0; i < params.Len(); i++ { 361 g.Printf(", _param_%s", g.paramName(params, i)) 362 } 363 g.Printf(")\n") 364 var retName string 365 if res.Len() > 0 { 366 if res.Len() == 1 { 367 T := res.At(0).Type() 368 g.genRead("_res", "res", T, modeRetained) 369 retName = "_res" 370 } else { 371 var rvs []string 372 for i := 0; i < res.Len(); i++ { 373 rv := fmt.Sprintf("res_%d", i) 374 g.genRead(rv, fmt.Sprintf("res.r%d", i), res.At(i).Type(), modeRetained) 375 rvs = append(rvs, rv) 376 } 377 retName = strings.Join(rvs, ", ") 378 } 379 g.Printf("return %s\n", retName) 380 } 381 g.Outdent() 382 g.Printf("}\n\n") 383 } 384 } 385 386 func (g *goGen) genRead(toVar, fromVar string, typ types.Type, mode varMode) { 387 switch t := typ.(type) { 388 case *types.Basic: 389 switch t.Kind() { 390 case types.String: 391 g.Printf("%s := decodeString(%s)\n", toVar, fromVar) 392 case types.Bool: 393 g.Printf("%s := %s != 0\n", toVar, fromVar) 394 default: 395 g.Printf("%s := %s(%s)\n", toVar, t.Underlying().String(), fromVar) 396 } 397 case *types.Slice: 398 switch e := t.Elem().(type) { 399 case *types.Basic: 400 switch e.Kind() { 401 case types.Uint8: // Byte. 402 g.Printf("%s := toSlice(%s, %v)\n", toVar, fromVar, mode == modeRetained) 403 default: 404 g.errorf("unsupported type: %s", t) 405 } 406 default: 407 g.errorf("unsupported type: %s", t) 408 } 409 case *types.Pointer: 410 switch u := t.Elem().(type) { 411 case *types.Named: 412 o := u.Obj() 413 oPkg := o.Pkg() 414 if !g.validPkg(oPkg) { 415 g.errorf("type %s is defined in %s, which is not bound", u, oPkg) 416 return 417 } 418 g.Printf("// Must be a Go object\n") 419 g.Printf("var %s *%s%s\n", toVar, g.pkgName(oPkg), o.Name()) 420 g.Printf("if %s_ref := _seq.FromRefNum(int32(%s)); %s_ref != nil {\n", toVar, fromVar, toVar) 421 g.Printf(" %s = %s_ref.Get().(*%s%s)\n", toVar, toVar, g.pkgName(oPkg), o.Name()) 422 g.Printf("}\n") 423 default: 424 g.errorf("unsupported pointer type %s", t) 425 } 426 case *types.Named: 427 switch t.Underlying().(type) { 428 case *types.Interface, *types.Pointer: 429 hasProxy := true 430 if iface, ok := t.Underlying().(*types.Interface); ok { 431 hasProxy = makeIfaceSummary(iface).implementable 432 } 433 pkgFirst := typePkgFirstElem(t) 434 isWrapper := pkgFirst == "Java" || pkgFirst == "ObjC" 435 o := t.Obj() 436 oPkg := o.Pkg() 437 if !isErrorType(t) && !g.validPkg(oPkg) && !isWrapper { 438 g.errorf("type %s is defined in %s, which is not bound", t, oPkg) 439 return 440 } 441 g.Printf("var %s %s\n", toVar, g.typeString(t)) 442 g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", toVar, fromVar) 443 g.Printf("if %s_ref != nil {\n", toVar) 444 g.Printf(" if %s < 0 { // go object \n", fromVar) 445 g.Printf(" %s = %s_ref.Get().(%s%s)\n", toVar, toVar, g.pkgName(oPkg), o.Name()) 446 if hasProxy { 447 g.Printf(" } else { // foreign object \n") 448 if isWrapper { 449 var clsName string 450 switch pkgFirst { 451 case "Java": 452 clsName = flattenName(classNameFor(t)) 453 case "ObjC": 454 clsName = t.Obj().Name() 455 } 456 g.Printf(" %s = (*proxy_class_%s)(%s_ref)\n", toVar, clsName, toVar) 457 } else { 458 g.Printf(" %s = (*proxy%s_%s)(%s_ref)\n", toVar, pkgPrefix(oPkg), o.Name(), toVar) 459 } 460 } 461 g.Printf(" }\n") 462 g.Printf("}\n") 463 default: 464 g.errorf("unsupported named type %s", t) 465 } 466 default: 467 g.errorf("unsupported type: %s", typ) 468 } 469 } 470 471 func (g *goGen) typeString(typ types.Type) string { 472 pkg := g.Pkg 473 474 switch t := typ.(type) { 475 case *types.Named: 476 obj := t.Obj() 477 if obj.Pkg() == nil { // e.g. error type is *types.Named. 478 return types.TypeString(typ, types.RelativeTo(pkg)) 479 } 480 oPkg := obj.Pkg() 481 if !g.validPkg(oPkg) && !isWrapperType(t) { 482 g.errorf("type %s is defined in %s, which is not bound", t, oPkg) 483 return "TODO" 484 } 485 486 switch t.Underlying().(type) { 487 case *types.Interface, *types.Struct: 488 return fmt.Sprintf("%s%s", g.pkgName(oPkg), types.TypeString(typ, types.RelativeTo(oPkg))) 489 default: 490 g.errorf("unsupported named type %s / %T", t, t) 491 } 492 case *types.Pointer: 493 switch t := t.Elem().(type) { 494 case *types.Named: 495 return fmt.Sprintf("*%s", g.typeString(t)) 496 default: 497 g.errorf("not yet supported, pointer type %s / %T", t, t) 498 } 499 default: 500 return types.TypeString(typ, types.RelativeTo(pkg)) 501 } 502 return "" 503 } 504 505 // genPreamble generates the preamble. It is generated after everything 506 // else, where we know which bound packages to import. 507 func (g *goGen) genPreamble() { 508 pkgName := "" 509 pkgPath := "" 510 if g.Pkg != nil { 511 pkgName = g.Pkg.Name() 512 pkgPath = g.Pkg.Path() 513 } else { 514 pkgName = "universe" 515 } 516 g.Printf(goPreamble, pkgName, pkgPath) 517 g.Printf("import (\n") 518 g.Indent() 519 g.Printf("_seq \"github.com/F4RD1N/gomobile/bind/seq\"\n") 520 for _, imp := range g.imports { 521 g.Printf("%s\n", imp) 522 } 523 g.Outdent() 524 g.Printf(")\n\n") 525 } 526 527 func (g *goGen) gen() error { 528 g.importNames = make(map[string]struct{}) 529 g.importMap = make(map[*types.Package]string) 530 531 // Switch to a temporary buffer so the preamble can be 532 // written last. 533 oldBuf := g.Printer.Buf 534 newBuf := new(bytes.Buffer) 535 g.Printer.Buf = newBuf 536 g.Printf("// suppress the error if seq ends up unused\n") 537 g.Printf("var _ = _seq.FromRefNum\n") 538 539 for _, s := range g.structs { 540 g.genStruct(s.obj, s.t) 541 } 542 for _, intf := range g.interfaces { 543 g.genInterface(intf.obj) 544 } 545 for _, v := range g.vars { 546 g.genVar(v) 547 } 548 for _, f := range g.funcs { 549 g.genFunc(f) 550 } 551 // Switch to the original buffer, write the preamble 552 // and append the rest of the file. 553 g.Printer.Buf = oldBuf 554 g.genPreamble() 555 g.Printer.Buf.Write(newBuf.Bytes()) 556 if len(g.err) > 0 { 557 return g.err 558 } 559 return nil 560 } 561 562 // pkgName retuns the package name and adds the package to the list of 563 // imports. 564 func (g *goGen) pkgName(pkg *types.Package) string { 565 // The error type has no package 566 if pkg == nil { 567 return "" 568 } 569 if name, exists := g.importMap[pkg]; exists { 570 return name + "." 571 } 572 i := 0 573 pname := pkg.Name() 574 name := pkg.Name() 575 for { 576 if _, exists := g.importNames[name]; !exists { 577 g.importNames[name] = struct{}{} 578 g.importMap[pkg] = name 579 var imp string 580 if pname != name { 581 imp = fmt.Sprintf("%s %q", name, pkg.Path()) 582 } else { 583 imp = fmt.Sprintf("%q", pkg.Path()) 584 } 585 g.imports = append(g.imports, imp) 586 break 587 } 588 i++ 589 name = fmt.Sprintf("%s_%d", pname, i) 590 } 591 g.importMap[pkg] = name 592 return name + "." 593 }