Convert all Go wrapped objects to pointers so the Go GC can track
all of the Objective-C pointers. Still working on bug with typedefs to wrapped types.
This commit is contained in:
parent
b0139b9aa8
commit
ac9eecafd8
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -13,3 +13,4 @@ examples/memory/memory
|
||||||
examples/memory/ns
|
examples/memory/ns
|
||||||
examples/gc/gc
|
examples/gc/gc
|
||||||
examples/gc/ns
|
examples/gc/ns
|
||||||
|
ns-old
|
||||||
|
|
|
@ -20,8 +20,12 @@ func pb2() {
|
||||||
a.Terminate(a)
|
a.Terminate(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
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 n = %p\n",n)
|
||||||
|
fmt.Printf("Notification n.Ptr() = %p\n",n.Ptr())
|
||||||
|
fmt.Printf("Notification n.Name() = %p\n",n.Name())
|
||||||
|
fmt.Printf("Notification n.Name().Ptr() = %p\n",n.Name().Ptr())
|
||||||
fmt.Printf("Notification: %s\n", n.Name().UTF8String())
|
fmt.Printf("Notification: %s\n", n.Name().UTF8String())
|
||||||
//Set up an NSWindow
|
//Set up an NSWindow
|
||||||
win = ns.NSWindowAlloc().InitWithContentRectStyleMask(
|
win = ns.NSWindowAlloc().InitWithContentRectStyleMask(
|
||||||
|
@ -83,40 +87,39 @@ func didFinishLaunching(n ns.NSNotification) {
|
||||||
|
|
||||||
cv := win.ContentView()
|
cv := win.ContentView()
|
||||||
|
|
||||||
cv.AddSubview(b1.NSView)
|
cv.AddSubview(&b1.NSView)
|
||||||
cv.AddSubview(b2.NSView)
|
cv.AddSubview(&b2.NSView)
|
||||||
|
|
||||||
viewmap := ns.NSDictionaryWithObjectsForKeys(
|
viewmap := ns.NSDictionaryWithObjectsForKeys(
|
||||||
ns.NSArrayWithObjects(b1, b2),
|
ns.NSArrayWithObjects(b1, b2),
|
||||||
ns.NSArrayWithObjects(nst("b1"), nst("b2")))
|
ns.NSArrayWithObjects(nst("b1"), nst("b2")))
|
||||||
|
|
||||||
cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
|
cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
|
||||||
nst("V:|-[b1]"), 0, ns.NSDictionary{}, viewmap))
|
nst("V:|-[b1]"), 0, nil, viewmap))
|
||||||
cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
|
cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
|
||||||
nst("H:|-[b1]"), 0, ns.NSDictionary{}, viewmap))
|
nst("H:|-[b1]"), 0, nil, viewmap))
|
||||||
cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
|
cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
|
||||||
nst("H:[b1]-[b2]"), ns.NSLayoutFormatAlignAllBaseline,
|
nst("H:[b1]-[b2]"), ns.NSLayoutFormatAlignAllBaseline, nil, viewmap))
|
||||||
ns.NSDictionary{}, viewmap))
|
|
||||||
|
|
||||||
a.ActivateIgnoringOtherApps(1)
|
a.ActivateIgnoringOtherApps(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func shouldTerminateAfterLastWindowClosed(s ns.NSApplication) ns.BOOL {
|
func shouldTerminateAfterLastWindowClosed(s *ns.NSApplication) ns.BOOL {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func willTerminate(n ns.NSNotification) {
|
func willTerminate(n *ns.NSNotification) {
|
||||||
fmt.Println("Go: will terminate")
|
fmt.Println("Go: will terminate")
|
||||||
}
|
}
|
||||||
|
|
||||||
func didBecomeActive(n ns.NSNotification) {
|
func didBecomeActive(n *ns.NSNotification) {
|
||||||
fmt.Println("Go: did become active")
|
fmt.Println("Go: did become active")
|
||||||
fmt.Printf("Notification: %s\n", n.Name().UTF8String())
|
fmt.Printf("Notification: %s\n", n.Name().UTF8String())
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
a ns.NSApplication
|
a *ns.NSApplication
|
||||||
win ns.NSWindow
|
win *ns.NSWindow
|
||||||
)
|
)
|
||||||
|
|
||||||
func app() {
|
func app() {
|
||||||
|
|
|
@ -38,21 +38,21 @@ func main() {
|
||||||
fmt.Printf("i1 = %@\n", i1)
|
fmt.Printf("i1 = %@\n", i1)
|
||||||
fmt.Printf("i1.Ptr() = %p\n", i1.Ptr())
|
fmt.Printf("i1.Ptr() = %p\n", i1.Ptr())
|
||||||
fmt.Printf("\nNSArray.ObjectEnumerator().ForIn():\n")
|
fmt.Printf("\nNSArray.ObjectEnumerator().ForIn():\n")
|
||||||
a.ObjectEnumerator().ForIn(func(o ns.Id) bool {
|
a.ObjectEnumerator().ForIn(func(o *ns.Id) bool {
|
||||||
fmt.Println(o.NSString())
|
fmt.Println(o.NSString())
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
fmt.Printf("\nNSSetWithObjectsCount():\n")
|
fmt.Printf("\nNSSetWithObjectsCount():\n")
|
||||||
s1 := ns.NSSetWithObjectsCount(&[]ns.Id{n1.Id, n2.Id}, 2)
|
s1 := ns.NSSetWithObjectsCount(&[]*ns.Id{&n1.Id, &n2.Id}, 2)
|
||||||
fmt.Printf("\nNSSet.ObjectEnumerator().ForIn():\n")
|
fmt.Printf("\nNSSet.ObjectEnumerator().ForIn():\n")
|
||||||
s1.ObjectEnumerator().ForIn(func(o ns.Id) bool {
|
s1.ObjectEnumerator().ForIn(func(o *ns.Id) bool {
|
||||||
fmt.Println(o.NSString())
|
fmt.Println(o.NSString())
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
fmt.Printf("\nNSMutableArrayWithObjects()\n")
|
fmt.Printf("\nNSMutableArrayWithObjects()\n")
|
||||||
a = ns.NSMutableArrayWithObjects(n1, s1)
|
a = ns.NSMutableArrayWithObjects(n1, s1)
|
||||||
fmt.Printf("\nNSArray.ObjectEnumerator().ForIn():\n")
|
fmt.Printf("\nNSArray.ObjectEnumerator().ForIn():\n")
|
||||||
a.ObjectEnumerator().ForIn(func(o ns.Id) bool {
|
a.ObjectEnumerator().ForIn(func(o *ns.Id) bool {
|
||||||
fmt.Printf("%s -- ", o.ClassName().UTF8String())
|
fmt.Printf("%s -- ", o.ClassName().UTF8String())
|
||||||
switch {
|
switch {
|
||||||
case o.IsKindOfClass(ns.NSStringClass()):
|
case o.IsKindOfClass(ns.NSStringClass()):
|
||||||
|
@ -67,7 +67,7 @@ func main() {
|
||||||
fmt.Printf("\nNSArrayWithObjects()\n")
|
fmt.Printf("\nNSArrayWithObjects()\n")
|
||||||
a2 = ns.NSArrayWithObjects(n1, n2, n3, s1)
|
a2 = ns.NSArrayWithObjects(n1, n2, n3, s1)
|
||||||
fmt.Printf("\nNSArray.ObjectEnumerator().ForIn():\n")
|
fmt.Printf("\nNSArray.ObjectEnumerator().ForIn():\n")
|
||||||
a2.ObjectEnumerator().ForIn(func(o ns.Id) bool {
|
a2.ObjectEnumerator().ForIn(func(o *ns.Id) bool {
|
||||||
switch {
|
switch {
|
||||||
case o.IsKindOfClass(ns.NSStringClass()):
|
case o.IsKindOfClass(ns.NSStringClass()):
|
||||||
fmt.Println(o.NSString().UTF8String())
|
fmt.Println(o.NSString().UTF8String())
|
||||||
|
@ -84,9 +84,9 @@ func main() {
|
||||||
ns.NSArrayWithObjects(nst("obj1"), nst("obj2")),
|
ns.NSArrayWithObjects(nst("obj1"), nst("obj2")),
|
||||||
ns.NSArrayWithObjects(nst("key1"), nst("key2")),
|
ns.NSArrayWithObjects(nst("key1"), nst("key2")),
|
||||||
)
|
)
|
||||||
os := make([]ns.Id, 0, 5)
|
os := make([]*ns.Id, 0, 5)
|
||||||
fmt.Printf("Length of os is %d\n", len(os))
|
fmt.Printf("Length of os is %d\n", len(os))
|
||||||
ks := make([]ns.Id, 0, 5)
|
ks := make([]*ns.Id, 0, 5)
|
||||||
fmt.Printf("\nGetObjects()\n")
|
fmt.Printf("\nGetObjects()\n")
|
||||||
d.GetObjects(&os, &ks, 4)
|
d.GetObjects(&os, &ks, 4)
|
||||||
fmt.Printf("Length of os is now %d\n", len(os))
|
fmt.Printf("Length of os is now %d\n", len(os))
|
||||||
|
@ -94,7 +94,7 @@ func main() {
|
||||||
fmt.Printf("-- %s -> %s\n", k.NSString(), os[i].NSString())
|
fmt.Printf("-- %s -> %s\n", k.NSString(), os[i].NSString())
|
||||||
}
|
}
|
||||||
fmt.Printf("\nNSStringWithContentsOfURLEncoding()\n")
|
fmt.Printf("\nNSStringWithContentsOfURLEncoding()\n")
|
||||||
err := make([]ns.NSError, 1)
|
err := make([]*ns.NSError, 1)
|
||||||
n1 = ns.NSStringWithContentsOfURLEncoding(ns.NSURLWithGoString("htttypo://example.com"), 0, &err)
|
n1 = ns.NSStringWithContentsOfURLEncoding(ns.NSURLWithGoString("htttypo://example.com"), 0, &err)
|
||||||
fmt.Printf("err: %s\n", err[0].LocalizedDescription())
|
fmt.Printf("err: %s\n", err[0].LocalizedDescription())
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ func releaseX(x int) func (ns.MyClassSupermethods) {
|
||||||
func memtest1() {
|
func memtest1() {
|
||||||
fmt.Println("memtest1 started")
|
fmt.Println("memtest1 started")
|
||||||
for {
|
for {
|
||||||
arr := make([]ns.MyClass,1000)
|
arr := make([]*ns.MyClass,1000)
|
||||||
for i := 0; i < 1000; i++ {
|
for i := 0; i < 1000; i++ {
|
||||||
// Alloc methods set a finalizer that causes the Go GC to
|
// Alloc methods set a finalizer that causes the Go GC to
|
||||||
// Release these objects.
|
// Release these objects.
|
||||||
|
@ -27,8 +27,6 @@ func memtest1() {
|
||||||
|
|
||||||
// You can still manually retain objects, but that will cause
|
// You can still manually retain objects, but that will cause
|
||||||
// them to stick around after their Go pointers are collected.
|
// them to stick around after their Go pointers are collected.
|
||||||
// This may be necessary if you are adding objects to an
|
|
||||||
// Objective-C collection?
|
|
||||||
//arr[i].Retain() // uncomment for leak
|
//arr[i].Retain() // uncomment for leak
|
||||||
}
|
}
|
||||||
// Manually run the Go GC at every loop iteration. May not be needed
|
// Manually run the Go GC at every loop iteration. May not be needed
|
||||||
|
@ -41,24 +39,31 @@ func memtest1() {
|
||||||
|
|
||||||
func memtest2() {
|
func memtest2() {
|
||||||
fmt.Println("memtest2 started")
|
fmt.Println("memtest2 started")
|
||||||
|
i := 0
|
||||||
for {
|
for {
|
||||||
o1 := ns.NSStringAlloc().InitWithGoString("one string")
|
o1 := ns.NSStringAlloc().InitWithGoString(fmt.Sprintf("two string %d",i))
|
||||||
|
o2 := ns.NSStringWithGoString(fmt.Sprintf("two string %d",i))
|
||||||
|
|
||||||
// NSWrap runs object constructors inside an @autoreleasepool block,
|
// NSWrap runs object constructors inside an @autoreleasepool block,
|
||||||
// and then calls "retain" on them before returning to Go. A Go
|
// and then calls "retain" on them before returning to Go. A Go
|
||||||
// finalizer is set allowing the Go GC to call Release().
|
// finalizer is set allowing the Go GC to call Release().
|
||||||
|
|
||||||
o2 := ns.NSStringWithGoString("two string") // does not leak
|
o3 := ns.NSStringWithString(o1)
|
||||||
|
o4 := ns.NSStringAlloc()
|
||||||
|
_ = o4
|
||||||
|
|
||||||
arr := ns.NSArrayAlloc().InitWithObjects(o1,o2)
|
//arr := ns.NSArrayAlloc().InitWithObjects(o1,o1)
|
||||||
|
arr := ns.NSArrayWithObjects(o1,o2,o3,o4)
|
||||||
_ = arr
|
_ = arr
|
||||||
|
|
||||||
|
//o1.Release()
|
||||||
|
//o1.Release()
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
time.Sleep(time.Second/50)
|
time.Sleep(time.Second/50)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addStr(arr ns.NSMutableArray) {
|
func addStr(arr *ns.NSMutableArray) {
|
||||||
s1 := ns.NSStringAlloc().InitWithGoString("a string")
|
s1 := ns.NSStringAlloc().InitWithGoString("a string")
|
||||||
arr.AddObject(s1)
|
arr.AddObject(s1)
|
||||||
|
|
||||||
|
@ -86,14 +91,31 @@ func memtest4() {
|
||||||
c1 := o1.UTF8String()
|
c1 := o1.UTF8String()
|
||||||
_ = o1
|
_ = o1
|
||||||
_ = c1
|
_ = c1
|
||||||
|
runtime.GC()
|
||||||
time.Sleep(time.Second/10)
|
time.Sleep(time.Second/10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func memtest5() {
|
||||||
|
fmt.Println("memtest5 started")
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
str := ns.NSStringWithGoString(fmt.Sprintf("five string %d",i))
|
||||||
|
_ = str
|
||||||
|
sub := str.SubstringFromIndex(5)
|
||||||
|
_ = sub
|
||||||
|
fmt.Printf("sub = %s\n",sub)
|
||||||
|
time.Sleep(time.Second/10)
|
||||||
|
runtime.GC()
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
go memtest1()
|
go memtest1()
|
||||||
go memtest2()
|
go memtest2()
|
||||||
go memtest3()
|
go memtest3()
|
||||||
go memtest4()
|
go memtest4()
|
||||||
|
go memtest5()
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
package ns
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo CFLAGS: -x objective-c -fno-objc-arc
|
|
||||||
#cgo LDFLAGS: -framework Foundation
|
|
||||||
#pragma clang diagnostic ignored "-Wformat-security"
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
//export MyClassRelease
|
|
||||||
func MyClassRelease(o unsafe.Pointer) {
|
|
||||||
MyClassMux.RLock()
|
|
||||||
cb := MyClassLookup[o].Release
|
|
||||||
MyClassMux.RUnlock()
|
|
||||||
if cb == nil { return }
|
|
||||||
self := MyClass{}
|
|
||||||
self.ptr = o
|
|
||||||
super := MyClassSupermethods{
|
|
||||||
self.SuperRelease,
|
|
||||||
}
|
|
||||||
cb(super)
|
|
||||||
}
|
|
||||||
|
|
||||||
//export MyClassDealloc
|
|
||||||
func MyClassDealloc(o unsafe.Pointer) {
|
|
||||||
MyClassMux.RLock()
|
|
||||||
cb := MyClassLookup[o].Dealloc
|
|
||||||
MyClassMux.RUnlock()
|
|
||||||
if cb == nil { return }
|
|
||||||
cb()
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,6 +11,8 @@ subclasses:
|
||||||
NSObject:
|
NSObject:
|
||||||
- dealloc
|
- dealloc
|
||||||
- release
|
- release
|
||||||
|
functions:
|
||||||
|
- NSMakeRange
|
||||||
frameworks:
|
frameworks:
|
||||||
- Foundation
|
- Foundation
|
||||||
pragma: [ clang diagnostic ignored "-Wformat-security" ]
|
pragma: [ clang diagnostic ignored "-Wformat-security" ]
|
||||||
|
|
|
@ -74,6 +74,7 @@ func memtest2() {
|
||||||
s1 := ns.NSStringWithGoString(fmt.Sprintf("string-%d", i))
|
s1 := ns.NSStringWithGoString(fmt.Sprintf("string-%d", i))
|
||||||
_ = s1
|
_ = s1
|
||||||
//o1.Retain() // uncomment for leak
|
//o1.Retain() // uncomment for leak
|
||||||
|
i++
|
||||||
})
|
})
|
||||||
time.Sleep(time.Second / 3)
|
time.Sleep(time.Second / 3)
|
||||||
}
|
}
|
||||||
|
@ -94,24 +95,24 @@ func memtest3() {
|
||||||
arr.Autorelease()
|
arr.Autorelease()
|
||||||
arr.AddObject(ns.NSStringWithGoString(fmt.Sprintf("my string %d",i)))
|
arr.AddObject(ns.NSStringWithGoString(fmt.Sprintf("my string %d",i)))
|
||||||
s1 := ns.NSStringWithGoString(fmt.Sprintf("my other string %d",i))
|
s1 := ns.NSStringWithGoString(fmt.Sprintf("my other string %d",i))
|
||||||
|
fmt.Printf("%s\n",arr.ObjectAtIndex(0).NSString())
|
||||||
_ = s1
|
_ = s1
|
||||||
i++
|
|
||||||
|
|
||||||
for {
|
for x := 0; x < 3; x++ {
|
||||||
ns.Autoreleasepool(func() {
|
ns.Autoreleasepool(func() {
|
||||||
str := arr.ObjectAtIndex(0).NSString()
|
str := arr.ObjectAtIndex(0).NSString()
|
||||||
fmt.Println(str) // does not leak in an autorelease pool
|
fmt.Printf("%d->%s\n",x,str) // does not leak in an autorelease pool
|
||||||
time.Sleep(time.Second / 2)
|
time.Sleep(time.Second / 5)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second/2)
|
||||||
|
i++
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fmt.Println("memtest3: done")
|
fmt.Println("memtest3: done")
|
||||||
}
|
}
|
||||||
|
|
||||||
//Test of manual memory management. Lets run multiple goroutines here to
|
//Test of manual memory management.
|
||||||
//confirm we can use multiple threads if autorelease pools are not in play.
|
|
||||||
func memtest4() {
|
func memtest4() {
|
||||||
go memtest4a()
|
go memtest4a()
|
||||||
go memtest4a()
|
go memtest4a()
|
||||||
|
@ -122,10 +123,16 @@ func memtest4() {
|
||||||
go memtest4c()
|
go memtest4c()
|
||||||
go memtest4c()
|
go memtest4c()
|
||||||
go memtest4c()
|
go memtest4c()
|
||||||
// Exactly one goroutine (locked to an OS thread) can use an
|
// running multiple separate threads with autorelease pools...
|
||||||
// autorelease pool (?)
|
|
||||||
go memtest1()
|
go memtest1()
|
||||||
go memtest2()
|
go memtest2()
|
||||||
|
go memtest3()
|
||||||
|
go memtest1()
|
||||||
|
go memtest2()
|
||||||
|
go memtest3()
|
||||||
|
go memtest1()
|
||||||
|
go memtest2()
|
||||||
|
go memtest3()
|
||||||
}
|
}
|
||||||
|
|
||||||
func memtest4a() {
|
func memtest4a() {
|
||||||
|
@ -140,24 +147,34 @@ func memtest4b() {
|
||||||
i := 0
|
i := 0
|
||||||
for {
|
for {
|
||||||
o1 := ns.NSObjectAlloc() // need to Release
|
o1 := ns.NSObjectAlloc() // need to Release
|
||||||
|
|
||||||
|
// These object constructors will always leak. In the case of an
|
||||||
|
// immutable string, it is not an issue unless a large number of different
|
||||||
|
// strings are going to be made.
|
||||||
//s1 := ns.NSStringWithGoString(fmt.Sprintf("a string %d",i)) // uncomment for leak
|
//s1 := ns.NSStringWithGoString(fmt.Sprintf("a string %d",i)) // uncomment for leak
|
||||||
s1 := ns.NSStringWithGoString("a string")
|
s1 := ns.NSStringWithGoString("a string")
|
||||||
i++
|
i++
|
||||||
arr := ns.NSArrayAlloc().InitWithObjects(s1) // need to Release arr
|
arr := ns.NSArrayAlloc().InitWithObjects(s1) // need to Release arr
|
||||||
s2 := arr.ObjectAtIndex(0).NSString()
|
s2 := arr.ObjectAtIndex(0).NSString()
|
||||||
|
|
||||||
//If you try to convert an NSString to UTF8String, CString (*Char),
|
// If you try to convert an NSString to UTF8String, CString (*Char),
|
||||||
//or GoString, Objective-C runtime will leak an
|
// or GoString, Objective-C runtime creates an autoreleased
|
||||||
//NSTaggedPointerCStringContainer. Don't know why or how to fix it.
|
// NSTaggedPointerCStringContainer internally and there is no way to
|
||||||
//There would be no leak if we were using an autorelease pool.
|
// release it unless you called your method from within an autorelease
|
||||||
//u := str.UTF8String() // uncomment for leak
|
// pool. The following two calls cause a leak.
|
||||||
|
//u := s1.UTF8String() // uncomment for leak
|
||||||
//fmt.Println(s1) // uncomment for leak
|
//fmt.Println(s1) // uncomment for leak
|
||||||
|
|
||||||
time.Sleep(time.Second / 50)
|
time.Sleep(time.Second / 50)
|
||||||
|
|
||||||
o1.Release()
|
o1.Release()
|
||||||
arr.Release()
|
arr.Release()
|
||||||
//s1.Release() // does not work
|
|
||||||
|
//s1.Release() // does not prevent the leak caused by
|
||||||
|
// NSStringWithGoString: s1 is autoreleased by the Objective-C
|
||||||
|
// runtime, these methods will always leak without autorelease
|
||||||
|
// pools.
|
||||||
|
|
||||||
_ = o1
|
_ = o1
|
||||||
_ = s2
|
_ = s2
|
||||||
}
|
}
|
||||||
|
@ -173,17 +190,6 @@ func memtest4c() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fin(o *ns.MyClass) {
|
|
||||||
o.Release()
|
|
||||||
}
|
|
||||||
|
|
||||||
func releaseX(x int) func (ns.MyClassSupermethods) {
|
|
||||||
return func(super ns.MyClassSupermethods) {
|
|
||||||
fmt.Printf("--release %d\n", x)
|
|
||||||
super.Release() // comment out for leak
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
//Uncomment more than one test at a time for a crash.
|
//Uncomment more than one test at a time for a crash.
|
||||||
//Note: You may not run autorelease pools from multiple goroutines.
|
//Note: You may not run autorelease pools from multiple goroutines.
|
||||||
|
|
4
main.go
4
main.go
|
@ -300,7 +300,9 @@ func Start() (err error) {
|
||||||
case *ast.ObjCCategoryDecl:
|
case *ast.ObjCCategoryDecl:
|
||||||
w.AddCategory(x)
|
w.AddCategory(x)
|
||||||
case *ast.TypedefDecl:
|
case *ast.TypedefDecl:
|
||||||
w.AddTypedef(x.Name, x.Type)
|
if !x.IsImplicit {
|
||||||
|
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)
|
||||||
|
|
|
@ -17,6 +17,10 @@ func ShouldWrap(gt string) bool {
|
||||||
return wrapped[gt]
|
return wrapped[gt]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PtrShouldWrap(gt string) bool {
|
||||||
|
return gt != "" && gt[0] == '*' && wrapped[gt[1:]]
|
||||||
|
}
|
||||||
|
|
||||||
//goInterfaces records the names of top level Go interfaces.
|
//goInterfaces records the names of top level Go interfaces.
|
||||||
var goInterfaces map[string]bool
|
var goInterfaces map[string]bool
|
||||||
|
|
||||||
|
@ -24,6 +28,10 @@ func IsGoInterface(gt string) bool {
|
||||||
return goInterfaces[gt]
|
return goInterfaces[gt]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PtrIsGoInterface(gt string) bool {
|
||||||
|
return gt != "" && gt[0] == '*' && goInterfaces[gt[1:]]
|
||||||
|
}
|
||||||
|
|
||||||
//TypeParameters maps, for each class, a TypedefName to a type, representing
|
//TypeParameters maps, for each class, a TypedefName to a type, representing
|
||||||
//the Objective-C type parameters for that class
|
//the Objective-C type parameters for that class
|
||||||
var TypeParameters map[string]map[string]string
|
var TypeParameters map[string]map[string]string
|
||||||
|
@ -148,6 +156,7 @@ func (t *Type) PointsTo() *Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Wrap(s string) {
|
func Wrap(s string) {
|
||||||
|
//fmt.Printf("wrapped[%s] = true\n",s)
|
||||||
wrapped[s] = true
|
wrapped[s] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +164,9 @@ func (t *Type) BaseType() *Type {
|
||||||
if t == nil {
|
if t == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
// if td := t.Typedef(); td != nil {
|
||||||
|
// return td.BaseType()
|
||||||
|
// }
|
||||||
ret := NewType(
|
ret := NewType(
|
||||||
t.Node.BaseType(),
|
t.Node.BaseType(),
|
||||||
t.Class,
|
t.Class,
|
||||||
|
@ -184,19 +196,21 @@ func (t *Type) GoType() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func _goType(ct string) string {
|
func _goType(ct string) string {
|
||||||
ct = swapstars(ct)
|
|
||||||
ct = strings.Title(ct)
|
ct = strings.Title(ct)
|
||||||
ct = strings.ReplaceAll(ct, " ", "")
|
ct = strings.ReplaceAll(ct, " ", "")
|
||||||
ct = strings.ReplaceAll(ct, "Struct", "")
|
ct = strings.TrimPrefix(ct, "Struct")
|
||||||
if IsGoInterface(ct) {
|
ct = swapstars(ct)
|
||||||
return ct
|
if len(ct) > 0 && ct[0] == '*' && IsGoInterface(ct[1:]) {
|
||||||
|
//return ct[1:]
|
||||||
|
return ct // ??
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if ct == "Id" {
|
if ct == "Id" {
|
||||||
ct = "Id"
|
ct = "*Id"
|
||||||
}*/
|
}
|
||||||
if len(ct) > 1 && ShouldWrap(ct[1:]) {
|
//if len(ct) > 1 && ShouldWrap(ct[1:]) {
|
||||||
return ct[1:]
|
if ShouldWrap(ct) {
|
||||||
|
return ct
|
||||||
}
|
}
|
||||||
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"
|
||||||
|
@ -234,32 +248,37 @@ func (t *Type) GoTypeDecl() string {
|
||||||
if wrapped[t.GoType()] {
|
if wrapped[t.GoType()] {
|
||||||
return t.GoInterfaceDecl()
|
return t.GoInterfaceDecl()
|
||||||
}
|
}
|
||||||
tp := t.BaseType()
|
if t.Node.IsId() {
|
||||||
if tp.Node.IsId() {
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
gt := tp.GoType()
|
gt := t.GoType()
|
||||||
|
if Debug {
|
||||||
|
fmt.Printf(" writing GoTypeDecl for %s\n",gt)
|
||||||
|
}
|
||||||
switch gt {
|
switch gt {
|
||||||
case "", "Void":
|
case "", "Void":
|
||||||
return ""
|
return ""
|
||||||
default:
|
default:
|
||||||
var cgt string
|
|
||||||
if td := tp.Typedef(); td != nil {
|
|
||||||
cgt = td.CGoType()
|
|
||||||
} else {
|
|
||||||
cgt = tp.CGoType()
|
|
||||||
}
|
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
type %s %s
|
type %s %s
|
||||||
`, gt, cgt)
|
`, gt, t.CGoType())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Type) GoInterfaceDecl() string {
|
func (t *Type) GoInterfaceDecl() string {
|
||||||
ct := t.CType()
|
ct := t.CType()
|
||||||
gt := t.GoType()
|
gt := t.GoType()
|
||||||
|
if Debug {
|
||||||
|
fmt.Printf(" writing GoInterfaceDecl for %s\n",gt)
|
||||||
|
}
|
||||||
|
if gt[0] == '*' {
|
||||||
|
gt = gt[1:] // dereference wrapped types
|
||||||
|
ct = ct[:len(ct)-1]
|
||||||
|
fmt.Printf(" dereferenced %s\n",gt)
|
||||||
|
}
|
||||||
super := Super(ct)
|
super := Super(ct)
|
||||||
if super == "" {
|
if super == "" {
|
||||||
|
//fmt.Printf("goInterfaces[%s] = true\n",gt)
|
||||||
goInterfaces[gt] = true
|
goInterfaces[gt] = true
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
type %s interface {
|
type %s interface {
|
||||||
|
@ -272,9 +291,9 @@ type %s interface {
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
type %s struct { %s }
|
type %s struct { %s }
|
||||||
func (o %s) Ptr() unsafe.Pointer { return o.ptr }
|
func (o *%s) Ptr() unsafe.Pointer { if o == nil { return nil }; return o.ptr }
|
||||||
func (o Id) %s() %s {
|
func (o *Id) %s() *%s {
|
||||||
ret := %s{}
|
ret := &%s{}
|
||||||
ret.ptr = o.ptr
|
ret.ptr = o.ptr
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
@ -344,7 +363,7 @@ func (t *Type) CToGo(cval string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call a C function from Go with a given return type and parameter types
|
// Call a C function from Go with a given return type and parameter types
|
||||||
func GoToC(name string, pnames, snames []string, rtype *Type, ptypes []*Type, fun, gogc bool) string {
|
func GoToC(name string, pnames, snames []string, rtype *Type, ptypes []*Type, fun, fin bool) string {
|
||||||
if rtype == nil {
|
if rtype == nil {
|
||||||
//fmt.Println("nil sent to GoToC")
|
//fmt.Println("nil sent to GoToC")
|
||||||
return ""
|
return ""
|
||||||
|
@ -352,15 +371,17 @@ func GoToC(name string, pnames, snames []string, rtype *Type, ptypes []*Type, fu
|
||||||
var ret strings.Builder
|
var ret strings.Builder
|
||||||
rt := rtype.CType()
|
rt := rtype.CType()
|
||||||
rtgt := rtype.GoType()
|
rtgt := rtype.GoType()
|
||||||
if IsGoInterface(rtgt) {
|
//fmt.Printf("GoToC(%s): rtgt == %s\n",name,rtgt)
|
||||||
rtgt = "Id"
|
if PtrIsGoInterface(rtgt) {
|
||||||
|
//fmt.Printf(" PtrIsGoInterface(%s) = true\n",rtgt)
|
||||||
|
rtgt = "*Id"
|
||||||
}
|
}
|
||||||
sw := ShouldWrap(rtgt) || rtgt == "Id"
|
sw := PtrShouldWrap(rtgt) || rtgt == "*Id"
|
||||||
if rt != "void" {
|
if rt != "void" {
|
||||||
if sw {
|
if sw {
|
||||||
ret.WriteString(fmt.Sprintf(
|
ret.WriteString(fmt.Sprintf(
|
||||||
`ret := %s{}
|
`ret := &%s{}
|
||||||
ret.ptr = `, rtgt))
|
ret.ptr = `, rtgt[1:]))
|
||||||
} else {
|
} else {
|
||||||
if rtgt == "BOOL" {
|
if rtgt == "BOOL" {
|
||||||
ret.WriteString("ret := (")
|
ret.WriteString("ret := (")
|
||||||
|
@ -378,7 +399,7 @@ func GoToC(name string, pnames, snames []string, rtype *Type, ptypes []*Type, fu
|
||||||
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 (PtrShouldWrap(pt.GoType()) || PtrIsGoInterface(pt.GoType())) && !pt.Variadic {
|
||||||
p = pn + ".Ptr()"
|
p = pn + ".Ptr()"
|
||||||
} else {
|
} else {
|
||||||
switch {
|
switch {
|
||||||
|
@ -409,6 +430,10 @@ func GoToC(name string, pnames, snames []string, rtype *Type, ptypes []*Type, fu
|
||||||
if sname == "" {
|
if sname == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
ptgt := (ptypes[i].GoType())[2:]
|
||||||
|
if IsGoInterface(ptgt) {
|
||||||
|
ptgt = "Id"
|
||||||
|
}
|
||||||
ret.WriteString(fmt.Sprintf(`
|
ret.WriteString(fmt.Sprintf(`
|
||||||
(*%s) = (*%s)[:cap(*%s)]
|
(*%s) = (*%s)[:cap(*%s)]
|
||||||
for i := 0; i < len(*%s); i++ {
|
for i := 0; i < len(*%s); i++ {
|
||||||
|
@ -416,17 +441,18 @@ func GoToC(name string, pnames, snames []string, rtype *Type, ptypes []*Type, fu
|
||||||
(*%s) = (*%s)[:i]
|
(*%s) = (*%s)[:i]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if (*%s)[i] == nil {
|
||||||
|
(*%s)[i] = &%s{}
|
||||||
|
}
|
||||||
(*%s)[i].ptr = %s[i]
|
(*%s)[i].ptr = %s[i]
|
||||||
}`, pnames[i], pnames[i], pnames[i], pnames[i], sname, pnames[i], pnames[i], pnames[i], sname))
|
}`, pnames[i], pnames[i], pnames[i], pnames[i], sname, pnames[i], pnames[i], pnames[i], pnames[i], ptgt, pnames[i], sname))
|
||||||
}
|
}
|
||||||
if rt != "void" {
|
if rt != "void" {
|
||||||
if sw && gogc && rtgt != "NSAutoreleasePool" {
|
if fin {
|
||||||
// if m,_ :=regexp.MatchString(`Alloc(WithZone)?`,name); m {
|
ret.WriteString(fmt.Sprintf(`
|
||||||
ret.WriteString(fmt.Sprintf(`
|
runtime.SetFinalizer(ret, func(o *%s) {
|
||||||
runtime.SetFinalizer(&ret, func(o *%s) {
|
|
||||||
o.Release()
|
o.Release()
|
||||||
})`,rtgt))
|
})`,rtgt))
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
ret.WriteString(`
|
ret.WriteString(`
|
||||||
return ret`)
|
return ret`)
|
||||||
|
|
131
wrap/main.go
131
wrap/main.go
|
@ -75,7 +75,7 @@ func NewWrapper(debug bool) *Wrapper {
|
||||||
type Id struct {
|
type Id struct {
|
||||||
ptr unsafe.Pointer
|
ptr unsafe.Pointer
|
||||||
}
|
}
|
||||||
func (o Id) Ptr() unsafe.Pointer { return o.ptr }
|
func (o *Id) Ptr() unsafe.Pointer { if o == nil { return nil }; return o.ptr }
|
||||||
`)
|
`)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
@ -150,6 +150,14 @@ type Method struct {
|
||||||
Unavailable bool
|
Unavailable bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Method) ShouldFinalize() bool {
|
||||||
|
return shouldFinalize(m.Type.GoType(), m.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldFinalize (grtype, name string) bool {
|
||||||
|
return Gogc && grtype != "NSAutoreleasePool" && (types.ShouldWrap(grtype) || grtype == "Id") && (len(name) < 4 || name[:4] != "init")
|
||||||
|
}
|
||||||
|
|
||||||
//Fully disambiguated method name (m.GoName + all parameter names)
|
//Fully disambiguated method name (m.GoName + all parameter names)
|
||||||
func (m *Method) LongName() string {
|
func (m *Method) LongName() string {
|
||||||
ret := m.GoName
|
ret := m.GoName
|
||||||
|
@ -331,14 +339,17 @@ func (w *Wrapper) gpntp(m *Method) ([]string, []string, []*types.Type, string) {
|
||||||
if gt == "*Void" {
|
if gt == "*Void" {
|
||||||
gt = "unsafe.Pointer"
|
gt = "unsafe.Pointer"
|
||||||
}
|
}
|
||||||
|
if types.PtrIsGoInterface(gt) {
|
||||||
|
gt = gt[1:]
|
||||||
|
}
|
||||||
if tps[i].Variadic {
|
if tps[i].Variadic {
|
||||||
gt = "..." + gt
|
gt = "..." + gt
|
||||||
ns[i] = ns[i] + "s"
|
ns[i] = ns[i] + "s"
|
||||||
}
|
}
|
||||||
if len(gt) > 2 && gt[:2] == "**" && types.ShouldWrap(gt[2:]) {
|
if len(gt) > 2 && gt[:1] == "*" && types.PtrShouldWrap(gt[1:]) {
|
||||||
x := gt[2:]
|
x := gt[1:]
|
||||||
if types.IsGoInterface(x) {
|
if types.PtrIsGoInterface(x) {
|
||||||
x = "Id"
|
x = "*Id"
|
||||||
}
|
}
|
||||||
gt = "*[]" + x
|
gt = "*[]" + x
|
||||||
snames[i] = "goSlice" + strconv.Itoa(i)
|
snames[i] = "goSlice" + strconv.Itoa(i)
|
||||||
|
@ -747,13 +758,19 @@ func (w *Wrapper) AddTypedef(n, t string) {
|
||||||
}
|
}
|
||||||
if types.ShouldWrap(gt) {
|
if types.ShouldWrap(gt) {
|
||||||
if Debug {
|
if Debug {
|
||||||
fmt.Printf(" processing type for %s (%s)\n", n, gt)
|
fmt.Printf(" processing wrapped type for %s (%s)\n", n, gt)
|
||||||
}
|
}
|
||||||
types.Wrap(n)
|
types.Wrap(n)
|
||||||
types.SetSuper(n, gt)
|
types.SetSuper(n, gt)
|
||||||
w._processType(tp, "*"+n)
|
//w._processType(tp, n)
|
||||||
|
w._processType(tp)
|
||||||
} else {
|
} else {
|
||||||
|
cgt := tp.CGoType()
|
||||||
|
if Debug {
|
||||||
|
fmt.Printf(" processing un-wrapped type for %s -> %s\n", n, cgt)
|
||||||
|
}
|
||||||
types.AddTypedef(n, tp)
|
types.AddTypedef(n, tp)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -765,11 +782,14 @@ 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)
|
//w._processType(bt, gt)
|
||||||
|
w._processType(bt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Wrapper) _processType(bt *types.Type, gt string) {
|
//func (w *Wrapper) _processType(bt *types.Type, gt string) {
|
||||||
|
func (w *Wrapper) _processType(bt *types.Type) {
|
||||||
|
gt := bt.GoType()
|
||||||
if Debug {
|
if Debug {
|
||||||
fmt.Printf("processType: gt = %s bt = %s\n", gt, bt)
|
fmt.Printf("processType: gt = %s bt = %s\n", gt, bt)
|
||||||
}
|
}
|
||||||
|
@ -802,6 +822,9 @@ func (w *Wrapper) _processType(bt *types.Type, gt string) {
|
||||||
types.Wrap(tp.GoType())
|
types.Wrap(tp.GoType())
|
||||||
w.processType(tp)
|
w.processType(tp)
|
||||||
}
|
}
|
||||||
|
if Debug {
|
||||||
|
fmt.Printf("Writing go type for %s -> %s\n",bt.CType(),gt)
|
||||||
|
}
|
||||||
w.goTypes.WriteString(bt.GoTypeDecl())
|
w.goTypes.WriteString(bt.GoTypeDecl())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,7 +850,7 @@ func (c *Char) Free() {
|
||||||
|
|
||||||
func (w *Wrapper) StringHelpers() {
|
func (w *Wrapper) StringHelpers() {
|
||||||
w.goHelpers.WriteString(`
|
w.goHelpers.WriteString(`
|
||||||
func (o NSString) String() string {
|
func (o *NSString) String() string {
|
||||||
return o.UTF8String().String()
|
return o.UTF8String().String()
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
|
@ -835,7 +858,7 @@ func (o NSString) 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.Ptr() != nil; o = e.NextObject() {
|
for o := e.NextObject(); o.Ptr() != nil; o = e.NextObject() {
|
||||||
if !f(o) { break }
|
if !f(o) { break }
|
||||||
}
|
}
|
||||||
|
@ -924,9 +947,9 @@ func (w *Wrapper) _processMethod(m *Method, fun bool) {
|
||||||
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 + ") "
|
||||||
}
|
}
|
||||||
//Disambiguate instance methods with same name as a class method
|
//Disambiguate instance methods with same name as a class method
|
||||||
cname = "inst_" + cname
|
cname = "inst_" + cname
|
||||||
|
@ -969,8 +992,8 @@ func (w *Wrapper) _processMethod(m *Method, fun bool) {
|
||||||
if grtype == "Void" {
|
if grtype == "Void" {
|
||||||
grtype = ""
|
grtype = ""
|
||||||
}
|
}
|
||||||
if types.IsGoInterface(grtype) {
|
if types.PtrIsGoInterface(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"
|
||||||
|
@ -1022,7 +1045,7 @@ func %s%s(%s) %s {
|
||||||
`, snames[i], n, n, snames[i], n))
|
`, snames[i], n, n, snames[i], n))
|
||||||
}
|
}
|
||||||
w.goCode.WriteString(` ` +
|
w.goCode.WriteString(` ` +
|
||||||
types.GoToC(cname, ns, snames, m.Type, tps, fun, Gogc) + "\n}\n")
|
types.GoToC(cname, ns, snames, m.Type, tps, fun, m.ShouldFinalize()) + "\n}\n")
|
||||||
|
|
||||||
cret := ""
|
cret := ""
|
||||||
if !m.isVoid() {
|
if !m.isVoid() {
|
||||||
|
@ -1062,9 +1085,15 @@ func %s%s(%s) %s {
|
||||||
default:
|
default:
|
||||||
if Gogc && !m.isVoid() {
|
if Gogc && !m.isVoid() {
|
||||||
rtn := ""
|
rtn := ""
|
||||||
|
//if m.ClassMethod && types.ShouldWrap(m.Type.GoType()) {
|
||||||
if types.ShouldWrap(m.Type.GoType()) {
|
if types.ShouldWrap(m.Type.GoType()) {
|
||||||
|
if m.ClassMethod {
|
||||||
rtn = `
|
rtn = `
|
||||||
[ret retain];`
|
[ret retain];`
|
||||||
|
} else {
|
||||||
|
rtn = `
|
||||||
|
if (o != ret) { [ret retain]; }`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
w.cCode.WriteString(fmt.Sprintf(
|
w.cCode.WriteString(fmt.Sprintf(
|
||||||
` %s ret;
|
` %s ret;
|
||||||
|
@ -1097,10 +1126,10 @@ func %s%s(%s) %s {
|
||||||
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])
|
||||||
cvts = cvts + gStringToNSString(ns[i])
|
cvts = gStringToNSString(ns[i])
|
||||||
ns[i] = "NSStringWithUTF8String(" + ns[i] + "_chr)"
|
ns[i] = "NSStringWithUTF8String(" + ns[i] + "_chr)"
|
||||||
}
|
}
|
||||||
gps = append(gps, ns2+" "+gt)
|
gps = append(gps, ns2+" "+gt)
|
||||||
|
@ -1111,11 +1140,21 @@ func %s%s(%s) %s {
|
||||||
obj = "o."
|
obj = "o."
|
||||||
ns = ns[1:]
|
ns = ns[1:]
|
||||||
}
|
}
|
||||||
|
finalizer := ""
|
||||||
|
if m.ShouldFinalize() && false {
|
||||||
|
w.goImports["runtime"] = true
|
||||||
|
finalizer = fmt.Sprintf(
|
||||||
|
`runtime.SetFinalizer(ret, func(o *%s) {
|
||||||
|
o.Release()
|
||||||
|
})
|
||||||
|
`, grtype)
|
||||||
|
}
|
||||||
w.goCode.WriteString(fmt.Sprintf(`
|
w.goCode.WriteString(fmt.Sprintf(`
|
||||||
func %s%s(%s) %s {
|
func %s%s(%s) %s {
|
||||||
%sreturn %s%s(%s)
|
%sret := %s%s(%s)
|
||||||
|
%sreturn ret
|
||||||
}
|
}
|
||||||
`, receiver, gname2, gplist, grtype, cvts, obj, gname, strings.Join(ns, ", ")))
|
`, receiver, gname2, gplist, grtype, cvts, obj, gname, strings.Join(ns, ", "), finalizer))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1214,6 +1253,9 @@ func (w *Wrapper) ProcessSubclass(sname string, sc *Subclass) {
|
||||||
for i, sig := range sc.NewMethods {
|
for i, sig := range sc.NewMethods {
|
||||||
nms[i] = w.MethodFromSig(sig, sname)
|
nms[i] = w.MethodFromSig(sig, sname)
|
||||||
}
|
}
|
||||||
|
if Debug {
|
||||||
|
fmt.Println("ProcessSubclass(%s)\n",sname)
|
||||||
|
}
|
||||||
w._ProcessDelSub(sname, ps, nms, true)
|
w._ProcessDelSub(sname, ps, nms, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1567,17 +1609,17 @@ void*
|
||||||
|
|
||||||
//5. Go constructor
|
//5. Go constructor
|
||||||
var finalizer string
|
var finalizer string
|
||||||
if Gogc {
|
if shouldFinalize(gname,"") {
|
||||||
w.goImports["runtime"] = true
|
w.goImports["runtime"] = true
|
||||||
finalizer = fmt.Sprintf(
|
finalizer = fmt.Sprintf(
|
||||||
`runtime.SetFinalizer(&ret,func(o *%s) {
|
`runtime.SetFinalizer(ret,func(o *%s) {
|
||||||
o.Release()
|
o.Release()
|
||||||
})
|
})
|
||||||
`,gname)
|
`,gname)
|
||||||
}
|
}
|
||||||
gocode.WriteString(fmt.Sprintf(`
|
gocode.WriteString(fmt.Sprintf(`
|
||||||
func %sAlloc() %s {
|
func %sAlloc() *%s {
|
||||||
ret := %s{}
|
ret := &%s{}
|
||||||
ret.ptr = unsafe.Pointer(C.%sAlloc())
|
ret.ptr = unsafe.Pointer(C.%sAlloc())
|
||||||
%sreturn ret
|
%sreturn ret
|
||||||
}
|
}
|
||||||
|
@ -1646,10 +1688,10 @@ func (d %s) %sCallback(f func(%s)%s) {
|
||||||
} else {
|
} else {
|
||||||
gt2 = gtypes[i][j-1]
|
gt2 = gtypes[i][j-1]
|
||||||
}
|
}
|
||||||
if types.IsGoInterface(gt2) {
|
if types.IsGoInterface(gt2) || types.ShouldWrap(gt2) {
|
||||||
gt2 = "Id"
|
gt2 = "*Id"
|
||||||
}
|
}
|
||||||
if types.ShouldWrap(gt2) || gt2 == "Id" {
|
if gt2 == "*Id" {
|
||||||
garglist = append(garglist, fmt.Sprintf(
|
garglist = append(garglist, fmt.Sprintf(
|
||||||
`a%d`, j))
|
`a%d`, j))
|
||||||
gargconv = append(gargconv, fmt.Sprintf(
|
gargconv = append(gargconv, fmt.Sprintf(
|
||||||
|
@ -1723,14 +1765,14 @@ 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"
|
||||||
}
|
}
|
||||||
if sub {
|
if sub {
|
||||||
gocode.WriteString(fmt.Sprintf(`
|
gocode.WriteString(fmt.Sprintf(`
|
||||||
func (o %s) Super%s(%s) %s {
|
func (o *%s) Super%s(%s) %s {
|
||||||
`, gname, gnames[i], strings.Join(earglist[1:], ", "), grtype))
|
`, gname, gnames[i], strings.Join(earglist[1:], ", "), grtype))
|
||||||
ns, snames, tps, _ := w.gpntp(m)
|
ns, snames, tps, _ := w.gpntp(m)
|
||||||
lparm := len(tps) - 1
|
lparm := len(tps) - 1
|
||||||
|
@ -1745,7 +1787,7 @@ func (o %s) Super%s(%s) %s {
|
||||||
}
|
}
|
||||||
`, vn, w.Vaargs, vn, vn))
|
`, vn, w.Vaargs, vn, vn))
|
||||||
}
|
}
|
||||||
gocode.WriteString("\t" + types.GoToC(dname+"_super_"+m.Name, ns, snames, m.Type, tps, false, Gogc) + "\n}\n")
|
gocode.WriteString("\t" + types.GoToC(dname+"_super_"+m.Name, ns, snames, m.Type, tps, false, m.ShouldFinalize()) + "\n}\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.cCode.WriteString(cprotos.String())
|
w.cCode.WriteString(cprotos.String())
|
||||||
|
@ -1823,6 +1865,27 @@ func (w *Wrapper) AddProtocolMethods(i *Interface, p *Protocol) {
|
||||||
procmeths(i.InstanceMethods, p.InstanceMethods)
|
procmeths(i.InstanceMethods, p.InstanceMethods)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printDebug() {
|
||||||
|
fmt.Printf("ShouldWrap(NSString) = %t\n",types.ShouldWrap("NSString"))
|
||||||
|
fmt.Printf("ShouldWrap(*NSString) = %t\n",types.ShouldWrap("*NSString"))
|
||||||
|
fmt.Printf("IsGoInterface(NSObject) = %t\n",types.IsGoInterface("NSObject"))
|
||||||
|
fmt.Printf("IsGoInterface(*NSObject) = %t\n",types.IsGoInterface("*NSObject"))
|
||||||
|
fmt.Printf("IsGoInterface(NSString) = %t\n",types.IsGoInterface("NSString"))
|
||||||
|
fmt.Printf("IsGoInterface(*NSString) = %t\n",types.IsGoInterface("*NSString"))
|
||||||
|
fmt.Printf("PtrShouldWrap(NSString) = %t\n",types.PtrShouldWrap("NSString"))
|
||||||
|
fmt.Printf("PtrShouldWrap(*NSString) = %t\n",types.PtrShouldWrap("*NSString"))
|
||||||
|
fmt.Printf("PtrIsGoInterface(NSObject) = %t\n",types.PtrIsGoInterface("NSObject"))
|
||||||
|
fmt.Printf("PtrIsGoInterface(*NSObject) = %t\n",types.PtrIsGoInterface("*NSObject"))
|
||||||
|
fmt.Printf("PtrIsGoInterface(NSString) = %t\n",types.PtrIsGoInterface("NSString"))
|
||||||
|
fmt.Printf("PtrIsGoInterface(*NSString) = %t\n",types.PtrIsGoInterface("*NSString"))
|
||||||
|
fmt.Printf("Super(NSString) = %s\n",types.Super("NSString"))
|
||||||
|
fmt.Printf("Super(*NSString) = %s\n",types.Super("*NSString"))
|
||||||
|
fmt.Printf("Super(NSObject) = %s\n",types.Super("NSObject"))
|
||||||
|
fmt.Printf("Super(*NSObject) = %s\n",types.Super("*NSObject"))
|
||||||
|
fmt.Printf("Super(NSString*) = %s\n",types.Super("NSString*"))
|
||||||
|
fmt.Printf("Super(NSObject*) = %s\n",types.Super("NSObject*"))
|
||||||
|
}
|
||||||
|
|
||||||
func (w *Wrapper) Wrap(toproc []string) {
|
func (w *Wrapper) Wrap(toproc []string) {
|
||||||
if w.Package == "" {
|
if w.Package == "" {
|
||||||
w.Package = "ns"
|
w.Package = "ns"
|
||||||
|
@ -1879,12 +1942,6 @@ func (w *Wrapper) Wrap(toproc []string) {
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
w.AddProtocolMethods(i,prot)
|
w.AddProtocolMethods(i,prot)
|
||||||
// for _, m := range prot.ClassMethods.Methods {
|
|
||||||
// w.ProcessMethodForClass(m, i.Name)
|
|
||||||
// }
|
|
||||||
// for _, m := range prot.InstanceMethods.Methods {
|
|
||||||
// w.ProcessMethodForClass(m, i.Name)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
Disambiguate(i.ClassMethods)
|
Disambiguate(i.ClassMethods)
|
||||||
Disambiguate(i.InstanceMethods)
|
Disambiguate(i.InstanceMethods)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user