github.com/acrespo/mobile@v0.0.0-20190107162257-dc0771356504/bind/genobjc.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 "fmt" 9 "go/constant" 10 "go/types" 11 "math" 12 "strings" 13 14 "golang.org/x/mobile/internal/importers/objc" 15 ) 16 17 // TODO(hyangah): handle method name conflicts. 18 // - struct with SetF method and exported F field. 19 // - method names conflicting with NSObject methods. e.g. Init 20 // - interface type with InitWithRef. 21 22 // TODO(hyangah): error code/domain propagation 23 24 type ObjcGen struct { 25 Prefix string // prefix arg passed by flag. 26 27 *Generator 28 29 // fields set by init. 30 namePrefix string 31 // Map of all wrapped Objc types 32 wrapMap map[string]*objc.Named 33 // Structs that embeds Objc wrapper types. 34 ostructs map[*types.TypeName]*objcClassInfo 35 modules []string 36 // Constructors is a map from Go struct types to a list 37 // of exported constructor functions for the type, on the form 38 // func New<Type>(...) *Type 39 constructors map[*types.TypeName][]*types.Func 40 } 41 42 type objcClassInfo struct { 43 // The Objc class this class extends. 44 extends *objc.Named 45 // All classes and protocols this class extends and conforms to. 46 supers []*objc.Named 47 methods map[string]*objc.Func 48 } 49 50 func (g *ObjcGen) Init(wrappers []*objc.Named) { 51 g.Generator.Init() 52 g.namePrefix = g.namePrefixOf(g.Pkg) 53 g.wrapMap = make(map[string]*objc.Named) 54 g.constructors = make(map[*types.TypeName][]*types.Func) 55 modMap := make(map[string]struct{}) 56 for _, w := range wrappers { 57 g.wrapMap[w.GoName] = w 58 if _, exists := modMap[w.Module]; !exists { 59 if !w.Generated { 60 g.modules = append(g.modules, w.Module) 61 } 62 modMap[w.Module] = struct{}{} 63 } 64 } 65 if _, exists := modMap["Foundation"]; !exists { 66 g.modules = append(g.modules, "Foundation") 67 } 68 g.ostructs = make(map[*types.TypeName]*objcClassInfo) 69 for _, s := range g.structs { 70 embds := embeddedObjcTypes(s.t) 71 if len(embds) == 0 { 72 continue 73 } 74 inf := &objcClassInfo{ 75 methods: make(map[string]*objc.Func), 76 } 77 for _, n := range embds { 78 t := g.wrapMap[n] 79 for _, f := range t.AllMethods { 80 inf.methods[f.GoName] = f 81 } 82 inf.supers = append(inf.supers, t) 83 if !t.Protocol { 84 if inf.extends != nil { 85 g.errorf("%s embeds more than one ObjC class; only one is allowed.", s.obj) 86 } 87 inf.extends = t 88 } 89 } 90 g.ostructs[s.obj] = inf 91 } 92 for _, f := range g.funcs { 93 if t := g.constructorType(f); t != nil { 94 g.constructors[t] = append(g.constructors[t], f) 95 } 96 } 97 } 98 99 func (g *ObjcGen) namePrefixOf(pkg *types.Package) string { 100 if pkg == nil { 101 return "Universe" 102 } 103 p := g.Prefix 104 return p + strings.Title(pkg.Name()) 105 } 106 107 func (g *ObjcGen) GenGoH() error { 108 var pkgPath string 109 if g.Pkg != nil { 110 pkgPath = g.Pkg.Path() 111 } 112 g.Printf(objcPreamble, pkgPath, g.gobindOpts(), pkgPath) 113 g.Printf("#ifndef __GO_%s_H__\n", g.pkgName) 114 g.Printf("#define __GO_%s_H__\n\n", g.pkgName) 115 g.Printf("#include <stdint.h>\n") 116 g.Printf("#include <objc/objc.h>\n") 117 118 for _, i := range g.interfaces { 119 if !i.summary.implementable { 120 continue 121 } 122 for _, m := range i.summary.callable { 123 if !g.isSigSupported(m.Type()) { 124 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", i.obj.Name(), m.Name()) 125 continue 126 } 127 g.genInterfaceMethodSignature(m, i.obj.Name(), true, g.paramName) 128 g.Printf("\n") 129 } 130 } 131 132 g.Printf("#endif\n") 133 134 if len(g.err) > 0 { 135 return g.err 136 } 137 return nil 138 } 139 140 func (g *ObjcGen) GenH() error { 141 var pkgPath string 142 if g.Pkg != nil { 143 pkgPath = g.Pkg.Path() 144 } 145 g.Printf(objcPreamble, pkgPath, g.gobindOpts(), pkgPath) 146 g.Printf("#ifndef __%s_H__\n", g.namePrefix) 147 g.Printf("#define __%s_H__\n", g.namePrefix) 148 g.Printf("\n") 149 for _, m := range g.modules { 150 g.Printf("@import %s;\n", m) 151 } 152 if g.Pkg != nil { 153 g.Printf("#include \"Universe.objc.h\"\n\n") 154 } 155 156 if g.Pkg != nil { 157 for _, pkg := range g.Pkg.Imports() { 158 if g.validPkg(pkg) { 159 g.Printf("#include %q\n", g.namePrefixOf(pkg)+".objc.h") 160 } 161 } 162 } 163 g.Printf("\n") 164 165 // Forward declaration of @class and @protocol 166 for _, s := range g.structs { 167 g.Printf("@class %s%s;\n", g.namePrefix, s.obj.Name()) 168 } 169 for _, i := range g.interfaces { 170 g.Printf("@protocol %s%s;\n", g.namePrefix, i.obj.Name()) 171 if i.summary.implementable { 172 g.Printf("@class %s%s;\n", g.namePrefix, i.obj.Name()) 173 // Forward declaration for other cases will be handled at the beginning of GenM. 174 } 175 } 176 if len(g.structs) > 0 || len(g.interfaces) > 0 { 177 g.Printf("\n") 178 } 179 180 // @interfaces 181 for _, i := range g.interfaces { 182 g.genInterfaceH(i.obj, i.t) 183 g.Printf("\n") 184 } 185 for _, s := range g.structs { 186 g.genStructH(s.obj, s.t) 187 g.Printf("\n") 188 } 189 190 // const 191 // TODO: prefix with k?, or use a class method? 192 for _, obj := range g.constants { 193 if _, ok := obj.Type().(*types.Basic); !ok || !g.isSupported(obj.Type()) { 194 g.Printf("// skipped const %s with unsupported type: %s\n\n", obj.Name(), obj.Type()) 195 continue 196 } 197 g.objcdoc(g.docs[obj.Name()].Doc()) 198 switch b := obj.Type().(*types.Basic); b.Kind() { 199 case types.String, types.UntypedString: 200 g.Printf("FOUNDATION_EXPORT NSString* const %s%s;\n", g.namePrefix, obj.Name()) 201 default: 202 g.Printf("FOUNDATION_EXPORT const %s %s%s;\n", g.objcType(obj.Type()), g.namePrefix, obj.Name()) 203 } 204 } 205 if len(g.constants) > 0 { 206 g.Printf("\n") 207 } 208 209 // var 210 if len(g.vars) > 0 { 211 g.Printf("@interface %s : NSObject\n", g.namePrefix) 212 for _, obj := range g.vars { 213 if t := obj.Type(); !g.isSupported(t) { 214 g.Printf("// skipped variable %s with unsupported type: %s\n\n", obj.Name(), t) 215 continue 216 } 217 objcType := g.objcType(obj.Type()) 218 g.objcdoc(g.docs[obj.Name()].Doc()) 219 g.Printf("+ (%s) %s;\n", objcType, objcNameReplacer(lowerFirst(obj.Name()))) 220 g.Printf("+ (void) set%s:(%s)v;\n", obj.Name(), objcType) 221 g.Printf("\n") 222 } 223 g.Printf("@end\n\n") 224 } 225 226 // static functions. 227 for _, obj := range g.funcs { 228 g.genFuncH(obj) 229 g.Printf("\n") 230 } 231 232 for _, i := range g.interfaces { 233 if i.summary.implementable { 234 g.Printf("@class %s%s;\n\n", g.namePrefix, i.obj.Name()) 235 } 236 } 237 for _, i := range g.interfaces { 238 if i.summary.implementable { 239 // @interface Interface -- similar to what genStructH does. 240 g.genInterfaceInterface(i.obj, i.summary, true) 241 g.Printf("\n") 242 } 243 } 244 245 g.Printf("#endif\n") 246 247 if len(g.err) > 0 { 248 return g.err 249 } 250 return nil 251 } 252 253 func (g *ObjcGen) gobindOpts() string { 254 opts := []string{"-lang=objc"} 255 if g.Prefix != "" { 256 opts = append(opts, fmt.Sprintf("-prefix=%q", g.Prefix)) 257 } 258 return strings.Join(opts, " ") 259 } 260 261 func (g *ObjcGen) GenM() error { 262 var pkgPath string 263 if g.Pkg != nil { 264 pkgPath = g.Pkg.Path() 265 } 266 g.Printf(objcPreamble, pkgPath, g.gobindOpts(), pkgPath) 267 g.Printf("#include <Foundation/Foundation.h>\n") 268 g.Printf("#include \"seq.h\"\n") 269 g.Printf("#include \"_cgo_export.h\"\n") 270 g.Printf("#include %q\n", g.namePrefix+".objc.h") 271 g.Printf("\n") 272 273 // struct 274 for _, s := range g.structs { 275 g.genStructM(s.obj, s.t) 276 g.Printf("\n") 277 } 278 279 // interface 280 var needProxy []*types.TypeName 281 for _, i := range g.interfaces { 282 if g.genInterfaceM(i.obj, i.t) { 283 needProxy = append(needProxy, i.obj) 284 } 285 g.Printf("\n") 286 } 287 288 // const 289 for _, o := range g.constants { 290 g.genConstM(o) 291 } 292 if len(g.constants) > 0 { 293 g.Printf("\n") 294 } 295 296 // vars 297 if len(g.vars) > 0 { 298 g.Printf("@implementation %s\n", g.namePrefix) 299 for _, o := range g.vars { 300 g.genVarM(o) 301 } 302 g.Printf("@end\n\n") 303 } 304 305 g.Printf("\n") 306 307 for _, obj := range g.funcs { 308 if !g.isSigSupported(obj.Type()) { 309 g.Printf("// skipped function %s with unsupported parameter or return types\n\n", obj.Name()) 310 continue 311 } 312 g.genFuncM(obj) 313 g.Printf("\n") 314 } 315 316 for _, i := range g.interfaces { 317 for _, m := range i.summary.callable { 318 if !g.isSigSupported(m.Type()) { 319 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", i.obj.Name(), m.Name()) 320 continue 321 } 322 g.genInterfaceMethodProxy(i.obj, m) 323 } 324 } 325 326 g.Printf("__attribute__((constructor)) static void init() {\n") 327 g.Indent() 328 g.Printf("init_seq();\n") 329 g.Outdent() 330 g.Printf("}\n") 331 332 if len(g.err) > 0 { 333 return g.err 334 } 335 336 return nil 337 } 338 339 func (g *ObjcGen) genVarM(o *types.Var) { 340 if t := o.Type(); !g.isSupported(t) { 341 g.Printf("// skipped variable %s with unsupported type: %s\n\n", o.Name(), t) 342 return 343 } 344 objcType := g.objcType(o.Type()) 345 346 // setter 347 g.Printf("+ (void) set%s:(%s)v {\n", o.Name(), objcType) 348 g.Indent() 349 g.genWrite("v", o.Type(), modeRetained) 350 g.Printf("var_set%s_%s(_v);\n", g.pkgPrefix, o.Name()) 351 g.genRelease("v", o.Type(), modeRetained) 352 g.Outdent() 353 g.Printf("}\n\n") 354 355 // getter 356 g.Printf("+ (%s) %s {\n", objcType, objcNameReplacer(lowerFirst(o.Name()))) 357 g.Indent() 358 g.Printf("%s r0 = ", g.cgoType(o.Type())) 359 g.Printf("var_get%s_%s();\n", g.pkgPrefix, o.Name()) 360 g.genRead("_r0", "r0", o.Type(), modeRetained) 361 g.Printf("return _r0;\n") 362 g.Outdent() 363 g.Printf("}\n\n") 364 } 365 366 func (g *ObjcGen) genConstM(o *types.Const) { 367 if _, ok := o.Type().(*types.Basic); !ok || !g.isSupported(o.Type()) { 368 g.Printf("// skipped const %s with unsupported type: %s\n\n", o.Name(), o.Type()) 369 return 370 } 371 cName := fmt.Sprintf("%s%s", g.namePrefix, o.Name()) 372 objcType := g.objcType(o.Type()) 373 374 switch b := o.Type().(*types.Basic); b.Kind() { 375 case types.Bool, types.UntypedBool: 376 v := "NO" 377 if constant.BoolVal(o.Val()) { 378 v = "YES" 379 } 380 g.Printf("const BOOL %s = %s;\n", cName, v) 381 382 case types.String, types.UntypedString: 383 g.Printf("NSString* const %s = @%s;\n", cName, o.Val().ExactString()) 384 385 case types.Int, types.Int8, types.Int16, types.Int32: 386 g.Printf("const %s %s = %s;\n", objcType, cName, o.Val()) 387 388 case types.Int64, types.UntypedInt: 389 i, exact := constant.Int64Val(o.Val()) 390 if !exact { 391 g.errorf("const value %s for %s cannot be represented as %s", o.Val(), o.Name(), objcType) 392 return 393 } 394 if i == math.MinInt64 { 395 // -9223372036854775808LL does not work because 922337203685477508 is 396 // larger than max int64. 397 g.Printf("const int64_t %s = %dLL-1;\n", cName, i+1) 398 } else { 399 g.Printf("const int64_t %s = %dLL;\n", cName, i) 400 } 401 402 case types.Float32, types.Float64, types.UntypedFloat: 403 f, _ := constant.Float64Val(o.Val()) 404 if math.IsInf(f, 0) || math.Abs(f) > math.MaxFloat64 { 405 g.errorf("const value %s for %s cannot be represented as double", o.Val(), o.Name()) 406 return 407 } 408 g.Printf("const %s %s = %g;\n", objcType, cName, f) 409 410 default: 411 g.errorf("unsupported const type %s for %s", b, o.Name()) 412 } 413 } 414 415 type funcSummary struct { 416 name string 417 goname string 418 ret string 419 sig *types.Signature 420 params, retParams []paramInfo 421 hasself bool 422 initName string 423 } 424 425 type paramInfo struct { 426 typ types.Type 427 name string 428 } 429 430 func (g *ObjcGen) funcSummary(obj *types.TypeName, f *types.Func) *funcSummary { 431 sig := f.Type().(*types.Signature) 432 s := &funcSummary{goname: f.Name(), sig: sig} 433 var om *objc.Func 434 var sigElems []string 435 oinf := g.ostructs[obj] 436 if oinf != nil { 437 om = oinf.methods[f.Name()] 438 } 439 if om != nil { 440 sigElems = strings.Split(om.Sig, ":") 441 s.name = sigElems[0] 442 } else { 443 s.name = f.Name() 444 } 445 params := sig.Params() 446 first := 0 447 if oinf != nil { 448 if params.Len() > 0 { 449 v := params.At(0) 450 if v.Name() == "self" { 451 t := v.Type() 452 if t, ok := t.(*types.Named); ok { 453 if pkg := t.Obj().Pkg(); pkgFirstElem(pkg) == "ObjC" { 454 s.hasself = true 455 module := pkg.Path()[len("ObjC/"):] 456 typName := module + "." + t.Obj().Name() 457 exp := g.namePrefix + "." + obj.Name() 458 if typName != exp { 459 g.errorf("the type %s of the `this` argument to method %s is not %s", typName, f.Name(), exp) 460 } 461 } 462 } 463 } 464 } 465 } 466 for i := first; i < params.Len(); i++ { 467 p := params.At(i) 468 v := paramInfo{ 469 typ: p.Type(), 470 } 471 if om != nil { 472 v.name = sigElems[i-first] 473 } else { 474 v.name = g.paramName(params, i) 475 } 476 s.params = append(s.params, v) 477 } 478 if obj != nil { 479 if pref := "New" + obj.Name(); strings.Index(f.Name(), pref) != -1 { 480 s.initName = "init" + f.Name()[len(pref):] 481 } 482 } 483 res := sig.Results() 484 switch res.Len() { 485 case 0: 486 s.ret = "void" 487 case 1: 488 p := res.At(0) 489 if isErrorType(p.Type()) { 490 s.retParams = append(s.retParams, paramInfo{ 491 typ: p.Type(), 492 name: "error", 493 }) 494 s.ret = "BOOL" 495 } else { 496 name := p.Name() 497 if name == "" || paramRE.MatchString(name) { 498 name = "ret0_" 499 } 500 typ := p.Type() 501 s.retParams = append(s.retParams, paramInfo{typ: typ, name: name}) 502 s.ret = g.objcType(typ) 503 } 504 case 2: 505 name := res.At(0).Name() 506 if name == "" || paramRE.MatchString(name) { 507 name = "ret0_" 508 } 509 typ := res.At(0).Type() 510 s.retParams = append(s.retParams, paramInfo{ 511 typ: typ, 512 name: name, 513 }) 514 if isNullableType(typ) { 515 s.ret = g.objcType(typ) // Return is nullable, so satisfies the ObjC/Swift error protocol 516 } else { 517 s.ret = "BOOL" // Return is not nullable, must use an output parameter and return bool 518 } 519 520 if !isErrorType(res.At(1).Type()) { 521 g.errorf("second result value must be of type error: %s", f) 522 return nil 523 } 524 s.retParams = append(s.retParams, paramInfo{ 525 typ: res.At(1).Type(), 526 name: "error", // TODO(hyangah): name collision check. 527 }) 528 default: 529 // TODO(hyangah): relax the constraint on multiple return params. 530 g.errorf("too many result values: %s", f) 531 return nil 532 } 533 534 return s 535 } 536 537 func (s *funcSummary) asFunc(g *ObjcGen) string { 538 var params []string 539 for _, p := range s.params { 540 params = append(params, g.objcType(p.typ)+" "+p.name) 541 } 542 skip := 0 543 if s.returnsVal() { 544 skip = 1 545 } 546 for _, p := range s.retParams[skip:] { 547 params = append(params, g.objcType(p.typ)+"* "+p.name) 548 } 549 paramContents := "void" 550 if len(params) > 0 { 551 paramContents = strings.Join(params, ", ") 552 } 553 return fmt.Sprintf("%s %s%s(%s)", s.ret, g.namePrefix, s.name, paramContents) 554 } 555 556 func (s *funcSummary) asMethod(g *ObjcGen) string { 557 return fmt.Sprintf("(%s)%s%s", s.ret, objcNameReplacer(lowerFirst(s.name)), s.asSignature(g)) 558 } 559 560 func (s *funcSummary) asSignature(g *ObjcGen) string { 561 var params []string 562 skip := 0 563 if s.hasself { 564 skip = 1 565 } 566 for i, p := range s.params[skip:] { 567 var key string 568 if i != 0 { 569 key = p.name 570 } 571 params = append(params, fmt.Sprintf("%s:(%s)%s", key, g.objcType(p.typ), p.name)) 572 } 573 skip = 0 574 if s.returnsVal() { 575 skip = 1 576 } 577 for _, p := range s.retParams[skip:] { 578 var key string 579 if len(params) > 0 { 580 key = p.name 581 } 582 params = append(params, fmt.Sprintf("%s:(%s)%s", key, g.objcType(p.typ)+"*", p.name)) 583 } 584 return strings.Join(params, " ") 585 } 586 587 func (s *funcSummary) asInitSignature(g *ObjcGen) string { 588 var params []string 589 for i, p := range s.params { 590 var key string 591 if i > 0 { 592 key = p.name 593 } 594 params = append(params, fmt.Sprintf("%s:(%s)%s", key, g.objcType(p.typ), p.name)) 595 } 596 return strings.Join(params, " ") 597 } 598 599 func (s *funcSummary) callMethod(g *ObjcGen) string { 600 var params []string 601 for i, p := range s.params { 602 var key string 603 if i != 0 { 604 key = p.name 605 } 606 params = append(params, fmt.Sprintf("%s:_%s", key, p.name)) 607 } 608 skip := 0 609 if s.returnsVal() { 610 skip = 1 611 } 612 for _, p := range s.retParams[skip:] { 613 var key string 614 if len(params) > 0 { 615 key = p.name 616 } 617 params = append(params, fmt.Sprintf("%s:&%s", key, p.name)) 618 } 619 return fmt.Sprintf("%s%s", objcNameReplacer(lowerFirst(s.name)), strings.Join(params, " ")) 620 } 621 622 func (s *funcSummary) returnsVal() bool { 623 return (len(s.retParams) == 1 && !isErrorType(s.retParams[0].typ)) || (len(s.retParams) == 2 && isNullableType(s.retParams[0].typ)) 624 } 625 626 func (g *ObjcGen) paramName(params *types.Tuple, pos int) string { 627 name := basicParamName(params, pos) 628 return objcNameReplacer(name) 629 } 630 631 func (g *ObjcGen) genFuncH(obj *types.Func) { 632 if !g.isSigSupported(obj.Type()) { 633 g.Printf("// skipped function %s with unsupported parameter or return types\n\n", obj.Name()) 634 return 635 } 636 if s := g.funcSummary(nil, obj); s != nil { 637 g.objcdoc(g.docs[obj.Name()].Doc()) 638 g.Printf("FOUNDATION_EXPORT %s;\n", s.asFunc(g)) 639 } 640 } 641 642 func (g *ObjcGen) genFuncM(obj *types.Func) { 643 s := g.funcSummary(nil, obj) 644 if s == nil { 645 return 646 } 647 g.Printf("%s {\n", s.asFunc(g)) 648 g.Indent() 649 g.genFunc(s, "") 650 g.Outdent() 651 g.Printf("}\n") 652 } 653 654 func (g *ObjcGen) genGetter(oName string, f *types.Var) { 655 t := f.Type() 656 g.Printf("- (%s)%s {\n", g.objcType(t), objcNameReplacer(lowerFirst(f.Name()))) 657 g.Indent() 658 g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n") 659 g.Printf("%s r0 = ", g.cgoType(f.Type())) 660 g.Printf("proxy%s_%s_%s_Get(refnum);\n", g.pkgPrefix, oName, f.Name()) 661 g.genRead("_r0", "r0", f.Type(), modeRetained) 662 g.Printf("return _r0;\n") 663 g.Outdent() 664 g.Printf("}\n\n") 665 } 666 667 func (g *ObjcGen) genSetter(oName string, f *types.Var) { 668 t := f.Type() 669 670 g.Printf("- (void)set%s:(%s)v {\n", f.Name(), g.objcType(t)) 671 g.Indent() 672 g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n") 673 g.genWrite("v", f.Type(), modeRetained) 674 g.Printf("proxy%s_%s_%s_Set(refnum, _v);\n", g.pkgPrefix, oName, f.Name()) 675 g.genRelease("v", f.Type(), modeRetained) 676 g.Outdent() 677 g.Printf("}\n\n") 678 } 679 680 func (g *ObjcGen) genWrite(varName string, t types.Type, mode varMode) { 681 switch t := t.(type) { 682 case *types.Basic: 683 switch t.Kind() { 684 case types.String: 685 g.Printf("nstring _%s = go_seq_from_objc_string(%s);\n", varName, varName) 686 default: 687 g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) 688 } 689 case *types.Slice: 690 switch e := t.Elem().(type) { 691 case *types.Basic: 692 switch e.Kind() { 693 case types.Uint8: // Byte. 694 g.Printf("nbyteslice _%s = go_seq_from_objc_bytearray(%s, %d);\n", varName, varName, toCFlag(mode == modeRetained)) 695 default: 696 g.errorf("unsupported type: %s", t) 697 } 698 default: 699 g.errorf("unsupported type: %s", t) 700 } 701 case *types.Named: 702 switch u := t.Underlying().(type) { 703 case *types.Interface: 704 g.genRefWrite(varName) 705 default: 706 g.errorf("unsupported named type: %s / %T", u, u) 707 } 708 case *types.Pointer: 709 g.genRefWrite(varName) 710 default: 711 g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) 712 } 713 } 714 715 func (g *ObjcGen) genRefWrite(varName string) { 716 g.Printf("int32_t _%s;\n", varName) 717 g.Printf("if ([%s conformsToProtocol:@protocol(goSeqRefInterface)]) {\n", varName) 718 g.Indent() 719 g.Printf("id<goSeqRefInterface> %[1]s_proxy = (id<goSeqRefInterface>)(%[1]s);\n", varName) 720 g.Printf("_%s = go_seq_go_to_refnum(%s_proxy._ref);\n", varName, varName) 721 g.Outdent() 722 g.Printf("} else {\n") 723 g.Indent() 724 g.Printf("_%s = go_seq_to_refnum(%s);\n", varName, varName) 725 g.Outdent() 726 g.Printf("}\n") 727 } 728 729 func (g *ObjcGen) genRefRead(toName, fromName string, t types.Type) { 730 ptype := g.refTypeBase(t) 731 g.Printf("%s* %s = nil;\n", ptype, toName) 732 g.Printf("GoSeqRef* %s_ref = go_seq_from_refnum(%s);\n", toName, fromName) 733 g.Printf("if (%s_ref != NULL) {\n", toName) 734 g.Printf(" %s = %s_ref.obj;\n", toName, toName) 735 g.Printf(" if (%s == nil) {\n", toName) 736 if isObjcType(t) { 737 g.Printf(" LOG_FATAL(@\"unexpected NULL reference\");\n") 738 } else { 739 g.Printf(" %s = [[%s alloc] initWithRef:%s_ref];\n", toName, ptype, toName) 740 } 741 g.Printf(" }\n") 742 g.Printf("}\n") 743 } 744 745 func (g *ObjcGen) genRead(toName, fromName string, t types.Type, mode varMode) { 746 switch t := t.(type) { 747 case *types.Basic: 748 switch t.Kind() { 749 case types.String: 750 g.Printf("NSString *%s = go_seq_to_objc_string(%s);\n", toName, fromName) 751 case types.Bool: 752 g.Printf("BOOL %s = %s ? YES : NO;\n", toName, fromName) 753 default: 754 g.Printf("%s %s = (%s)%s;\n", g.objcType(t), toName, g.objcType(t), fromName) 755 } 756 case *types.Slice: 757 switch e := t.Elem().(type) { 758 case *types.Basic: 759 switch e.Kind() { 760 case types.Uint8: // Byte. 761 g.Printf("NSData *%s = go_seq_to_objc_bytearray(%s, %d);\n", toName, fromName, toCFlag(mode == modeRetained)) 762 default: 763 g.errorf("unsupported type: %s", t) 764 } 765 default: 766 g.errorf("unsupported type: %s", t) 767 } 768 case *types.Pointer: 769 switch t := t.Elem().(type) { 770 case *types.Named: 771 g.genRefRead(toName, fromName, types.NewPointer(t)) 772 default: 773 g.errorf("unsupported type %s", t) 774 } 775 case *types.Named: 776 switch t.Underlying().(type) { 777 case *types.Interface, *types.Pointer: 778 g.genRefRead(toName, fromName, t) 779 default: 780 g.errorf("unsupported, direct named type %s", t) 781 } 782 default: 783 g.Printf("%s %s = (%s)%s;\n", g.objcType(t), toName, g.objcType(t), fromName) 784 } 785 } 786 787 func (g *ObjcGen) genFunc(s *funcSummary, objName string) { 788 skip := 0 789 if objName != "" { 790 g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n") 791 if s.hasself { 792 skip = 1 793 g.Printf("int32_t _self = go_seq_to_refnum(self);\n") 794 } 795 } 796 for _, p := range s.params[skip:] { 797 g.genWrite(p.name, p.typ, modeTransient) 798 } 799 resPrefix := "" 800 if len(s.retParams) > 0 { 801 if len(s.retParams) == 1 { 802 g.Printf("%s r0 = ", g.cgoType(s.retParams[0].typ)) 803 } else { 804 resPrefix = "res." 805 g.Printf("struct proxy%s_%s_%s_return res = ", g.pkgPrefix, objName, s.goname) 806 } 807 } 808 g.Printf("proxy%s_%s_%s(", g.pkgPrefix, objName, s.goname) 809 if objName != "" { 810 g.Printf("refnum") 811 if s.hasself { 812 g.Printf(", _self") 813 } 814 } 815 for i, p := range s.params[skip:] { 816 if i > 0 || objName != "" { 817 g.Printf(", ") 818 } 819 g.Printf("_%s", p.name) 820 } 821 g.Printf(");\n") 822 for _, p := range s.params { 823 g.genRelease(p.name, p.typ, modeTransient) 824 } 825 826 for i, r := range s.retParams { 827 g.genRead("_"+r.name, fmt.Sprintf("%sr%d", resPrefix, i), r.typ, modeRetained) 828 } 829 skip = 0 830 if s.returnsVal() { 831 skip = 1 832 } 833 for _, p := range s.retParams[skip:] { 834 if isErrorType(p.typ) { 835 g.Printf("if (_%s != nil && %s != nil) {\n", p.name, p.name) 836 g.Indent() 837 g.Printf("*%s = _%s;\n", p.name, p.name) 838 g.Outdent() 839 g.Printf("}\n") 840 } else { 841 g.Printf("*%s = _%s;\n", p.name, p.name) 842 } 843 } 844 845 if n := len(s.retParams); n > 0 { 846 var ( 847 first = s.retParams[0] 848 last = s.retParams[n-1] 849 ) 850 if (n == 1 && isErrorType(last.typ)) || (n == 2 && !isNullableType(first.typ) && isErrorType(last.typ)) { 851 g.Printf("return (_%s == nil);\n", last.name) 852 } else { 853 if s.returnsVal() && isErrorType(last.typ) { 854 g.Printf("if (_%s != nil) {\n", last.name) 855 g.Indent() 856 g.Printf("return nil;\n") 857 g.Outdent() 858 g.Printf("}\n") 859 } 860 g.Printf("return _%s;\n", first.name) 861 } 862 } 863 } 864 865 func (g *ObjcGen) genInterfaceInterface(obj *types.TypeName, summary ifaceSummary, isProtocol bool) { 866 doc := g.docs[obj.Name()] 867 g.objcdoc(doc.Doc()) 868 g.Printf("@interface %[1]s%[2]s : ", g.namePrefix, obj.Name()) 869 if isErrorType(obj.Type()) { 870 g.Printf("NSError") 871 } else { 872 g.Printf("NSObject") 873 } 874 prots := []string{"goSeqRefInterface"} 875 if isProtocol { 876 prots = append(prots, fmt.Sprintf("%[1]s%[2]s", g.namePrefix, obj.Name())) 877 } 878 g.Printf(" <%s>", strings.Join(prots, ", ")) 879 g.Printf(" {\n}\n") 880 g.Printf("@property(strong, readonly) id _ref;\n") 881 g.Printf("\n") 882 g.Printf("- (instancetype)initWithRef:(id)ref;\n") 883 for _, m := range summary.callable { 884 if !g.isSigSupported(m.Type()) { 885 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) 886 continue 887 } 888 s := g.funcSummary(nil, m) 889 g.objcdoc(doc.Member(m.Name())) 890 g.Printf("- %s;\n", s.asMethod(g)) 891 } 892 g.Printf("@end\n") 893 } 894 895 func (g *ObjcGen) genInterfaceH(obj *types.TypeName, t *types.Interface) { 896 summary := makeIfaceSummary(t) 897 if !summary.implementable { 898 g.genInterfaceInterface(obj, summary, false) 899 return 900 } 901 g.Printf("@protocol %s%s <NSObject>\n", g.namePrefix, obj.Name()) 902 for _, m := range makeIfaceSummary(t).callable { 903 if !g.isSigSupported(m.Type()) { 904 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) 905 continue 906 } 907 s := g.funcSummary(nil, m) 908 g.Printf("- %s;\n", s.asMethod(g)) 909 } 910 g.Printf("@end\n") 911 } 912 913 func (g *ObjcGen) genInterfaceM(obj *types.TypeName, t *types.Interface) bool { 914 summary := makeIfaceSummary(t) 915 916 // @implementation Interface -- similar to what genStructM does. 917 g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name()) 918 g.Printf("}\n") 919 g.Printf("\n") 920 g.Printf("- (instancetype)initWithRef:(id)ref {\n") 921 g.Indent() 922 if isErrorType(obj.Type()) { 923 g.Printf("if (self) {\n") 924 g.Printf(" __ref = ref;\n") 925 g.Printf(" self = [super initWithDomain:@\"go\" code:1 userInfo:@{NSLocalizedDescriptionKey: [self error]}];\n") 926 g.Printf("}\n") 927 } else { 928 g.Printf("self = [super init];\n") 929 g.Printf("if (self) { __ref = ref; }\n") 930 } 931 g.Printf("return self;\n") 932 g.Outdent() 933 g.Printf("}\n") 934 g.Printf("\n") 935 936 for _, m := range summary.callable { 937 if !g.isSigSupported(m.Type()) { 938 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) 939 continue 940 } 941 s := g.funcSummary(nil, m) 942 g.Printf("- %s {\n", s.asMethod(g)) 943 g.Indent() 944 g.genFunc(s, obj.Name()) 945 g.Outdent() 946 g.Printf("}\n\n") 947 } 948 g.Printf("@end\n") 949 g.Printf("\n") 950 951 return summary.implementable 952 } 953 954 func (g *ObjcGen) genInterfaceMethodProxy(obj *types.TypeName, m *types.Func) { 955 oName := obj.Name() 956 s := g.funcSummary(nil, m) 957 g.genInterfaceMethodSignature(m, oName, false, g.paramName) 958 g.Indent() 959 g.Printf("@autoreleasepool {\n") 960 g.Indent() 961 g.Printf("%s* o = go_seq_objc_from_refnum(refnum);\n", g.refTypeBase(obj.Type())) 962 for _, p := range s.params { 963 g.genRead("_"+p.name, p.name, p.typ, modeTransient) 964 } 965 966 // call method 967 for _, p := range s.retParams { 968 if isErrorType(p.typ) { 969 g.Printf("NSError* %s = nil;\n", p.name) 970 } else { 971 g.Printf("%s %s;\n", g.objcType(p.typ), p.name) 972 } 973 } 974 975 if isErrorType(obj.Type()) && m.Name() == "Error" { 976 // As a special case, ObjC NSErrors are passed to Go pretending to implement the Go error interface. 977 // They don't actually have an Error method, so calls to to it needs to be rerouted. 978 g.Printf("%s = [o localizedDescription];\n", s.retParams[0].name) 979 } else { 980 if s.ret == "void" { 981 g.Printf("[o %s];\n", s.callMethod(g)) 982 } else if !s.returnsVal() { 983 g.Printf("%s returnVal = [o %s];\n", s.ret, s.callMethod(g)) 984 } else { 985 g.Printf("%s = [o %s];\n", s.retParams[0].name, s.callMethod(g)) 986 } 987 } 988 989 if len(s.retParams) > 0 { 990 if len(s.retParams) == 1 && !isErrorType(s.retParams[0].typ) { 991 p := s.retParams[0] 992 g.genWrite(p.name, p.typ, modeRetained) 993 g.Printf("return _%s;\n", p.name) 994 } else { 995 var rets []string 996 for _, p := range s.retParams { 997 if isErrorType(p.typ) { 998 g.Printf("NSError *_%s = nil;\n", p.name) 999 if !s.returnsVal() { 1000 g.Printf("if (!returnVal) {\n") 1001 } else { 1002 g.Printf("if (%s != nil) {\n", p.name) 1003 } 1004 g.Indent() 1005 g.Printf("_%[1]s = %[1]s;\n", p.name) 1006 g.Outdent() 1007 g.Printf("}\n") 1008 g.genWrite("_"+p.name, p.typ, modeRetained) 1009 rets = append(rets, "__"+p.name) 1010 } else { 1011 g.genWrite(p.name, p.typ, modeRetained) 1012 rets = append(rets, "_"+p.name) 1013 } 1014 } 1015 if len(rets) > 1 { 1016 g.Printf("cproxy%s_%s_%s_return _sres = {\n", g.pkgPrefix, oName, m.Name()) 1017 g.Printf(" %s\n", strings.Join(rets, ", ")) 1018 g.Printf("};\n") 1019 g.Printf("return _sres;\n") 1020 } else { 1021 g.Printf("return %s;\n", rets[0]) 1022 } 1023 } 1024 } 1025 g.Outdent() 1026 g.Printf("}\n") 1027 g.Outdent() 1028 g.Printf("}\n\n") 1029 } 1030 1031 // genRelease cleans up arguments that weren't copied in genWrite. 1032 func (g *ObjcGen) genRelease(varName string, t types.Type, mode varMode) { 1033 switch t := t.(type) { 1034 case *types.Slice: 1035 switch e := t.Elem().(type) { 1036 case *types.Basic: 1037 switch e.Kind() { 1038 case types.Uint8: // Byte. 1039 if mode == modeTransient { 1040 // If the argument was not mutable, go_seq_from_objc_bytearray created a copy. 1041 // Free it here. 1042 g.Printf("if (![%s isKindOfClass:[NSMutableData class]]) {\n", varName) 1043 g.Printf(" free(_%s.ptr);\n", varName) 1044 g.Printf("}\n") 1045 } 1046 } 1047 } 1048 } 1049 } 1050 1051 func (g *ObjcGen) genStructH(obj *types.TypeName, t *types.Struct) { 1052 doc := g.docs[obj.Name()] 1053 g.objcdoc(doc.Doc()) 1054 g.Printf("@interface %s%s : ", g.namePrefix, obj.Name()) 1055 oinf := g.ostructs[obj] 1056 var prots []string 1057 if oinf != nil { 1058 for _, sup := range oinf.supers { 1059 if !sup.Protocol { 1060 g.Printf(sup.Name) 1061 } else { 1062 prots = append(prots, sup.Name) 1063 } 1064 } 1065 } else { 1066 g.Printf("NSObject") 1067 prots = append(prots, "goSeqRefInterface") 1068 } 1069 pT := types.NewPointer(obj.Type()) 1070 for _, iface := range g.allIntf { 1071 p := iface.obj.Pkg() 1072 if g.Pkg != nil && g.Pkg != p { 1073 // To avoid header include cycles, only declare implementation of interfaces 1074 // from imported packages. TODO(elias.naur): Include every interface that 1075 // doesn't introduce an include cycle. 1076 found := false 1077 for _, imp := range g.Pkg.Imports() { 1078 if imp == p { 1079 found = true 1080 break 1081 } 1082 } 1083 if !found { 1084 continue 1085 } 1086 } 1087 obj := iface.obj 1088 if types.AssignableTo(pT, obj.Type()) { 1089 n := fmt.Sprintf("%s%s", g.namePrefixOf(obj.Pkg()), obj.Name()) 1090 prots = append(prots, n) 1091 } 1092 } 1093 1094 if len(prots) > 0 { 1095 g.Printf(" <%s>", strings.Join(prots, ", ")) 1096 } 1097 g.Printf(" {\n") 1098 g.Printf("}\n") 1099 g.Printf("@property(strong, readonly) id _ref;\n") 1100 g.Printf("\n") 1101 g.Printf("- (instancetype)initWithRef:(id)ref;\n") 1102 cons := g.constructors[obj] 1103 if oinf == nil { 1104 for _, f := range cons { 1105 if !g.isSigSupported(f.Type()) { 1106 g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", obj.Name(), f.Name()) 1107 continue 1108 } 1109 g.genInitH(obj, f) 1110 } 1111 } 1112 if oinf != nil || len(cons) == 0 { 1113 g.Printf("- (instancetype)init;\n") 1114 } 1115 1116 // accessors to exported fields. 1117 for _, f := range exportedFields(t) { 1118 if t := f.Type(); !g.isSupported(t) { 1119 g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", obj.Name(), f.Name(), t) 1120 continue 1121 } 1122 name, typ := f.Name(), g.objcFieldType(f.Type()) 1123 g.objcdoc(doc.Member(f.Name())) 1124 g.Printf("- (%s)%s;\n", typ, objcNameReplacer(lowerFirst(name))) 1125 g.Printf("- (void)set%s:(%s)v;\n", name, typ) 1126 } 1127 1128 // exported methods 1129 for _, m := range exportedMethodSet(types.NewPointer(obj.Type())) { 1130 if !g.isSigSupported(m.Type()) { 1131 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) 1132 continue 1133 } 1134 s := g.funcSummary(obj, m) 1135 g.objcdoc(doc.Member(m.Name())) 1136 g.Printf("- %s;\n", s.asMethod(g)) 1137 } 1138 g.Printf("@end\n") 1139 } 1140 1141 func (g *ObjcGen) objcdoc(doc string) { 1142 if doc == "" { 1143 return 1144 } 1145 g.Printf("/**\n * %s */\n", doc) 1146 } 1147 1148 func (g *ObjcGen) genStructM(obj *types.TypeName, t *types.Struct) { 1149 fields := exportedFields(t) 1150 methods := exportedMethodSet(types.NewPointer(obj.Type())) 1151 1152 g.Printf("\n") 1153 oinf := g.ostructs[obj] 1154 g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name()) 1155 g.Printf("}\n\n") 1156 g.Printf("- (instancetype)initWithRef:(id)ref {\n") 1157 g.Indent() 1158 g.Printf("self = [super init];\n") 1159 g.Printf("if (self) { __ref = ref; }\n") 1160 g.Printf("return self;\n") 1161 g.Outdent() 1162 g.Printf("}\n\n") 1163 cons := g.constructors[obj] 1164 if oinf == nil { 1165 for _, f := range cons { 1166 if !g.isSigSupported(f.Type()) { 1167 g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", obj, f.Name()) 1168 continue 1169 } 1170 g.genInitM(obj, f) 1171 } 1172 } 1173 if oinf != nil || len(cons) == 0 { 1174 g.Printf("- (instancetype)init {\n") 1175 g.Indent() 1176 g.Printf("self = [super init];\n") 1177 g.Printf("if (self) {\n") 1178 g.Indent() 1179 g.Printf("__ref = go_seq_from_refnum(new_%s_%s());\n", g.pkgPrefix, obj.Name()) 1180 g.Outdent() 1181 g.Printf("}\n") 1182 g.Printf("return self;\n") 1183 g.Outdent() 1184 g.Printf("}\n\n") 1185 } 1186 1187 for _, f := range fields { 1188 if !g.isSupported(f.Type()) { 1189 g.Printf("// skipped unsupported field %s with type %s\n\n", f.Name(), f.Type()) 1190 continue 1191 } 1192 g.genGetter(obj.Name(), f) 1193 g.genSetter(obj.Name(), f) 1194 } 1195 1196 for _, m := range methods { 1197 if !g.isSigSupported(m.Type()) { 1198 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) 1199 continue 1200 } 1201 s := g.funcSummary(obj, m) 1202 g.Printf("- %s {\n", s.asMethod(g)) 1203 g.Indent() 1204 g.genFunc(s, obj.Name()) 1205 g.Outdent() 1206 g.Printf("}\n\n") 1207 } 1208 g.Printf("@end\n\n") 1209 } 1210 1211 func (g *ObjcGen) genInitH(obj *types.TypeName, f *types.Func) { 1212 s := g.funcSummary(obj, f) 1213 doc := g.docs[f.Name()] 1214 g.objcdoc(doc.Doc()) 1215 g.Printf("- (instancetype)%s%s;\n", s.initName, s.asInitSignature(g)) 1216 } 1217 1218 func (g *ObjcGen) genInitM(obj *types.TypeName, f *types.Func) { 1219 s := g.funcSummary(obj, f) 1220 g.Printf("- (instancetype)%s%s {\n", s.initName, s.asInitSignature(g)) 1221 g.Indent() 1222 g.Printf("self = [super init];\n") 1223 g.Printf("if (!self) return nil;\n") 1224 for _, p := range s.params { 1225 g.genWrite(p.name, p.typ, modeTransient) 1226 } 1227 // Constructors always return a mandatory *T and an optional error 1228 if len(s.retParams) == 1 { 1229 g.Printf("%s refnum = ", g.cgoType(s.retParams[0].typ)) 1230 } else { 1231 g.Printf("struct proxy%s__%s_return res = ", g.pkgPrefix, s.goname) 1232 } 1233 g.Printf("proxy%s__%s(", g.pkgPrefix, s.goname) 1234 for i, p := range s.params { 1235 if i > 0 { 1236 g.Printf(", ") 1237 } 1238 g.Printf("_%s", p.name) 1239 } 1240 g.Printf(");\n") 1241 for _, p := range s.params { 1242 g.genRelease(p.name, p.typ, modeTransient) 1243 } 1244 if len(s.retParams) == 2 { 1245 g.Printf("int32_t refnum = res.r0;\n") 1246 g.Printf("GoSeqRef *_err = go_seq_from_refnum(res.r1);\n") 1247 } 1248 g.Printf("__ref = go_seq_from_refnum(refnum);\n") 1249 if len(s.retParams) == 2 { 1250 g.Printf("if (_err != NULL)\n") 1251 g.Printf(" return nil;\n") 1252 } 1253 g.Printf("return self;\n") 1254 g.Outdent() 1255 g.Printf("}\n\n") 1256 } 1257 1258 func (g *ObjcGen) errorf(format string, args ...interface{}) { 1259 g.err = append(g.err, fmt.Errorf(format, args...)) 1260 } 1261 1262 func (g *ObjcGen) refTypeBase(typ types.Type) string { 1263 switch typ := typ.(type) { 1264 case *types.Pointer: 1265 if _, ok := typ.Elem().(*types.Named); ok { 1266 return g.objcType(typ.Elem()) 1267 } 1268 case *types.Named: 1269 n := typ.Obj() 1270 if isObjcType(typ) { 1271 return g.wrapMap[n.Name()].Name 1272 } 1273 if isErrorType(typ) || g.validPkg(n.Pkg()) { 1274 switch typ.Underlying().(type) { 1275 case *types.Interface, *types.Struct: 1276 return g.namePrefixOf(n.Pkg()) + n.Name() 1277 } 1278 } 1279 } 1280 1281 // fallback to whatever objcType returns. This must not happen. 1282 return g.objcType(typ) 1283 } 1284 1285 func (g *ObjcGen) objcFieldType(t types.Type) string { 1286 if isErrorType(t) { 1287 return "NSError*" 1288 } 1289 return g.objcType(t) 1290 } 1291 1292 func (g *ObjcGen) objcType(typ types.Type) string { 1293 if isErrorType(typ) { 1294 return "NSError*" 1295 } 1296 1297 switch typ := typ.(type) { 1298 case *types.Basic: 1299 switch typ.Kind() { 1300 case types.Bool, types.UntypedBool: 1301 return "BOOL" 1302 case types.Int: 1303 return "long" 1304 case types.Int8: 1305 return "int8_t" 1306 case types.Int16: 1307 return "int16_t" 1308 case types.Int32, types.UntypedRune: // types.Rune 1309 return "int32_t" 1310 case types.Int64, types.UntypedInt: 1311 return "int64_t" 1312 case types.Uint8: 1313 // byte is an alias of uint8, and the alias is lost. 1314 return "byte" 1315 case types.Uint16: 1316 return "uint16_t" 1317 case types.Uint32: 1318 return "uint32_t" 1319 case types.Uint64: 1320 return "uint64_t" 1321 case types.Float32: 1322 return "float" 1323 case types.Float64, types.UntypedFloat: 1324 return "double" 1325 case types.String, types.UntypedString: 1326 return "NSString*" 1327 default: 1328 g.errorf("unsupported type: %s", typ) 1329 return "TODO" 1330 } 1331 case *types.Slice: 1332 elem := g.objcType(typ.Elem()) 1333 // Special case: NSData seems to be a better option for byte slice. 1334 if elem == "byte" { 1335 return "NSData*" 1336 } 1337 // TODO(hyangah): support other slice types: NSArray or CFArrayRef. 1338 // Investigate the performance implication. 1339 g.errorf("unsupported type: %s", typ) 1340 return "TODO" 1341 case *types.Pointer: 1342 if _, ok := typ.Elem().(*types.Named); ok { 1343 return g.objcType(typ.Elem()) + "*" 1344 } 1345 g.errorf("unsupported pointer to type: %s", typ) 1346 return "TODO" 1347 case *types.Named: 1348 n := typ.Obj() 1349 if isObjcType(typ) { 1350 w := g.wrapMap[n.Name()] 1351 return w.ObjcType() 1352 } 1353 if !isErrorType(typ) && !g.validPkg(n.Pkg()) { 1354 g.errorf("type %s is in package %s, which is not bound", n.Name(), n.Pkg().Name()) 1355 return "TODO" 1356 } 1357 switch t := typ.Underlying().(type) { 1358 case *types.Interface: 1359 if makeIfaceSummary(t).implementable { 1360 return "id<" + g.namePrefixOf(n.Pkg()) + n.Name() + ">" 1361 } else { 1362 return g.namePrefixOf(n.Pkg()) + n.Name() + "*" 1363 } 1364 case *types.Struct: 1365 return g.namePrefixOf(n.Pkg()) + n.Name() 1366 } 1367 g.errorf("unsupported, named type %s", typ) 1368 return "TODO" 1369 default: 1370 g.errorf("unsupported type: %#+v, %s", typ, typ) 1371 return "TODO" 1372 } 1373 } 1374 1375 // embeddedObjcTypes returns the possible empty list of Objc types embedded 1376 // in the given struct type. 1377 func embeddedObjcTypes(t *types.Struct) []string { 1378 typeSet := make(map[string]struct{}) 1379 var typs []string 1380 for i := 0; i < t.NumFields(); i++ { 1381 f := t.Field(i) 1382 if !f.Exported() { 1383 continue 1384 } 1385 if ft := f.Type(); isObjcType(ft) { 1386 name := ft.(*types.Named).Obj().Name() 1387 if _, exists := typeSet[name]; !exists { 1388 typeSet[name] = struct{}{} 1389 typs = append(typs, name) 1390 } 1391 } 1392 } 1393 return typs 1394 } 1395 1396 func isObjcType(t types.Type) bool { 1397 return typePkgFirstElem(t) == "ObjC" 1398 } 1399 1400 var objcNameReplacer = newNameSanitizer([]string{ 1401 "bool", "bycopy", "byref", "char", "const", "double", "float", 1402 "id", "in", "init", "inout", "int", "long", "nil", "oneway", 1403 "out", "self", "short", "signed", "super", "unsigned", "void", 1404 "volatile"}) 1405 1406 const ( 1407 objcPreamble = `// Objective-C API for talking to %[1]s Go package. 1408 // gobind %[2]s %[3]s 1409 // 1410 // File is generated by gobind. Do not edit. 1411 1412 ` 1413 )