github.com/F4RD1N/gomobile@v1.0.1/bind/genobjcw.go (about)

     1  // Copyright 2016 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  	"path"
     9  	"strings"
    10  
    11  	"github.com/F4RD1N/gomobile/internal/importers/objc"
    12  )
    13  
    14  type (
    15  	// ObjCWrapper generates Go and C stubs for ObjC interfaces and protocols.
    16  	ObjcWrapper struct {
    17  		*Printer
    18  		imported map[string]*objc.Named
    19  		// The list of ObjC types.
    20  		types []*objc.Named
    21  		// The list of Go package paths with ObjC wrappers.
    22  		pkgNames []string
    23  		modules  []string
    24  		// For each ObjC module, the list of ObjC types within.
    25  		modMap map[string][]*objc.Named
    26  		// For each module/name Go package path, the ObjC type
    27  		// with static functions or constants.
    28  		typePkgs map[string]*objc.Named
    29  		// supers is the map of types that need Super methods.
    30  		supers map[string]struct{}
    31  	}
    32  )
    33  
    34  // Init initializes the ObjC types wrapper generator. Types is the
    35  // list of types to wrap, genNames the list of generated type names.
    36  func (g *ObjcWrapper) Init(types []*objc.Named, genNames []string) {
    37  	g.supers = make(map[string]struct{})
    38  	for _, s := range genNames {
    39  		g.supers[s] = struct{}{}
    40  	}
    41  	g.types = types
    42  	g.imported = make(map[string]*objc.Named)
    43  	g.modMap = make(map[string][]*objc.Named)
    44  	g.typePkgs = make(map[string]*objc.Named)
    45  	pkgSet := make(map[string]struct{})
    46  	for _, n := range types {
    47  		g.imported[n.GoName] = n
    48  		typePkg := n.Module + "/" + n.GoName
    49  		g.typePkgs[typePkg] = n
    50  		if !n.Generated {
    51  			if _, exists := g.modMap[n.Module]; !exists {
    52  				g.modules = append(g.modules, n.Module)
    53  			}
    54  		}
    55  		g.modMap[n.Module] = append(g.modMap[n.Module], n)
    56  		if _, exists := pkgSet[n.Module]; !exists {
    57  			pkgSet[n.Module] = struct{}{}
    58  			g.pkgNames = append(g.pkgNames, n.Module)
    59  		}
    60  		g.pkgNames = append(g.pkgNames, typePkg)
    61  	}
    62  }
    63  
    64  func (g *ObjcWrapper) GenM() {
    65  	g.Printf(gobindPreamble)
    66  	// For objc_msgSend* functions.
    67  	g.Printf("@import ObjectiveC.message;\n")
    68  	g.Printf("#include \"seq.h\"\n")
    69  	g.Printf("#include \"interfaces.h\"\n\n")
    70  	for _, n := range g.types {
    71  		g.genM(n)
    72  	}
    73  	g.Printf("\n")
    74  	for _, n := range g.types {
    75  		for _, f := range n.AllMethods {
    76  			if !g.isFuncSupported(f) {
    77  				continue
    78  			}
    79  			g.genCFuncDecl("cproxy", n.GoName, f)
    80  			g.genCFuncBody(n, f, false)
    81  			if _, exists := g.supers[n.GoName]; exists {
    82  				g.genCFuncDecl("csuper", n.GoName, f)
    83  				g.genCFuncBody(n, f, true)
    84  			}
    85  		}
    86  	}
    87  }
    88  
    89  func (g *ObjcWrapper) genCFuncBody(n *objc.Named, f *objc.Func, super bool) {
    90  	g.Printf(" {\n")
    91  	g.Indent()
    92  	if !f.Static {
    93  		g.Printf("%s _this = go_seq_from_refnum(this).obj;\n", n.ObjcType())
    94  	}
    95  	var errParam *objc.Param
    96  	for i, a := range f.Params {
    97  		if i == len(f.Params)-1 && g.isErrorType(a.Type) {
    98  			errParam = a
    99  			break
   100  		}
   101  		g.genCToObjC(a.Name, a.Type, modeTransient)
   102  	}
   103  	if errParam != nil {
   104  		g.Printf("NSError *%s = nil;\n", errParam.Name)
   105  	}
   106  	if f.Constructor {
   107  		g.Printf("%s _this = [%s alloc];\n", n.ObjcType(), n.Name)
   108  	}
   109  	if super {
   110  		g.Printf("struct objc_super _super = {\n")
   111  		g.Printf("	.receiver = _this,\n")
   112  		g.Printf("	.super_class = class_getSuperclass([%s class]),\n", n.Name)
   113  		g.Printf("};\n")
   114  	}
   115  	retType := "void"
   116  	if f.Ret != nil {
   117  		retType = g.objcType(f.Ret)
   118  		g.Printf("%s res = ", retType)
   119  	}
   120  	// There is no direct way to send a message to a class' super
   121  	// class from outside the class itself. Use objc_msgSendSuper instead
   122  	// which is what the compiler uses itself. To keep us honest and to exercise
   123  	// the code paths more use objc_msgSend for regular calls as well.
   124  	//
   125  	// A regular call looks like this:
   126  	//
   127  	// res = ((<return type> (*)(id, SEL, <argument_types>))objc_msgSend)(_this, @selector(...), <arguments>)
   128  	//
   129  	// a call to super looks like this:
   130  	//
   131  	// ret = ((<return type> (*)(id, SEL, <argument_types>))objc_msgSendSuper)(<struct objc_super>, <arguments>)
   132  	if f.Ret != nil {
   133  		switch f.Ret.Kind {
   134  		case objc.String, objc.Bool, objc.Data, objc.Int, objc.Uint, objc.Short, objc.Ushort, objc.Char, objc.Uchar, objc.Float, objc.Double, objc.Class, objc.Protocol:
   135  		default:
   136  			// If support for struct results is added, objc_msgSend_stret must be used
   137  			panic("unsupported type kind - use objc_msgSend_stret?")
   138  		}
   139  	}
   140  	g.Printf("((%s (*)(", retType)
   141  	if super {
   142  		g.Printf("struct objc_super *")
   143  	} else {
   144  		g.Printf("id")
   145  	}
   146  	g.Printf(", SEL")
   147  	for _, a := range f.Params {
   148  		g.Printf(", %s", g.objcType(a.Type))
   149  	}
   150  	g.Printf("))")
   151  	if super {
   152  		g.Printf("objc_msgSendSuper")
   153  	} else {
   154  		g.Printf("objc_msgSend")
   155  	}
   156  	g.Printf(")(")
   157  	if f.Static && !f.Constructor {
   158  		g.Printf("[%s class]", n.Name)
   159  	} else {
   160  		if super {
   161  			g.Printf("&_super")
   162  		} else {
   163  			g.Printf("_this")
   164  		}
   165  	}
   166  	g.Printf(", @selector(%s)", f.Sig)
   167  	for _, a := range f.Params {
   168  		arg := "_" + a.Name
   169  		if a == errParam {
   170  			arg = "&" + a.Name
   171  		}
   172  		g.Printf(", %s", arg)
   173  	}
   174  	g.Printf(");\n")
   175  	if errParam != nil {
   176  		g.Printf("NSError *_%s = nil;\n", errParam.Name)
   177  		if f.Ret != nil {
   178  			g.Printf("if (!res && %s != nil) {\n", errParam.Name)
   179  		} else {
   180  			g.Printf("if (%s != nil) {\n", errParam.Name)
   181  		}
   182  		g.Printf("	_%[1]s = %[1]s;\n", errParam.Name)
   183  		g.Printf("}\n")
   184  		g.genObjCToC("_"+errParam.Name, g.errType(), modeRetained)
   185  	}
   186  	ret := f.Ret
   187  	if ret != nil && ret.Kind == objc.Bool && errParam != nil {
   188  		ret = nil
   189  	}
   190  	if ret != nil {
   191  		g.genObjCToC("res", ret, modeRetained)
   192  	}
   193  	switch {
   194  	case ret != nil && errParam != nil:
   195  		stype := strings.Replace(g.cType(ret), " ", "_", -1)
   196  		g.Printf("ret_%s _sres = {_res, __%s};\n", stype, errParam.Name)
   197  		g.Printf("return _sres;\n")
   198  	case ret != nil:
   199  		g.Printf("return _res;\n")
   200  	case errParam != nil:
   201  		g.Printf("return __%s;\n", errParam.Name)
   202  	}
   203  	g.Outdent()
   204  	g.Printf("}\n\n")
   205  }
   206  
   207  func (_ *ObjcWrapper) errType() *objc.Type {
   208  	return &objc.Type{Kind: objc.Class, Name: "NSError"}
   209  }
   210  
   211  func (g *ObjcWrapper) genM(n *objc.Named) {
   212  	for _, f := range n.Funcs {
   213  		if !g.isFuncSupported(f) {
   214  			continue
   215  		}
   216  		g.genCFuncDecl("cproxy", n.GoName, f)
   217  		g.genCFuncBody(n, f, false)
   218  	}
   219  }
   220  
   221  func (g *ObjcWrapper) GenH() {
   222  	g.Printf(gobindPreamble)
   223  	g.Printf("#include \"seq.h\"\n\n")
   224  	for _, m := range g.modules {
   225  		g.Printf("@import %s;\n", m)
   226  	}
   227  	// Include header files for generated types
   228  	for _, n := range g.pkgNames {
   229  		hasGen := false
   230  		for _, t := range g.modMap[n] {
   231  			if t.Generated {
   232  				hasGen = true
   233  				break
   234  			}
   235  		}
   236  		if hasGen {
   237  			g.Printf("#import %q\n", n+".objc.h")
   238  		}
   239  	}
   240  	for _, tn := range []string{"int", "nstring", "nbyteslice", "long", "unsigned long", "short", "unsigned short", "bool", "char", "unsigned char", "float", "double"} {
   241  		sn := strings.Replace(tn, " ", "_", -1)
   242  		g.Printf("typedef struct ret_%s {\n", sn)
   243  		g.Printf("	%s res;\n", tn)
   244  		g.Printf("	int err;\n")
   245  		g.Printf("} ret_%s;\n", sn)
   246  	}
   247  	g.Printf("\n")
   248  	for _, n := range g.types {
   249  		for _, f := range n.AllMethods {
   250  			if !g.isFuncSupported(f) {
   251  				continue
   252  			}
   253  			g.Printf("extern ")
   254  			g.genCFuncDecl("cproxy", n.GoName, f)
   255  			g.Printf(";\n")
   256  			if _, exists := g.supers[n.GoName]; exists {
   257  				g.Printf("extern ")
   258  				g.genCFuncDecl("csuper", n.GoName, f)
   259  				g.Printf(";\n")
   260  			}
   261  		}
   262  	}
   263  	for _, cls := range g.types {
   264  		g.genH(cls)
   265  	}
   266  }
   267  
   268  func (g *ObjcWrapper) genH(n *objc.Named) {
   269  	for _, f := range n.Funcs {
   270  		if !g.isFuncSupported(f) {
   271  			continue
   272  		}
   273  		g.Printf("extern ")
   274  		g.genCFuncDecl("cproxy", n.GoName, f)
   275  		g.Printf(";\n")
   276  	}
   277  }
   278  
   279  func (g *ObjcWrapper) genCFuncDecl(prefix, name string, f *objc.Func) {
   280  	returnsErr := len(f.Params) > 0 && g.isErrorType(f.Params[len(f.Params)-1].Type)
   281  	ret := f.Ret
   282  	if ret != nil && returnsErr && ret.Kind == objc.Bool {
   283  		ret = nil
   284  	}
   285  	switch {
   286  	case ret != nil && returnsErr:
   287  		g.Printf("ret_%s", strings.Replace(g.cType(ret), " ", "_", -1))
   288  	case ret != nil:
   289  		g.Printf(g.cType(ret))
   290  	case returnsErr:
   291  		g.Printf("int")
   292  	default:
   293  		g.Printf("void")
   294  	}
   295  	g.Printf(" ")
   296  	g.Printf(prefix)
   297  	if f.Static {
   298  		g.Printf("_s")
   299  	}
   300  	g.Printf("_%s_%s(", name, f.GoName)
   301  	if !f.Static {
   302  		g.Printf("int this")
   303  	}
   304  	for i, p := range f.Params {
   305  		if i == len(f.Params)-1 && returnsErr {
   306  			break
   307  		}
   308  		if !f.Static || i > 0 {
   309  			g.Printf(", ")
   310  		}
   311  		g.Printf("%s %s", g.cType(p.Type), p.Name)
   312  	}
   313  	g.Printf(")")
   314  }
   315  
   316  func (g *ObjcWrapper) GenGo() {
   317  	g.Printf(gobindPreamble)
   318  	g.Printf("package main\n\n")
   319  	g.Printf("// #include \"interfaces.h\"\n")
   320  	g.Printf("import \"C\"\n\n")
   321  	g.Printf("import \"ObjC\"\n")
   322  	g.Printf("import _seq \"github.com/F4RD1N/gomobile/bind/seq\"\n")
   323  
   324  	for _, n := range g.types {
   325  		for _, f := range n.Funcs {
   326  			if g.isFuncSupported(f) {
   327  				pkgName := n.Module + "/" + n.GoName
   328  				g.Printf("import %q\n", "ObjC/"+pkgName)
   329  				break
   330  			}
   331  		}
   332  	}
   333  	g.Printf("\n")
   334  	g.Printf("type proxy interface { Bind_proxy_refnum__() int32 }\n\n")
   335  	g.Printf("// Suppress unused package error\n\n")
   336  	g.Printf("var _ = _seq.FromRefNum\n")
   337  	g.Printf("const _ = ObjC.Dummy\n\n")
   338  	for _, n := range g.types {
   339  		g.genGo(n)
   340  	}
   341  }
   342  
   343  func (g *ObjcWrapper) genGo(n *objc.Named) {
   344  	g.Printf("func init() {\n")
   345  	g.Indent()
   346  	for _, f := range n.Funcs {
   347  		if !g.isFuncSupported(f) {
   348  			continue
   349  		}
   350  		g.Printf("%s.%s = func", n.GoName, f.GoName)
   351  		g.genFuncDecl(false, f)
   352  		g.genFuncBody(n, f, "cproxy")
   353  	}
   354  	g.Outdent()
   355  	g.Printf("}\n\n")
   356  	g.Printf("type proxy_class_%s _seq.Ref\n\n", n.GoName)
   357  	g.Printf("func (p *proxy_class_%s) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }\n\n", n.GoName)
   358  	for _, f := range n.AllMethods {
   359  		if !g.isFuncSupported(f) {
   360  			continue
   361  		}
   362  		g.Printf("func (p *proxy_class_%s) %s", n.GoName, f.GoName)
   363  		g.genFuncDecl(false, f)
   364  		g.genFuncBody(n, f, "cproxy")
   365  	}
   366  	if _, exists := g.supers[n.GoName]; exists {
   367  		g.Printf("func (p *proxy_class_%s) Super() ObjC.%s {\n", n.GoName, n.Module+"_"+n.GoName)
   368  		g.Printf("  return &super_%s{p}\n", n.GoName)
   369  		g.Printf("}\n\n")
   370  		g.Printf("type super_%s struct {*proxy_class_%[1]s}\n\n", n.GoName)
   371  		for _, f := range n.AllMethods {
   372  			if !g.isFuncSupported(f) {
   373  				continue
   374  			}
   375  			g.Printf("func (p *super_%s) %s", n.GoName, f.GoName)
   376  			g.genFuncDecl(false, f)
   377  			g.genFuncBody(n, f, "csuper")
   378  		}
   379  	}
   380  }
   381  
   382  func (g *ObjcWrapper) genFuncBody(n *objc.Named, f *objc.Func, prefix string) {
   383  	g.Printf(" {\n")
   384  	g.Indent()
   385  	var errParam *objc.Param
   386  	for i, a := range f.Params {
   387  		if i == len(f.Params)-1 && g.isErrorType(a.Type) {
   388  			errParam = a
   389  			break
   390  		}
   391  		g.genWrite(a)
   392  	}
   393  	ret := f.Ret
   394  	if ret != nil && errParam != nil && ret.Kind == objc.Bool {
   395  		ret = nil
   396  	}
   397  	if ret != nil || errParam != nil {
   398  		g.Printf("res := ")
   399  	}
   400  	g.Printf("C.")
   401  	g.Printf(prefix)
   402  	if f.Static {
   403  		g.Printf("_s")
   404  	}
   405  	g.Printf("_%s_%s(", n.GoName, f.GoName)
   406  	if !f.Static {
   407  		g.Printf("C.int(p.Bind_proxy_refnum__())")
   408  	}
   409  	for i, a := range f.Params {
   410  		if a == errParam {
   411  			break
   412  		}
   413  		if !f.Static || i > 0 {
   414  			g.Printf(", ")
   415  		}
   416  		g.Printf("_%s", a.Name)
   417  	}
   418  	g.Printf(")\n")
   419  	switch {
   420  	case ret != nil && errParam != nil:
   421  		g.genRead("_res", "res.res", ret)
   422  		g.genRefRead("_"+errParam.Name, "res.err", "error", "proxy_error")
   423  		g.Printf("return _res, _%s\n", errParam.Name)
   424  	case ret != nil:
   425  		g.genRead("_res", "res", ret)
   426  		g.Printf("return _res\n")
   427  	case errParam != nil:
   428  		g.genRefRead("_"+errParam.Name, "res", "error", "proxy_error")
   429  		g.Printf("return _%s\n", errParam.Name)
   430  	}
   431  	g.Outdent()
   432  	g.Printf("}\n\n")
   433  }
   434  
   435  func (g *ObjcWrapper) genCToObjC(name string, t *objc.Type, mode varMode) {
   436  	switch t.Kind {
   437  	case objc.String:
   438  		g.Printf("NSString *_%s = go_seq_to_objc_string(%s);\n", name, name)
   439  	case objc.Bool:
   440  		g.Printf("BOOL _%s = %s ? YES : NO;\n", name, name)
   441  	case objc.Data:
   442  		g.Printf("NSData *_%s = go_seq_to_objc_bytearray(%s, %d);\n", name, name, toCFlag(mode == modeRetained))
   443  	case objc.Int, objc.Uint, objc.Short, objc.Ushort, objc.Char, objc.Uchar, objc.Float, objc.Double:
   444  		g.Printf("%s _%s = (%s)%s;\n", g.objcType(t), name, g.objcType(t), name)
   445  	case objc.Class, objc.Protocol:
   446  		g.Printf("GoSeqRef* %s_ref = go_seq_from_refnum(%s);\n", name, name)
   447  		g.Printf("%s _%s;\n", g.objcType(t), name)
   448  		g.Printf("if (%s_ref != NULL) {\n", name)
   449  		g.Printf("	_%s = %s_ref.obj;\n", name, name)
   450  		g.Printf("}\n")
   451  	default:
   452  		panic("invalid kind")
   453  	}
   454  }
   455  
   456  func (g *ObjcWrapper) genObjCToC(name string, t *objc.Type, mode varMode) {
   457  	switch t.Kind {
   458  	case objc.String:
   459  		g.Printf("nstring _%s = go_seq_from_objc_string(%s);\n", name, name)
   460  	case objc.Data:
   461  		g.Printf("nbyteslice _%s = go_seq_from_objc_bytearray(%s, %d);\n", name, name, toCFlag(mode == modeRetained))
   462  	case objc.Bool, objc.Int, objc.Uint, objc.Short, objc.Ushort, objc.Char, objc.Uchar, objc.Float, objc.Double:
   463  		g.Printf("%s _%s = (%s)%s;\n", g.cType(t), name, g.cType(t), name)
   464  	case objc.Protocol, objc.Class:
   465  		g.Printf("int _%s = go_seq_to_refnum(%s);\n", name, name)
   466  	default:
   467  		panic("invalid kind")
   468  	}
   469  }
   470  
   471  func (g *ObjcWrapper) genWrite(a *objc.Param) {
   472  	switch a.Type.Kind {
   473  	case objc.String:
   474  		g.Printf("_%s := encodeString(%s)\n", a.Name, a.Name)
   475  	case objc.Data:
   476  		g.Printf("_%s := fromSlice(%s, false)\n", a.Name, a.Name)
   477  	case objc.Bool:
   478  		g.Printf("_%s := %s(0)\n", a.Name, g.cgoType(a.Type))
   479  		g.Printf("if %s {\n", a.Name)
   480  		g.Printf("  _%s = %s(1)\n", a.Name, g.cgoType(a.Type))
   481  		g.Printf("}\n")
   482  	case objc.Int, objc.Uint, objc.Short, objc.Ushort, objc.Char, objc.Uchar, objc.Float, objc.Double:
   483  		g.Printf("_%s := %s(%s)\n", a.Name, g.cgoType(a.Type), a.Name)
   484  	case objc.Protocol, objc.Class:
   485  		g.Printf("var _%s %s = _seq.NullRefNum\n", a.Name, g.cgoType(a.Type))
   486  		g.Printf("if %s != nil {\n", a.Name)
   487  		g.Printf("  _%s = %s(_seq.ToRefNum(%s))\n", a.Name, g.cgoType(a.Type), a.Name)
   488  		g.Printf("}\n")
   489  	default:
   490  		panic("invalid kind")
   491  	}
   492  }
   493  
   494  func (g *ObjcWrapper) genRead(to, from string, t *objc.Type) {
   495  	switch t.Kind {
   496  	case objc.Int, objc.Uint, objc.Uchar, objc.Short, objc.Ushort, objc.Char, objc.Float, objc.Double:
   497  		g.Printf("%s := %s(%s)\n", to, g.goType(t, false), from)
   498  	case objc.Bool:
   499  		g.Printf("%s := %s != 0\n", to, from)
   500  	case objc.String:
   501  		g.Printf("%s := decodeString(%s)\n", to, from)
   502  	case objc.Data:
   503  		g.Printf("%s := toSlice(%s, true)\n", to, from)
   504  	case objc.Protocol, objc.Class:
   505  		var proxyName string
   506  		if n := g.lookupImported(t); n != nil {
   507  			proxyName = "proxy_class_" + n.GoName
   508  		}
   509  		g.genRefRead(to, from, g.goType(t, false), proxyName)
   510  	default:
   511  		panic("invalid kind")
   512  	}
   513  }
   514  
   515  func (g *ObjcWrapper) genRefRead(to, from string, intfName, proxyName string) {
   516  	g.Printf("var %s %s\n", to, intfName)
   517  	g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", to, from)
   518  	g.Printf("if %s_ref != nil {\n", to)
   519  	g.Printf("	if %s < 0 { // go object\n", from)
   520  	g.Printf("		%s = %s_ref.Get().(%s)\n", to, to, intfName)
   521  	if proxyName != "" {
   522  		g.Printf("	} else { // foreign object\n")
   523  		g.Printf("		%s = (*%s)(%s_ref)\n", to, proxyName, to)
   524  	}
   525  	g.Printf("	}\n")
   526  	g.Printf("}\n")
   527  }
   528  
   529  // Packages return the list of Go packages to be generated.
   530  func (g *ObjcWrapper) Packages() []string {
   531  	return g.pkgNames
   532  }
   533  
   534  func (g *ObjcWrapper) GenPackage(idx int) {
   535  	pkg := g.pkgNames[idx]
   536  	g.Printf(gobindPreamble)
   537  	g.Printf("package %s\n\n", path.Base(pkg))
   538  	g.Printf("import \"ObjC\"\n\n")
   539  	g.Printf("const _ = ObjC.Dummy\n\n")
   540  	for _, n := range g.modMap[pkg] {
   541  		g.Printf("type %s ObjC.%s\n", n.GoName, n.Module+"_"+n.GoName)
   542  	}
   543  	if n, ok := g.typePkgs[pkg]; ok {
   544  		g.Printf("var (\n")
   545  		g.Indent()
   546  		// Functions
   547  		for _, f := range n.Funcs {
   548  			if !g.isFuncSupported(f) {
   549  				continue
   550  			}
   551  			g.Printf("%s func", f.GoName)
   552  			g.genFuncDecl(false, f)
   553  			g.Printf("\n")
   554  		}
   555  		g.Outdent()
   556  		g.Printf(")\n\n")
   557  	}
   558  }
   559  
   560  func (g *ObjcWrapper) GenInterfaces() {
   561  	g.Printf(gobindPreamble)
   562  	g.Printf("package ObjC\n\n")
   563  	g.Printf("// Used to silence this package not used errors\n")
   564  	g.Printf("const Dummy = 0\n\n")
   565  	for _, n := range g.types {
   566  		g.genInterface(n)
   567  	}
   568  }
   569  
   570  func (g *ObjcWrapper) genInterface(n *objc.Named) {
   571  	g.Printf("type %s interface {\n", n.Module+"_"+n.GoName)
   572  	g.Indent()
   573  	// Methods
   574  	for _, f := range n.AllMethods {
   575  		if !g.isFuncSupported(f) {
   576  			continue
   577  		}
   578  		g.Printf(f.GoName)
   579  		g.genFuncDecl(true, f)
   580  		g.Printf("\n")
   581  	}
   582  	if _, exists := g.supers[n.GoName]; exists {
   583  		g.Printf("Super() %s\n", n.Module+"_"+n.GoName)
   584  	}
   585  	g.Outdent()
   586  	g.Printf("}\n\n")
   587  }
   588  
   589  func (g *ObjcWrapper) genFuncDecl(local bool, f *objc.Func) {
   590  	var returnsErr bool
   591  	g.Printf("(")
   592  	for i, p := range f.Params {
   593  		if i == len(f.Params)-1 && g.isErrorType(p.Type) {
   594  			returnsErr = true
   595  			break
   596  		}
   597  		if i > 0 {
   598  			g.Printf(", ")
   599  		}
   600  		g.Printf("%s %s", p.Name, g.goType(p.Type, local))
   601  	}
   602  	g.Printf(")")
   603  	if f.Ret != nil || returnsErr {
   604  		ret := f.Ret
   605  		if ret.Kind == objc.Bool && returnsErr {
   606  			// Skip the bool result and use the error results.
   607  			ret = nil
   608  		}
   609  		if ret != nil {
   610  			g.Printf(" (%s", g.goType(f.Ret, local))
   611  			if returnsErr {
   612  				g.Printf(", error")
   613  			}
   614  			g.Printf(")")
   615  		} else {
   616  			g.Printf(" error")
   617  		}
   618  	}
   619  }
   620  
   621  func (g *ObjcWrapper) isFuncSupported(f *objc.Func) bool {
   622  	for i, p := range f.Params {
   623  		if !g.isSupported(p.Type) {
   624  			if i < len(f.Params)-1 || !g.isErrorType(p.Type) {
   625  				return false
   626  			}
   627  		}
   628  	}
   629  	if f.Ret != nil {
   630  		return g.isSupported(f.Ret)
   631  	}
   632  	return true
   633  }
   634  
   635  func (g *ObjcWrapper) isErrorType(t *objc.Type) bool {
   636  	// Must be a NSError ** type
   637  	return t.Kind == objc.Class && t.Indirect && t.Name == "NSError"
   638  }
   639  
   640  func (g *ObjcWrapper) isSupported(t *objc.Type) bool {
   641  	if t.Indirect {
   642  		return false
   643  	}
   644  	switch t.Kind {
   645  	case objc.Unknown:
   646  		return false
   647  	case objc.Protocol:
   648  		// TODO: support inout parameters.
   649  		return !strings.HasSuffix(t.Decl, " *")
   650  	case objc.Class:
   651  		return t.Name != "SEL" && t.Name != "void"
   652  	default:
   653  		return true
   654  	}
   655  }
   656  
   657  func (g *ObjcWrapper) cgoType(t *objc.Type) string {
   658  	switch t.Kind {
   659  	case objc.Uint:
   660  		return "C.ulong"
   661  	case objc.Ushort:
   662  		return "C.ushort"
   663  	case objc.Uchar:
   664  		return "C.uchar"
   665  	default:
   666  		return "C." + g.cType(t)
   667  	}
   668  }
   669  
   670  func (g *ObjcWrapper) cType(t *objc.Type) string {
   671  	switch t.Kind {
   672  	case objc.Protocol, objc.Class:
   673  		return "int"
   674  	case objc.String:
   675  		return "nstring"
   676  	case objc.Data:
   677  		return "nbyteslice"
   678  	case objc.Int:
   679  		return "long"
   680  	case objc.Uint:
   681  		return "unsigned long"
   682  	case objc.Short:
   683  		return "short"
   684  	case objc.Ushort:
   685  		return "unsigned short"
   686  	case objc.Bool:
   687  		return "char"
   688  	case objc.Char:
   689  		return "char"
   690  	case objc.Uchar:
   691  		return "unsigned char"
   692  	case objc.Float:
   693  		return "float"
   694  	case objc.Double:
   695  		return "double"
   696  	default:
   697  		panic("invalid kind")
   698  	}
   699  }
   700  
   701  func (g *ObjcWrapper) objcType(t *objc.Type) string {
   702  	return t.Decl
   703  }
   704  
   705  func (g *ObjcWrapper) lookupImported(t *objc.Type) *objc.Named {
   706  	var mangled string
   707  	switch t.Kind {
   708  	case objc.Class:
   709  		mangled = t.Name + "C"
   710  	case objc.Protocol:
   711  		mangled = t.Name + "P"
   712  	default:
   713  		panic("invalid type kind")
   714  	}
   715  	if n, exists := g.imported[mangled]; exists {
   716  		return n
   717  	}
   718  	return g.imported[t.Name]
   719  }
   720  
   721  func (g *ObjcWrapper) goType(t *objc.Type, local bool) string {
   722  	switch t.Kind {
   723  	case objc.String:
   724  		return "string"
   725  	case objc.Data:
   726  		return "[]byte"
   727  	case objc.Int:
   728  		return "int"
   729  	case objc.Uint:
   730  		return "uint"
   731  	case objc.Short:
   732  		return "int16"
   733  	case objc.Ushort:
   734  		return "uint16"
   735  	case objc.Bool:
   736  		return "bool"
   737  	case objc.Char:
   738  		return "byte"
   739  	case objc.Uchar:
   740  		return "uint8"
   741  	case objc.Float:
   742  		return "float32"
   743  	case objc.Double:
   744  		return "float64"
   745  	case objc.Protocol, objc.Class:
   746  		var n *objc.Named
   747  		n = g.lookupImported(t)
   748  		name := n.Module + "_" + n.GoName
   749  		if !local {
   750  			name = "ObjC." + name
   751  		}
   752  		return name
   753  	default:
   754  		panic("invalid kind")
   755  	}
   756  }