Complete implementation of delegates. Update app example with an
NSApplicationDelegate.
This commit is contained in:
parent
0d2321d516
commit
44b3b75e23
|
@ -196,6 +196,7 @@ func Start() (err error) {
|
||||||
w.Import(Config.Imports)
|
w.Import(Config.Imports)
|
||||||
w.SysImport(Config.Sysimports)
|
w.SysImport(Config.Sysimports)
|
||||||
w.Pragma(Config.Pragma)
|
w.Pragma(Config.Pragma)
|
||||||
|
w.Delegate(Config.Delegates)
|
||||||
if Config.Vaargs == 0 {
|
if Config.Vaargs == 0 {
|
||||||
Config.Vaargs = 16
|
Config.Vaargs = 16
|
||||||
}
|
}
|
||||||
|
@ -215,13 +216,10 @@ func Start() (err error) {
|
||||||
w.AddFunction(x)
|
w.AddFunction(x)
|
||||||
}
|
}
|
||||||
case *ast.ObjCProtocolDecl:
|
case *ast.ObjCProtocolDecl:
|
||||||
DELEGATES:
|
|
||||||
for _,ps := range Config.Delegates {
|
for _,ps := range Config.Delegates {
|
||||||
_ = ps
|
if matches(x.Name,ps) {
|
||||||
//if matches(x.Name,ps) {
|
w.AddProtocol(x)
|
||||||
// w.AddProtocol(x)
|
}
|
||||||
break DELEGATES
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
case *ast.EnumDecl:
|
case *ast.EnumDecl:
|
||||||
w.AddEnum(x,Config.Enums)
|
w.AddEnum(x,Config.Enums)
|
||||||
|
|
|
@ -2,15 +2,43 @@ package main
|
||||||
//go:generate nswrap
|
//go:generate nswrap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"gitlab.wow.st/gmp/nswrap/examples/app/ns"
|
"gitlab.wow.st/gmp/nswrap/examples/app/ns"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func didFinishLaunching(n *ns.NSNotification) {
|
||||||
|
fmt.Println("Go: did finish launching")
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldTerminate(s *ns.NSApplication) ns.NSApplicationTerminateReply {
|
||||||
|
fmt.Println("Go: should terminate")
|
||||||
|
return ns.NSTerminateNow
|
||||||
|
}
|
||||||
|
|
||||||
|
func willTerminate(n *ns.NSNotification) {
|
||||||
|
fmt.Println("Go: will terminate")
|
||||||
|
}
|
||||||
|
|
||||||
|
func didBecomeActive(n *ns.NSNotification) {
|
||||||
|
fmt.Println("Go: did become active")
|
||||||
|
}
|
||||||
|
|
||||||
func app() {
|
func app() {
|
||||||
//Lock OS thread because Cocoa uses thread-local storage
|
//Lock OS thread because Cocoa uses thread-local storage
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
a := ns.NSApplicationSharedApplication()
|
a := ns.NSApplicationSharedApplication()
|
||||||
a.SetActivationPolicy(ns.NSApplicationActivationPolicyRegular)
|
a.SetActivationPolicy(ns.NSApplicationActivationPolicyRegular)
|
||||||
|
|
||||||
|
//Set up an AppDelegate
|
||||||
|
del := ns.AppDelegateAlloc()
|
||||||
|
del.ApplicationDidFinishLaunchingCallback(didFinishLaunching)
|
||||||
|
del.ApplicationShouldTerminateCallback(shouldTerminate)
|
||||||
|
del.ApplicationWillTerminateCallback(willTerminate)
|
||||||
|
del.ApplicationDidBecomeActiveCallback(didBecomeActive)
|
||||||
|
a.SetDelegate(del)
|
||||||
|
|
||||||
|
//Set up an NSWindow
|
||||||
w := ns.NSWindowAlloc().InitWithContentRect(
|
w := ns.NSWindowAlloc().InitWithContentRect(
|
||||||
ns.NSMakeRect(200,200,600,600),
|
ns.NSMakeRect(200,200,600,600),
|
||||||
ns.NSWindowStyleMaskTitled,
|
ns.NSWindowStyleMaskTitled,
|
||||||
|
@ -22,6 +50,8 @@ func app() {
|
||||||
w.SetTitle(nst("Hi World"))
|
w.SetTitle(nst("Hi World"))
|
||||||
w.MakeKeyAndOrderFront(w)
|
w.MakeKeyAndOrderFront(w)
|
||||||
w.SetAlphaValue(0.85)
|
w.SetAlphaValue(0.85)
|
||||||
|
|
||||||
|
//Build a basic menu
|
||||||
m1 := ns.NSMenuAlloc().InitWithTitle(nst("Main"))
|
m1 := ns.NSMenuAlloc().InitWithTitle(nst("Main"))
|
||||||
appItem := ns.NSMenuItemAlloc()
|
appItem := ns.NSMenuItemAlloc()
|
||||||
fileItem := ns.NSMenuItemAlloc()
|
fileItem := ns.NSMenuItemAlloc()
|
||||||
|
@ -43,13 +73,17 @@ func app() {
|
||||||
|
|
||||||
a.SetMainMenu(m1)
|
a.SetMainMenu(m1)
|
||||||
|
|
||||||
|
//Add a random button that does nothing
|
||||||
b1 := ns.NSButtonWithTitle(nst("push"),s,nil)
|
b1 := ns.NSButtonWithTitle(nst("push"),s,nil)
|
||||||
b1.SetFrame(ns.NSMakeRect(0,550,100,50))
|
b1.Id.NSView().SetFrame(ns.NSMakeRect(0,550,100,50))
|
||||||
w.ContentView().AddSubview(&b1.NSView,ns.NSWindowAbove,nil)
|
w.ContentView().AddSubview(&b1.NSView,ns.NSWindowAbove,nil)
|
||||||
|
|
||||||
|
//Run the app
|
||||||
a.Run()
|
a.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
//Run our app in an autorelease pool just for fun
|
||||||
go ns.Autorelease(app)
|
go ns.Autorelease(app)
|
||||||
select { }
|
select { }
|
||||||
}
|
}
|
||||||
|
|
355
wrap/main.go
355
wrap/main.go
|
@ -22,7 +22,8 @@ type Wrapper struct {
|
||||||
Functions map[string]*Method
|
Functions map[string]*Method
|
||||||
NamedEnums map[string]*Enum
|
NamedEnums map[string]*Enum
|
||||||
AnonEnums []*Enum
|
AnonEnums []*Enum
|
||||||
Protocols []*Protocol
|
Delegates map[string][]string
|
||||||
|
Protocols map[string]*Protocol
|
||||||
|
|
||||||
cgoFlags strings.Builder // put cGo directives here
|
cgoFlags strings.Builder // put cGo directives here
|
||||||
cCode strings.Builder // put cGo code here
|
cCode strings.Builder // put cGo code here
|
||||||
|
@ -43,7 +44,7 @@ func NewWrapper(debug bool) *Wrapper {
|
||||||
Functions: map[string]*Method{},
|
Functions: map[string]*Method{},
|
||||||
NamedEnums: map[string]*Enum{},
|
NamedEnums: map[string]*Enum{},
|
||||||
AnonEnums: []*Enum{},
|
AnonEnums: []*Enum{},
|
||||||
Protocols: []*Protocol{},
|
Protocols: map[string]*Protocol{},
|
||||||
Processed: map[string]bool{},
|
Processed: map[string]bool{},
|
||||||
Vaargs: 16,
|
Vaargs: 16,
|
||||||
}
|
}
|
||||||
|
@ -62,20 +63,20 @@ func (w *Wrapper) Frameworks(ss []string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _,s := range ss {
|
for _,s := range ss {
|
||||||
w.cCode.WriteString(fmt.Sprintf("#import <%s/%s.h>\n",s,s))
|
w.cgoFlags.WriteString(fmt.Sprintf("#import <%s/%s.h>\n",s,s))
|
||||||
}
|
}
|
||||||
w.cgoFlags.WriteString("#cgo LDFLAGS: -framework " + strings.Join(ss," -framework "))
|
w.cgoFlags.WriteString("#cgo LDFLAGS: -framework " + strings.Join(ss," -framework "))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Wrapper) Import(ss []string) {
|
func (w *Wrapper) Import(ss []string) {
|
||||||
for _,s := range ss {
|
for _,s := range ss {
|
||||||
w.cCode.WriteString("\n#import \"" + s + "\"\n")
|
w.cgoFlags.WriteString("\n#import \"" + s + "\"\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Wrapper) SysImport(ss []string) {
|
func (w *Wrapper) SysImport(ss []string) {
|
||||||
for _,s := range ss {
|
for _,s := range ss {
|
||||||
w.cCode.WriteString("\n#import <" + s + ">\n")
|
w.cgoFlags.WriteString("\n#import <" + s + ">\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +86,10 @@ func (w *Wrapper) Pragma(ss []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Wrapper) Delegate(ds map[string][]string) {
|
||||||
|
w.Delegates = ds
|
||||||
|
}
|
||||||
|
|
||||||
type Property struct {
|
type Property struct {
|
||||||
Name, Attr string
|
Name, Attr string
|
||||||
Type *types.Type
|
Type *types.Type
|
||||||
|
@ -110,7 +115,7 @@ type Enum struct {
|
||||||
|
|
||||||
type Protocol struct {
|
type Protocol struct {
|
||||||
Name, GoName string
|
Name, GoName string
|
||||||
Methods []*Method
|
Methods map[string]*Method
|
||||||
Polymorphic map[string]bool
|
Polymorphic map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,9 +134,10 @@ func (m Method) hasFunctionParam() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w Wrapper) cparamlist(m *Method) (string,string) {
|
func (w Wrapper) cparamlist(m *Method) (string,string,string) {
|
||||||
ns := make([]string,0)
|
ns := make([]string,0)
|
||||||
ret := make([]string,0)
|
ret := make([]string,0)
|
||||||
|
tps := []string{"void*"}
|
||||||
if !m.ClassMethod {
|
if !m.ClassMethod {
|
||||||
ret = append(ret,"void* o")
|
ret = append(ret,"void* o")
|
||||||
}
|
}
|
||||||
|
@ -144,8 +150,9 @@ func (w Wrapper) cparamlist(m *Method) (string,string) {
|
||||||
}
|
}
|
||||||
ns = append(ns,p.Vname)
|
ns = append(ns,p.Vname)
|
||||||
ret = append(ret,fmt.Sprintf("%s %s",tp,p.Vname))
|
ret = append(ret,fmt.Sprintf("%s %s",tp,p.Vname))
|
||||||
|
tps = append(tps,tp)
|
||||||
}
|
}
|
||||||
return strings.Join(ns,", "),strings.Join(ret,", ")
|
return strings.Join(ns,", "),strings.Join(ret,", "),strings.Join(tps,", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w Wrapper) objcparamlist(m *Method) string {
|
func (w Wrapper) objcparamlist(m *Method) string {
|
||||||
|
@ -182,7 +189,6 @@ var goreserved map[string]bool = map[string]bool{
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Wrapper) gpntp(m *Method) ([]string,[]*types.Type,string) {
|
func (w *Wrapper) gpntp(m *Method) ([]string,[]*types.Type,string) {
|
||||||
w.processType(m.Type)
|
|
||||||
ns := []string{}
|
ns := []string{}
|
||||||
tps := []*types.Type{}
|
tps := []*types.Type{}
|
||||||
if !m.ClassMethod {
|
if !m.ClassMethod {
|
||||||
|
@ -278,14 +284,16 @@ func (w *Wrapper) AddFunction(n *ast.FunctionDecl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Wrapper) AddProtocol(n *ast.ObjCProtocolDecl) {
|
func (w *Wrapper) AddProtocol(n *ast.ObjCProtocolDecl) {
|
||||||
p := &Protocol{
|
p := w.Protocols[n.Name]
|
||||||
Name: n.Name,
|
if p == nil {
|
||||||
GoName: types.NewTypeFromString(n.Name,n.Name).GoType(),
|
fmt.Printf("Adding protocol %s\n",n.Name)
|
||||||
Methods: []*Method{},
|
p = &Protocol{
|
||||||
Polymorphic: map[string]bool{},
|
Name: n.Name,
|
||||||
|
GoName: types.NewTypeFromString(n.Name,n.Name).GoType(),
|
||||||
|
Methods: map[string]*Method{},
|
||||||
|
Polymorphic: map[string]bool{},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
seen := make(map[string]bool)
|
|
||||||
fmt.Printf("Adding protocol %s\n",n.Name)
|
|
||||||
for _,c := range n.Children() {
|
for _,c := range n.Children() {
|
||||||
switch x := c.(type) {
|
switch x := c.(type) {
|
||||||
case *ast.ObjCMethodDecl:
|
case *ast.ObjCMethodDecl:
|
||||||
|
@ -299,16 +307,14 @@ func (w *Wrapper) AddProtocol(n *ast.ObjCProtocolDecl) {
|
||||||
var avail bool
|
var avail bool
|
||||||
m.Parameters, avail = w.GetParms(x,p.Name)
|
m.Parameters, avail = w.GetParms(x,p.Name)
|
||||||
if avail {
|
if avail {
|
||||||
fmt.Printf(" method %s\n",m.Name)
|
if p.Methods[m.Name] != nil {
|
||||||
p.Methods = append(p.Methods,m)
|
|
||||||
if seen[m.Name] {
|
|
||||||
p.Polymorphic[m.Name] = true
|
p.Polymorphic[m.Name] = true
|
||||||
}
|
}
|
||||||
seen[m.Name] = true
|
p.Methods[m.Name] = m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Protocols = append(w.Protocols,p)
|
w.Protocols[n.Name] = p
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME: copied from nswrap/main.go, should put this in a utils package
|
//FIXME: copied from nswrap/main.go, should put this in a utils package
|
||||||
|
@ -436,12 +442,12 @@ func (w *Wrapper) add(name string, ns []ast.Node) {
|
||||||
Parameters: []*Parameter{},
|
Parameters: []*Parameter{},
|
||||||
}
|
}
|
||||||
for _,p := range m.Parameters {
|
for _,p := range m.Parameters {
|
||||||
m2.Parameters = append(m2.Parameters,
|
p2 := &Parameter{
|
||||||
&Parameter{
|
|
||||||
Pname: p.Pname,
|
Pname: p.Pname,
|
||||||
Vname: p.Vname,
|
Vname: p.Vname,
|
||||||
Type: p.Type.CloneToClass(i.Name),
|
Type: p.Type.CloneToClass(i.Name),
|
||||||
})
|
}
|
||||||
|
m2.Parameters = append(m2.Parameters,p2)
|
||||||
}
|
}
|
||||||
i.Methods[m.Name] = m2
|
i.Methods[m.Name] = m2
|
||||||
}
|
}
|
||||||
|
@ -525,10 +531,6 @@ func (w *Wrapper) GetParms(n ast.Node,class string) ([]*Parameter,bool) {
|
||||||
if !avail.Available() {
|
if !avail.Available() {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
// check that we found the right number of parameters
|
|
||||||
//if len(ret) != len(n.Parameters) {
|
|
||||||
// fmt.Printf("Error in method declaration %s: Wrong number of ParmVarDecl children: %d parameters but %d ParmVarDecl children\n",n.Name,len(n.Parameters),len(ret))
|
|
||||||
//}
|
|
||||||
return ret, true
|
return ret, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -685,6 +687,8 @@ func (w *Wrapper) _processMethod(m *Method,fun bool) {
|
||||||
if m.Type.IsFunction() || m.Type.IsFunctionPtr() || m.hasFunctionParam() {
|
if m.Type.IsFunction() || m.Type.IsFunctionPtr() || m.hasFunctionParam() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
w.processType(m.Type)
|
||||||
|
//w.processType(m.GoClass) //??
|
||||||
gname := strings.Title(m.Name)
|
gname := strings.Title(m.Name)
|
||||||
receiver := ""
|
receiver := ""
|
||||||
switch {
|
switch {
|
||||||
|
@ -769,8 +773,7 @@ func %s%s(%s) %s {
|
||||||
} else {
|
} else {
|
||||||
cobj = "(" + m.Class + "*)o"
|
cobj = "(" + m.Class + "*)o"
|
||||||
}
|
}
|
||||||
cns,cntps := w.cparamlist(m)
|
cns,cntps,_ := w.cparamlist(m)
|
||||||
_ = cns
|
|
||||||
if fun {
|
if fun {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -829,6 +832,7 @@ func gStringToNsstring(s string) string {
|
||||||
|
|
||||||
func (w *Wrapper) ProcessEnum(e *Enum) {
|
func (w *Wrapper) ProcessEnum(e *Enum) {
|
||||||
//fmt.Printf("Processing enum (%s)\n",e.Name)
|
//fmt.Printf("Processing enum (%s)\n",e.Name)
|
||||||
|
w.processType(e.Type)
|
||||||
gtp := ""
|
gtp := ""
|
||||||
ctp := ""
|
ctp := ""
|
||||||
if e.Name != "" {
|
if e.Name != "" {
|
||||||
|
@ -858,52 +862,237 @@ const %s %s= C.%s
|
||||||
//FIXME: need to disambiguate polymorphic method names. Something like:
|
//FIXME: need to disambiguate polymorphic method names. Something like:
|
||||||
//func Disambiguate([]*Method) []*Method {} ...
|
//func Disambiguate([]*Method) []*Method {} ...
|
||||||
//Can allow user to decide on a disambiguation strategy
|
//Can allow user to decide on a disambiguation strategy
|
||||||
func (w *Wrapper) ProcessProtocol(p *Protocol) {
|
//NOTE: The delegate wrapper does not support variadic callback functions.
|
||||||
fmt.Printf("Processing protocol (%s)\n",p.Name)
|
func (w *Wrapper) ProcessDelegate(dname string, ps []string) {
|
||||||
//To create (per protocol):
|
//To create (per delegate):
|
||||||
//1. ObjC protocol interface
|
//1. ObjC interface
|
||||||
//2. ObjC protocol implementation
|
//2. ObjC implementation
|
||||||
//3. Go type
|
//3. ObjC constructor function
|
||||||
//4. Go constructor
|
//4. Go type
|
||||||
//5. Go dispatch database for callbacks
|
//5. Go constructor
|
||||||
|
//6. Go dispatch database for callbacks
|
||||||
//To create (per method):
|
//To create (per method):
|
||||||
//1. ObjC function prototypes for go exports
|
//1. ObjC function prototypes for go exports
|
||||||
//2. ObjC constructor function
|
//2. Go callback registration functions
|
||||||
//3. Go exported callback function wrappers
|
//3. Go exported callback function wrappers
|
||||||
|
|
||||||
var ccode, gocode, goexports strings.Builder
|
//organize output into string builders
|
||||||
//1. ObjC protocol interface
|
var cprotos, ccode, gotypes, gocode, goexports strings.Builder
|
||||||
ccode.WriteString(fmt.Sprintf(`
|
|
||||||
@interface %s : %s
|
//set up array of methods for this delegate
|
||||||
`,p.Name,p.Name))
|
methods := []*Method{}
|
||||||
//2. ObjC protocol implementation
|
for _,pname := range ps {
|
||||||
ccode.WriteString(fmt.Sprintf(`
|
proto := w.Protocols[pname]
|
||||||
`))
|
if proto == nil {
|
||||||
//3. Go type
|
fmt.Printf("Failed to find protocol %s for delegate %s\n",pname,dname)
|
||||||
gocode.WriteString(fmt.Sprintf(`
|
os.Exit(-1)
|
||||||
`))
|
}
|
||||||
//4. Go constructor
|
fmt.Printf(" proto %s\n",pname)
|
||||||
gocode.WriteString(fmt.Sprintf(`
|
for _,m := range proto.Methods {
|
||||||
`))
|
if proto.Polymorphic[m.Name] {
|
||||||
//5. Go dispatch database for callbacks
|
//FIXME: skip polymorphic methods for now
|
||||||
gocode.WriteString(fmt.Sprintf(`
|
fmt.Printf(" Skipping polymorphic method '%s'\n",m.Name)
|
||||||
`))
|
continue
|
||||||
//6. Go callback registration function
|
}
|
||||||
gocode.WriteString(fmt.Sprintf(`
|
methods = append(methods,m)
|
||||||
`))
|
}
|
||||||
//To create (per method):
|
|
||||||
for _,m := range p.Methods {
|
|
||||||
_ = m
|
|
||||||
//1. ObjC function prototypes for go exports
|
|
||||||
ccode.WriteString(fmt.Sprintf(`
|
|
||||||
`))
|
|
||||||
//2. ObjC constructor function
|
|
||||||
ccode.WriteString(fmt.Sprintf(`
|
|
||||||
`))
|
|
||||||
//3. Go exported callback function wrappers
|
|
||||||
goexports.WriteString(fmt.Sprintf(`
|
|
||||||
`))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
methprotos := make([]string,len(methods)) // objc method prototypes
|
||||||
|
gnames := make([]string,len(methods)) // go names for methods
|
||||||
|
gname := strings.Title(dname) // go name for this Delegate
|
||||||
|
vnames := make([][]string,len(methods)) // objc variable names
|
||||||
|
gtypes := make([][]string,len(methods)) // go parameter types for each method
|
||||||
|
getypes := make([][]string,len(methods)) // parameter types for go export
|
||||||
|
grtypes := make([]string,len(methods)) // go retrun types for each method
|
||||||
|
cgtypes := make([]string,len(methods)) // cgo return types
|
||||||
|
crtypes := make([]string,len(methods)) // c return types for each method
|
||||||
|
|
||||||
|
//1. ObjC interface
|
||||||
|
fmt.Printf("Delegate %s <%s>: %d methods\n",dname,strings.Join(ps,", "),len(methods))
|
||||||
|
for i,m := range methods {
|
||||||
|
w.processType(m.Type)
|
||||||
|
vnames[i] = make([]string,len(m.Parameters)+1)
|
||||||
|
getypes[i] = make([]string,len(m.Parameters)+1)
|
||||||
|
vnames[i][0] = "self"
|
||||||
|
getypes[i][0] = "unsafe.Pointer"
|
||||||
|
gtypes[i] = make([]string,len(m.Parameters))
|
||||||
|
//fmt.Printf("%s: %s\n",dname,m.Name)
|
||||||
|
var parms string
|
||||||
|
if len(m.Parameters) == 0 {
|
||||||
|
parms = ""
|
||||||
|
} else {
|
||||||
|
pm := m.Parameters[0]
|
||||||
|
w.processType(pm.Type)
|
||||||
|
parms = fmt.Sprintf(":(%s)%s",pm.Type.Node.Ctype(),pm.Vname)
|
||||||
|
vnames[i][1] = pm.Vname
|
||||||
|
gtypes[i][0] = pm.Type.GoType()
|
||||||
|
if pm.Type.IsPointer() {
|
||||||
|
getypes[i][1] = "unsafe.Pointer"
|
||||||
|
} else {
|
||||||
|
getypes[i][1] = gtypes[i][0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for j := 1; j < len(m.Parameters); j++ {
|
||||||
|
pm := m.Parameters[j]
|
||||||
|
w.processType(pm.Type)
|
||||||
|
parms = parms + fmt.Sprintf(" %s:(%s)%s",pm.Pname,pm.Type.Node.Ctype(),pm.Vname)
|
||||||
|
vnames[i][j+1] = pm.Vname
|
||||||
|
gtypes[i][j] = pm.Type.GoType()
|
||||||
|
var getp string
|
||||||
|
if pm.Type.IsPointer() {
|
||||||
|
getp = "unsafe.Pointer"
|
||||||
|
} else {
|
||||||
|
getp = gtypes[i][j]
|
||||||
|
}
|
||||||
|
getypes[i][j+1] = getp
|
||||||
|
}
|
||||||
|
methprotos[i] = fmt.Sprintf(
|
||||||
|
`- (%s)%s%s;`,m.Type.Node.Ctype(),m.Name,parms)
|
||||||
|
gnames[i] = strings.Title(m.Name)
|
||||||
|
if x := m.Type.GoType(); x == "Void" {
|
||||||
|
grtypes[i] = ""
|
||||||
|
} else {
|
||||||
|
grtypes[i] = " " + x
|
||||||
|
}
|
||||||
|
crtypes[i] = m.Type.CTypeAttrib()
|
||||||
|
if m.Type.IsPointer() {
|
||||||
|
// work around cgo bugs with struct size calculation
|
||||||
|
/*FIXME: DON'T NEED TO DO THIS?
|
||||||
|
crtypes[i] = "void*"
|
||||||
|
if x := m.Type.Node.Qualifiers(); x != "" {
|
||||||
|
crtypes[i] = x + " " + crtypes[i]
|
||||||
|
}
|
||||||
|
if x := m.Type.Node.Annotations(); x != "" {
|
||||||
|
crtypes[i] = crtypes[i] + " " + x
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
cgtypes[i] = "unsafe.Pointer"
|
||||||
|
} else {
|
||||||
|
crtypes[i] = m.Type.CTypeAttrib()
|
||||||
|
cgtypes[i] = m.Type.CGoType()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ccode.WriteString(fmt.Sprintf(`
|
||||||
|
@interface %s : NSObject <%s>
|
||||||
|
{ }
|
||||||
|
%s
|
||||||
|
@end
|
||||||
|
`,dname,strings.Join(ps,", "),strings.Join(methprotos,"\n")))
|
||||||
|
|
||||||
|
//2. ObjC implementation
|
||||||
|
methdecls := make([]string,len(methods))
|
||||||
|
for i,mp := range methprotos {
|
||||||
|
var ret string
|
||||||
|
if crtypes[i] != "void" {
|
||||||
|
ret = "return "
|
||||||
|
}
|
||||||
|
methdecls[i] = fmt.Sprintf(`
|
||||||
|
%s
|
||||||
|
{
|
||||||
|
%s%s(%s);
|
||||||
|
}`,mp[:len(mp)-1],ret,gname + gnames[i],strings.Join(vnames[i],", "))
|
||||||
|
}
|
||||||
|
ccode.WriteString(fmt.Sprintf(`
|
||||||
|
@implementation %s
|
||||||
|
%s
|
||||||
|
@end
|
||||||
|
`,dname,strings.Join(methdecls,"\n")))
|
||||||
|
|
||||||
|
//3. ObjC constructor function
|
||||||
|
ccode.WriteString(fmt.Sprintf(`
|
||||||
|
void*
|
||||||
|
%sAlloc() {
|
||||||
|
return [[%s alloc] autorelease];
|
||||||
|
}
|
||||||
|
`,dname,dname))
|
||||||
|
|
||||||
|
//4. Go type
|
||||||
|
gotypes.WriteString(fmt.Sprintf(`
|
||||||
|
type %s struct { Id }
|
||||||
|
func (o *%s) Ptr() unsafe.Pointer { return unsafe.Pointer(o) }
|
||||||
|
func (o *Id) %s() *%s { return (*%s)(unsafe.Pointer(o)) }
|
||||||
|
`,gname,gname,gname,gname,gname))
|
||||||
|
|
||||||
|
//5. Go constructor
|
||||||
|
gocode.WriteString(fmt.Sprintf(`
|
||||||
|
func %sAlloc() *%s {
|
||||||
|
return (*%s)(unsafe.Pointer(C.%sAlloc()))
|
||||||
|
}
|
||||||
|
`,gname,gname,gname,dname))
|
||||||
|
|
||||||
|
//6. Go dispatch database for callbacks
|
||||||
|
dispitems := make([]string,len(gnames))
|
||||||
|
for i,n := range gnames {
|
||||||
|
dispitems[i] = fmt.Sprintf(
|
||||||
|
` %s func(%s)%s`,n,strings.Join(gtypes[i],", "),grtypes[i])
|
||||||
|
}
|
||||||
|
gocode.WriteString(fmt.Sprintf(`
|
||||||
|
type %sDispatch struct {
|
||||||
|
%s
|
||||||
|
}
|
||||||
|
var %sLookup map[unsafe.Pointer]*%sDispatch =
|
||||||
|
map[unsafe.Pointer]*%sDispatch{}
|
||||||
|
`,gname,strings.Join(dispitems,"\n"),gname,gname,gname))
|
||||||
|
//To create (per method):
|
||||||
|
cprotos.WriteString("\n\n")
|
||||||
|
for i,m := range methods {
|
||||||
|
//1. ObjC function prototypes for go exports
|
||||||
|
_,_,ctps := w.cparamlist(m)
|
||||||
|
cprotos.WriteString(fmt.Sprintf(
|
||||||
|
`%s %s%s(%s);
|
||||||
|
`,crtypes[i],gname,gnames[i],ctps))
|
||||||
|
//2. Go callback registration functions
|
||||||
|
gocode.WriteString(fmt.Sprintf(`
|
||||||
|
func (d *%s) %sCallback(f func(%s)%s) {
|
||||||
|
dispatch := %sLookup[d.Ptr()]
|
||||||
|
if dispatch == nil {
|
||||||
|
dispatch = &%sDispatch{}
|
||||||
|
%sLookup[d.Ptr()] = dispatch
|
||||||
|
}
|
||||||
|
dispatch.%s = f
|
||||||
|
}
|
||||||
|
`,gname,gnames[i],strings.Join(gtypes[i],", "),grtypes[i],gname,gname,gname,gnames[i]))
|
||||||
|
//3. Go exported callback function wrappers
|
||||||
|
earglist := []string{"self unsafe.Pointer"}
|
||||||
|
garglist := []string{}
|
||||||
|
for j := 1; j < len(vnames[i]); j++ {
|
||||||
|
earglist = append(earglist,vnames[i][j] + " " + getypes[i][j])
|
||||||
|
garglist = append(garglist,fmt.Sprintf(
|
||||||
|
`(%s)(%s)`,gtypes[i][j-1],vnames[i][j]))
|
||||||
|
}
|
||||||
|
retdecl := ""
|
||||||
|
retname := ""
|
||||||
|
retn := ""
|
||||||
|
retnparen := ""
|
||||||
|
crtype := ""
|
||||||
|
if cgtypes[i] != "C.void" {
|
||||||
|
retdecl = "var ret " + cgtypes[i] + "\n\t"
|
||||||
|
retname = " ret"
|
||||||
|
if cgtypes[i] == "unsafe.Pointer" {
|
||||||
|
retn = "return unsafe.Pointer("
|
||||||
|
crtype = " unsafe.Pointer"
|
||||||
|
} else {
|
||||||
|
retn = "return (" + cgtypes[i] + ")("
|
||||||
|
crtype = " " + cgtypes[i]
|
||||||
|
}
|
||||||
|
retnparen = ")"
|
||||||
|
}
|
||||||
|
goexports.WriteString(fmt.Sprintf(`
|
||||||
|
//export %s%s
|
||||||
|
func %s%s(%s)%s {
|
||||||
|
%scb := %sLookup[self].%s
|
||||||
|
if cb == nil { return%s }
|
||||||
|
%scb(%s)%s
|
||||||
|
}
|
||||||
|
`,gname,gnames[i],gname,gnames[i],strings.Join(earglist,", "),crtype,retdecl,gname,gnames[i],retname,retn,strings.Join(garglist,", "),retnparen))
|
||||||
|
}
|
||||||
|
//DEBUG
|
||||||
|
w.cCode.WriteString(cprotos.String())
|
||||||
|
w.cCode.WriteString(ccode.String())
|
||||||
|
w.goTypes.WriteString(gotypes.String())
|
||||||
|
w.goCode.WriteString(gocode.String())
|
||||||
|
w.goExports.WriteString(goexports.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Wrapper) Wrap(toproc []string) {
|
func (w *Wrapper) Wrap(toproc []string) {
|
||||||
|
@ -918,6 +1107,11 @@ func (w *Wrapper) Wrap(toproc []string) {
|
||||||
fmt.Printf("Error opening file %s\n%s\n",path.Join(w.Package,"main.go"),err)
|
fmt.Printf("Error opening file %s\n%s\n",path.Join(w.Package,"main.go"),err)
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
|
ef,err := os.Create(path.Join(w.Package,"exports.go"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error opening file %s\n%s\n",path.Join(w.Package,"exports.go"),err)
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
fmt.Printf("Writing output to %s\n",path.Join(w.Package,"main.go"))
|
fmt.Printf("Writing output to %s\n",path.Join(w.Package,"main.go"))
|
||||||
pInterfaces := map[string]*Interface{}
|
pInterfaces := map[string]*Interface{}
|
||||||
for _,iface := range toproc {
|
for _,iface := range toproc {
|
||||||
|
@ -976,13 +1170,17 @@ void*
|
||||||
for _,e := range w.AnonEnums {
|
for _,e := range w.AnonEnums {
|
||||||
w.ProcessEnum(e)
|
w.ProcessEnum(e)
|
||||||
}
|
}
|
||||||
for _,p := range w.Protocols {
|
for n,p := range w.Delegates {
|
||||||
w.ProcessProtocol(p)
|
w.ProcessDelegate(n,p)
|
||||||
}
|
}
|
||||||
fmt.Printf("%d functions\n", len(w.Functions))
|
fmt.Printf("%d functions\n", len(w.Functions))
|
||||||
fmt.Printf("%d enums\n", len(w.NamedEnums) + len(w.AnonEnums))
|
fmt.Printf("%d enums\n", len(w.NamedEnums) + len(w.AnonEnums))
|
||||||
of.WriteString("package " + w.Package + "\n\n")
|
of.WriteString("package " + w.Package + "\n\n")
|
||||||
|
ef.WriteString("package " + w.Package + "\n\n")
|
||||||
|
|
||||||
of.WriteString(w.cgoFlags.String() + "\n")
|
of.WriteString(w.cgoFlags.String() + "\n")
|
||||||
|
ef.WriteString(w.cgoFlags.String() + "\n")
|
||||||
|
|
||||||
of.WriteString(w.cCode.String())
|
of.WriteString(w.cCode.String())
|
||||||
of.WriteString(`
|
of.WriteString(`
|
||||||
*/
|
*/
|
||||||
|
@ -997,4 +1195,15 @@ import (
|
||||||
of.WriteString(w.goHelpers.String())
|
of.WriteString(w.goHelpers.String())
|
||||||
of.WriteString(w.goCode.String())
|
of.WriteString(w.goCode.String())
|
||||||
of.Close()
|
of.Close()
|
||||||
|
|
||||||
|
ef.WriteString(`
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
`)
|
||||||
|
ef.WriteString(w.goExports.String())
|
||||||
|
ef.Close()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user