From 4f6930002d6c6422cff5ae30458bb9f6a219a4e3 Mon Sep 17 00:00:00 2001 From: Greg Date: Tue, 21 May 2019 16:26:52 -0400 Subject: [PATCH] First draft that handles subclasses and improvements to delegate implementation. --- cmd/nswrap/main.go | 19 ++- examples/app/main.go | 44 +++--- examples/app/nswrap.yaml | 40 ++--- examples/bluetooth/nswrap.yaml | 10 +- examples/simple/main.go | 2 + examples/simple/nswrap.yaml | 4 + wrap/main.go | 266 ++++++++++++++++++++++++++++----- 7 files changed, 298 insertions(+), 87 deletions(-) diff --git a/cmd/nswrap/main.go b/cmd/nswrap/main.go index 2e73a7e..a84879d 100644 --- a/cmd/nswrap/main.go +++ b/cmd/nswrap/main.go @@ -27,7 +27,8 @@ type conf struct { Classes []string Functions []string Enums []string - Delegates map[string][]string + Delegates map[string]map[string][]string + Subclasses map[string]map[string][]string Frameworks []string Imports []string Sysimports []string @@ -204,6 +205,7 @@ func Start() (err error) { w.SysImport(Config.Sysimports) w.Pragma(Config.Pragma) w.Delegate(Config.Delegates) + w.Subclass(Config.Subclasses) if Config.Vaargs == 0 { Config.Vaargs = 16 } @@ -214,6 +216,13 @@ func Start() (err error) { switch x := n.(type) { case *ast.ObjCInterfaceDecl: 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: w.AddCategory(x) case *ast.TypedefDecl: @@ -223,9 +232,11 @@ func Start() (err error) { w.AddFunction(x) } case *ast.ObjCProtocolDecl: - for _,ps := range Config.Delegates { - if matches(x.Name,ps) { - w.AddProtocol(x) + for _,ds := range Config.Delegates { + for ps,_ := range ds { + if matches(x.Name,[]string{ps}) { + w.AddProtocol(x) + } } } case *ast.EnumDecl: diff --git a/examples/app/main.go b/examples/app/main.go index 3c4a6ea..64ebca9 100644 --- a/examples/app/main.go +++ b/examples/app/main.go @@ -7,15 +7,12 @@ import ( "gitlab.wow.st/gmp/nswrap/examples/app/ns" ) +var nst = ns.NSStringWithGoString + 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 shouldTerminateAfterLastWindowClosed(s *ns.NSApplication) ns.BOOL { return 1 } @@ -26,8 +23,18 @@ func willTerminate(n *ns.NSNotification) { func didBecomeActive(n *ns.NSNotification) { 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() { //Lock OS thread because Cocoa uses thread-local storage runtime.LockOSThread() @@ -37,24 +44,23 @@ func app() { //Set up an AppDelegate del := ns.AppDelegateAlloc() del.ApplicationDidFinishLaunchingCallback(didFinishLaunching) - del.ApplicationShouldTerminateCallback(shouldTerminate) del.ApplicationShouldTerminateAfterLastWindowClosedCallback(shouldTerminateAfterLastWindowClosed) del.ApplicationWillTerminateCallback(willTerminate) del.ApplicationDidBecomeActiveCallback(didBecomeActive) a.SetDelegate(del) //Set up an NSWindow - w := ns.NSWindowAlloc().InitWithContentRect( + win = ns.NSWindowAlloc().InitWithContentRect( ns.NSMakeRect(200,200,600,600), - ns.NSWindowStyleMaskTitled | ns.NSWindowStyleMaskClosable, + ns.NSWindowStyleMaskTitled | ns.NSWindowStyleMaskClosable | + ns.NSWindowStyleMaskResizable, ns.NSBackingStoreBuffered, 0, nil, ) - nst := ns.NSStringWithGoString - w.SetTitle(nst("Hi World")) - w.MakeKeyAndOrderFront(w) - w.SetAlphaValue(0.85) + win.SetTitle(nst("Hi World")) + win.MakeKeyAndOrderFront(win) + win.SetAlphaValue(0.85) //Build a basic menu m1 := ns.NSMenuAlloc().InitWithTitle(nst("Main")) @@ -68,21 +74,15 @@ func app() { m1.SetSubmenu(appMenu, appItem) m1.SetSubmenu(fileMenu, fileItem) - s := ns.NSStringWithGoString("") - appMenu.AddItemWithTitle(nst("About"), nil, s) - appMenu.AddItemWithTitle(nst("Preferences"), nil, s) + appMenu.AddItemWithTitle(nst("About"), nil, nst("")) + appMenu.AddItemWithTitle(nst("Preferences"), nil, nst("")) appMenu.AddItemWithTitle(nst("Quit"),ns.Selector("terminate:"), nst("q")) a.SetMainMenu(m1) - fileMenu.AddItemWithTitle(nst("Open"), nil, s) - fileMenu.AddItemWithTitle(nst("New"), nil, s) + fileMenu.AddItemWithTitle(nst("Open"), nil, nst("")) + fileMenu.AddItemWithTitle(nst("New"), nil, nst("")) 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 a.Run() } diff --git a/examples/app/nswrap.yaml b/examples/app/nswrap.yaml index f05d0aa..89c3b5e 100644 --- a/examples/app/nswrap.yaml +++ b/examples/app/nswrap.yaml @@ -4,31 +4,20 @@ inputfiles: classes: - NSAutoreleasePool - - NSArray - - NSMutableArray - - NSDictionary - NSEnumerator - - NSSet - - NSDate - - NSTimeZone - - NSCalendar - - NSLocale - - NSCharacterSet - NSString - - NSScanner - - NSFileManager - NSApplication - - NSBundle - - NSApp - - NSMenu - - NSMenuItem - NSWindow - NSView - - NSScreen + - NSMenu + - NSMenuItem - NSButton - - NSEvent - - NSResponder - - NSRunLoop + - NSNotification + - NSStackView + - NSLayoutConstraint + - NSDictionary + - NSArray + - NSColor functions: [NSMake.*] @@ -41,7 +30,18 @@ enums: - NSWindowOrderingMode delegates: - AppDelegate: [NSApplicationDelegate] + AppDelegate: + NSApplicationDelegate: + - applicationWillTerminate + - applicationDidFinishLaunching + - applicationShouldTerminateAfterLastWindowClosed + - applicationDidBecomeActive +subclasses: + ViewController: + NSViewController: + - viewDidLoad + - viewDidDisappear + - loadView frameworks: [ Foundation, AppKit, CoreGraphics ] pragma: [ clang diagnostic ignored "-Wformat-security" ] diff --git a/examples/bluetooth/nswrap.yaml b/examples/bluetooth/nswrap.yaml index 4031d70..f6eb854 100644 --- a/examples/bluetooth/nswrap.yaml +++ b/examples/bluetooth/nswrap.yaml @@ -27,6 +27,14 @@ functions: [ NSMakeRange, dispatch_queue_create ] enums: [ CB.* ] frameworks: [ Foundation, CoreBluetooth ] delegates: - BleDelegate: [ CBCentralManagerDelegate, CBPeripheralDelegate ] + BleDelegate: + CBCentralManagerDelegate: + - centralManagerDidUpdateState + - centralManagerDidDiscoverPeripheral + - centralManagerDidConnectPeripheral + CBPeripheralDelegate: + - peripheralDidDiscoverServices + - peripheralDidDiscoverCharacteristicsForService + - peripheralDidUpdateValueForCharacteristic pragma: [ clang diagnostic ignored "-Wformat-security" ] diff --git a/examples/simple/main.go b/examples/simple/main.go index 00bb9ae..29acf4e 100644 --- a/examples/simple/main.go +++ b/examples/simple/main.go @@ -20,5 +20,7 @@ func main() { fmt.Println(o.Hi2(np)) o2 := ns.ClassTwoAlloc().Init() fmt.Println(o2.Hi1(ns1)) + o3 := ns.ClassThreeAlloc().Init() + fmt.Println(o3.Hi2(np)) } diff --git a/examples/simple/nswrap.yaml b/examples/simple/nswrap.yaml index d5fa645..ab74417 100644 --- a/examples/simple/nswrap.yaml +++ b/examples/simple/nswrap.yaml @@ -3,5 +3,9 @@ inputfiles: [ ClassOne/simple.h ] classes: - ClassOne - ClassTwo +subclasses: + ClassThree: + ClassTwo: + - hi.* imports: [ simple.h ] frameworks: [ Foundation ] diff --git a/wrap/main.go b/wrap/main.go index 4d57489..fad7fbf 100644 --- a/wrap/main.go +++ b/wrap/main.go @@ -22,11 +22,12 @@ type Wrapper struct { Functions map[string]*Method NamedEnums map[string]*Enum AnonEnums []*Enum - Delegates map[string][]string + Delegates map[string]map[string][]string + Subclasses map[string]map[string][]string Protocols map[string]*Protocol 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 goTypes strings.Builder // put Go type declarations 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 } +func (w *Wrapper) Subclass(ds map[string]map[string][]string) { + w.Subclasses = ds +} + type Property struct { Name, Attr string Type *types.Type @@ -312,8 +317,8 @@ func (w *Wrapper) AddProtocol(n *ast.ObjCProtocolDecl) { if x := p.Polymorphic[m.Name]; x != 0 { p.Polymorphic[m.Name] = x + 1 pname = pname + strings.Title(m.Parameters[1].Pname) - if m2 := p.Methods[m.Name]; m2 != nil { - pname2 := strings.Title(m.Name) + strings.Title(m2.Parameters[1].Pname) + if m2 := p.Methods[pname]; m2 != nil { + pname2 := pname + strings.Title(m2.Parameters[1].Pname) p.Methods[pname2] = m2 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) { var i *Interface var ok bool - goname := types.NewTypeFromString(name,name).GoType() + goname := strings.Title(types.NewTypeFromString(name,name).GoType()) types.Wrap(goname) if i,ok = w.Interfaces[name]; !ok { i = &Interface{ @@ -418,7 +423,7 @@ func (w *Wrapper) add(name string, ns []ast.Node) { //fmt.Println(m.Type.Node.String()) m.Parameters, avail = w.GetParms(x,name) if avail { - i.Methods[m.Name] = m + i.Methods[strings.Title(m.Name)] = m } case *ast.ObjCProtocol: //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) } - i.Methods[m.Name] = m2 + i.Methods[strings.Title(m.Name)] = m2 } } 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. -func (w *Wrapper) ProcessDelegate(dname string, ps []string) { +func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool) { //To create (per delegate): //1. ObjC interface //2. ObjC implementation @@ -884,10 +897,12 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) { //4. Go type //5. Go constructor //6. Go dispatch database for callbacks + //7. Go superclass dispatch function //To create (per method): //1. ObjC function prototypes for go exports //2. Go callback registration functions //3. Go exported callback function wrappers + //4. Go wrapper functions for superclass methods //organize output into string builders 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 methods := []*Method{} gnames := []string{} // go names for methods - for _,pname := range ps { - proto := w.Protocols[pname] - if proto == nil { - fmt.Printf("Failed to find protocol %s for delegate %s\n",pname,dname) - os.Exit(-1) + pnames := make([]string,len(ps)) + var supr string + i := 0 + for pname,pats := range ps { + 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 proto.Methods { + for gname,m := range ms { + //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() { continue } @@ -912,8 +951,11 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) { } 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 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 getypes := make([][]string,len(methods)) // parameter types for go export 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 //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 { w.processType(m.Type) vnames[i] = make([]string,len(m.Parameters)+1) + vpnames[i] = make([]string,len(m.Parameters)) getypes[i] = make([]string,len(m.Parameters)+1) vnames[i][0] = "self" 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) var parms string + var cparms string if len(m.Parameters) == 0 { parms = "" + cparms = "void* self" + vpnames[i] = []string{m.Name} } else { pm := m.Parameters[0] w.processType(pm.Type) 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 - gtypes[i][0] = pm.Type.GoType() + vpnames[i][0] = pm.Pname + ":" + pm.Vname + gtypes[i][1] = pm.Type.GoType() if pm.Type.IsPointer() { getypes[i][1] = "unsafe.Pointer" } else { - getypes[i][1] = gtypes[i][0] + getypes[i][1] = gtypes[i][1] } } 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) + cparms = cparms + fmt.Sprintf(", %s %s",pm.Type.Node.CType(),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 if pm.Type.IsPointer() { getp = "unsafe.Pointer" } else { - getp = gtypes[i][j] + getp = gtypes[i][j+1] } getypes[i][j+1] = getp } methprotos[i] = fmt.Sprintf( `- (%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" { grtypes[i] = "" } else { @@ -984,16 +1048,38 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) { 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(` -@interface %s : NSObject <%s> +@interface %s : %s %s { } %s +`,dname,supcls,protos,strings.Join(methprotos,"\n"))) + if sub { + ccode.WriteString(strings.Join(smethprotos,"\n")) + } + ccode.WriteString(` @end -`,dname,strings.Join(ps,", "),strings.Join(methprotos,"\n"))) +`) + if sub { + ccode.WriteString(strings.Join(sfunprotos,"\n")) + } //2. ObjC implementation methdecls := make([]string,len(methods)) + smethdecls := make([]string,len(methods)) + sfundecls := make([]string,len(methods)) 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 if crtypes[i] != "void" { ret = "return " @@ -1002,13 +1088,42 @@ func (w *Wrapper) ProcessDelegate(dname string, ps []string) { %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(` @implementation %s %s -@end `,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 ccode.WriteString(fmt.Sprintf(` @@ -1019,11 +1134,12 @@ void* `,dname,dname)) //4. Go type + gotypes.WriteString(fmt.Sprintf(` -type %s struct { Id } +type %s struct { %s } 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)) +`,gname,supr,gname,gname,gname,gname)) //5. Go constructor gocode.WriteString(fmt.Sprintf(` @@ -1034,17 +1150,32 @@ func %sAlloc() *%s { //6. Go dispatch database for callbacks dispitems := make([]string,len(gnames)) + sdispitems := make([]string,len(gnames)) for i,n := range gnames { + if !sub { + gtypes[i] = gtypes[i][1:] + } dispitems[i] = fmt.Sprintf( ` %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(` type %sDispatch struct { %s } -var %sLookup map[unsafe.Pointer]*%sDispatch = - map[unsafe.Pointer]*%sDispatch{} +var %sLookup map[unsafe.Pointer]%sDispatch = + map[unsafe.Pointer]%sDispatch{} `,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): cprotos.WriteString("\n\n") for i,m := range methods { @@ -1057,19 +1188,24 @@ var %sLookup map[unsafe.Pointer]*%sDispatch = 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 + %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 - earglist := []string{"self unsafe.Pointer"} + earglist := []string{"o unsafe.Pointer"} garglist := []string{} + if sub { + garglist = []string{"super"} + } for j := 1; j < len(vnames[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) { gt2 = "*Id" } @@ -1093,14 +1229,59 @@ func (d *%s) %sCallback(f func(%s)%s) { } 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(` //export %s%s func %s%s(%s)%s { - %scb := %sLookup[self].%s + %scb := %sLookup[o].%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(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")) pInterfaces := map[string]*Interface{} + //Note: the following code eliminates duplicates, so it is acceptable + //to have duplicate interfaces in 'toproc' for _,iface := range toproc { pInterfaces[iface] = w.Interfaces[iface] } @@ -1193,6 +1376,9 @@ void* for n,p := range w.Delegates { 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 enums\n", len(w.NamedEnums) + len(w.AnonEnums)) of.WriteString("package " + w.Package + "\n\n")