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  }