Adding upstream version 0.0~git20250520.a1d9079+dfsg.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
590ac7ff5f
commit
20149b7f3a
456 changed files with 70406 additions and 0 deletions
754
bind/genobjcw.go
Normal file
754
bind/genobjcw.go
Normal file
|
@ -0,0 +1,754 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bind
|
||||
|
||||
import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/mobile/internal/importers/objc"
|
||||
)
|
||||
|
||||
type (
|
||||
// ObjCWrapper generates Go and C stubs for ObjC interfaces and protocols.
|
||||
ObjcWrapper struct {
|
||||
*Printer
|
||||
imported map[string]*objc.Named
|
||||
// The list of ObjC types.
|
||||
types []*objc.Named
|
||||
// The list of Go package paths with ObjC wrappers.
|
||||
pkgNames []string
|
||||
modules []string
|
||||
// For each ObjC module, the list of ObjC types within.
|
||||
modMap map[string][]*objc.Named
|
||||
// For each module/name Go package path, the ObjC type
|
||||
// with static functions or constants.
|
||||
typePkgs map[string]*objc.Named
|
||||
// supers is the map of types that need Super methods.
|
||||
supers map[string]struct{}
|
||||
}
|
||||
)
|
||||
|
||||
// Init initializes the ObjC types wrapper generator. Types is the
|
||||
// list of types to wrap, genNames the list of generated type names.
|
||||
func (g *ObjcWrapper) Init(types []*objc.Named, genNames []string) {
|
||||
g.supers = make(map[string]struct{})
|
||||
for _, s := range genNames {
|
||||
g.supers[s] = struct{}{}
|
||||
}
|
||||
g.types = types
|
||||
g.imported = make(map[string]*objc.Named)
|
||||
g.modMap = make(map[string][]*objc.Named)
|
||||
g.typePkgs = make(map[string]*objc.Named)
|
||||
pkgSet := make(map[string]struct{})
|
||||
for _, n := range types {
|
||||
g.imported[n.GoName] = n
|
||||
typePkg := n.Module + "/" + n.GoName
|
||||
g.typePkgs[typePkg] = n
|
||||
if !n.Generated {
|
||||
if _, exists := g.modMap[n.Module]; !exists {
|
||||
g.modules = append(g.modules, n.Module)
|
||||
}
|
||||
}
|
||||
g.modMap[n.Module] = append(g.modMap[n.Module], n)
|
||||
if _, exists := pkgSet[n.Module]; !exists {
|
||||
pkgSet[n.Module] = struct{}{}
|
||||
g.pkgNames = append(g.pkgNames, n.Module)
|
||||
}
|
||||
g.pkgNames = append(g.pkgNames, typePkg)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) GenM() {
|
||||
g.Printf(gobindPreamble)
|
||||
// For objc_msgSend* functions.
|
||||
g.Printf("@import ObjectiveC.message;\n")
|
||||
g.Printf("#include \"seq.h\"\n")
|
||||
g.Printf("#include \"interfaces.h\"\n\n")
|
||||
for _, n := range g.types {
|
||||
g.genM(n)
|
||||
}
|
||||
g.Printf("\n")
|
||||
for _, n := range g.types {
|
||||
for _, f := range n.AllMethods {
|
||||
if !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.genCFuncDecl("cproxy", n.GoName, f)
|
||||
g.genCFuncBody(n, f, false)
|
||||
if _, exists := g.supers[n.GoName]; exists {
|
||||
g.genCFuncDecl("csuper", n.GoName, f)
|
||||
g.genCFuncBody(n, f, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) genCFuncBody(n *objc.Named, f *objc.Func, super bool) {
|
||||
g.Printf(" {\n")
|
||||
g.Indent()
|
||||
if !f.Static {
|
||||
g.Printf("%s _this = go_seq_from_refnum(this).obj;\n", n.ObjcType())
|
||||
}
|
||||
var errParam *objc.Param
|
||||
for i, a := range f.Params {
|
||||
if i == len(f.Params)-1 && g.isErrorType(a.Type) {
|
||||
errParam = a
|
||||
break
|
||||
}
|
||||
g.genCToObjC(a.Name, a.Type, modeTransient)
|
||||
}
|
||||
if errParam != nil {
|
||||
g.Printf("NSError *%s = nil;\n", errParam.Name)
|
||||
}
|
||||
if f.Constructor {
|
||||
g.Printf("%s _this = [%s alloc];\n", n.ObjcType(), n.Name)
|
||||
}
|
||||
if super {
|
||||
g.Printf("struct objc_super _super = {\n")
|
||||
g.Printf(" .receiver = _this,\n")
|
||||
g.Printf(" .super_class = class_getSuperclass([%s class]),\n", n.Name)
|
||||
g.Printf("};\n")
|
||||
}
|
||||
retType := "void"
|
||||
if f.Ret != nil {
|
||||
retType = g.objcType(f.Ret)
|
||||
g.Printf("%s res = ", retType)
|
||||
}
|
||||
// There is no direct way to send a message to a class' super
|
||||
// class from outside the class itself. Use objc_msgSendSuper instead
|
||||
// which is what the compiler uses itself. To keep us honest and to exercise
|
||||
// the code paths more use objc_msgSend for regular calls as well.
|
||||
//
|
||||
// A regular call looks like this:
|
||||
//
|
||||
// res = ((<return type> (*)(id, SEL, <argument_types>))objc_msgSend)(_this, @selector(...), <arguments>)
|
||||
//
|
||||
// a call to super looks like this:
|
||||
//
|
||||
// ret = ((<return type> (*)(id, SEL, <argument_types>))objc_msgSendSuper)(<struct objc_super>, <arguments>)
|
||||
if f.Ret != nil {
|
||||
switch f.Ret.Kind {
|
||||
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:
|
||||
default:
|
||||
// If support for struct results is added, objc_msgSend_stret must be used
|
||||
panic("unsupported type kind - use objc_msgSend_stret?")
|
||||
}
|
||||
}
|
||||
g.Printf("((%s (*)(", retType)
|
||||
if super {
|
||||
g.Printf("struct objc_super *")
|
||||
} else {
|
||||
g.Printf("id")
|
||||
}
|
||||
g.Printf(", SEL")
|
||||
for _, a := range f.Params {
|
||||
g.Printf(", %s", g.objcType(a.Type))
|
||||
}
|
||||
g.Printf("))")
|
||||
if super {
|
||||
g.Printf("objc_msgSendSuper")
|
||||
} else {
|
||||
g.Printf("objc_msgSend")
|
||||
}
|
||||
g.Printf(")(")
|
||||
if f.Static && !f.Constructor {
|
||||
g.Printf("[%s class]", n.Name)
|
||||
} else {
|
||||
if super {
|
||||
g.Printf("&_super")
|
||||
} else {
|
||||
g.Printf("_this")
|
||||
}
|
||||
}
|
||||
g.Printf(", @selector(%s)", f.Sig)
|
||||
for _, a := range f.Params {
|
||||
arg := "_" + a.Name
|
||||
if a == errParam {
|
||||
arg = "&" + a.Name
|
||||
}
|
||||
g.Printf(", %s", arg)
|
||||
}
|
||||
g.Printf(");\n")
|
||||
if errParam != nil {
|
||||
g.Printf("NSError *_%s = nil;\n", errParam.Name)
|
||||
if f.Ret != nil {
|
||||
g.Printf("if (!res && %s != nil) {\n", errParam.Name)
|
||||
} else {
|
||||
g.Printf("if (%s != nil) {\n", errParam.Name)
|
||||
}
|
||||
g.Printf(" _%[1]s = %[1]s;\n", errParam.Name)
|
||||
g.Printf("}\n")
|
||||
g.genObjCToC("_"+errParam.Name, g.errType(), modeRetained)
|
||||
}
|
||||
ret := f.Ret
|
||||
if ret != nil && ret.Kind == objc.Bool && errParam != nil {
|
||||
ret = nil
|
||||
}
|
||||
if ret != nil {
|
||||
g.genObjCToC("res", ret, modeRetained)
|
||||
}
|
||||
switch {
|
||||
case ret != nil && errParam != nil:
|
||||
stype := strings.Replace(g.cType(ret), " ", "_", -1)
|
||||
g.Printf("ret_%s _sres = {_res, __%s};\n", stype, errParam.Name)
|
||||
g.Printf("return _sres;\n")
|
||||
case ret != nil:
|
||||
g.Printf("return _res;\n")
|
||||
case errParam != nil:
|
||||
g.Printf("return __%s;\n", errParam.Name)
|
||||
}
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
|
||||
func (_ *ObjcWrapper) errType() *objc.Type {
|
||||
return &objc.Type{Kind: objc.Class, Name: "NSError"}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) genM(n *objc.Named) {
|
||||
for _, f := range n.Funcs {
|
||||
if !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.genCFuncDecl("cproxy", n.GoName, f)
|
||||
g.genCFuncBody(n, f, false)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) GenH() {
|
||||
g.Printf(gobindPreamble)
|
||||
g.Printf("#include \"seq.h\"\n\n")
|
||||
for _, m := range g.modules {
|
||||
g.Printf("@import %s;\n", m)
|
||||
}
|
||||
// Include header files for generated types
|
||||
for _, n := range g.pkgNames {
|
||||
hasGen := false
|
||||
for _, t := range g.modMap[n] {
|
||||
if t.Generated {
|
||||
hasGen = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if hasGen {
|
||||
g.Printf("#import %q\n", n+".objc.h")
|
||||
}
|
||||
}
|
||||
for _, tn := range []string{"int", "nstring", "nbyteslice", "long", "unsigned long", "short", "unsigned short", "bool", "char", "unsigned char", "float", "double"} {
|
||||
sn := strings.Replace(tn, " ", "_", -1)
|
||||
g.Printf("typedef struct ret_%s {\n", sn)
|
||||
g.Printf(" %s res;\n", tn)
|
||||
g.Printf(" int err;\n")
|
||||
g.Printf("} ret_%s;\n", sn)
|
||||
}
|
||||
g.Printf("\n")
|
||||
for _, n := range g.types {
|
||||
for _, f := range n.AllMethods {
|
||||
if !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.Printf("extern ")
|
||||
g.genCFuncDecl("cproxy", n.GoName, f)
|
||||
g.Printf(";\n")
|
||||
if _, exists := g.supers[n.GoName]; exists {
|
||||
g.Printf("extern ")
|
||||
g.genCFuncDecl("csuper", n.GoName, f)
|
||||
g.Printf(";\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, cls := range g.types {
|
||||
g.genH(cls)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) genH(n *objc.Named) {
|
||||
for _, f := range n.Funcs {
|
||||
if !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.Printf("extern ")
|
||||
g.genCFuncDecl("cproxy", n.GoName, f)
|
||||
g.Printf(";\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) genCFuncDecl(prefix, name string, f *objc.Func) {
|
||||
returnsErr := len(f.Params) > 0 && g.isErrorType(f.Params[len(f.Params)-1].Type)
|
||||
ret := f.Ret
|
||||
if ret != nil && returnsErr && ret.Kind == objc.Bool {
|
||||
ret = nil
|
||||
}
|
||||
switch {
|
||||
case ret != nil && returnsErr:
|
||||
g.Printf("ret_%s", strings.Replace(g.cType(ret), " ", "_", -1))
|
||||
case ret != nil:
|
||||
g.Printf("%s", g.cType(ret))
|
||||
case returnsErr:
|
||||
g.Printf("int")
|
||||
default:
|
||||
g.Printf("void")
|
||||
}
|
||||
g.Printf(" %s", prefix)
|
||||
if f.Static {
|
||||
g.Printf("_s")
|
||||
}
|
||||
g.Printf("_%s_%s(", name, f.GoName)
|
||||
if !f.Static {
|
||||
g.Printf("int this")
|
||||
}
|
||||
for i, p := range f.Params {
|
||||
if i == len(f.Params)-1 && returnsErr {
|
||||
break
|
||||
}
|
||||
if !f.Static || i > 0 {
|
||||
g.Printf(", ")
|
||||
}
|
||||
g.Printf("%s %s", g.cType(p.Type), p.Name)
|
||||
}
|
||||
g.Printf(")")
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) GenGo() {
|
||||
g.Printf(gobindPreamble)
|
||||
g.Printf("package main\n\n")
|
||||
g.Printf("// #include \"interfaces.h\"\n")
|
||||
g.Printf("import \"C\"\n\n")
|
||||
g.Printf("import \"ObjC\"\n")
|
||||
g.Printf("import _seq \"golang.org/x/mobile/bind/seq\"\n")
|
||||
|
||||
for _, n := range g.types {
|
||||
for _, f := range n.Funcs {
|
||||
if g.isFuncSupported(f) {
|
||||
pkgName := n.Module + "/" + n.GoName
|
||||
g.Printf("import %q\n", "ObjC/"+pkgName)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
g.Printf("\n")
|
||||
g.Printf("type proxy interface { Bind_proxy_refnum__() int32 }\n\n")
|
||||
g.Printf("// Suppress unused package error\n\n")
|
||||
g.Printf("var _ = _seq.FromRefNum\n")
|
||||
g.Printf("const _ = ObjC.Dummy\n\n")
|
||||
for _, n := range g.types {
|
||||
g.genGo(n)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) genGo(n *objc.Named) {
|
||||
g.Printf("func init() {\n")
|
||||
g.Indent()
|
||||
for _, f := range n.Funcs {
|
||||
if !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.Printf("%s.%s = func", n.GoName, f.GoName)
|
||||
g.genFuncDecl(false, f)
|
||||
g.genFuncBody(n, f, "cproxy")
|
||||
}
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
g.Printf("type proxy_class_%s _seq.Ref\n\n", n.GoName)
|
||||
g.Printf("func (p *proxy_class_%s) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }\n\n", n.GoName)
|
||||
for _, f := range n.AllMethods {
|
||||
if !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.Printf("func (p *proxy_class_%s) %s", n.GoName, f.GoName)
|
||||
g.genFuncDecl(false, f)
|
||||
g.genFuncBody(n, f, "cproxy")
|
||||
}
|
||||
if _, exists := g.supers[n.GoName]; exists {
|
||||
g.Printf("func (p *proxy_class_%s) Super() ObjC.%s {\n", n.GoName, n.Module+"_"+n.GoName)
|
||||
g.Printf(" return &super_%s{p}\n", n.GoName)
|
||||
g.Printf("}\n\n")
|
||||
g.Printf("type super_%s struct {*proxy_class_%[1]s}\n\n", n.GoName)
|
||||
for _, f := range n.AllMethods {
|
||||
if !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.Printf("func (p *super_%s) %s", n.GoName, f.GoName)
|
||||
g.genFuncDecl(false, f)
|
||||
g.genFuncBody(n, f, "csuper")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) genFuncBody(n *objc.Named, f *objc.Func, prefix string) {
|
||||
g.Printf(" {\n")
|
||||
g.Indent()
|
||||
var errParam *objc.Param
|
||||
for i, a := range f.Params {
|
||||
if i == len(f.Params)-1 && g.isErrorType(a.Type) {
|
||||
errParam = a
|
||||
break
|
||||
}
|
||||
g.genWrite(a)
|
||||
}
|
||||
ret := f.Ret
|
||||
if ret != nil && errParam != nil && ret.Kind == objc.Bool {
|
||||
ret = nil
|
||||
}
|
||||
if ret != nil || errParam != nil {
|
||||
g.Printf("res := ")
|
||||
}
|
||||
g.Printf("C.%s", prefix)
|
||||
if f.Static {
|
||||
g.Printf("_s")
|
||||
}
|
||||
g.Printf("_%s_%s(", n.GoName, f.GoName)
|
||||
if !f.Static {
|
||||
g.Printf("C.int(p.Bind_proxy_refnum__())")
|
||||
}
|
||||
for i, a := range f.Params {
|
||||
if a == errParam {
|
||||
break
|
||||
}
|
||||
if !f.Static || i > 0 {
|
||||
g.Printf(", ")
|
||||
}
|
||||
g.Printf("_%s", a.Name)
|
||||
}
|
||||
g.Printf(")\n")
|
||||
switch {
|
||||
case ret != nil && errParam != nil:
|
||||
g.genRead("_res", "res.res", ret)
|
||||
g.genRefRead("_"+errParam.Name, "res.err", "error", "proxy_error")
|
||||
g.Printf("return _res, _%s\n", errParam.Name)
|
||||
case ret != nil:
|
||||
g.genRead("_res", "res", ret)
|
||||
g.Printf("return _res\n")
|
||||
case errParam != nil:
|
||||
g.genRefRead("_"+errParam.Name, "res", "error", "proxy_error")
|
||||
g.Printf("return _%s\n", errParam.Name)
|
||||
}
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) genCToObjC(name string, t *objc.Type, mode varMode) {
|
||||
switch t.Kind {
|
||||
case objc.String:
|
||||
g.Printf("NSString *_%s = go_seq_to_objc_string(%s);\n", name, name)
|
||||
case objc.Bool:
|
||||
g.Printf("BOOL _%s = %s ? YES : NO;\n", name, name)
|
||||
case objc.Data:
|
||||
g.Printf("NSData *_%s = go_seq_to_objc_bytearray(%s, %d);\n", name, name, toCFlag(mode == modeRetained))
|
||||
case objc.Int, objc.Uint, objc.Short, objc.Ushort, objc.Char, objc.Uchar, objc.Float, objc.Double:
|
||||
g.Printf("%s _%s = (%s)%s;\n", g.objcType(t), name, g.objcType(t), name)
|
||||
case objc.Class, objc.Protocol:
|
||||
g.Printf("GoSeqRef* %s_ref = go_seq_from_refnum(%s);\n", name, name)
|
||||
g.Printf("%s _%s;\n", g.objcType(t), name)
|
||||
g.Printf("if (%s_ref != NULL) {\n", name)
|
||||
g.Printf(" _%s = %s_ref.obj;\n", name, name)
|
||||
g.Printf("}\n")
|
||||
default:
|
||||
panic("invalid kind")
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) genObjCToC(name string, t *objc.Type, mode varMode) {
|
||||
switch t.Kind {
|
||||
case objc.String:
|
||||
g.Printf("nstring _%s = go_seq_from_objc_string(%s);\n", name, name)
|
||||
case objc.Data:
|
||||
g.Printf("nbyteslice _%s = go_seq_from_objc_bytearray(%s, %d);\n", name, name, toCFlag(mode == modeRetained))
|
||||
case objc.Bool, objc.Int, objc.Uint, objc.Short, objc.Ushort, objc.Char, objc.Uchar, objc.Float, objc.Double:
|
||||
g.Printf("%s _%s = (%s)%s;\n", g.cType(t), name, g.cType(t), name)
|
||||
case objc.Protocol, objc.Class:
|
||||
g.Printf("int _%s = go_seq_to_refnum(%s);\n", name, name)
|
||||
default:
|
||||
panic("invalid kind")
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) genWrite(a *objc.Param) {
|
||||
switch a.Type.Kind {
|
||||
case objc.String:
|
||||
g.Printf("_%s := encodeString(%s)\n", a.Name, a.Name)
|
||||
case objc.Data:
|
||||
g.Printf("_%s := fromSlice(%s, false)\n", a.Name, a.Name)
|
||||
case objc.Bool:
|
||||
g.Printf("_%s := %s(0)\n", a.Name, g.cgoType(a.Type))
|
||||
g.Printf("if %s {\n", a.Name)
|
||||
g.Printf(" _%s = %s(1)\n", a.Name, g.cgoType(a.Type))
|
||||
g.Printf("}\n")
|
||||
case objc.Int, objc.Uint, objc.Short, objc.Ushort, objc.Char, objc.Uchar, objc.Float, objc.Double:
|
||||
g.Printf("_%s := %s(%s)\n", a.Name, g.cgoType(a.Type), a.Name)
|
||||
case objc.Protocol, objc.Class:
|
||||
g.Printf("var _%s %s = _seq.NullRefNum\n", a.Name, g.cgoType(a.Type))
|
||||
g.Printf("if %s != nil {\n", a.Name)
|
||||
g.Printf(" _%s = %s(_seq.ToRefNum(%s))\n", a.Name, g.cgoType(a.Type), a.Name)
|
||||
g.Printf("}\n")
|
||||
default:
|
||||
panic("invalid kind")
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) genRead(to, from string, t *objc.Type) {
|
||||
switch t.Kind {
|
||||
case objc.Int, objc.Uint, objc.Uchar, objc.Short, objc.Ushort, objc.Char, objc.Float, objc.Double:
|
||||
g.Printf("%s := %s(%s)\n", to, g.goType(t, false), from)
|
||||
case objc.Bool:
|
||||
g.Printf("%s := %s != 0\n", to, from)
|
||||
case objc.String:
|
||||
g.Printf("%s := decodeString(%s)\n", to, from)
|
||||
case objc.Data:
|
||||
g.Printf("%s := toSlice(%s, true)\n", to, from)
|
||||
case objc.Protocol, objc.Class:
|
||||
var proxyName string
|
||||
if n := g.lookupImported(t); n != nil {
|
||||
proxyName = "proxy_class_" + n.GoName
|
||||
}
|
||||
g.genRefRead(to, from, g.goType(t, false), proxyName)
|
||||
default:
|
||||
panic("invalid kind")
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) genRefRead(to, from string, intfName, proxyName string) {
|
||||
g.Printf("var %s %s\n", to, intfName)
|
||||
g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", to, from)
|
||||
g.Printf("if %s_ref != nil {\n", to)
|
||||
g.Printf(" if %s < 0 { // go object\n", from)
|
||||
g.Printf(" %s = %s_ref.Get().(%s)\n", to, to, intfName)
|
||||
if proxyName != "" {
|
||||
g.Printf(" } else { // foreign object\n")
|
||||
g.Printf(" %s = (*%s)(%s_ref)\n", to, proxyName, to)
|
||||
}
|
||||
g.Printf(" }\n")
|
||||
g.Printf("}\n")
|
||||
}
|
||||
|
||||
// Packages return the list of Go packages to be generated.
|
||||
func (g *ObjcWrapper) Packages() []string {
|
||||
return g.pkgNames
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) GenPackage(idx int) {
|
||||
pkg := g.pkgNames[idx]
|
||||
g.Printf(gobindPreamble)
|
||||
g.Printf("package %s\n\n", path.Base(pkg))
|
||||
g.Printf("import \"ObjC\"\n\n")
|
||||
g.Printf("const _ = ObjC.Dummy\n\n")
|
||||
for _, n := range g.modMap[pkg] {
|
||||
g.Printf("type %s ObjC.%s\n", n.GoName, n.Module+"_"+n.GoName)
|
||||
}
|
||||
if n, ok := g.typePkgs[pkg]; ok {
|
||||
g.Printf("var (\n")
|
||||
g.Indent()
|
||||
// Functions
|
||||
for _, f := range n.Funcs {
|
||||
if !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.Printf("%s func", f.GoName)
|
||||
g.genFuncDecl(false, f)
|
||||
g.Printf("\n")
|
||||
}
|
||||
g.Outdent()
|
||||
g.Printf(")\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) GenInterfaces() {
|
||||
g.Printf(gobindPreamble)
|
||||
g.Printf("package ObjC\n\n")
|
||||
g.Printf("// Used to silence this package not used errors\n")
|
||||
g.Printf("const Dummy = 0\n\n")
|
||||
for _, n := range g.types {
|
||||
g.genInterface(n)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) genInterface(n *objc.Named) {
|
||||
g.Printf("type %s interface {\n", n.Module+"_"+n.GoName)
|
||||
g.Indent()
|
||||
// Methods
|
||||
for _, f := range n.AllMethods {
|
||||
if !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.Printf("%s", f.GoName)
|
||||
g.genFuncDecl(true, f)
|
||||
g.Printf("\n")
|
||||
}
|
||||
if _, exists := g.supers[n.GoName]; exists {
|
||||
g.Printf("Super() %s\n", n.Module+"_"+n.GoName)
|
||||
}
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) genFuncDecl(local bool, f *objc.Func) {
|
||||
var returnsErr bool
|
||||
g.Printf("(")
|
||||
for i, p := range f.Params {
|
||||
if i == len(f.Params)-1 && g.isErrorType(p.Type) {
|
||||
returnsErr = true
|
||||
break
|
||||
}
|
||||
if i > 0 {
|
||||
g.Printf(", ")
|
||||
}
|
||||
g.Printf("%s %s", p.Name, g.goType(p.Type, local))
|
||||
}
|
||||
g.Printf(")")
|
||||
if f.Ret != nil || returnsErr {
|
||||
ret := f.Ret
|
||||
if ret.Kind == objc.Bool && returnsErr {
|
||||
// Skip the bool result and use the error results.
|
||||
ret = nil
|
||||
}
|
||||
if ret != nil {
|
||||
g.Printf(" (%s", g.goType(f.Ret, local))
|
||||
if returnsErr {
|
||||
g.Printf(", error")
|
||||
}
|
||||
g.Printf(")")
|
||||
} else {
|
||||
g.Printf(" error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) isFuncSupported(f *objc.Func) bool {
|
||||
for i, p := range f.Params {
|
||||
if !g.isSupported(p.Type) {
|
||||
if i < len(f.Params)-1 || !g.isErrorType(p.Type) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
if f.Ret != nil {
|
||||
return g.isSupported(f.Ret)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) isErrorType(t *objc.Type) bool {
|
||||
// Must be a NSError ** type
|
||||
return t.Kind == objc.Class && t.Indirect && t.Name == "NSError"
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) isSupported(t *objc.Type) bool {
|
||||
if t.Indirect {
|
||||
return false
|
||||
}
|
||||
switch t.Kind {
|
||||
case objc.Unknown:
|
||||
return false
|
||||
case objc.Protocol:
|
||||
// TODO: support inout parameters.
|
||||
return !strings.HasSuffix(t.Decl, " *")
|
||||
case objc.Class:
|
||||
return t.Name != "SEL" && t.Name != "void"
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) cgoType(t *objc.Type) string {
|
||||
switch t.Kind {
|
||||
case objc.Uint:
|
||||
return "C.ulong"
|
||||
case objc.Ushort:
|
||||
return "C.ushort"
|
||||
case objc.Uchar:
|
||||
return "C.uchar"
|
||||
default:
|
||||
return "C." + g.cType(t)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) cType(t *objc.Type) string {
|
||||
switch t.Kind {
|
||||
case objc.Protocol, objc.Class:
|
||||
return "int"
|
||||
case objc.String:
|
||||
return "nstring"
|
||||
case objc.Data:
|
||||
return "nbyteslice"
|
||||
case objc.Int:
|
||||
return "long"
|
||||
case objc.Uint:
|
||||
return "unsigned long"
|
||||
case objc.Short:
|
||||
return "short"
|
||||
case objc.Ushort:
|
||||
return "unsigned short"
|
||||
case objc.Bool:
|
||||
return "char"
|
||||
case objc.Char:
|
||||
return "char"
|
||||
case objc.Uchar:
|
||||
return "unsigned char"
|
||||
case objc.Float:
|
||||
return "float"
|
||||
case objc.Double:
|
||||
return "double"
|
||||
default:
|
||||
panic("invalid kind")
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) objcType(t *objc.Type) string {
|
||||
return t.Decl
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) lookupImported(t *objc.Type) *objc.Named {
|
||||
var mangled string
|
||||
switch t.Kind {
|
||||
case objc.Class:
|
||||
mangled = t.Name + "C"
|
||||
case objc.Protocol:
|
||||
mangled = t.Name + "P"
|
||||
default:
|
||||
panic("invalid type kind")
|
||||
}
|
||||
if n, exists := g.imported[mangled]; exists {
|
||||
return n
|
||||
}
|
||||
return g.imported[t.Name]
|
||||
}
|
||||
|
||||
func (g *ObjcWrapper) goType(t *objc.Type, local bool) string {
|
||||
switch t.Kind {
|
||||
case objc.String:
|
||||
return "string"
|
||||
case objc.Data:
|
||||
return "[]byte"
|
||||
case objc.Int:
|
||||
return "int"
|
||||
case objc.Uint:
|
||||
return "uint"
|
||||
case objc.Short:
|
||||
return "int16"
|
||||
case objc.Ushort:
|
||||
return "uint16"
|
||||
case objc.Bool:
|
||||
return "bool"
|
||||
case objc.Char:
|
||||
return "byte"
|
||||
case objc.Uchar:
|
||||
return "uint8"
|
||||
case objc.Float:
|
||||
return "float32"
|
||||
case objc.Double:
|
||||
return "float64"
|
||||
case objc.Protocol, objc.Class:
|
||||
var n *objc.Named
|
||||
n = g.lookupImported(t)
|
||||
name := n.Module + "_" + n.GoName
|
||||
if !local {
|
||||
name = "ObjC." + name
|
||||
}
|
||||
return name
|
||||
default:
|
||||
panic("invalid kind")
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue