Change Go types to plain structs instead of pointers to structs.

Add methods for protocols that Objective-C interfaces claim to
implement. Separate class methods from instance methods in
internal data structures. Add layout constraints with visual
formats to examples/app. Fix typedefs for wrapped objective-c
object types.
This commit is contained in:
Greg 2019-05-23 16:31:47 -04:00
parent 4f6930002d
commit a616761475
10 changed files with 355 additions and 220 deletions

View File

@ -13,7 +13,6 @@ import (
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"gitlab.wow.st/gmp/nswrap/ast" "gitlab.wow.st/gmp/nswrap/ast"
"gitlab.wow.st/gmp/nswrap/types"
"gitlab.wow.st/gmp/nswrap/wrap" "gitlab.wow.st/gmp/nswrap/wrap"
) )
@ -226,19 +225,13 @@ func Start() (err error) {
case *ast.ObjCCategoryDecl: case *ast.ObjCCategoryDecl:
w.AddCategory(x) w.AddCategory(x)
case *ast.TypedefDecl: case *ast.TypedefDecl:
types.AddTypedef(x.Name,x.Type) w.AddTypedef(x.Name,x.Type)
case *ast.FunctionDecl: case *ast.FunctionDecl:
if matches(x.Name,Config.Functions) { if matches(x.Name,Config.Functions) {
w.AddFunction(x) w.AddFunction(x)
} }
case *ast.ObjCProtocolDecl: case *ast.ObjCProtocolDecl:
for _,ds := range Config.Delegates {
for ps,_ := range ds {
if matches(x.Name,[]string{ps}) {
w.AddProtocol(x) w.AddProtocol(x)
}
}
}
case *ast.EnumDecl: case *ast.EnumDecl:
w.AddEnum(x,Config.Enums) w.AddEnum(x,Config.Enums)
} }

View File

@ -7,48 +7,12 @@ import (
"gitlab.wow.st/gmp/nswrap/examples/app/ns" "gitlab.wow.st/gmp/nswrap/examples/app/ns"
) )
//Shortcut for literal NSStrings
var nst = ns.NSStringWithGoString 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")
} fmt.Printf("Notification: %s\n",n.Name().UTF8String())
func shouldTerminateAfterLastWindowClosed(s *ns.NSApplication) ns.BOOL {
return 1
}
func willTerminate(n *ns.NSNotification) {
fmt.Println("Go: will terminate")
}
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()
a := ns.NSApplicationSharedApplication()
a.SetActivationPolicy(ns.NSApplicationActivationPolicyRegular)
//Set up an AppDelegate
del := ns.AppDelegateAlloc()
del.ApplicationDidFinishLaunchingCallback(didFinishLaunching)
del.ApplicationShouldTerminateAfterLastWindowClosedCallback(shouldTerminateAfterLastWindowClosed)
del.ApplicationWillTerminateCallback(willTerminate)
del.ApplicationDidBecomeActiveCallback(didBecomeActive)
a.SetDelegate(del)
//Set up an NSWindow //Set up an NSWindow
win = ns.NSWindowAlloc().InitWithContentRect( win = ns.NSWindowAlloc().InitWithContentRect(
ns.NSMakeRect(200,200,600,600), ns.NSMakeRect(200,200,600,600),
@ -56,8 +20,11 @@ func app() {
ns.NSWindowStyleMaskResizable, ns.NSWindowStyleMaskResizable,
ns.NSBackingStoreBuffered, ns.NSBackingStoreBuffered,
0, 0,
nil, ns.NSScreen{},
) )
// retain win since we called Alloc and did not add it to a collection
win.Retain()
win.SetTitle(nst("Hi World")) win.SetTitle(nst("Hi World"))
win.MakeKeyAndOrderFront(win) win.MakeKeyAndOrderFront(win)
win.SetAlphaValue(0.85) win.SetAlphaValue(0.85)
@ -83,6 +50,67 @@ func app() {
a.SetMainMenu(m1) a.SetMainMenu(m1)
//add some buttons and do some layout
//don't do this:
//b := ns.NSButtonAlloc().InitWithFrame(ns.NSMakeRect(100,100,100,50))
b1 := ns.NSButtonWithTitle(nst("PUSH"),ns.Id{},ns.Selector(""))
b2 := ns.NSButtonWithTitle(nst("QUIT"),ns.Id{},ns.Selector("terminate:"))
b1.SetTranslatesAutoresizingMaskIntoConstraints(0)
b2.SetTranslatesAutoresizingMaskIntoConstraints(0)
cv := win.ContentView()
cv.AddSubview(b1.NSView,ns.NSWindowAbove,ns.NSView{})
cv.AddSubview(b2.NSView,ns.NSWindowAbove,ns.NSView{})
viewmap := ns.NSDictionaryWithObjects(
ns.NSArrayWithObjects(b1,b2),
ns.NSArrayWithObjects(nst("b1"),nst("b2")))
cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
nst("V:|-[b1]"),0, ns.NSDictionary{}, viewmap))
cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
nst("H:|-[b1]"),0, ns.NSDictionary{}, viewmap))
cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
nst("H:[b1]-[b2]"),ns.NSLayoutFormatAlignAllBaseline,
ns.NSDictionary{}, viewmap))
}
func shouldTerminateAfterLastWindowClosed(s ns.NSApplication) ns.BOOL {
return 1
}
func willTerminate(n ns.NSNotification) {
fmt.Println("Go: will terminate")
}
func didBecomeActive(n ns.NSNotification) {
fmt.Println("Go: did become active")
fmt.Printf("Notification: %s\n",n.Name().UTF8String())
}
var (
a ns.NSApplication
win ns.NSWindow
)
func app() {
//Lock OS thread because Cocoa uses thread-local storage
runtime.LockOSThread()
a = ns.NSApplicationSharedApplication()
a.SetActivationPolicy(ns.NSApplicationActivationPolicyRegular)
//Set up an AppDelegate
del := ns.AppDelegateAlloc()
del.ApplicationDidFinishLaunchingCallback(didFinishLaunching)
del.ApplicationShouldTerminateAfterLastWindowClosedCallback(shouldTerminateAfterLastWindowClosed)
del.ApplicationWillTerminateCallback(willTerminate)
del.ApplicationDidBecomeActiveCallback(didBecomeActive)
a.SetDelegate(del)
//Run the app //Run the app
a.Run() a.Run()
} }

View File

@ -1,3 +1,4 @@
# nswrap.yaml
inputfiles: inputfiles:
- /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h - /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h
- /System/Library/Frameworks/AppKit.framework/Headers/AppKit.h - /System/Library/Frameworks/AppKit.framework/Headers/AppKit.h
@ -17,17 +18,17 @@ classes:
- NSLayoutConstraint - NSLayoutConstraint
- NSDictionary - NSDictionary
- NSArray - NSArray
- NSColor - NSObject
functions: [NSMake.*] functions: [NSMake.*]
enums: enums:
- CF.*
- NSApplication.* - NSApplication.*
- NSBackingStore.* - NSBackingStore.*
- NSWindowStyleMask.* - NSWindowStyleMask.*
- NSWindowButton - NSWindowButton
- NSWindowOrderingMode - NSWindowOrderingMode
- NSLayout.*
delegates: delegates:
AppDelegate: AppDelegate:
@ -36,15 +37,7 @@ delegates:
- applicationDidFinishLaunching - applicationDidFinishLaunching
- applicationShouldTerminateAfterLastWindowClosed - applicationShouldTerminateAfterLastWindowClosed
- applicationDidBecomeActive - applicationDidBecomeActive
subclasses:
ViewController:
NSViewController:
- viewDidLoad
- viewDidDisappear
- loadView
frameworks: [ Foundation, AppKit, CoreGraphics ] frameworks: [ Foundation, AppKit ]
pragma: [ clang diagnostic ignored "-Wformat-security" ] pragma: [ clang diagnostic ignored "-Wformat-security" ]
vaargs: 32

View File

@ -8,7 +8,7 @@ import (
"gitlab.wow.st/gmp/nswrap/examples/bluetooth/ns" "gitlab.wow.st/gmp/nswrap/examples/bluetooth/ns"
) )
func updateState(c *ns.CBCentralManager) { func updateState(c ns.CBCentralManager) {
fmt.Printf("Go: did update state\n") fmt.Printf("Go: did update state\n")
switch cm.CBManager.State() { switch cm.CBManager.State() {
case ns.CBManagerStateUnknown: case ns.CBManagerStateUnknown:
@ -23,44 +23,44 @@ func updateState(c *ns.CBCentralManager) {
fmt.Printf(" powered off\n") fmt.Printf(" powered off\n")
case ns.CBManagerStatePoweredOn: case ns.CBManagerStatePoweredOn:
fmt.Printf(" powered on\n") fmt.Printf(" powered on\n")
cm.ScanForPeripheralsWithServices(ns.NSArrayWithObjects(hrm_uuid),nil) cm.ScanForPeripheralsWithServices(ns.NSArrayWithObjects(hrm_uuid),ns.NSDictionary{})
} }
} }
func discoverPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral, d *ns.NSDictionary, rssi *ns.NSNumber) { func discoverPeripheral(c ns.CBCentralManager, p ns.CBPeripheral, d ns.NSDictionary, rssi ns.NSNumber) {
fmt.Printf("Did discover peripheral\n") fmt.Printf("Did discover peripheral\n")
c.StopScan() c.StopScan()
if peripheral != nil { if peripheral.Ptr() != nil {
peripheral.Release() peripheral.Release()
} }
peripheral = p peripheral = p
peripheral.Retain() peripheral.Retain()
c.ConnectPeripheral(peripheral,nil) c.ConnectPeripheral(peripheral,ns.NSDictionary{})
} }
func connectPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral) { func connectPeripheral(c ns.CBCentralManager, p ns.CBPeripheral) {
fmt.Printf("Did connect peripheral\n") fmt.Printf("Did connect peripheral\n")
p.SetDelegate(cd) p.SetDelegate(cd)
p.DiscoverServices(nil) p.DiscoverServices(ns.NSArray{})
} }
func discoverServices(p *ns.CBPeripheral, e *ns.NSError) { func discoverServices(p ns.CBPeripheral, e ns.NSError) {
fmt.Printf("Did discover services\n") fmt.Printf("Did discover services\n")
p.Services().ObjectEnumerator().ForIn(func(o *ns.Id) bool { p.Services().ObjectEnumerator().ForIn(func(o ns.Id) bool {
serv := o.CBService() serv := o.CBService()
switch { switch {
case serv.UUID().IsEqualTo(hrm_uuid): case serv.UUID().IsEqualTo(hrm_uuid):
fmt.Printf("--heart rate monitor service\n") fmt.Printf("--heart rate monitor service\n")
p.DiscoverCharacteristics(nil,serv) p.DiscoverCharacteristics(ns.NSArray{},serv)
case serv.UUID().IsEqualTo(ns.CBUUIDWithGoString("180A")): case serv.UUID().IsEqualTo(ns.CBUUIDWithGoString("180A")):
fmt.Printf("--device information service\n") fmt.Printf("--device information service\n")
p.DiscoverCharacteristics(nil,serv) p.DiscoverCharacteristics(ns.NSArray{},serv)
} }
return true return true
}) })
} }
func hr(d *ns.NSData) int { func hr(d ns.NSData) int {
if l := int(d.Length()); l < 4 { if l := int(d.Length()); l < 4 {
return 0 return 0
} }
@ -73,11 +73,11 @@ func hr(d *ns.NSData) int {
} }
} }
func discoverCharacteristics(p *ns.CBPeripheral, s *ns.CBService, e *ns.NSError) { func discoverCharacteristics(p ns.CBPeripheral, s ns.CBService, e ns.NSError) {
fmt.Printf("Did discover characteristics\n") fmt.Printf("Did discover characteristics\n")
fmt.Printf("----%s\n",s.UUID().UUIDString().UTF8String()) fmt.Printf("----%s\n",s.UUID().UUIDString().UTF8String())
if s.UUID().IsEqualTo(hrm_uuid) { if s.UUID().IsEqualTo(hrm_uuid) {
s.Characteristics().ObjectEnumerator().ForIn(func(o *ns.Id) bool { s.Characteristics().ObjectEnumerator().ForIn(func(o ns.Id) bool {
chr := o.CBCharacteristic() chr := o.CBCharacteristic()
fmt.Printf("------%s\n",chr.UUID().UUIDString().UTF8String()) fmt.Printf("------%s\n",chr.UUID().UUIDString().UTF8String())
if chr.UUID().IsEqualTo(hrv_uuid) { if chr.UUID().IsEqualTo(hrv_uuid) {
@ -90,7 +90,7 @@ func discoverCharacteristics(p *ns.CBPeripheral, s *ns.CBService, e *ns.NSError)
} }
} }
func updateValue(p *ns.CBPeripheral, chr *ns.CBCharacteristic, e *ns.NSError) { func updateValue(p ns.CBPeripheral, chr ns.CBCharacteristic, e ns.NSError) {
if chr.UUID().IsEqualTo(hrv_uuid) { if chr.UUID().IsEqualTo(hrv_uuid) {
v := chr.Value() v := chr.Value()
fmt.Printf("Heart rate: %d\n",hr(v)) fmt.Printf("Heart rate: %d\n",hr(v))
@ -98,17 +98,17 @@ func updateValue(p *ns.CBPeripheral, chr *ns.CBCharacteristic, e *ns.NSError) {
} }
var ( var (
hrm_uuid *ns.CBUUID hrm_uuid ns.CBUUID
hrv_uuid *ns.CBUUID hrv_uuid ns.CBUUID
cd *ns.BleDelegate cd ns.CBDelegate
cm *ns.CBCentralManager cm ns.CBCentralManager
peripheral *ns.CBPeripheral peripheral ns.CBPeripheral
) )
func main() { func main() {
queue := ns.DispatchQueueCreate(ns.CharWithGoString("st.wow.gitlab.ble"),nil) queue := ns.DispatchQueueCreate(ns.CharWithGoString("st.wow.gitlab.ble"),nil)
cd = ns.BleDelegateAlloc() cd = ns.CBDelegateAlloc()
cd.CentralManagerDidUpdateStateCallback(updateState) cd.CentralManagerDidUpdateStateCallback(updateState)
cd.CentralManagerDidDiscoverPeripheralCallback(discoverPeripheral) cd.CentralManagerDidDiscoverPeripheralCallback(discoverPeripheral)
@ -120,8 +120,7 @@ func main() {
hrm_uuid = ns.CBUUIDWithGoString("180D") hrm_uuid = ns.CBUUIDWithGoString("180D")
hrv_uuid = ns.CBUUIDWithGoString("2A37") hrv_uuid = ns.CBUUIDWithGoString("2A37")
cm = ns.CBCentralManagerAlloc() cm = ns.CBCentralManagerAlloc().InitWithDelegate(cd,queue,ns.NSDictionary{})
cm.InitWithDelegate(cd,queue,nil)
select { } select { }
} }

View File

@ -27,7 +27,7 @@ functions: [ NSMakeRange, dispatch_queue_create ]
enums: [ CB.* ] enums: [ CB.* ]
frameworks: [ Foundation, CoreBluetooth ] frameworks: [ Foundation, CoreBluetooth ]
delegates: delegates:
BleDelegate: CBDelegate:
CBCentralManagerDelegate: CBCentralManagerDelegate:
- centralManagerDidUpdateState - centralManagerDidUpdateState
- centralManagerDidDiscoverPeripheral - centralManagerDidDiscoverPeripheral

View File

@ -27,9 +27,35 @@ func main() {
a2 := a.SubarrayWithRange(ns.NSMakeRange(1,3)) a2 := a.SubarrayWithRange(ns.NSMakeRange(1,3))
fmt.Println("Length(a2) = ",a2.Count()) fmt.Println("Length(a2) = ",a2.Count())
i1 := a.ObjectAtIndex(1).NSString() i1 := a.ObjectAtIndex(1).NSString()
fmt.Println(i1.UTF8String()) fmt.Printf("i1 = %@\n",i1)
a.ObjectEnumerator().ForIn(func(o *ns.Id) bool { fmt.Printf("i1.Ptr() = %p\n",i1.Ptr())
a.ObjectEnumerator().ForIn(func(o ns.Id) bool {
fmt.Println(o.NSString().UTF8String()) fmt.Println(o.NSString().UTF8String())
return true return true
}) })
s1 := ns.NSSetWithObjects(n1,n2)
a = ns.NSMutableArrayWithObjects(n1,s1)
a.ObjectEnumerator().ForIn(func(o ns.Id) bool {
fmt.Printf("%s -- ",o.ClassName().UTF8String())
switch {
case o.IsKindOfClass(ns.NSStringClass()):
fmt.Printf("It's a string\n")
case o.IsKindOfClass(ns.NSSetClass()):
fmt.Printf("It's a set\n")
default:
fmt.Printf("I don't know what it is!\n")
}
return true
})
a2 = ns.NSArrayWithObjects(n1,n2,n3,s1)
a2.ObjectEnumerator().ForIn(func (o ns.Id) bool {
switch {
case o.IsKindOfClass(ns.NSStringClass()):
fmt.Println(o.NSString().UTF8String())
return true // continue enumeration
default:
fmt.Println("Unknown class")
return false // terminate enumeration
}
})
} }

View File

@ -15,6 +15,7 @@ classes:
- NSString - NSString
- NSScanner - NSScanner
- NSFileManager - NSFileManager
- NSObject
functions: [ NSMakeRange ] functions: [ NSMakeRange ]
enums: [ P_ALL, CF.* ] enums: [ P_ALL, CF.* ]
frameworks: [ Foundation ] frameworks: [ Foundation ]

View File

@ -6,6 +6,6 @@ classes:
subclasses: subclasses:
ClassThree: ClassThree:
ClassTwo: ClassTwo:
- hi.* - .*
imports: [ simple.h ] imports: [ simple.h ]
frameworks: [ Foundation ] frameworks: [ Foundation ]

View File

@ -13,12 +13,11 @@ var super map[string]string
//go struct. //go struct.
var wrapped map[string]bool var wrapped map[string]bool
func shouldWrap(gt string) bool { func ShouldWrap(gt string) bool {
return gt != "" && gt[0] == '*' && wrapped[gt[1:]] return wrapped[gt]
} }
//goInterfaces records the names of top level Go interfaces. Pointers to these //goInterfaces records the names of top level Go interfaces.
//are dereferenced to bare interface names.
var goInterfaces map[string]bool var goInterfaces map[string]bool
func IsGoInterface(gt string) bool { func IsGoInterface(gt string) bool {
@ -69,9 +68,9 @@ func SetTypeParam(c, n, t string) {
TypeParameters[c][n] = t TypeParameters[c][n] = t
} }
func AddTypedef(n,t string) { func AddTypedef(n string, tp *Type) {
//fmt.Printf("AddTypedef(): %s -> %s\n",n,t) //fmt.Printf("AddTypedef(): %s -> %s\n",n,t)
typedefs[n] = NewTypeFromString(t,"") typedefs[n] = tp
} }
type Type struct { type Type struct {
@ -189,11 +188,11 @@ func _goType(ct string) string {
ct = strings.Title(ct) ct = strings.Title(ct)
ct = strings.ReplaceAll(ct," ","") ct = strings.ReplaceAll(ct," ","")
ct = strings.ReplaceAll(ct,"Struct","") ct = strings.ReplaceAll(ct,"Struct","")
if len(ct) > 0 && ct[0] == '*' && IsGoInterface(ct[1:]) { if IsGoInterface(ct) {
return ct[1:] return ct
} }
if ct == "Id" { if ct == "Id" {
ct = "*Id" ct = "Id"
} }
if len(ct) > 4 && ct[len(ct)-4:len(ct)] == "Void" { if len(ct) > 4 && ct[len(ct)-4:len(ct)] == "Void" {
ct = ct[:len(ct)-5] + "unsafe.Pointer" ct = ct[:len(ct)-5] + "unsafe.Pointer"
@ -255,10 +254,6 @@ type %s %s
func (t *Type) GoInterfaceDecl() string { func (t *Type) GoInterfaceDecl() string {
ct := t.CType() ct := t.CType()
gt := t.GoType() gt := t.GoType()
if gt[0] == '*' {
gt = gt[1:] // dereference wrapped types
ct = ct[:len(ct)-1]
}
super := Super(ct) super := Super(ct)
if super == "" { if super == "" {
goInterfaces[gt] = true goInterfaces[gt] = true
@ -273,8 +268,12 @@ type %s interface {
} }
return fmt.Sprintf(` return fmt.Sprintf(`
type %s struct { %s } type %s struct { %s }
func (o *%s) Ptr() unsafe.Pointer { return unsafe.Pointer(o) } func (o %s) Ptr() unsafe.Pointer { return o.ptr }
func (o *Id) %s() *%s { return (*%s)(unsafe.Pointer(o)) } func (o Id) %s() %s {
ret := %s{}
ret.ptr = o.ptr
return ret
}
`,gt,super,gt,gt,gt,gt) `,gt,super,gt,gt,gt,gt)
} }
@ -332,11 +331,17 @@ func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type, fun bool)
} }
var ret strings.Builder var ret strings.Builder
rt := rtype.CType() rt := rtype.CType()
if rt != "void" {
rtgt := rtype.GoType() rtgt := rtype.GoType()
if IsGoInterface(rtgt) { if IsGoInterface(rtgt) {
rtgt = "*Id" rtgt = "Id"
} }
sw := ShouldWrap(rtgt) || rtgt == "Id"
if rt != "void" {
if sw {
ret.WriteString(fmt.Sprintf(
`ret := %s{}
ret.ptr = `,rtgt))
} else {
if rtgt == "BOOL" { if rtgt == "BOOL" {
ret.WriteString("return (") ret.WriteString("return (")
rtgt = "bool" rtgt = "bool"
@ -347,12 +352,13 @@ func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type, fun bool)
ret.WriteString("unsafe.Pointer(") ret.WriteString("unsafe.Pointer(")
} }
} }
}
ret.WriteString("C." + name + "(") ret.WriteString("C." + name + "(")
parms := []string{} parms := []string{}
for i := 0; i < len(pnames); i++ { for i := 0; i < len(pnames); i++ {
pn,pt := pnames[i],ptypes[i] pn,pt := pnames[i],ptypes[i]
p := pn p := pn
if (shouldWrap(pt.GoType()) || IsGoInterface(pt.GoType())) && !pt.Variadic { if (ShouldWrap(pt.GoType()) || IsGoInterface(pt.GoType())) && !pt.Variadic {
p = pn + ".Ptr()" p = pn + ".Ptr()"
} else { } else {
switch { switch {
@ -368,7 +374,7 @@ func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type, fun bool)
} }
ret.WriteString(strings.Join(parms,", ")) ret.WriteString(strings.Join(parms,", "))
ret.WriteString(")") ret.WriteString(")")
if rt != "void" { if rt != "void" && !sw {
ret.WriteString(")") ret.WriteString(")")
if rtype.IsPointer() { if rtype.IsPointer() {
ret.WriteString(")") ret.WriteString(")")
@ -377,6 +383,10 @@ func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type, fun bool)
if rt == "BOOL" { if rt == "BOOL" {
ret.WriteString(" != 0") ret.WriteString(" != 0")
} }
if sw {
ret.WriteString(`
return ret`)
}
return ret.String() return ret.String()
} }

View File

@ -34,7 +34,9 @@ type Wrapper struct {
goCode strings.Builder // put Go code here goCode strings.Builder // put Go code here
goExports strings.Builder // put exported Go functions here goExports strings.Builder // put exported Go functions here
goHelpers strings.Builder // put Go helper functions here goHelpers strings.Builder // put Go helper functions here
Processed map[string]bool
ProcessedTypes map[string]bool
ProcessedClassMethods map[string]bool
Vaargs int Vaargs int
} }
@ -47,15 +49,18 @@ func NewWrapper(debug bool) *Wrapper {
NamedEnums: map[string]*Enum{}, NamedEnums: map[string]*Enum{},
AnonEnums: []*Enum{}, AnonEnums: []*Enum{},
Protocols: map[string]*Protocol{}, Protocols: map[string]*Protocol{},
Processed: map[string]bool{}, ProcessedTypes: map[string]bool{},
ProcessedClassMethods: map[string]bool{},
Vaargs: 16, Vaargs: 16,
} }
ret.cgoFlags.WriteString(fmt.Sprintf(`/* ret.cgoFlags.WriteString(fmt.Sprintf(`/*
#cgo CFLAGS: -x objective-c #cgo CFLAGS: -x objective-c
`)) `))
ret.goTypes.WriteString(` ret.goTypes.WriteString(`
type Id struct { } type Id struct {
func (o *Id) Ptr() unsafe.Pointer { return unsafe.Pointer(o) } ptr unsafe.Pointer
}
func (o Id) Ptr() unsafe.Pointer { return o.ptr }
`) `)
return ret return ret
} }
@ -121,8 +126,10 @@ type Enum struct {
type Protocol struct { type Protocol struct {
Name, GoName string Name, GoName string
Methods map[string]*Method ClassMethods map[string]*Method
Polymorphic map[string]int InstanceMethods map[string]*Method
CPolymorphic map[string]int // polymorphic class methods
IPolymorphic map[string]int // polymorphic instance methods
} }
//isVoid() returns true if the method has no return value. //isVoid() returns true if the method has no return value.
@ -149,7 +156,8 @@ func (w Wrapper) cparamlist(m *Method) (string,string,string) {
} }
for _,p := range m.Parameters { for _,p := range m.Parameters {
var tp string var tp string
if p.Type.IsPointer() || p.Type.Variadic { wp := types.ShouldWrap(p.Type.GoType())
if wp || p.Type.IsPointer() || p.Type.Variadic {
tp = "void*" tp = "void*"
} else { } else {
tp = p.Type.CType() tp = p.Type.CType()
@ -231,7 +239,10 @@ func (w *Wrapper) gpntp(m *Method) ([]string,[]*types.Type,string) {
type Interface struct { type Interface struct {
Name, GoName string Name, GoName string
Properties map[string]*Property Properties map[string]*Property
Methods map[string]*Method ClassMethods map[string]*Method
InstanceMethods map[string]*Method
Protocols []string // Protocols impelemented by this Interface
ProcessedInstanceMethods map[string]bool
} }
func (w *Wrapper) AddInterface(n *ast.ObjCInterfaceDecl) { func (w *Wrapper) AddInterface(n *ast.ObjCInterfaceDecl) {
@ -292,14 +303,17 @@ func (w *Wrapper) AddFunction(n *ast.FunctionDecl) {
func (w *Wrapper) AddProtocol(n *ast.ObjCProtocolDecl) { func (w *Wrapper) AddProtocol(n *ast.ObjCProtocolDecl) {
p := w.Protocols[n.Name] p := w.Protocols[n.Name]
if p == nil { if p == nil {
fmt.Printf("Adding protocol %s\n",n.Name) //fmt.Printf("Adding protocol %s\n",n.Name)
p = &Protocol{ p = &Protocol{
Name: n.Name, Name: n.Name,
GoName: types.NewTypeFromString(n.Name,n.Name).GoType(), GoName: types.NewTypeFromString(n.Name,n.Name).GoType(),
Methods: map[string]*Method{}, ClassMethods: map[string]*Method{},
Polymorphic: map[string]int{}, InstanceMethods: map[string]*Method{},
CPolymorphic: map[string]int{},
IPolymorphic: map[string]int{},
} }
} }
//fmt.Printf("Protocol %s\n",p.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:
@ -310,22 +324,32 @@ func (w *Wrapper) AddProtocol(n *ast.ObjCProtocolDecl) {
GoClass: p.GoName, GoClass: p.GoName,
ClassMethod: x.ClassMethod, ClassMethod: x.ClassMethod,
} }
//fmt.Printf(" -- Method %s\n",m.Name)
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 {
var mth map[string]*Method
var poly map[string]int
if m.ClassMethod {
mth = p.ClassMethods
poly = p.CPolymorphic
} else {
mth = p.InstanceMethods
poly = p.IPolymorphic
}
pname := strings.Title(m.Name) pname := strings.Title(m.Name)
if x := p.Polymorphic[m.Name]; x != 0 { if x := poly[m.Name]; x != 0 && len(m.Parameters) > 1 {
p.Polymorphic[m.Name] = x + 1 poly[m.Name] = x + 1
pname = pname + strings.Title(m.Parameters[1].Pname) pname = pname + strings.Title(m.Parameters[1].Pname)
if m2 := p.Methods[pname]; m2 != nil { if m2 := mth[pname]; m2 != nil {
pname2 := pname + strings.Title(m2.Parameters[1].Pname) pname2 := pname + strings.Title(m2.Parameters[1].Pname)
p.Methods[pname2] = m2 mth[pname2] = m2
delete(p.Methods,m.Name) delete(mth,m.Name)
} }
} else { } else {
p.Polymorphic[m.Name] = 1 poly[m.Name] = 1
} }
p.Methods[pname] = m mth[pname] = m
} }
} }
} }
@ -382,6 +406,7 @@ func (w *Wrapper) AddEnum(n *ast.EnumDecl,rs []string) {
} }
} }
//Add an Interface
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
@ -392,8 +417,19 @@ func (w *Wrapper) add(name string, ns []ast.Node) {
Name: name, Name: name,
GoName: goname, GoName: goname,
Properties: map[string]*Property{}, Properties: map[string]*Property{},
Methods: map[string]*Method{}, InstanceMethods: map[string]*Method{},
Protocols: []string{},
ProcessedInstanceMethods: map[string]bool{},
} }
m := &Method{
Name: "class",
Class: i.Name,
GoClass: i.Name,
Type: types.NewTypeFromString("Class",i.Name),
ClassMethod: true,
Parameters: []*Parameter{},
}
i.ClassMethods = map[string]*Method{"class": m}
} }
var avail bool var avail bool
for _,c := range ns { for _,c := range ns {
@ -423,10 +459,15 @@ 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[strings.Title(m.Name)] = m if m.ClassMethod {
i.ClassMethods[strings.Title(m.Name)] = m
} else {
i.InstanceMethods[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)
i.Protocols = append(i.Protocols,x.Name)
case *ast.ObjCInterface: case *ast.ObjCInterface:
if x.Super { if x.Super {
//fmt.Printf("ast.ObjCInterface: %s inherits from %s\n",name,x.Name) //fmt.Printf("ast.ObjCInterface: %s inherits from %s\n",name,x.Name)
@ -447,10 +488,7 @@ func (w *Wrapper) add(name string, ns []ast.Node) {
if sup,ok := w.Interfaces[s]; !ok { if sup,ok := w.Interfaces[s]; !ok {
return return
} else { } else {
for _,m := range sup.Methods { for _,m := range sup.ClassMethods {
if !m.ClassMethod {
continue
}
m2 := &Method{ m2 := &Method{
Name: m.Name, Name: m.Name,
Class: i.Name, Class: i.Name,
@ -467,7 +505,7 @@ func (w *Wrapper) add(name string, ns []ast.Node) {
} }
m2.Parameters = append(m2.Parameters,p2) m2.Parameters = append(m2.Parameters,p2)
} }
i.Methods[strings.Title(m.Name)] = m2 i.ClassMethods[strings.Title(m.Name)] = m2
} }
} }
supmethods(i,types.Super(s)) supmethods(i,types.Super(s))
@ -552,6 +590,21 @@ func (w *Wrapper) GetParms(n ast.Node,class string) ([]*Parameter,bool) {
return ret, true return ret, true
} }
func (w *Wrapper) AddTypedef(n,t string) {
tp := types.NewTypeFromString(t,"")
gt := tp.GoType()
//fmt.Printf("Typedef %s -> %s\n",n,t)
if types.ShouldWrap(gt) {
//fmt.Printf(" should wrap\n")
//fmt.Printf(" processing type for %s (%s)\n",n,gt)
types.Wrap(n)
types.SetSuper(n,gt)
w._processType(tp,"*" + n)
} else {
types.AddTypedef(n,tp)
}
}
func (w *Wrapper) processTypes(tps []*types.Type) { func (w *Wrapper) processTypes(tps []*types.Type) {
for _,tp := range tps { for _,tp := range tps {
w.processType(tp) w.processType(tp)
@ -561,6 +614,11 @@ func (w *Wrapper) processTypes(tps []*types.Type) {
func (w *Wrapper) processType(tp *types.Type) { func (w *Wrapper) processType(tp *types.Type) {
bt := tp.BaseType() bt := tp.BaseType()
gt := bt.GoType() gt := bt.GoType()
w._processType(bt,gt)
}
func (w *Wrapper) _processType(bt *types.Type, gt string) {
//fmt.Printf("processType: gt = %s bt = %s\n",gt,bt)
if gt == "" { if gt == "" {
return return
} }
@ -568,11 +626,8 @@ func (w *Wrapper) processType(tp *types.Type) {
w.processType(bt.PointsTo()) w.processType(bt.PointsTo())
return return
} }
if w.Processed[gt] { return } if w.ProcessedTypes[gt] { return }
w.Processed[gt] = true w.ProcessedTypes[gt] = true
if gt == "NSObject" {
w.ObjectHelpers()
}
if gt == "Char" { if gt == "Char" {
w.CharHelpers() w.CharHelpers()
} }
@ -597,41 +652,13 @@ func (w *Wrapper) processType(tp *types.Type) {
w.goTypes.WriteString(bt.GoTypeDecl()) w.goTypes.WriteString(bt.GoTypeDecl())
} }
func (w *Wrapper) ObjectHelpers() {
w.goHelpers.WriteString(`
func (o *Id) Retain() {
C.retain(unsafe.Pointer(o))
}
func (o *Id) Release() {
C.release(unsafe.Pointer(o))
}
func (o *Id) Autorelease() {
C.autorelease(unsafe.Pointer(o))
}
`)
w.cCode.WriteString(`
void
retain(void* obj) {
[(NSObject*)obj retain];
}
void
release(void* obj) {
[(NSObject*)obj release];
}
void
autorelease(void* obj) {
[(NSObject*)obj autorelease];
}
`)
}
func (w *Wrapper) CharHelpers() { func (w *Wrapper) CharHelpers() {
w.goHelpers.WriteString(` w.goHelpers.WriteString(`
func CharWithGoString(s string) *Char { func CharWithGoString(s string) *Char {
return (*Char)(unsafe.Pointer(C.CString(s))) return (*Char)(unsafe.Pointer(C.CString(s)))
} }
func CharFromBytes(b []byte) *Char { func CharWithBytes(b []byte) *Char {
return (*Char)(unsafe.Pointer(C.CString(string(b)))) return (*Char)(unsafe.Pointer(C.CString(string(b))))
} }
@ -643,8 +670,8 @@ func (c *Char) String() string {
func (w *Wrapper) EnumeratorHelpers() { func (w *Wrapper) EnumeratorHelpers() {
w.goHelpers.WriteString(` w.goHelpers.WriteString(`
func (e *NSEnumerator) ForIn(f func(*Id) bool) { func (e NSEnumerator) ForIn(f func(Id) bool) {
for o := e.NextObject(); o != nil; o = e.NextObject() { for o := e.NextObject(); o.Ptr() != nil; o = e.NextObject() {
if !f(o) { break } if !f(o) { break }
} }
} }
@ -660,8 +687,10 @@ NSAutoreleasePool_init(void* o) {
} }
`) `)
w.goHelpers.WriteString(` w.goHelpers.WriteString(`
func (o *NSAutoreleasePool) Init() *NSAutoreleasePool { func (o NSAutoreleasePool) Init() NSAutoreleasePool {
return (*NSAutoreleasePool)(unsafe.Pointer(C.NSAutoreleasePool_init(o.Ptr()))) ret := NSAutoreleasePool{}
ret.ptr = C.NSAutoreleasePool_init(o.Ptr())
return ret
} }
func Autoreleasepool(f func()) { func Autoreleasepool(f func()) {
@ -690,6 +719,23 @@ func (w *Wrapper) ProcessMethod(m *Method) {
w._processMethod(m,false) w._processMethod(m,false)
} }
func (w *Wrapper) ProcessMethodForClass(m *Method, class string) {
goclass := strings.Title(types.NewTypeFromString(class,class).GoType())
m2 := &Method{
Name: m.Name, Class: class, GoClass: goclass,
Type: m.Type.CloneToClass(class),
ClassMethod: m.ClassMethod,
Parameters: make([]*Parameter,len(m.Parameters)),
}
for i,p := range m.Parameters {
m2.Parameters[i] = &Parameter{
Pname: p.Pname, Vname: p.Vname,
Type: p.Type.CloneToClass(class),
}
}
w._processMethod(m2,false)
}
func (w *Wrapper) ProcessFunction(m *Method) { func (w *Wrapper) ProcessFunction(m *Method) {
if m.Type.Node.IsId() { if m.Type.Node.IsId() {
//do not wrap functions that return ID because of CGo struct size bug //do not wrap functions that return ID because of CGo struct size bug
@ -712,15 +758,16 @@ func (w *Wrapper) _processMethod(m *Method,fun bool) {
gname = strings.Title(gname) gname = strings.Title(gname)
gname = strings.ReplaceAll(gname," ","") gname = strings.ReplaceAll(gname," ","")
receiver := "" receiver := ""
cname := m.Name
switch { switch {
case !m.ClassMethod: case !m.ClassMethod:
if types.IsGoInterface(m.GoClass) { if types.IsGoInterface(m.GoClass) {
receiver = "(o *Id) " receiver = "(o Id) "
} else { } else {
receiver = "(o *" + m.GoClass + ") " receiver = "(o " + m.GoClass + ") "
} }
case m.Type.GoType() != "*" + m.GoClass: //Disambiguate instance methods with same name as a class method
gname = m.GoClass + gname cname = "inst_" + cname
default: default:
//Shorten class method names //Shorten class method names
lens1 := len(m.Class) lens1 := len(m.Class)
@ -735,12 +782,11 @@ func (w *Wrapper) _processMethod(m *Method,fun bool) {
gname = m.GoClass + gname[lens1-i:] gname = m.GoClass + gname[lens1-i:]
} }
} }
cname := m.Name
if m.Class != "" { if m.Class != "" {
cname = m.Class + "_" + cname cname = m.Class + "_" + cname
} }
var cmtype string var cmtype string
if m.Type.IsPointer() { if m.Type.IsPointer() || types.ShouldWrap(m.Type.GoType()) {
// work around cgo bugs with struct size calculation // work around cgo bugs with struct size calculation
cmtype = "void*" cmtype = "void*"
if x := m.Type.Node.Qualifiers(); x != "" { if x := m.Type.Node.Qualifiers(); x != "" {
@ -758,7 +804,7 @@ func (w *Wrapper) _processMethod(m *Method,fun bool) {
grtype = "" grtype = ""
} }
if types.IsGoInterface(grtype) { if types.IsGoInterface(grtype) {
grtype = "*Id" grtype = "Id"
} }
if grtype == "BOOL" { // convert objective-c bools to Go bools if grtype == "BOOL" { // convert objective-c bools to Go bools
grtype = "bool" grtype = "bool"
@ -766,6 +812,23 @@ func (w *Wrapper) _processMethod(m *Method,fun bool) {
if gname == grtype { // avoid name conflicts between methods and types if gname == grtype { // avoid name conflicts between methods and types
gname = "Get" + gname gname = "Get" + gname
} }
if m.ClassMethod {
if w.ProcessedClassMethods[gname] {
return
}
w.ProcessedClassMethods[gname] = true
} else {
i, ok := w.Interfaces[m.Class]
if !ok {
fmt.Printf("Can't find interface %s for method %s\n",m.Class,m.Name)
os.Exit(-1)
}
if i.ProcessedInstanceMethods[gname] {
return
}
i.ProcessedInstanceMethods[gname] = true
}
w.goCode.WriteString(fmt.Sprintf(` w.goCode.WriteString(fmt.Sprintf(`
func %s%s(%s) %s { func %s%s(%s) %s {
`,receiver,gname,gplist,grtype)) `,receiver,gname,gplist,grtype))
@ -826,7 +889,7 @@ func %s%s(%s) %s {
gt := tps[i].GoType() gt := tps[i].GoType()
//fmt.Printf(" %s\n",gt) //fmt.Printf(" %s\n",gt)
ns2 := ns[i] ns2 := ns[i]
if gt == "*NSString" { if gt == "NSString" {
gt = "string" gt = "string"
ns[i] = gStringToNsstring(ns[i]) ns[i] = gStringToNsstring(ns[i])
} }
@ -864,20 +927,20 @@ func (w *Wrapper) ProcessEnum(e *Enum) {
ctp = e.Type.CGoType() ctp = e.Type.CGoType()
} }
if e.Type != nil { if e.Type != nil {
if !w.Processed[gtp] { if !w.ProcessedTypes[gtp] {
w.goTypes.WriteString(fmt.Sprintf(` w.goTypes.WriteString(fmt.Sprintf(`
type %s %s type %s %s
`,gtp,ctp)) `,gtp,ctp))
w.Processed[gtp] = true w.ProcessedTypes[gtp] = true
} }
} }
gtp = gtp + " " gtp = gtp + " "
//fmt.Printf(" gtp = %s; ctp = %s\n",gtp,ctp) //fmt.Printf(" gtp = %s; ctp = %s\n",gtp,ctp)
for _,c := range e.Constants { for _,c := range e.Constants {
w.goConst.WriteString(fmt.Sprintf(` w.goConst.WriteString(fmt.Sprintf(`const %s %s= C.%s
const %s %s= C.%s
`,c,gtp,c)) `,c,gtp,c))
} }
w.goConst.WriteString("\n")
} }
func (w *Wrapper) ProcessSubclass(sname string, ps map[string][]string) { func (w *Wrapper) ProcessSubclass(sname string, ps map[string][]string) {
@ -924,7 +987,7 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool)
os.Exit(-1) os.Exit(-1)
} }
//fmt.Printf(" subclass for %s\n",pname) //fmt.Printf(" subclass for %s\n",pname)
ms = interf.Methods ms = interf.InstanceMethods
supr = interf.GoName supr = interf.GoName
} else { } else {
proto := w.Protocols[pname] proto := w.Protocols[pname]
@ -933,7 +996,7 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool)
os.Exit(-1) os.Exit(-1)
} }
//fmt.Printf(" proto %s\n",pname) //fmt.Printf(" proto %s\n",pname)
ms = proto.Methods ms = proto.InstanceMethods
supr = "Id" supr = "Id"
} }
for gname,m := range ms { for gname,m := range ms {
@ -1032,16 +1095,6 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool)
} }
crtypes[i] = m.Type.CTypeAttrib() crtypes[i] = m.Type.CTypeAttrib()
if m.Type.IsPointer() { 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" cgtypes[i] = "unsafe.Pointer"
} else { } else {
crtypes[i] = m.Type.CTypeAttrib() crtypes[i] = m.Type.CTypeAttrib()
@ -1106,7 +1159,7 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool)
sfundecls[i] = fmt.Sprintf(` sfundecls[i] = fmt.Sprintf(`
%s %s
{ {
%s[%s super_%s]; %s[(%s*)self super_%s];
} }
`,sfp,ret,gname,strings.Join(vpnames[i]," ")) `,sfp,ret,gname,strings.Join(vpnames[i]," "))
} }
@ -1137,14 +1190,15 @@ void*
gotypes.WriteString(fmt.Sprintf(` gotypes.WriteString(fmt.Sprintf(`
type %s struct { %s } type %s struct { %s }
func (o *%s) Ptr() unsafe.Pointer { return unsafe.Pointer(o) } func (o %s) Ptr() unsafe.Pointer { return o.ptr }
func (o *Id) %s() *%s { return (*%s)(unsafe.Pointer(o)) } `,gname,supr,gname))
`,gname,supr,gname,gname,gname,gname))
//5. Go constructor //5. Go constructor
gocode.WriteString(fmt.Sprintf(` gocode.WriteString(fmt.Sprintf(`
func %sAlloc() *%s { func %sAlloc() %s {
return (*%s)(unsafe.Pointer(C.%sAlloc())) ret := %s{}
ret.ptr = unsafe.Pointer(C.%sAlloc())
return ret
} }
`,gname,gname,gname,dname)) `,gname,gname,gname,dname))
@ -1195,6 +1249,7 @@ func (d *%s) %sCallback(f func(%s)%s) {
//3. Go exported callback function wrappers //3. Go exported callback function wrappers
earglist := []string{"o unsafe.Pointer"} earglist := []string{"o unsafe.Pointer"}
garglist := []string{} garglist := []string{}
gargconv := []string{}
if sub { if sub {
garglist = []string{"super"} garglist = []string{"super"}
} }
@ -1207,11 +1262,18 @@ func (d *%s) %sCallback(f func(%s)%s) {
gt2 = gtypes[i][j-1] gt2 = gtypes[i][j-1]
} }
if types.IsGoInterface(gt2) { if types.IsGoInterface(gt2) {
gt2 = "*Id" gt2 = "Id"
} }
if types.ShouldWrap(gt2) || gt2 == "Id" {
garglist = append(garglist,fmt.Sprintf(
`a%d`,j))
gargconv = append(gargconv,fmt.Sprintf(
` a%d := %s{}; a%d.ptr = %s`,j,gt2,j,vnames[i][j]))
} else {
garglist = append(garglist,fmt.Sprintf( garglist = append(garglist,fmt.Sprintf(
`(%s)(%s)`,gt2,vnames[i][j])) `(%s)(%s)`,gt2,vnames[i][j]))
} }
}
retdecl := "" retdecl := ""
retname := "" retname := ""
retn := "" retn := ""
@ -1243,14 +1305,19 @@ func (d *%s) %sCallback(f func(%s)%s) {
} }
`,gname,gname,strings.Join(sdispentries,",\n")) `,gname,gname,strings.Join(sdispentries,",\n"))
} }
if len(gargconv) > 0 {
retn = "\n " + retn
} else {
retn = " " + retn
}
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[o].%s %scb := %sLookup[o].%s
if cb == nil { return%s } if cb == nil { return%s }
%s%scb(%s)%s %s%s%scb(%s)%s
} }
`,gname,gnames[i],gname,gnames[i],strings.Join(earglist,", "),crtype,retdecl,gname,gnames[i],retname,sper,retn,strings.Join(garglist,", "),retnparen)) `,gname,gnames[i],gname,gnames[i],strings.Join(earglist,", "),crtype,retdecl,gname,gnames[i],retname,sper,strings.Join(gargconv,"\n"),retn,strings.Join(garglist,", "),retnparen))
//4. Go wrapper functions for superclass methods //4. Go wrapper functions for superclass methods
if !sub { continue } // for subclasses only if !sub { continue } // for subclasses only
grtype := m.Type.GoType() grtype := m.Type.GoType()
@ -1258,7 +1325,7 @@ func %s%s(%s)%s {
grtype = "" grtype = ""
} }
if types.IsGoInterface(grtype) { if types.IsGoInterface(grtype) {
grtype = "*Id" grtype = "Id"
} }
if grtype == "BOOL" { if grtype == "BOOL" {
grtype = "bool" grtype = "bool"
@ -1325,12 +1392,14 @@ func (w *Wrapper) Wrap(toproc []string) {
if types.IsGoInterface(i.GoName) { if types.IsGoInterface(i.GoName) {
gname = "Id" gname = "Id"
} }
fmt.Printf("Interface %s: %d properties, %d methods\n", fmt.Printf("Interface %s: %d properties, %d class methods, %d instance methods\n",
i.Name, len(i.Properties), len(i.Methods)) i.Name, len(i.Properties), len(i.ClassMethods), len(i.InstanceMethods))
w.goCode.WriteString(fmt.Sprintf(` w.goCode.WriteString(fmt.Sprintf(`
func %sAlloc() *%s { func %sAlloc() %s {
return (*%s)(unsafe.Pointer(C.%sAlloc())) ret := %s{}
ret.ptr = unsafe.Pointer(C.%sAlloc())
return ret
} }
`,i.GoName,gname,gname,i.Name)) `,i.GoName,gname,gname,i.Name))
@ -1358,9 +1427,25 @@ void*
} }
} }
//FIXME: sort methods //FIXME: sort methods
for _,m := range i.Methods { for _,m := range i.ClassMethods {
w.ProcessMethod(m) w.ProcessMethod(m)
}
for _,m := range i.InstanceMethods {
w.ProcessMethod(m)
}
// add methods for Protocols that this interface implements
for _,p := range i.Protocols {
prot,ok := w.Protocols[p]
if !ok {
fmt.Printf("Failed to find protocol %s for interface %s\n",p,i.Name)
os.Exit(-1)
}
for _,m := range prot.ClassMethods {
w.ProcessMethodForClass(m,i.Name)
}
for _,m := range prot.InstanceMethods {
w.ProcessMethodForClass(m,i.Name)
}
} }
} }
for _,m := range w.Functions { for _,m := range w.Functions {