github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/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/token" 10 "go/types" 11 "strings" 12 "unicode" 13 "unicode/utf8" 14 ) 15 16 // TODO(hyangah): error code/domain propagation 17 18 type objcGen struct { 19 *printer 20 fset *token.FileSet 21 pkg *types.Package 22 err ErrorList 23 24 // fields set by init. 25 pkgName string 26 namePrefix string 27 funcs []*types.Func 28 names []*types.TypeName 29 } 30 31 func capitalize(n string) string { 32 firstRune, size := utf8.DecodeRuneInString(n) 33 return string(unicode.ToUpper(firstRune)) + n[size:] 34 } 35 36 func (g *objcGen) init() { 37 g.pkgName = g.pkg.Name() 38 g.namePrefix = "Go" + capitalize(g.pkgName) 39 g.funcs = nil 40 g.names = nil 41 42 scope := g.pkg.Scope() 43 for _, name := range scope.Names() { 44 obj := scope.Lookup(name) 45 if !obj.Exported() { 46 continue 47 } 48 switch obj := obj.(type) { 49 case *types.Func: 50 if isCallable(obj) { 51 g.funcs = append(g.funcs, obj) 52 } 53 case *types.TypeName: 54 g.names = append(g.names, obj) 55 // TODO(hyangah): *types.Const, *types.Var 56 } 57 } 58 } 59 60 const objcPreamble = `// Objective-C API for talking to %s Go package. 61 // gobind -lang=objc %s 62 // 63 // File is generated by gobind. Do not edit. 64 65 ` 66 67 func (g *objcGen) genH() error { 68 g.init() 69 70 g.Printf(objcPreamble, g.pkg.Path(), g.pkg.Path()) 71 g.Printf("#ifndef __Go%s_H__\n", capitalize(g.pkgName)) 72 g.Printf("#define __Go%s_H__\n", capitalize(g.pkgName)) 73 g.Printf("\n") 74 g.Printf("#include <Foundation/Foundation.h>") 75 g.Printf("\n\n") 76 77 // @class names 78 for _, obj := range g.names { 79 named := obj.Type().(*types.Named) 80 switch t := named.Underlying().(type) { 81 case *types.Struct: 82 g.Printf("@class %s%s;\n\n", g.namePrefix, obj.Name()) 83 case *types.Interface: 84 if !makeIfaceSummary(t).implementable { 85 g.Printf("@class %s%s;\n\n", g.namePrefix, obj.Name()) 86 } 87 } 88 } 89 90 // @interfaces 91 for _, obj := range g.names { 92 named := obj.Type().(*types.Named) 93 switch t := named.Underlying().(type) { 94 case *types.Struct: 95 g.genStructH(obj, t) 96 g.Printf("\n") 97 case *types.Interface: 98 g.genInterfaceH(obj, t) 99 g.Printf("\n") 100 } 101 } 102 103 // static functions. 104 for _, obj := range g.funcs { 105 g.genFuncH(obj) 106 g.Printf("\n") 107 } 108 109 // declare all named types first. 110 g.Printf("#endif\n") 111 112 if len(g.err) > 0 { 113 return g.err 114 } 115 return nil 116 } 117 118 func (g *objcGen) genM() error { 119 g.init() 120 121 g.Printf(objcPreamble, g.pkg.Path(), g.pkg.Path()) 122 g.Printf("#include %q\n", g.namePrefix+".h") 123 g.Printf("#include <Foundation/Foundation.h>\n") 124 g.Printf("#include \"seq.h\"\n") 125 g.Printf("\n") 126 g.Printf("static NSString* errDomain = @\"go.%s\";\n", g.pkg.Path()) 127 g.Printf("\n") 128 129 g.Printf("@protocol goSeqRefInterface\n") 130 g.Printf("-(GoSeqRef*) ref;\n") 131 g.Printf("@end\n") 132 g.Printf("\n") 133 134 g.Printf("#define _DESCRIPTOR_ %q\n\n", g.pkgName) 135 for i, obj := range g.funcs { 136 g.Printf("#define _CALL_%s_ %d\n", obj.Name(), i+1) 137 } 138 g.Printf("\n") 139 140 // struct, interface. 141 var interfaces []*types.TypeName 142 for _, obj := range g.names { 143 named := obj.Type().(*types.Named) 144 switch t := named.Underlying().(type) { 145 case *types.Struct: 146 g.genStructM(obj, t) 147 case *types.Interface: 148 if g.genInterfaceM(obj, t) { 149 interfaces = append(interfaces, obj) 150 } 151 } 152 g.Printf("\n") 153 } 154 155 // global functions. 156 for _, obj := range g.funcs { 157 g.genFuncM(obj) 158 g.Printf("\n") 159 } 160 161 // register proxy functions. 162 if len(interfaces) > 0 { 163 g.Printf("__attribute__((constructor)) static void init() {\n") 164 g.Indent() 165 for _, obj := range interfaces { 166 g.Printf("go_seq_register_proxy(\"go.%s.%s\", proxy%s%s);\n", g.pkgName, obj.Name(), g.namePrefix, obj.Name()) 167 } 168 g.Outdent() 169 g.Printf("}\n") 170 } 171 172 if len(g.err) > 0 { 173 return g.err 174 } 175 176 return nil 177 } 178 179 type funcSummary struct { 180 name string 181 ret string 182 params, retParams []paramInfo 183 } 184 185 type paramInfo struct { 186 typ types.Type 187 name string 188 } 189 190 func (g *objcGen) funcSummary(obj *types.Func) *funcSummary { 191 s := &funcSummary{name: obj.Name()} 192 193 sig := obj.Type().(*types.Signature) 194 params := sig.Params() 195 for i := 0; i < params.Len(); i++ { 196 p := params.At(i) 197 v := paramInfo{ 198 typ: p.Type(), 199 name: paramName(params, i), 200 } 201 s.params = append(s.params, v) 202 } 203 204 res := sig.Results() 205 switch res.Len() { 206 case 0: 207 s.ret = "void" 208 case 1: 209 p := res.At(0) 210 if isErrorType(p.Type()) { 211 s.retParams = append(s.retParams, paramInfo{ 212 typ: p.Type(), 213 name: "error", 214 }) 215 s.ret = "BOOL" 216 } else { 217 name := p.Name() 218 if name == "" || paramRE.MatchString(name) { 219 name = "ret0_" 220 } 221 typ := p.Type() 222 s.retParams = append(s.retParams, paramInfo{typ: typ, name: name}) 223 s.ret = g.objcType(typ) 224 } 225 case 2: 226 name := res.At(0).Name() 227 if name == "" || paramRE.MatchString(name) { 228 name = "ret0_" 229 } 230 s.retParams = append(s.retParams, paramInfo{ 231 typ: res.At(0).Type(), 232 name: name, 233 }) 234 235 if !isErrorType(res.At(1).Type()) { 236 g.errorf("second result value must be of type error: %s", obj) 237 return nil 238 } 239 s.retParams = append(s.retParams, paramInfo{ 240 typ: res.At(1).Type(), 241 name: "error", // TODO(hyangah): name collision check. 242 }) 243 s.ret = "BOOL" 244 default: 245 // TODO(hyangah): relax the constraint on multiple return params. 246 g.errorf("too many result values: %s", obj) 247 return nil 248 } 249 250 return s 251 } 252 253 func (s *funcSummary) asFunc(g *objcGen) string { 254 var params []string 255 for _, p := range s.params { 256 params = append(params, g.objcType(p.typ)+" "+p.name) 257 } 258 if !s.returnsVal() { 259 for _, p := range s.retParams { 260 params = append(params, g.objcType(p.typ)+"* "+p.name) 261 } 262 } 263 return fmt.Sprintf("%s %s%s(%s)", s.ret, g.namePrefix, s.name, strings.Join(params, ", ")) 264 } 265 266 func (s *funcSummary) asMethod(g *objcGen) string { 267 var params []string 268 for i, p := range s.params { 269 var key string 270 if i != 0 { 271 key = p.name 272 } 273 params = append(params, fmt.Sprintf("%s:(%s)%s", key, g.objcType(p.typ), p.name)) 274 } 275 if !s.returnsVal() { 276 for _, p := range s.retParams { 277 var key string 278 if len(params) > 0 { 279 key = p.name 280 } 281 params = append(params, fmt.Sprintf("%s:(%s)%s", key, g.objcType(p.typ)+"*", p.name)) 282 } 283 } 284 return fmt.Sprintf("(%s)%s%s", s.ret, s.name, strings.Join(params, " ")) 285 } 286 287 func (s *funcSummary) callMethod(g *objcGen) string { 288 var params []string 289 for i, p := range s.params { 290 var key string 291 if i != 0 { 292 key = p.name 293 } 294 params = append(params, fmt.Sprintf("%s:%s", key, p.name)) 295 } 296 if !s.returnsVal() { 297 for _, p := range s.retParams { 298 var key string 299 if len(params) > 0 { 300 key = p.name 301 } 302 params = append(params, fmt.Sprintf("%s:&%s", key, p.name)) 303 } 304 } 305 return fmt.Sprintf("%s%s", s.name, strings.Join(params, " ")) 306 } 307 308 func (s *funcSummary) returnsVal() bool { 309 return len(s.retParams) == 1 && !isErrorType(s.retParams[0].typ) 310 } 311 312 func (g *objcGen) genFuncH(obj *types.Func) { 313 if s := g.funcSummary(obj); s != nil { 314 g.Printf("FOUNDATION_EXPORT %s;\n", s.asFunc(g)) 315 } 316 } 317 318 func (g *objcGen) seqType(typ types.Type) string { 319 s := seqType(typ) 320 if s == "String" { 321 // TODO(hyangah): non utf-8 strings. 322 s = "UTF8" 323 } 324 return s 325 } 326 327 func (g *objcGen) genFuncM(obj *types.Func) { 328 s := g.funcSummary(obj) 329 if s == nil { 330 return 331 } 332 g.Printf("%s {\n", s.asFunc(g)) 333 g.Indent() 334 g.genFunc("_DESCRIPTOR_", fmt.Sprintf("_CALL_%s_", s.name), s, false) 335 g.Outdent() 336 g.Printf("}\n") 337 } 338 339 func (g *objcGen) genGetter(desc string, f *types.Var) { 340 t := f.Type() 341 if isErrorType(t) { 342 t = types.Typ[types.String] 343 } 344 s := &funcSummary{ 345 name: f.Name(), 346 ret: g.objcType(t), 347 retParams: []paramInfo{{typ: t, name: "ret_"}}, 348 } 349 350 g.Printf("- %s {\n", s.asMethod(g)) 351 g.Indent() 352 g.genFunc(desc+"_DESCRIPTOR_", desc+"_FIELD_"+f.Name()+"_GET_", s, true) 353 g.Outdent() 354 g.Printf("}\n\n") 355 } 356 357 func (g *objcGen) genSetter(desc string, f *types.Var) { 358 t := f.Type() 359 if isErrorType(t) { 360 t = types.Typ[types.String] 361 } 362 s := &funcSummary{ 363 name: "set" + f.Name(), 364 ret: "void", 365 params: []paramInfo{{typ: t, name: "v"}}, 366 } 367 368 g.Printf("- %s {\n", s.asMethod(g)) 369 g.Indent() 370 g.genFunc(desc+"_DESCRIPTOR_", desc+"_FIELD_"+f.Name()+"_SET_", s, true) 371 g.Outdent() 372 g.Printf("}\n\n") 373 } 374 375 func (g *objcGen) genFunc(pkgDesc, callDesc string, s *funcSummary, isMethod bool) { 376 g.Printf("GoSeq in_ = {};\n") 377 g.Printf("GoSeq out_ = {};\n") 378 if isMethod { 379 g.Printf("go_seq_writeRef(&in_, self.ref);\n") 380 } 381 for _, p := range s.params { 382 st := g.seqType(p.typ) 383 if st == "Ref" { 384 g.Printf("if ([(id<NSObject>)(%s) isKindOfClass:[%s class]]) {\n", p.name, g.refTypeBase(p.typ)) 385 g.Indent() 386 g.Printf("id<goSeqRefInterface> %[1]s_proxy = (id<goSeqRefInterface>)(%[1]s);\n", p.name) 387 g.Printf("go_seq_writeRef(&in_, %s_proxy.ref);\n", p.name) 388 g.Outdent() 389 g.Printf("} else {\n") 390 g.Indent() 391 g.Printf("go_seq_writeObjcRef(&in_, %s);\n", p.name) 392 g.Outdent() 393 g.Printf("}\n") 394 } else { 395 g.Printf("go_seq_write%s(&in_, %s);\n", st, p.name) 396 } 397 } 398 g.Printf("go_seq_send(%s, %s, &in_, &out_);\n", pkgDesc, callDesc) 399 400 if s.returnsVal() { 401 p := s.retParams[0] 402 if seqTyp := g.seqType(p.typ); seqTyp != "Ref" { 403 g.Printf("%s %s = go_seq_read%s(&out_);\n", g.objcType(p.typ), p.name, g.seqType(p.typ)) 404 } else { 405 ptype := g.objcType(p.typ) 406 g.Printf("GoSeqRef* %s_ref = go_seq_readRef(&out_);\n", p.name) 407 g.Printf("%s %s = %s_ref.obj;\n", ptype, p.name, p.name) 408 g.Printf("if (%s == NULL) {\n", p.name) 409 g.Indent() 410 g.Printf("%s = [[%s alloc] initWithRef:%s_ref];\n", p.name, g.refTypeBase(p.typ), p.name) 411 g.Outdent() 412 g.Printf("}\n") 413 } 414 } else { 415 for _, p := range s.retParams { 416 if isErrorType(p.typ) { 417 g.Printf("NSString* _%s = go_seq_readUTF8(&out_);\n", p.name) 418 g.Printf("if ([_%s length] != 0 && %s != nil) {\n", p.name, p.name) 419 g.Indent() 420 g.Printf("NSMutableDictionary* details = [NSMutableDictionary dictionary];\n") 421 g.Printf("[details setValue:_%s forKey:NSLocalizedDescriptionKey];\n", p.name) 422 g.Printf("*%s = [NSError errorWithDomain:errDomain code:1 userInfo:details];\n", p.name) 423 g.Outdent() 424 g.Printf("}\n") 425 } else if seqTyp := g.seqType(p.typ); seqTyp != "Ref" { 426 g.Printf("%s %s_val = go_seq_read%s(&out_);\n", g.objcType(p.typ), p.name, g.seqType(p.typ)) 427 g.Printf("if (%s != NULL) {\n", p.name) 428 g.Indent() 429 g.Printf("*%s = %s_val;\n", p.name, p.name) 430 g.Outdent() 431 g.Printf("}\n") 432 } else { 433 g.Printf("GoSeqRef* %s_ref = go_seq_readRef(&out_);\n", p.name) 434 g.Printf("if (%s != NULL) {\n", p.name) 435 g.Indent() 436 g.Printf("*%s = %s_ref.obj;\n", p.name, p.name) 437 g.Printf("if (*%s == NULL) {\n", p.name) 438 g.Indent() 439 g.Printf("*%s = [[%s alloc] initWithRef:%s_ref];\n", p.name, g.refTypeBase(p.typ), p.name) 440 g.Outdent() 441 g.Printf("}\n") 442 g.Outdent() 443 g.Printf("}\n") 444 } 445 } 446 } 447 448 g.Printf("go_seq_free(&in_);\n") 449 g.Printf("go_seq_free(&out_);\n") 450 if n := len(s.retParams); n > 0 { 451 p := s.retParams[n-1] 452 if isErrorType(p.typ) { 453 g.Printf("return ([_%s length] == 0);\n", p.name) 454 } else { 455 g.Printf("return %s;\n", p.name) 456 } 457 } 458 } 459 460 func (g *objcGen) genInterfaceInterface(obj *types.TypeName, summary ifaceSummary, isProtocol bool) { 461 g.Printf("@interface %[1]s%[2]s : NSObject", g.namePrefix, obj.Name()) 462 if isProtocol { 463 g.Printf(" <%[1]s%[2]s>", g.namePrefix, obj.Name()) 464 } 465 g.Printf(" {\n}\n") 466 g.Printf("@property(strong, readonly) id ref;\n") 467 g.Printf("\n") 468 g.Printf("- (id)initWithRef:(id)ref;\n") 469 for _, m := range summary.callable { 470 s := g.funcSummary(m) 471 g.Printf("- %s;\n", s.asMethod(g)) 472 } 473 g.Printf("@end\n") 474 g.Printf("\n") 475 } 476 477 func (g *objcGen) genInterfaceH(obj *types.TypeName, t *types.Interface) { 478 summary := makeIfaceSummary(t) 479 if !summary.implementable { 480 g.genInterfaceInterface(obj, summary, false) 481 return 482 } 483 g.Printf("@protocol %s%s\n", g.namePrefix, obj.Name()) 484 for _, m := range makeIfaceSummary(t).callable { 485 s := g.funcSummary(m) 486 g.Printf("- %s;\n", s.asMethod(g)) 487 } 488 g.Printf("@end\n") 489 } 490 491 func (g *objcGen) genInterfaceM(obj *types.TypeName, t *types.Interface) bool { 492 summary := makeIfaceSummary(t) 493 494 desc := fmt.Sprintf("_GO_%s_%s", g.pkgName, obj.Name()) 495 g.Printf("#define %s_DESCRIPTOR_ \"go.%s.%s\"\n", desc, g.pkgName, obj.Name()) 496 for i, m := range summary.callable { 497 g.Printf("#define %s_%s_ (0x%x0a)\n", desc, m.Name(), i+1) 498 } 499 g.Printf("\n") 500 501 if summary.implementable { 502 // @interface Interface -- similar to what genStructH does. 503 g.genInterfaceInterface(obj, summary, true) 504 } 505 506 // @implementation Interface -- similar to what genStructM does. 507 g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name()) 508 g.Printf("}\n") 509 g.Printf("\n") 510 g.Printf("- (id)initWithRef:(id)ref {\n") 511 g.Indent() 512 g.Printf("self = [super init];\n") 513 g.Printf("if (self) { _ref = ref; }\n") 514 g.Printf("return self;\n") 515 g.Outdent() 516 g.Printf("}\n") 517 g.Printf("\n") 518 519 for _, m := range summary.callable { 520 s := g.funcSummary(m) 521 g.Printf("- %s {\n", s.asMethod(g)) 522 g.Indent() 523 g.genFunc(desc+"_DESCRIPTOR_", desc+"_"+m.Name()+"_", s, true) 524 g.Outdent() 525 g.Printf("}\n\n") 526 } 527 g.Printf("@end\n") 528 g.Printf("\n") 529 530 // proxy function. 531 if summary.implementable { 532 g.Printf("static void proxy%s%s(id obj, int code, GoSeq* in, GoSeq* out) {\n", g.namePrefix, obj.Name()) 533 g.Indent() 534 g.Printf("switch (code) {\n") 535 for _, m := range summary.callable { 536 g.Printf("case %s_%s_: {\n", desc, m.Name()) 537 g.Indent() 538 g.genInterfaceMethodProxy(obj, g.funcSummary(m)) 539 g.Outdent() 540 g.Printf("} break;\n") 541 } 542 g.Printf("default:\n") 543 g.Indent() 544 g.Printf("NSLog(@\"unknown code %%x for %s_DESCRIPTOR_\", code);\n", desc) 545 g.Outdent() 546 g.Printf("}\n") 547 g.Outdent() 548 g.Printf("}\n") 549 } 550 551 return summary.implementable 552 } 553 554 func (g *objcGen) genInterfaceMethodProxy(obj *types.TypeName, s *funcSummary) { 555 g.Printf("id<%[1]s%[2]s> o = (id<%[1]s%[2]s>)(obj);\n", g.namePrefix, obj.Name()) 556 // read params from GoSeq* inseq 557 for _, p := range s.params { 558 stype := g.seqType(p.typ) 559 ptype := g.objcType(p.typ) 560 if stype == "Ref" { 561 g.Printf("GoSeqRef* %s_ref = go_seq_readRef(in);\n", p.name) 562 g.Printf("%s %s = %s_ref.obj;\n", ptype, p.name, p.name) 563 g.Printf("if (%s == NULL) {\n", p.name) 564 g.Indent() 565 g.Printf("%s = [[%s alloc] initWithRef:%s_ref];\n", p.name, g.refTypeBase(p.typ), p.name) 566 g.Outdent() 567 g.Printf("}\n") 568 } else { 569 g.Printf("%s %s = go_seq_read%s(in);\n", ptype, p.name, stype) 570 } 571 } 572 573 // call method 574 if !s.returnsVal() { 575 for _, p := range s.retParams { 576 if isErrorType(p.typ) { 577 g.Printf("NSError* %s = NULL;\n", p.name) 578 } else { 579 g.Printf("%s %s;\n", g.objcType(p.typ), p.name) 580 } 581 } 582 } 583 584 if s.ret == "void" { 585 g.Printf("[o %s];\n", s.callMethod(g)) 586 } else { 587 g.Printf("%s returnVal = [o %s];\n", s.ret, s.callMethod(g)) 588 } 589 590 // write result to GoSeq* outseq 591 if len(s.retParams) == 0 { 592 return 593 } 594 if s.returnsVal() { // len(s.retParams) == 1 && s.retParams[0] != error 595 p := s.retParams[0] 596 if stype := g.seqType(p.typ); stype == "Ref" { 597 g.Printf("if [(id<NSObject>)(returnVal) isKindOfClass:[%s class]]) {\n", g.refTypeBase(p.typ)) 598 g.Indent() 599 g.Printf("id<goSeqRefInterface>retVal_proxy = (id<goSeqRefInterface>)(returnVal);\n") 600 g.Printf("go_seq_writeRef(out, retVal_proxy.ref);\n") 601 g.Outdent() 602 g.Printf("} else {\n") 603 g.Indent() 604 g.Printf("go_seq_writeRef(out, returnVal);\n") 605 g.Outdent() 606 g.Printf("}\n") 607 } else { 608 g.Printf("go_seq_write%s(out, returnVal);\n", stype) 609 } 610 return 611 } 612 for i, p := range s.retParams { 613 if isErrorType(p.typ) { 614 if i == len(s.retParams)-1 { // last param. 615 g.Printf("if (returnVal) {\n") 616 } else { 617 g.Printf("if (%s == NULL) {\n", p.name) 618 } 619 g.Indent() 620 g.Printf("go_seq_writeUTF8(out, NULL);\n") 621 g.Outdent() 622 g.Printf("} else {\n") 623 g.Indent() 624 g.Printf("NSString* %[1]sDesc = [%[1]s localizedDescription];\n", p.name) 625 g.Printf("if (%[1]sDesc == NULL || %[1]sDesc.length == 0) {\n", p.name) 626 g.Indent() 627 g.Printf("%[1]sDesc = @\"gobind: unknown error\";\n", p.name) 628 g.Outdent() 629 g.Printf("}\n") 630 g.Printf("go_seq_writeUTF8(out, %sDesc);\n", p.name) 631 g.Outdent() 632 g.Printf("}\n") 633 } else if seqTyp := g.seqType(p.typ); seqTyp != "Ref" { 634 // TODO(hyangah): NULL. 635 g.Printf("if [(id<NSObject>)(%s) isKindOfClass:[%s class]]) {\n", p.name, g.refTypeBase(p.typ)) 636 g.Indent() 637 g.Printf("id<goSeqRefInterface>%[1]s_proxy = (id<goSeqRefInterface>)(%[1]s);\n", p.name) 638 g.Printf("go_seq_writeRef(out, %s_proxy.ref);\n", p.name) 639 g.Outdent() 640 g.Printf("} else {\n") 641 g.Indent() 642 g.Printf("go_seq_writeObjcRef(out, %s);\n", p.name) 643 g.Outdent() 644 g.Printf("}\n") 645 } else { 646 g.Printf("go_seq_write%s(out, %s);\n", seqTyp, p.name) 647 } 648 } 649 } 650 651 func (g *objcGen) genStructH(obj *types.TypeName, t *types.Struct) { 652 g.Printf("@interface %s%s : NSObject {\n", g.namePrefix, obj.Name()) 653 g.Printf("}\n") 654 g.Printf("@property(strong, readonly) id ref;\n") 655 g.Printf("\n") 656 g.Printf("- (id)initWithRef:(id)ref;\n") 657 658 // accessors to exported fields. 659 for _, f := range exportedFields(t) { 660 name, typ := f.Name(), g.objcFieldType(f.Type()) 661 g.Printf("- (%s)%s;\n", typ, name) 662 g.Printf("- (void)set%s:(%s)v;\n", name, typ) 663 } 664 665 // exported methods 666 for _, m := range exportedMethodSet(types.NewPointer(obj.Type())) { 667 s := g.funcSummary(m) 668 g.Printf("- %s;\n", s.asMethod(g)) 669 } 670 g.Printf("@end\n") 671 } 672 673 func (g *objcGen) genStructM(obj *types.TypeName, t *types.Struct) { 674 fields := exportedFields(t) 675 methods := exportedMethodSet(types.NewPointer(obj.Type())) 676 677 desc := fmt.Sprintf("_GO_%s_%s", g.pkgName, obj.Name()) 678 g.Printf("#define %s_DESCRIPTOR_ \"go.%s.%s\"\n", desc, g.pkgName, obj.Name()) 679 for i, f := range fields { 680 g.Printf("#define %s_FIELD_%s_GET_ (0x%x0f)\n", desc, f.Name(), i) 681 g.Printf("#define %s_FIELD_%s_SET_ (0x%x1f)\n", desc, f.Name(), i) 682 } 683 for i, m := range methods { 684 g.Printf("#define %s_%s_ (0x%x0c)\n", desc, m.Name(), i) 685 } 686 687 g.Printf("\n") 688 g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name()) 689 g.Printf("}\n\n") 690 g.Printf("- (id)initWithRef:(id)ref {\n") 691 g.Indent() 692 g.Printf("self = [super init];\n") 693 g.Printf("if (self) { _ref = ref; }\n") 694 g.Printf("return self;\n") 695 g.Outdent() 696 g.Printf("}\n\n") 697 698 for _, f := range fields { 699 g.genGetter(desc, f) 700 g.genSetter(desc, f) 701 } 702 703 for _, m := range methods { 704 s := g.funcSummary(m) 705 g.Printf("- %s {\n", s.asMethod(g)) 706 g.Indent() 707 g.genFunc(desc+"_DESCRIPTOR_", desc+"_"+m.Name()+"_", s, true) 708 g.Outdent() 709 g.Printf("}\n\n") 710 } 711 g.Printf("@end\n") 712 } 713 714 func (g *objcGen) errorf(format string, args ...interface{}) { 715 g.err = append(g.err, fmt.Errorf(format, args...)) 716 } 717 718 func (g *objcGen) refTypeBase(typ types.Type) string { 719 switch typ := typ.(type) { 720 case *types.Pointer: 721 if _, ok := typ.Elem().(*types.Named); ok { 722 return g.objcType(typ.Elem()) 723 } 724 case *types.Named: 725 n := typ.Obj() 726 if n.Pkg() == g.pkg { 727 switch typ.Underlying().(type) { 728 case *types.Interface, *types.Struct: 729 return g.namePrefix + n.Name() 730 } 731 } 732 } 733 734 // fallback to whatever objcType returns. This must not happen. 735 return g.objcType(typ) 736 } 737 738 func (g *objcGen) objcFieldType(t types.Type) string { 739 if isErrorType(t) { 740 return "NSString*" 741 } 742 return g.objcType(t) 743 } 744 745 func (g *objcGen) objcType(typ types.Type) string { 746 if isErrorType(typ) { 747 return "NSError*" 748 } 749 750 switch typ := typ.(type) { 751 case *types.Basic: 752 switch typ.Kind() { 753 case types.Bool: 754 return "BOOL" 755 case types.Int: 756 return "int" 757 case types.Int8: 758 return "int8_t" 759 case types.Int16: 760 return "int16_t" 761 case types.Int32: 762 return "int32_t" 763 case types.Int64: 764 return "int64_t" 765 case types.Uint8: 766 // byte is an alias of uint8, and the alias is lost. 767 return "byte" 768 case types.Uint16: 769 return "uint16_t" 770 case types.Uint32: 771 return "uint32_t" 772 case types.Uint64: 773 return "uint64_t" 774 case types.Float32: 775 return "float" 776 case types.Float64: 777 return "double" 778 case types.String: 779 return "NSString*" 780 default: 781 g.errorf("unsupported type: %s", typ) 782 return "TODO" 783 } 784 case *types.Slice: 785 elem := g.objcType(typ.Elem()) 786 // Special case: NSData seems to be a better option for byte slice. 787 if elem == "byte" { 788 return "NSData*" 789 } 790 // TODO(hyangah): support other slice types: NSArray or CFArrayRef. 791 // Investigate the performance implication. 792 g.errorf("unsupported type: %s", typ) 793 return "TODO" 794 case *types.Pointer: 795 if _, ok := typ.Elem().(*types.Named); ok { 796 return g.objcType(typ.Elem()) + "*" 797 } 798 g.errorf("unsupported pointer to type: %s", typ) 799 return "TODO" 800 case *types.Named: 801 n := typ.Obj() 802 if n.Pkg() != g.pkg { 803 g.errorf("type %s is in package %s; only types defined in package %s is supported", n.Name(), n.Pkg().Name(), g.pkg.Name()) 804 return "TODO" 805 } 806 switch t := typ.Underlying().(type) { 807 case *types.Interface: 808 if makeIfaceSummary(t).implementable { 809 return "id<" + g.namePrefix + n.Name() + ">" 810 } else { 811 return g.namePrefix + n.Name() + "*" 812 } 813 case *types.Struct: 814 return g.namePrefix + n.Name() 815 } 816 g.errorf("unsupported, named type %s", typ) 817 return "TODO" 818 default: 819 g.errorf("unsupported type: %#+v, %s", typ, typ) 820 return "TODO" 821 } 822 }