First draft that handles subclasses and improvements to delegate

implementation.
This commit is contained in:
Greg 2019-05-21 16:26:52 -04:00
parent 8de87cddb7
commit 4f6930002d
7 changed files with 298 additions and 87 deletions

View File

@ -27,7 +27,8 @@ type conf struct {
Classes []string Classes []string
Functions []string Functions []string
Enums []string Enums []string
Delegates map[string][]string Delegates map[string]map[string][]string
Subclasses map[string]map[string][]string
Frameworks []string Frameworks []string
Imports []string Imports []string
Sysimports []string Sysimports []string
@ -204,6 +205,7 @@ func Start() (err error) {
w.SysImport(Config.Sysimports) w.SysImport(Config.Sysimports)
w.Pragma(Config.Pragma) w.Pragma(Config.Pragma)
w.Delegate(Config.Delegates) w.Delegate(Config.Delegates)
w.Subclass(Config.Subclasses)
if Config.Vaargs == 0 { if Config.Vaargs == 0 {
Config.Vaargs = 16 Config.Vaargs = 16
} }
@ -214,6 +216,13 @@ func Start() (err error) {
switch x := n.(type) { switch x := n.(type) {
case *ast.ObjCInterfaceDecl: case *ast.ObjCInterfaceDecl:
w.AddInterface(x) w.AddInterface(x)
for _,ss := range Config.Subclasses {
for ps,_ := range ss {
if matches(x.Name,[]string{ps}) {
Config.Classes = append(Config.Classes,x.Name)
}
}
}
case *ast.ObjCCategoryDecl: case *ast.ObjCCategoryDecl:
w.AddCategory(x) w.AddCategory(x)
case *ast.TypedefDecl: case *ast.TypedefDecl:
@ -223,9 +232,11 @@ func Start() (err error) {
w.AddFunction(x) w.AddFunction(x)
} }
case *ast.ObjCProtocolDecl: case *ast.ObjCProtocolDecl:
for _,ps := range Config.Delegates { for _,ds := range Config.Delegates {
if matches(x.Name,ps) { for ps,_ := range ds {
w.AddProtocol(x) if matches(x.Name,[]string{ps}) {
w.AddProtocol(x)
}
} }
} }
case *ast.EnumDecl: case *ast.EnumDecl:

View File

@ -7,15 +7,12 @@ import (
"gitlab.wow.st/gmp/nswrap/examples/app/ns" "gitlab.wow.st/gmp/nswrap/examples/app/ns"
) )
var nst = ns.NSStringWithGoString
func didFinishLaunching(n *ns.NSNotification) { func didFinishLaunching(n *ns.NSNotification) {
fmt.Println("Go: did finish launching") fmt.Println("Go: did finish launching")
} }
func shouldTerminate(s *ns.NSApplication) ns.NSApplicationTerminateReply {
fmt.Println("Go: should terminate")
return ns.NSTerminateNow
}
func shouldTerminateAfterLastWindowClosed(s *ns.NSApplication) ns.BOOL { func shouldTerminateAfterLastWindowClosed(s *ns.NSApplication) ns.BOOL {
return 1 return 1
} }
@ -26,8 +23,18 @@ func willTerminate(n *ns.NSNotification) {
func didBecomeActive(n *ns.NSNotification) { func didBecomeActive(n *ns.NSNotification) {
fmt.Println("Go: did become active") fmt.Println("Go: did become active")
vc := win.ContentViewController()
if vc == nil {
fmt.Println("vc == nil")
} else {
fmt.Println("vc is not nil")
}
} }
var (
win *ns.NSWindow
)
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()
@ -37,24 +44,23 @@ func app() {
//Set up an AppDelegate //Set up an AppDelegate
del := ns.AppDelegateAlloc() del := ns.AppDelegateAlloc()
del.ApplicationDidFinishLaunchingCallback(didFinishLaunching) del.ApplicationDidFinishLaunchingCallback(didFinishLaunching)
del.ApplicationShouldTerminateCallback(shouldTerminate)
del.ApplicationShouldTerminateAfterLastWindowClosedCallback(shouldTerminateAfterLastWindowClosed) del.ApplicationShouldTerminateAfterLastWindowClosedCallback(shouldTerminateAfterLastWindowClosed)
del.ApplicationWillTerminateCallback(willTerminate) del.ApplicationWillTerminateCallback(willTerminate)
del.ApplicationDidBecomeActiveCallback(didBecomeActive) del.ApplicationDidBecomeActiveCallback(didBecomeActive)
a.SetDelegate(del) a.SetDelegate(del)
//Set up an NSWindow //Set up an NSWindow
w := ns.NSWindowAlloc().InitWithContentRect( win = ns.NSWindowAlloc().InitWithContentRect(
ns.NSMakeRect(200,200,600,600), ns.NSMakeRect(200,200,600,600),
ns.NSWindowStyleMaskTitled | ns.NSWindowStyleMaskClosable, ns.NSWindowStyleMaskTitled | ns.NSWindowStyleMaskClosable |
ns.NSWindowStyleMaskResizable,
ns.NSBackingStoreBuffered, ns.NSBackingStoreBuffered,
0, 0,
nil, nil,
) )
nst := ns.NSStringWithGoString win.SetTitle(nst("Hi World"))
w.SetTitle(nst("Hi World")) win.MakeKeyAndOrderFront(win)
w.MakeKeyAndOrderFront(w) win.SetAlphaValue(0.85)
w.SetAlphaValue(0.85)
//Build a basic menu //Build a basic menu
m1 := ns.NSMenuAlloc().InitWithTitle(nst("Main")) m1 := ns.NSMenuAlloc().InitWithTitle(nst("Main"))
@ -68,21 +74,15 @@ func app() {
m1.SetSubmenu(appMenu, appItem) m1.SetSubmenu(appMenu, appItem)
m1.SetSubmenu(fileMenu, fileItem) m1.SetSubmenu(fileMenu, fileItem)
s := ns.NSStringWithGoString("") appMenu.AddItemWithTitle(nst("About"), nil, nst(""))
appMenu.AddItemWithTitle(nst("About"), nil, s) appMenu.AddItemWithTitle(nst("Preferences"), nil, nst(""))
appMenu.AddItemWithTitle(nst("Preferences"), nil, s)
appMenu.AddItemWithTitle(nst("Quit"),ns.Selector("terminate:"), nst("q")) appMenu.AddItemWithTitle(nst("Quit"),ns.Selector("terminate:"), nst("q"))
a.SetMainMenu(m1) a.SetMainMenu(m1)
fileMenu.AddItemWithTitle(nst("Open"), nil, s) fileMenu.AddItemWithTitle(nst("Open"), nil, nst(""))
fileMenu.AddItemWithTitle(nst("New"), nil, s) fileMenu.AddItemWithTitle(nst("New"), nil, nst(""))
a.SetMainMenu(m1) a.SetMainMenu(m1)
//Add a random button that does nothing
b1 := ns.NSButtonWithTitle(nst("push"),s,nil)
b1.Id.NSView().SetFrame(ns.NSMakeRect(0,550,100,50))
w.ContentView().AddSubview(&b1.NSView,ns.NSWindowAbove,nil)
//Run the app //Run the app
a.Run() a.Run()
} }

View File

@ -4,31 +4,20 @@ inputfiles:
classes: classes:
- NSAutoreleasePool - NSAutoreleasePool
- NSArray
- NSMutableArray
- NSDictionary
- NSEnumerator - NSEnumerator
- NSSet
- NSDate
- NSTimeZone
- NSCalendar
- NSLocale
- NSCharacterSet
- NSString - NSString
- NSScanner
- NSFileManager
- NSApplication - NSApplication
- NSBundle
- NSApp
- NSMenu
- NSMenuItem
- NSWindow - NSWindow
- NSView - NSView
- NSScreen - NSMenu
- NSMenuItem
- NSButton - NSButton
- NSEvent - NSNotification
- NSResponder - NSStackView
- NSRunLoop - NSLayoutConstraint
- NSDictionary
- NSArray
- NSColor
functions: [NSMake.*] functions: [NSMake.*]
@ -41,7 +30,18 @@ enums:
- NSWindowOrderingMode - NSWindowOrderingMode
delegates: delegates:
AppDelegate: [NSApplicationDelegate] AppDelegate:
NSApplicationDelegate:
- applicationWillTerminate
- applicationDidFinishLaunching
- applicationShouldTerminateAfterLastWindowClosed
- applicationDidBecomeActive
subclasses:
ViewController:
NSViewController:
- viewDidLoad
- viewDidDisappear
- loadView
frameworks: [ Foundation, AppKit, CoreGraphics ] frameworks: [ Foundation, AppKit, CoreGraphics ]
pragma: [ clang diagnostic ignored "-Wformat-security" ] pragma: [ clang diagnostic ignored "-Wformat-security" ]

View File

@ -27,6 +27,14 @@ functions: [ NSMakeRange, dispatch_queue_create ]
enums: [ CB.* ] enums: [ CB.* ]
frameworks: [ Foundation, CoreBluetooth ] frameworks: [ Foundation, CoreBluetooth ]
delegates: delegates:
BleDelegate: [ CBCentralManagerDelegate, CBPeripheralDelegate ] BleDelegate:
CBCentralManagerDelegate:
- centralManagerDidUpdateState
- centralManagerDidDiscoverPeripheral
- centralManagerDidConnectPeripheral
CBPeripheralDelegate:
- peripheralDidDiscoverServices
- peripheralDidDiscoverCharacteristicsForService
- peripheralDidUpdateValueForCharacteristic
pragma: [ clang diagnostic ignored "-Wformat-security" ] pragma: [ clang diagnostic ignored "-Wformat-security" ]

View File

@ -20,5 +20,7 @@ func main() {
fmt.Println(o.Hi2(np)) fmt.Println(o.Hi2(np))
o2 := ns.ClassTwoAlloc().Init() o2 := ns.ClassTwoAlloc().Init()
fmt.Println(o2.Hi1(ns1)) fmt.Println(o2.Hi1(ns1))
o3 := ns.ClassThreeAlloc().Init()
fmt.Println(o3.Hi2(np))
} }

View File

@ -3,5 +3,9 @@ inputfiles: [ ClassOne/simple.h ]
classes: classes:
- ClassOne - ClassOne
- ClassTwo - ClassTwo
subclasses:
ClassThree:
ClassTwo:
- hi.*
imports: [ simple.h ] imports: [ simple.h ]
frameworks: [ Foundation ] frameworks: [ Foundation ]

View File

@ -22,11 +22,12 @@ type Wrapper struct {
Functions map[string]*Method Functions map[string]*Method
NamedEnums map[string]*Enum NamedEnums map[string]*Enum
AnonEnums []*Enum AnonEnums []*Enum
Delegates map[string][]string Delegates map[string]map[string][]string
Subclasses map[string]map[string][]string
Protocols map[string]*Protocol Protocols map[string]*Protocol
cgoFlags strings.Builder // put cGo directives here cgoFlags strings.Builder // put cGo directives here
cImports strings.Builder // put c imports and sysimports here cImports strings.Builder // put C imports and sysimports here
cCode strings.Builder // put cGo code here cCode strings.Builder // put cGo code here
goTypes strings.Builder // put Go type declarations here goTypes strings.Builder // put Go type declarations here
goConst strings.Builder // put Go constants (from C enums) here goConst strings.Builder // put Go constants (from C enums) here
@ -87,10 +88,14 @@ func (w *Wrapper) Pragma(ss []string) {
} }
} }
func (w *Wrapper) Delegate(ds map[string][]string) { func (w *Wrapper) Delegate(ds map[string]map[string][]string) {
w.Delegates = ds w.Delegates = ds
} }
func (w *Wrapper) Subclass(ds map[string]map[string][]string) {
w.Subclasses = ds
}
type Property struct { type Property struct {
Name, Attr string Name, Attr string
Type *types.Type Type *types.Type
@ -312,8 +317,8 @@ func (w *Wrapper) AddProtocol(n *ast.ObjCProtocolDecl) {
if x := p.Polymorphic[m.Name]; x != 0 { if x := p.Polymorphic[m.Name]; x != 0 {
p.Polymorphic[m.Name] = x + 1 p.Polymorphic[m.Name] = x + 1
pname = pname + strings.Title(m.Parameters[1].Pname) pname = pname + strings.Title(m.Parameters[1].Pname)
if m2 := p.Methods[m.Name]; m2 != nil { if m2 := p.Methods[pname]; m2 != nil {
pname2 := strings.Title(m.Name) + strings.Title(m2.Parameters[1].Pname) pname2 := pname + strings.Title(m2.Parameters[1].Pname)
p.Methods[pname2] = m2 p.Methods[pname2] = m2
delete(p.Methods,m.Name) delete(p.Methods,m.Name)
} }
@ -380,7 +385,7 @@ func (w *Wrapper) AddEnum(n *ast.EnumDecl,rs []string) {
func (w *Wrapper) add(name string, ns []ast.Node) { func (w *Wrapper) add(name string, ns []ast.Node) {
var i *Interface var i *Interface
var ok bool var ok bool
goname := types.NewTypeFromString(name,name).GoType() goname := strings.Title(types.NewTypeFromString(name,name).GoType())
types.Wrap(goname) types.Wrap(goname)
if i,ok = w.Interfaces[name]; !ok { if i,ok = w.Interfaces[name]; !ok {
i = &Interface{ i = &Interface{
@ -418,7 +423,7 @@ func (w *Wrapper) add(name string, ns []ast.Node) {
//fmt.Println(m.Type.Node.String()) //fmt.Println(m.Type.Node.String())
m.Parameters, avail = w.GetParms(x,name) m.Parameters, avail = w.GetParms(x,name)
if avail { if avail {
i.Methods[m.Name] = m i.Methods[strings.Title(m.Name)] = m
} }
case *ast.ObjCProtocol: case *ast.ObjCProtocol:
//fmt.Printf("ast.ObjCProtocol: %s\n",x.Name) //fmt.Printf("ast.ObjCProtocol: %s\n",x.Name)
@ -462,7 +467,7 @@ func (w *Wrapper) add(name string, ns []ast.Node) {
} }
m2.Parameters = append(m2.Parameters,p2) m2.Parameters = append(m2.Parameters,p2)
} }
i.Methods[m.Name] = m2 i.Methods[strings.Title(m.Name)] = m2
} }
} }
supmethods(i,types.Super(s)) supmethods(i,types.Super(s))
@ -875,8 +880,16 @@ const %s %s= C.%s
} }
} }
func (w *Wrapper) ProcessSubclass(sname string, ps map[string][]string) {
w._ProcessDelSub(sname,ps,true)
}
func (w *Wrapper) ProcessDelegate(dname string, ps map[string][]string) {
w._ProcessDelSub(dname,ps,false)
}
//NOTE: The delegate wrapper does not support variadic callback functions. //NOTE: The delegate wrapper does not support variadic callback functions.
func (w *Wrapper) ProcessDelegate(dname string, ps []string) { func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool) {
//To create (per delegate): //To create (per delegate):
//1. ObjC interface //1. ObjC interface
//2. ObjC implementation //2. ObjC implementation
@ -884,10 +897,12 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) {
//4. Go type //4. Go type
//5. Go constructor //5. Go constructor
//6. Go dispatch database for callbacks //6. Go dispatch database for callbacks
//7. Go superclass dispatch function
//To create (per method): //To create (per method):
//1. ObjC function prototypes for go exports //1. ObjC function prototypes for go exports
//2. Go callback registration functions //2. Go callback registration functions
//3. Go exported callback function wrappers //3. Go exported callback function wrappers
//4. Go wrapper functions for superclass methods
//organize output into string builders //organize output into string builders
var cprotos, ccode, gotypes, gocode, goexports strings.Builder var cprotos, ccode, gotypes, gocode, goexports strings.Builder
@ -895,14 +910,38 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) {
//set up array of methods for this delegate //set up array of methods for this delegate
methods := []*Method{} methods := []*Method{}
gnames := []string{} // go names for methods gnames := []string{} // go names for methods
for _,pname := range ps { pnames := make([]string,len(ps))
proto := w.Protocols[pname] var supr string
if proto == nil { i := 0
fmt.Printf("Failed to find protocol %s for delegate %s\n",pname,dname) for pname,pats := range ps {
os.Exit(-1) pnames[i] = pname
i++
var ms map[string]*Method
if sub {
interf := w.Interfaces[pname]
if interf == nil {
fmt.Printf("Failed to find interface %s for subclass %s\n",pname,dname)
os.Exit(-1)
}
//fmt.Printf(" subclass for %s\n",pname)
ms = interf.Methods
supr = interf.GoName
} else {
proto := w.Protocols[pname]
if proto == nil {
fmt.Printf("Failed to find protocol %s for delegate %s\n",pname,dname)
os.Exit(-1)
}
//fmt.Printf(" proto %s\n",pname)
ms = proto.Methods
supr = "Id"
} }
fmt.Printf(" proto %s\n",pname) for gname,m := range ms {
for gname,m := range proto.Methods { //note:we may have capitalized the first character to make a goname,
//but m.Name is not disambiguated for polymorphics...
if !matches(string(m.Name[0])+gname[1:],pats) {
continue
}
if m.Type.IsFunction() || m.Type.IsFunctionPtr() || m.hasFunctionParam() { if m.Type.IsFunction() || m.Type.IsFunctionPtr() || m.hasFunctionParam() {
continue continue
} }
@ -912,8 +951,11 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) {
} }
methprotos := make([]string,len(methods)) // objc method prototypes methprotos := make([]string,len(methods)) // objc method prototypes
smethprotos := make([]string,len(methods)) // super method prototypes
sfunprotos := make([]string,len(methods)) // super method prototypes
gname := strings.Title(dname) // go name for this Delegate gname := strings.Title(dname) // go name for this Delegate
vnames := make([][]string,len(methods)) // objc variable names vnames := make([][]string,len(methods)) // objc variable names
vpnames := make([][]string,len(methods)) // objc parameter:variable names
gtypes := make([][]string,len(methods)) // go parameter types for each method gtypes := make([][]string,len(methods)) // go parameter types for each method
getypes := make([][]string,len(methods)) // parameter types for go export getypes := make([][]string,len(methods)) // parameter types for go export
grtypes := make([]string,len(methods)) // go retrun types for each method grtypes := make([]string,len(methods)) // go retrun types for each method
@ -921,46 +963,68 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) {
crtypes := make([]string,len(methods)) // c return types for each method crtypes := make([]string,len(methods)) // c return types for each method
//1. ObjC interface //1. ObjC interface
fmt.Printf("Delegate %s <%s>: %d methods\n",dname,strings.Join(ps,", "),len(methods)) if sub {
fmt.Printf("Subclass ")
} else {
fmt.Printf("Delegate ")
}
fmt.Printf("%s <%s>: %d methods\n",dname,strings.Join(pnames,", "),len(methods))
for i,m := range methods { for i,m := range methods {
w.processType(m.Type) w.processType(m.Type)
vnames[i] = make([]string,len(m.Parameters)+1) vnames[i] = make([]string,len(m.Parameters)+1)
vpnames[i] = make([]string,len(m.Parameters))
getypes[i] = make([]string,len(m.Parameters)+1) getypes[i] = make([]string,len(m.Parameters)+1)
vnames[i][0] = "self" vnames[i][0] = "self"
getypes[i][0] = "unsafe.Pointer" getypes[i][0] = "unsafe.Pointer"
gtypes[i] = make([]string,len(m.Parameters)) gtypes[i] = make([]string,len(m.Parameters)+1)
gtypes[i][0] = gname + "Supermethods"
//fmt.Printf("%s: %s\n",dname,m.Name) //fmt.Printf("%s: %s\n",dname,m.Name)
var parms string var parms string
var cparms string
if len(m.Parameters) == 0 { if len(m.Parameters) == 0 {
parms = "" parms = ""
cparms = "void* self"
vpnames[i] = []string{m.Name}
} else { } else {
pm := m.Parameters[0] pm := m.Parameters[0]
w.processType(pm.Type) w.processType(pm.Type)
parms = fmt.Sprintf(":(%s)%s",pm.Type.Node.CType(),pm.Vname) parms = fmt.Sprintf(":(%s)%s",pm.Type.Node.CType(),pm.Vname)
cparms = fmt.Sprintf("void* self, %s %s",pm.Type.Node.CType(),pm.Vname)
vnames[i][1] = pm.Vname vnames[i][1] = pm.Vname
gtypes[i][0] = pm.Type.GoType() vpnames[i][0] = pm.Pname + ":" + pm.Vname
gtypes[i][1] = pm.Type.GoType()
if pm.Type.IsPointer() { if pm.Type.IsPointer() {
getypes[i][1] = "unsafe.Pointer" getypes[i][1] = "unsafe.Pointer"
} else { } else {
getypes[i][1] = gtypes[i][0] getypes[i][1] = gtypes[i][1]
} }
} }
for j := 1; j < len(m.Parameters); j++ { for j := 1; j < len(m.Parameters); j++ {
pm := m.Parameters[j] pm := m.Parameters[j]
w.processType(pm.Type) w.processType(pm.Type)
parms = parms + fmt.Sprintf(" %s:(%s)%s",pm.Pname,pm.Type.Node.CType(),pm.Vname) parms = parms + fmt.Sprintf(" %s:(%s)%s",pm.Pname,pm.Type.Node.CType(),pm.Vname)
cparms = cparms + fmt.Sprintf(", %s %s",pm.Type.Node.CType(),pm.Vname)
vnames[i][j+1] = pm.Vname vnames[i][j+1] = pm.Vname
gtypes[i][j] = pm.Type.GoType() vpnames[i][j] = pm.Pname + ":" + pm.Vname
gtypes[i][j+1] = pm.Type.GoType()
var getp string var getp string
if pm.Type.IsPointer() { if pm.Type.IsPointer() {
getp = "unsafe.Pointer" getp = "unsafe.Pointer"
} else { } else {
getp = gtypes[i][j] getp = gtypes[i][j+1]
} }
getypes[i][j+1] = getp getypes[i][j+1] = getp
} }
methprotos[i] = fmt.Sprintf( methprotos[i] = fmt.Sprintf(
`- (%s)%s%s;`,m.Type.Node.CType(),m.Name,parms) `- (%s)%s%s;`,m.Type.Node.CType(),m.Name,parms)
ct := m.Type.Node.CType()
smethprotos[i] = fmt.Sprintf(
`- (%s)super_%s%s;`,ct,m.Name,parms)
if ct == "instancetype" {
ct = gname + "*"
}
sfunprotos[i] = fmt.Sprintf(
`%s %s_super_%s(%s);`,ct,dname,m.Name,cparms)
if x := m.Type.GoType(); x == "Void" { if x := m.Type.GoType(); x == "Void" {
grtypes[i] = "" grtypes[i] = ""
} else { } else {
@ -984,16 +1048,38 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) {
cgtypes[i] = m.Type.CGoType() cgtypes[i] = m.Type.CGoType()
} }
} }
var supcls string
var protos string
if sub {
supcls = pnames[0]
protos = ""
} else {
supcls = "NSObject"
protos = "<" + strings.Join(pnames,", ") + ">"
}
ccode.WriteString(fmt.Sprintf(` ccode.WriteString(fmt.Sprintf(`
@interface %s : NSObject <%s> @interface %s : %s %s
{ } { }
%s %s
`,dname,supcls,protos,strings.Join(methprotos,"\n")))
if sub {
ccode.WriteString(strings.Join(smethprotos,"\n"))
}
ccode.WriteString(`
@end @end
`,dname,strings.Join(ps,", "),strings.Join(methprotos,"\n"))) `)
if sub {
ccode.WriteString(strings.Join(sfunprotos,"\n"))
}
//2. ObjC implementation //2. ObjC implementation
methdecls := make([]string,len(methods)) methdecls := make([]string,len(methods))
smethdecls := make([]string,len(methods))
sfundecls := make([]string,len(methods))
for i,mp := range methprotos { for i,mp := range methprotos {
mp := mp[:len(mp)-1]
smp := smethprotos[i][:len(smethprotos[i])-1]
sfp := sfunprotos[i][:len(sfunprotos[i])-1]
var ret string var ret string
if crtypes[i] != "void" { if crtypes[i] != "void" {
ret = "return " ret = "return "
@ -1002,13 +1088,42 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) {
%s %s
{ {
%s%s(%s); %s%s(%s);
}`,mp[:len(mp)-1],ret,gname + gnames[i],strings.Join(vnames[i],", ")) }
`,mp,ret,gname + gnames[i],strings.Join(vnames[i],", "))
methdecls[i] = fmt.Sprintf(`
%s
{
%s%s(%s);
}
`,mp,ret,gname + gnames[i],strings.Join(vnames[i],", "))
if sub {
smethdecls[i] = fmt.Sprintf(`
%s
{
%s[super %s];
}
`,smp,ret,strings.Join(vpnames[i]," "))
sfundecls[i] = fmt.Sprintf(`
%s
{
%s[%s super_%s];
}
`,sfp,ret,gname,strings.Join(vpnames[i]," "))
}
} }
ccode.WriteString(fmt.Sprintf(` ccode.WriteString(fmt.Sprintf(`
@implementation %s @implementation %s
%s %s
@end
`,dname,strings.Join(methdecls,"\n"))) `,dname,strings.Join(methdecls,"\n")))
if sub {
ccode.WriteString(strings.Join(smethdecls,"\n"))
}
ccode.WriteString(`
@end
`)
if sub {
ccode.WriteString(strings.Join(sfundecls,"\n"))
}
//3. ObjC constructor function //3. ObjC constructor function
ccode.WriteString(fmt.Sprintf(` ccode.WriteString(fmt.Sprintf(`
@ -1019,11 +1134,12 @@ void*
`,dname,dname)) `,dname,dname))
//4. Go type //4. Go type
gotypes.WriteString(fmt.Sprintf(` gotypes.WriteString(fmt.Sprintf(`
type %s struct { Id } type %s struct { %s }
func (o *%s) Ptr() unsafe.Pointer { return unsafe.Pointer(o) } func (o *%s) Ptr() unsafe.Pointer { return unsafe.Pointer(o) }
func (o *Id) %s() *%s { return (*%s)(unsafe.Pointer(o)) } func (o *Id) %s() *%s { return (*%s)(unsafe.Pointer(o)) }
`,gname,gname,gname,gname,gname)) `,gname,supr,gname,gname,gname,gname))
//5. Go constructor //5. Go constructor
gocode.WriteString(fmt.Sprintf(` gocode.WriteString(fmt.Sprintf(`
@ -1034,17 +1150,32 @@ func %sAlloc() *%s {
//6. Go dispatch database for callbacks //6. Go dispatch database for callbacks
dispitems := make([]string,len(gnames)) dispitems := make([]string,len(gnames))
sdispitems := make([]string,len(gnames))
for i,n := range gnames { for i,n := range gnames {
if !sub {
gtypes[i] = gtypes[i][1:]
}
dispitems[i] = fmt.Sprintf( dispitems[i] = fmt.Sprintf(
` %s func(%s)%s`,n,strings.Join(gtypes[i],", "),grtypes[i]) ` %s func(%s)%s`,n,strings.Join(gtypes[i],", "),grtypes[i])
if sub {
sdispitems[i] = fmt.Sprintf(
` %s func(%s)%s`,n,strings.Join(gtypes[i][1:],", "),grtypes[i])
}
} }
gocode.WriteString(fmt.Sprintf(` gocode.WriteString(fmt.Sprintf(`
type %sDispatch struct { type %sDispatch struct {
%s %s
} }
var %sLookup map[unsafe.Pointer]*%sDispatch = var %sLookup map[unsafe.Pointer]%sDispatch =
map[unsafe.Pointer]*%sDispatch{} map[unsafe.Pointer]%sDispatch{}
`,gname,strings.Join(dispitems,"\n"),gname,gname,gname)) `,gname,strings.Join(dispitems,"\n"),gname,gname,gname))
if sub {
gocode.WriteString(fmt.Sprintf(`
type %sSupermethods struct {
%s
}
`,gname,strings.Join(sdispitems,"\n")))
}
//To create (per method): //To create (per method):
cprotos.WriteString("\n\n") cprotos.WriteString("\n\n")
for i,m := range methods { for i,m := range methods {
@ -1057,19 +1188,24 @@ var %sLookup map[unsafe.Pointer]*%sDispatch =
gocode.WriteString(fmt.Sprintf(` gocode.WriteString(fmt.Sprintf(`
func (d *%s) %sCallback(f func(%s)%s) { func (d *%s) %sCallback(f func(%s)%s) {
dispatch := %sLookup[d.Ptr()] dispatch := %sLookup[d.Ptr()]
if dispatch == nil {
dispatch = &%sDispatch{}
%sLookup[d.Ptr()] = dispatch
}
dispatch.%s = f dispatch.%s = f
%sLookup[d.Ptr()] = dispatch
} }
`,gname,gnames[i],strings.Join(gtypes[i],", "),grtypes[i],gname,gname,gname,gnames[i])) `,gname,gnames[i],strings.Join(gtypes[i],", "),grtypes[i],gname,gnames[i],gname))
//3. Go exported callback function wrappers //3. Go exported callback function wrappers
earglist := []string{"self unsafe.Pointer"} earglist := []string{"o unsafe.Pointer"}
garglist := []string{} garglist := []string{}
if sub {
garglist = []string{"super"}
}
for j := 1; j < len(vnames[i]); j++ { for j := 1; j < len(vnames[i]); j++ {
earglist = append(earglist,vnames[i][j] + " " + getypes[i][j]) earglist = append(earglist,vnames[i][j] + " " + getypes[i][j])
gt2 := gtypes[i][j-1] var gt2 string
if sub {
gt2 = gtypes[i][j]
} else {
gt2 = gtypes[i][j-1]
}
if types.IsGoInterface(gt2) { if types.IsGoInterface(gt2) {
gt2 = "*Id" gt2 = "*Id"
} }
@ -1093,14 +1229,59 @@ func (d *%s) %sCallback(f func(%s)%s) {
} }
retnparen = ")" retnparen = ")"
} }
sdispentries := []string{}
for _,n := range gnames {
sdispentries = append(sdispentries,fmt.Sprintf(
` self.Super%s`,n))
}
sper := ""
if sub && len(gnames) > 0 {
sper = fmt.Sprintf(
`self := (*%s)(o)
super := %sSupermethods{
%s,
}
`,gname,gname,strings.Join(sdispentries,",\n"))
}
goexports.WriteString(fmt.Sprintf(` goexports.WriteString(fmt.Sprintf(`
//export %s%s //export %s%s
func %s%s(%s)%s { func %s%s(%s)%s {
%scb := %sLookup[self].%s %scb := %sLookup[o].%s
if cb == nil { return%s } if cb == nil { return%s }
%scb(%s)%s %s%scb(%s)%s
} }
`,gname,gnames[i],gname,gnames[i],strings.Join(earglist,", "),crtype,retdecl,gname,gnames[i],retname,retn,strings.Join(garglist,", "),retnparen)) `,gname,gnames[i],gname,gnames[i],strings.Join(earglist,", "),crtype,retdecl,gname,gnames[i],retname,sper,retn,strings.Join(garglist,", "),retnparen))
//4. Go wrapper functions for superclass methods
if !sub { continue } // for subclasses only
grtype := m.Type.GoType()
if grtype == "Void" {
grtype = ""
}
if types.IsGoInterface(grtype) {
grtype = "*Id"
}
if grtype == "BOOL" {
grtype = "bool"
}
if sub {
gocode.WriteString(fmt.Sprintf(`
func (o *%s) Super%s(%s) %s {
`,gname,gnames[i],strings.Join(earglist[1:],", "), grtype))
ns,tps,_ := w.gpntp(m)
lparm := len(tps)-1
if len(tps) > 0 && tps[lparm].Variadic {
vn := ns[lparm]
vn = vn[:len(vn)-1]
ns[lparm] = vn
gocode.WriteString(fmt.Sprintf(
` var %s [%d]unsafe.Pointer
for i,o := range %ss {
%s[i] = o.Ptr()
}
`,vn,w.Vaargs,vn,vn))
}
gocode.WriteString(` ` + types.GoToC(dname + "_super_"+m.Name,ns,m.Type,tps,false) + "\n}\n")
}
} }
w.cCode.WriteString(cprotos.String()) w.cCode.WriteString(cprotos.String())
w.cCode.WriteString(ccode.String()) w.cCode.WriteString(ccode.String())
@ -1129,6 +1310,8 @@ func (w *Wrapper) Wrap(toproc []string) {
} }
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{}
//Note: the following code eliminates duplicates, so it is acceptable
//to have duplicate interfaces in 'toproc'
for _,iface := range toproc { for _,iface := range toproc {
pInterfaces[iface] = w.Interfaces[iface] pInterfaces[iface] = w.Interfaces[iface]
} }
@ -1193,6 +1376,9 @@ void*
for n,p := range w.Delegates { for n,p := range w.Delegates {
w.ProcessDelegate(n,p) w.ProcessDelegate(n,p)
} }
for n,s := range w.Subclasses {
w.ProcessSubclass(n,s)
}
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")