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