Comprehensive update, add some GC fixes, update examples to new MacOS

header file layout.
This commit is contained in:
Greg 2020-06-24 13:03:53 -04:00
parent acc8cab583
commit 8b3a956bbe
26 changed files with 9729 additions and 354 deletions

View File

@ -12,28 +12,28 @@ import (
//Shortcut for literal NSStrings //Shortcut for literal NSStrings
var nst = ns.NSStringWithGoString var nst = ns.NSStringWithGoString
func pb1() { func pb1(self ns.GButton, super ns.GButtonSupermethods) {
fmt.Println("Pushed button 1") fmt.Println("Pushed button 1")
} }
func pb2() { func pb2(self ns.GButton, super ns.GButtonSupermethods) {
fmt.Println("Pushed button 2") fmt.Println("Pushed button 2")
a.Terminate(a) a.Terminate(a)
} }
func db() { func db(self ns.GButton, super ns.GButtonSupermethods) {
fmt.Println("button deallocated") fmt.Println("button deallocated")
} }
func didFinishLaunching(n *ns.NSNotification) { func didFinishLaunching(self ns.AppDelegate, n *ns.NSNotification) {
fmt.Println("Go: did finish launching") fmt.Println("Go: did finish launching")
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(
ns.NSMakeRect(200, 200, 600, 600), ns.NSMakeRect(200, 200, 600, 600),
ns.NSWindowStyleMaskTitled|ns.NSWindowStyleMaskClosable| ns.NSWindowStyleMask(ns.NSWindowStyleMaskTitled|ns.NSWindowStyleMaskClosable|
ns.NSWindowStyleMaskResizable, ns.NSWindowStyleMaskResizable),
ns.NSBackingStoreBuffered, ns.NSBackingStoreType(ns.NSBackingStoreBuffered),
0, 0,
) )
// We do not need to retain this because we are in garbage collection mode // We do not need to retain this because we are in garbage collection mode
@ -103,21 +103,21 @@ func didFinishLaunching(n *ns.NSNotification) {
cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat( cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
nst("H:|-[b1]"), 0, nil, viewmap)) nst("H:|-[b1]"), 0, nil, viewmap))
cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat( cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
nst("H:[b1]-[b2]"), ns.NSLayoutFormatAlignAllBaseline, nil, viewmap)) nst("H:[b1]-[b2]"), ns.NSLayoutFormatOptions(ns.NSLayoutFormatAlignAllBaseline), nil, viewmap))
a.ActivateIgnoringOtherApps(1) a.ActivateIgnoringOtherApps(1)
} }
func shouldTerminateAfterLastWindowClosed(s *ns.NSApplication) ns.BOOL { func shouldTerminateAfterLastWindowClosed(self ns.AppDelegate, s *ns.NSApplication) ns.BOOL {
fmt.Println("Go: should terminate after last window closed") fmt.Println("Go: should terminate after last window closed")
return 1 return 1
} }
func willTerminate(n *ns.NSNotification) { func willTerminate(self ns.AppDelegate, n *ns.NSNotification) {
fmt.Println("Go: will terminate") fmt.Println("Go: will terminate")
} }
func didBecomeActive(n *ns.NSNotification) { func didBecomeActive(self ns.AppDelegate, 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())
} }
@ -132,7 +132,7 @@ func app() {
// Lock OS thread because Cocoa uses thread-local storage // Lock OS thread because Cocoa uses thread-local storage
runtime.LockOSThread() runtime.LockOSThread()
a = ns.NSApplicationSharedApplication() a = ns.NSApplicationSharedApplication()
a.SetActivationPolicy(ns.NSApplicationActivationPolicyRegular) a.SetActivationPolicy(ns.NSApplicationActivationPolicy(ns.NSApplicationActivationPolicyRegular))
// Set up an AppDelegate // Set up an AppDelegate
// assign it to a global variable so it doesn't get garbage collected // assign it to a global variable so it doesn't get garbage collected

View File

@ -1,7 +1,7 @@
# nswrap.yaml # nswrap.yaml
inputfiles: inputfiles:
- /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h - /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h
- /System/Library/Frameworks/AppKit.framework/Headers/AppKit.h - /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/AppKit.framework/Headers/AppKit.h
classes: classes:
- NSAutoreleasePool - NSAutoreleasePool

View File

@ -5,14 +5,14 @@ import "C"
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"git.wow.st/gmp/nswrap/examples/bluetooth/ns"
"runtime" "runtime"
"time" "time"
"git.wow.st/gmp/nswrap/examples/bluetooth/ns"
) )
func updateState(c *ns.CBCentralManager) { func updateState(self ns.CBDelegate, c *ns.CBCentralManager) {
fmt.Printf("Go: did update state\n") fmt.Printf("Go: did update state\n")
switch cm.CBManager.State() { switch ns.NSInteger(cm.CBManager.State()) {
case ns.CBManagerStateUnknown: case ns.CBManagerStateUnknown:
fmt.Printf(" unknown\n") fmt.Printf(" unknown\n")
case ns.CBManagerStateResetting: case ns.CBManagerStateResetting:
@ -30,7 +30,7 @@ func updateState(c *ns.CBCentralManager) {
fmt.Printf("Go: updateState returning\n") fmt.Printf("Go: updateState returning\n")
} }
func discoverPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral, d *ns.NSDictionary, rssi *ns.NSNumber) { func discoverPeripheral(self ns.CBDelegate, 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()
@ -51,7 +51,7 @@ func discoverPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral, d *ns.NSDict
c.ConnectPeripheral(peripheral, nil) c.ConnectPeripheral(peripheral, nil)
} }
func connectPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral) { func connectPeripheral(self ns.CBDelegate, c *ns.CBCentralManager, p *ns.CBPeripheral) {
fmt.Printf("Did connect peripheral\n") fmt.Printf("Did connect peripheral\n")
// set ourselves up as a peripheral delegate // set ourselves up as a peripheral delegate
@ -64,7 +64,7 @@ func connectPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral) {
fmt.Printf("Go: discoverPeripheral returning\n") fmt.Printf("Go: discoverPeripheral returning\n")
} }
func discoverServices(p *ns.CBPeripheral, e *ns.NSError) { func discoverServices(self ns.CBDelegate, 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()
@ -97,7 +97,7 @@ func hr(d *ns.NSData) int {
} }
} }
func discoverCharacteristics(p *ns.CBPeripheral, s *ns.CBService, e *ns.NSError) { func discoverCharacteristics(self ns.CBDelegate, p *ns.CBPeripheral, s *ns.CBService, e *ns.NSError) {
fmt.Printf("Did discover characteristics\n") fmt.Printf("Did discover characteristics\n")
uuid := s.UUID() uuid := s.UUID()
fmt.Printf("----%s\n", uuid.UUIDString()) fmt.Printf("----%s\n", uuid.UUIDString())
@ -117,7 +117,7 @@ func discoverCharacteristics(p *ns.CBPeripheral, s *ns.CBService, e *ns.NSError)
fmt.Printf("Go: discoverCharacteristics returning\n") fmt.Printf("Go: discoverCharacteristics returning\n")
} }
func updateValue(p *ns.CBPeripheral, chr *ns.CBCharacteristic, e *ns.NSError) { func updateValue(self ns.CBDelegate, 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))

View File

@ -1,6 +1,6 @@
inputfiles: inputfiles:
- /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h - /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h
- /System/Library/Frameworks/CoreBluetooth.framework/Headers/CoreBluetooth.h - /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/CoreBluetooth.framework/Headers/CoreBluetooth.h
classes: classes:
- NSObject - NSObject

View File

@ -46,7 +46,7 @@ func main() {
fmt.Printf("\nNSArray.ObjectEnumerator().ForIn():\n") fmt.Printf("\nNSArray.ObjectEnumerator().ForIn():\n")
x := 0 x := 0
a.ObjectEnumerator().ForIn(func(o *ns.Id) bool { a.ObjectEnumerator().ForIn(func(o *ns.Id) bool {
fmt.Printf("%d: %s\n",x,o.NSString()) fmt.Printf("%d: %s\n", x, o.NSString())
x++ x++
return true return true
}) })
@ -72,7 +72,7 @@ func main() {
} }
return true return true
}) })
fmt.Printf("a = %p a.NSArray = %p\n",a,&a.NSArray) fmt.Printf("a = %p a.NSArray = %p\n", a, &a.NSArray)
fmt.Printf("\nNSArrayWithObjects() (length 1)\n") fmt.Printf("\nNSArrayWithObjects() (length 1)\n")
a2 = ns.NSArrayWithObjects(n1) a2 = ns.NSArrayWithObjects(n1)
a2.ObjectEnumerator().ForIn(func(o *ns.Id) bool { a2.ObjectEnumerator().ForIn(func(o *ns.Id) bool {
@ -109,8 +109,8 @@ func main() {
oarr := make([]*ns.Id, 0, 5) oarr := make([]*ns.Id, 0, 5)
fmt.Printf("Length of oarr is %d\n", len(oarr)) fmt.Printf("Length of oarr is %d\n", len(oarr))
karr := make([]*ns.Id, 0, 5) karr := make([]*ns.Id, 0, 5)
fmt.Printf("\nGetObjects()\n") fmt.Printf("\nGetObjectsAndKeysCount()\n")
d.GetObjects(&oarr, &karr, 4) d.GetObjectsAndKeysCount(&oarr, &karr, 4)
fmt.Printf("Length of oarr is now %d\n", len(oarr)) fmt.Printf("Length of oarr is now %d\n", len(oarr))
for i, k := range karr { for i, k := range karr {
fmt.Printf("-- %s -> %s\n", k.NSString(), oarr[i].NSString()) fmt.Printf("-- %s -> %s\n", k.NSString(), oarr[i].NSString())
@ -119,11 +119,11 @@ func main() {
err := make([]*ns.NSError, 1) err := make([]*ns.NSError, 1)
n1 = ns.NSStringWithContentsOfURLEncoding(ns.NSURLWithGoString("http://captive.apple.com"), ns.NSUTF8StringEncoding, &err) n1 = ns.NSStringWithContentsOfURLEncoding(ns.NSURLWithGoString("http://captive.apple.com"), ns.NSUTF8StringEncoding, &err)
if len(err) == 0 { if len(err) == 0 {
fmt.Printf("n1 = %s\n",n1) fmt.Printf("n1 = %s\n", n1)
} }
n1 = ns.NSStringWithContentsOfURLEncoding(ns.NSURLWithGoString("htttypo://example.com"), ns.NSUTF8StringEncoding, &err) n1 = ns.NSStringWithContentsOfURLEncoding(ns.NSURLWithGoString("htttypo://example.com"), ns.NSUTF8StringEncoding, &err)
if len(err) > 0 { if len(err) > 0 {
fmt.Printf("err[0] = %p -> %p\n",err[0],err[0].Ptr()) fmt.Printf("err[0] = %p -> %p\n", err[0], err[0].Ptr())
fmt.Printf("err: %s\n", err[0].LocalizedDescription()) fmt.Printf("err: %s\n", err[0].LocalizedDescription())
} }
@ -137,26 +137,26 @@ func main() {
fmt.Printf("\nArrayWithObjects\n") fmt.Printf("\nArrayWithObjects\n")
a2 = ns.NSArrayWithObjects(gs1, gs2) a2 = ns.NSArrayWithObjects(gs1, gs2)
a2.ObjectEnumerator().ForIn(func(o *ns.Id) bool { a2.ObjectEnumerator().ForIn(func(o *ns.Id) bool {
fmt.Printf("--%s\n",o.NSString()) fmt.Printf("--%s\n", o.NSString())
return true return true
}) })
dir,e := os.Getwd() dir, e := os.Getwd()
if e != nil { if e != nil {
fmt.Printf("Failed to get current working directory. %s\n",err) fmt.Printf("Failed to get current working directory. %s\n", err)
os.Exit(-1) os.Exit(-1)
} }
path := nst(dir) path := nst(dir)
filter := ns.NSArrayWithObjects(nst("ast"),nst("yaml")) filter := ns.NSArrayWithObjects(nst("ast"), nst("yaml"))
ost := make([]*ns.NSString,0,1) ost := make([]*ns.NSString, 0, 1)
oar:= make([]*ns.NSArray,0,1) oar := make([]*ns.NSArray, 0, 1)
fmt.Printf("\nCompletePathIntoString()\n") fmt.Printf("\nCompletePathIntoString()\n")
i := path.CompletePathIntoString(&ost,0,&oar,filter) i := path.CompletePathIntoString(&ost, 0, &oar, filter)
fmt.Printf("%d matches\n",i) fmt.Printf("%d matches\n", i)
if i > 0 { if i > 0 {
fmt.Printf("ost = %s\n",ost[0]) fmt.Printf("ost = %s\n", ost[0])
fmt.Printf("oar =\n") fmt.Printf("oar =\n")
oar[0].ObjectEnumerator().ForIn(func(o *ns.Id) bool { oar[0].ObjectEnumerator().ForIn(func(o *ns.Id) bool {
fmt.Printf("--%s\n",o.NSString()) fmt.Printf("--%s\n", o.NSString())
return true return true
}) })
} }

View File

@ -1,5 +1,5 @@
inputfiles: inputfiles:
- /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h - /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h
classes: classes:
- NSAutoreleasePool - NSAutoreleasePool
- NSArray - NSArray

View File

@ -2,25 +2,24 @@ package main
import ( import (
"fmt" "fmt"
"unsafe"
"git.wow.st/gmp/nswrap/examples/functions/ns" "git.wow.st/gmp/nswrap/examples/functions/ns"
"unsafe"
) )
func main() { func main() {
var s ns.Stat var s ns.Stat
ns.Puts(ns.CharWithGoString("Hi there")) ns.Puts(ns.CharWithGoString("Hi there"))
ret := ns.Fstat(3,&s) ret := ns.Fstat(3, &s)
fmt.Printf("Fstat: %d\n",ret) fmt.Printf("Fstat: %d\n", ret)
fmt.Printf("Opening file\n") fmt.Printf("Opening file\n")
f := ns.Fopen(ns.CharWithGoString("nswrap.yaml"),ns.CharWithGoString("r")) f := ns.Fopen(ns.CharWithGoString("nswrap.yaml"), ns.CharWithGoString("r"))
ret = ns.Fstat(3,&s) ret = ns.Fstat(3, &s)
fmt.Printf("Fstat: %d\n",ret) fmt.Printf("Fstat: %d\n", ret)
chr := make([]byte,4096) chr := make([]byte, 4096)
i := ns.Fread(unsafe.Pointer(&chr[0]), 1, 4096, f) i := ns.Fread(unsafe.Pointer(&chr[0]), 1, 4096, f)
if i < 4096 { if i < 4096 {
chr = chr[:i] chr = chr[:i]
} }
fmt.Printf("file contents:\n%s\n",string(chr)) fmt.Printf("file contents:\n%s\n", string(chr))
} }

View File

@ -1,7 +1,7 @@
inputfiles: inputfiles:
- /usr/include/stdio.h - /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/stdio.h
- /usr/include/stdlib.h - /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/stdlib.h
- /usr/include/sys/stat.h - /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/stat.h
sysimports: sysimports:
- stdio.h - stdio.h
- stdlib.h - stdlib.h

View File

@ -9,8 +9,8 @@ import (
"git.wow.st/gmp/nswrap/examples/gc/ns" "git.wow.st/gmp/nswrap/examples/gc/ns"
) )
func releaseX(x int) func (ns.MyClassSupermethods) { func releaseX(x int) func(ns.MyClass, ns.MyClassSupermethods) {
return func(super ns.MyClassSupermethods) { return func(self ns.MyClass, super ns.MyClassSupermethods) {
//fmt.Printf("--release %d\n", x) //fmt.Printf("--release %d\n", x)
super.Release() // comment out for leak super.Release() // comment out for leak
} }
@ -19,7 +19,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.
@ -33,7 +33,7 @@ func memtest1() {
// 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
// in a real program. // in a real program.
runtime.GC() runtime.GC()
time.Sleep(time.Second/50) time.Sleep(time.Second / 50)
//fmt.Printf("Loop complete\n") //fmt.Printf("Loop complete\n")
} }
} }
@ -42,8 +42,8 @@ func memtest2() {
fmt.Println("memtest2 started") fmt.Println("memtest2 started")
i := 0 i := 0
for { for {
o1 := ns.NSStringAlloc().InitWithGoString(fmt.Sprintf("two string %d",i)) o1 := ns.NSStringAlloc().InitWithGoString(fmt.Sprintf("two string %d", i))
o2 := ns.NSStringWithGoString(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
@ -58,9 +58,9 @@ func memtest2() {
// init methods in Objective-C always return a retained object. // init methods in Objective-C always return a retained object.
// init may or may not return the same object that was sent in. // init may or may not return the same object that was sent in.
a1 = a1.InitWithObjects(o1,o2,o3,o4) a1 = a1.InitWithObjects(o1, o2, o3, o4)
a2 := ns.NSArrayWithObjects(o1,o2,o3,o4) a2 := ns.NSArrayWithObjects(o1, o2, o3, o4)
// you can always nest alloc and init. // you can always nest alloc and init.
@ -74,7 +74,7 @@ func memtest2() {
_ = a3 _ = a3
runtime.GC() runtime.GC()
time.Sleep(time.Second/50) time.Sleep(time.Second / 50)
} }
} }
@ -121,7 +121,7 @@ func memtest4() {
_ = o1 _ = o1
_ = c1 _ = c1
runtime.GC() runtime.GC()
time.Sleep(time.Second/50) time.Sleep(time.Second / 50)
c1.Free() // you need to manually free UTF8Strings c1.Free() // you need to manually free UTF8Strings
} }
} }
@ -134,7 +134,7 @@ func memtest5() {
// a new NSString object at each loop iteration and cannot be reusing // a new NSString object at each loop iteration and cannot be reusing
// the same string object. // the same string object.
str := ns.NSStringWithGoString(fmt.Sprintf("blue string %d",i)) str := ns.NSStringWithGoString(fmt.Sprintf("blue string %d", i))
// SubstringFromIndex should be returning a newly allocated NSString, // SubstringFromIndex should be returning a newly allocated NSString,
// which is getting retained by NSWrap and released by a Go GC // which is getting retained by NSWrap and released by a Go GC
@ -146,7 +146,7 @@ func memtest5() {
u := sub.UTF8String() u := sub.UTF8String()
u2 := sub2.UTF8String() u2 := sub2.UTF8String()
u3 := sub3.UTF8String() u3 := sub3.UTF8String()
time.Sleep(time.Second/50) time.Sleep(time.Second / 50)
runtime.GC() runtime.GC()
i++ i++
u.Free() u.Free()
@ -160,30 +160,29 @@ func memtest5() {
} }
func tmpdict(i int) *ns.NSString { func tmpdict(i int) *ns.NSString {
o1 := ns.NSStringWithGoString(fmt.Sprintf("temp string 1-%d",i)) o1 := ns.NSStringWithGoString(fmt.Sprintf("temp string 1-%d", i))
o2 := ns.NSStringWithGoString(fmt.Sprintf("temp string 2-%d",i)) o2 := ns.NSStringWithGoString(fmt.Sprintf("temp string 2-%d", i))
k1 := ns.NSStringWithGoString(fmt.Sprintf("temp key 1-%d",i)) k1 := ns.NSStringWithGoString(fmt.Sprintf("temp key 1-%d", i))
k2 := ns.NSStringWithGoString(fmt.Sprintf("temp key 2-%d",i)) k2 := ns.NSStringWithGoString(fmt.Sprintf("temp key 2-%d", i))
dict := ns.NSDictionaryWithObjectsAndKeys(o1,k1,o2,k2) dict := ns.NSDictionaryWithObjectsAndKeys(o1, k1, o2, k2)
ret := dict.ValueForKey(k1) ret := dict.ValueForKey(k1)
//fmt.Printf("tmpdict(): string = %s\n",ret.NSString()) //fmt.Printf("tmpdict(): string = %s\n",ret.NSString())
defer runtime.GC() // o1, o2, k1, k2, and dict can be released after we return defer runtime.GC() // o1, o2, k1, k2, and dict can be released after we return
return ret.NSString() // should be retained by NSDictionary.ValueForKey() return ret.NSString() // should be retained by NSDictionary.ValueForKey()
} }
func tmparr(i int) *ns.NSString { func tmparr(i int) *ns.NSString {
o1 := ns.NSStringWithGoString(fmt.Sprintf("temp string 3-%d",i)) o1 := ns.NSStringWithGoString(fmt.Sprintf("temp string 3-%d", i))
o2 := ns.NSStringWithGoString(fmt.Sprintf("temp string 4-%d",i)) o2 := ns.NSStringWithGoString(fmt.Sprintf("temp string 4-%d", i))
arr := ns.NSArrayWithObjects(o1,o2) arr := ns.NSArrayWithObjects(o1, o2)
os := make([]*ns.Id,0,2) os := make([]*ns.Id, 0, 2)
arr.GetObjects(&os, ns.NSMakeRange(0,2)) arr.GetObjectsRange(&os, ns.NSMakeRange(0, 2))
defer runtime.GC() // collect o1, o2 and arr defer runtime.GC() // collect o1, o2 and arr
return os[1].NSString() // should have been retained by NSArray.GetObjects() return os[1].NSString() // should have been retained by NSArray.GetObjects()
} }
func memtest6() { func memtest6() {
fmt.Println("memtest6 started") fmt.Println("memtest6 started")
i := 0 i := 0
@ -193,13 +192,13 @@ func memtest6() {
time.Sleep(time.Second / 5) time.Sleep(time.Second / 5)
u1 := s1.String() // make sure s1 and s2 are still available u1 := s1.String() // make sure s1 and s2 are still available
u2 := s2.String() u2 := s2.String()
e1 := fmt.Sprintf("temp string 1-%d",i) e1 := fmt.Sprintf("temp string 1-%d", i)
if u1 != e1 { if u1 != e1 {
fmt.Printf("tmpdict() error: %s != %s\n",u1,e1) fmt.Printf("tmpdict() error: %s != %s\n", u1, e1)
} }
e2 := fmt.Sprintf("temp string 4-%d",i) e2 := fmt.Sprintf("temp string 4-%d", i)
if u2 != e2 { if u2 != e2 {
fmt.Printf("tmparr() error: %s != %s\n",u2,e2) fmt.Printf("tmparr() error: %s != %s\n", u2, e2)
} }
i++ i++
@ -221,7 +220,7 @@ func main() {
go func() { go func() {
for { for {
// print a progress indicator // print a progress indicator
fmt.Printf("t = %s\n",time.Now()) fmt.Printf("t = %s\n", time.Now())
time.Sleep(time.Second * 10) time.Sleep(time.Second * 10)
} }
}() }()

View File

@ -1,5 +1,5 @@
inputfiles: inputfiles:
- /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h - /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h
classes: classes:
- NSAutoreleasePool - NSAutoreleasePool
- NSArray - NSArray

View File

@ -10,13 +10,13 @@ import (
"git.wow.st/gmp/nswrap/examples/memory/ns" "git.wow.st/gmp/nswrap/examples/memory/ns"
) )
func dealloc() { func dealloc(self ns.MyClass, super ns.MyClassSupermethods) {
//[super dealloc] is called for you automatically, so no Supermethods //[super dealloc] is called for you automatically, so no Supermethods
//struct is provided here. //struct is provided here.
fmt.Println("--dealloc called") fmt.Println("--dealloc called")
} }
func release(super ns.MyClassSupermethods) { func release(self ns.MyClass, super ns.MyClassSupermethods) {
fmt.Println("--release called") fmt.Println("--release called")
super.Release() // comment out for leak super.Release() // comment out for leak
} }
@ -92,19 +92,19 @@ func memtest3() {
ns.Autoreleasepool(func() { ns.Autoreleasepool(func() {
arr := ns.NSMutableArrayAlloc().Init() arr := ns.NSMutableArrayAlloc().Init()
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()) fmt.Printf("%s\n", arr.ObjectAtIndex(0).NSString())
_ = s1 _ = s1
for x := 0; x < 3; x++ { for x := 0; x < 3; x++ {
ns.Autoreleasepool(func() { ns.Autoreleasepool(func() {
str := arr.ObjectAtIndex(0).NSString() str := arr.ObjectAtIndex(0).NSString()
fmt.Printf("%d->%s\n",x,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 / 5) time.Sleep(time.Second / 5)
}) })
} }
time.Sleep(time.Second/2) time.Sleep(time.Second / 2)
i++ i++
}) })
} }

View File

@ -1,5 +1,5 @@
inputfiles: inputfiles:
- /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h - /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h
classes: classes:
- NSAutoreleasePool - NSAutoreleasePool
- NSArray - NSArray

View File

@ -7,7 +7,7 @@ import (
ns "git.wow.st/gmp/nswrap/examples/simple/ClassOne" ns "git.wow.st/gmp/nswrap/examples/simple/ClassOne"
) )
func cb(super ns.ClassThreeSupermethods) ns.Int { func cb(self ns.ClassThree, super ns.ClassThreeSupermethods) ns.Int {
fmt.Printf("In Go callback\n") fmt.Printf("In Go callback\n")
return 0 return 0
} }

View File

@ -26,21 +26,21 @@ func incr() func(bool) (int, float64) {
if b == 0 { if b == 0 {
return i, 0.0 return i, 0.0
} else { } else {
return i, (b/float64(i)) * 100 return i, (b / float64(i)) * 100
} }
} }
} }
type tracker struct { type tracker struct {
add, drop func(*ns.Id) add, drop func(*ns.Id)
check func() check func()
i func(bool) (int, float64) i func(bool) (int, float64)
} }
type record struct { type record struct {
ptr unsafe.Pointer ptr unsafe.Pointer
goPtr *ns.Id goPtr *ns.Id
when time.Time when time.Time
} }
func newTracker() (func(*ns.Id), func(*ns.Id), func()) { func newTracker() (func(*ns.Id), func(*ns.Id), func()) {
@ -54,35 +54,35 @@ func newTracker() (func(*ns.Id), func(*ns.Id), func()) {
select { select {
case x := <-addch: case x := <-addch:
mux.Lock() mux.Lock()
data = append(data,record{ data = append(data, record{
x.Ptr(), x.Ptr(),
x, x,
time.Now(), time.Now(),
}) })
mux.Unlock() mux.Unlock()
case x := <-dropch: case x := <-dropch:
mux.Lock() mux.Lock()
data = append(data,record{ data = append(data, record{
nil, nil,
x, x,
time.Now(), time.Now(),
}) })
mux.Unlock() mux.Unlock()
} }
} }
}() }()
add := func(x *ns.Id) { add := func(x *ns.Id) {
addch<- x addch <- x
} }
drop := func(x *ns.Id) { drop := func(x *ns.Id) {
dropch<- x dropch <- x
} }
check := func() { check := func() {
live := map[unsafe.Pointer]*ns.Id{} live := map[unsafe.Pointer]*ns.Id{}
bad := false bad := false
mux.Lock() mux.Lock()
for _,r := range data { for _, r := range data {
if r.ptr != nil { if r.ptr != nil {
if live[r.ptr] != nil { if live[r.ptr] != nil {
fmt.Printf("COLLISION: %p & %p -> %p\n", r.goPtr, live[r.ptr], r.ptr) fmt.Printf("COLLISION: %p & %p -> %p\n", r.goPtr, live[r.ptr], r.ptr)
@ -90,10 +90,10 @@ func newTracker() (func(*ns.Id), func(*ns.Id), func()) {
} }
live[r.ptr] = r.goPtr live[r.ptr] = r.goPtr
} else { } else {
delete(live,r.ptr) delete(live, r.ptr)
} }
} }
fmt.Printf("Checked %d records -- ",len(data)) fmt.Printf("Checked %d records -- ", len(data))
if bad { if bad {
fmt.Printf("failed\n") fmt.Printf("failed\n")
} else { } else {
@ -101,25 +101,25 @@ func newTracker() (func(*ns.Id), func(*ns.Id), func()) {
} }
mux.Unlock() mux.Unlock()
} }
return add,drop,check return add, drop, check
} }
func mkstrings(t tracker) { func mkstrings(t tracker) {
for { for {
//fmt.Printf("main thread: %t\n",ns.NSThreadIsMainThread()) //fmt.Printf("main thread: %t\n",ns.NSThreadIsMainThread())
x,b := t.i(false) x, b := t.i(false)
str := fmt.Sprintf("string %d",x) str := fmt.Sprintf("string %d", x)
s := ns.NSStringWithGoString(str) s := ns.NSStringWithGoString(str)
//t.add(&s.Id) //t.add(&s.Id)
for j := 0; j < 10; j++ { for j := 0; j < 10; j++ {
sout := s.String() sout := s.String()
if str != sout { if str != sout {
_,b = t.i(true) _, b = t.i(true)
fmt.Printf("%3.2f%% -- %d: '%s' '%s'\n", b, x, str, sout) fmt.Printf("%3.2f%% -- %d: '%s' '%s'\n", b, x, str, sout)
} }
time.Sleep(time.Second/1000) time.Sleep(time.Second / 1000)
} }
if x % 1000 == 0 { if x%1000 == 0 {
fmt.Printf("%3.2f%% -- %s\n", b, time.Now().Format("03:04:05.000")) fmt.Printf("%3.2f%% -- %s\n", b, time.Now().Format("03:04:05.000"))
} }
//t.drop(&s.Id) //t.drop(&s.Id)
@ -145,7 +145,7 @@ func main() {
go func() { go func() {
for { for {
runtime.GC() runtime.GC()
time.Sleep(time.Second/100) time.Sleep(time.Second / 100)
} }
}() }()

View File

@ -1,5 +1,5 @@
inputfiles: inputfiles:
- /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h - /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h
classes: classes:
- NSString - NSString
- NSThread - NSThread

31
examples/subclass/main.go Normal file
View File

@ -0,0 +1,31 @@
package main
import (
"fmt"
"git.wow.st/gmp/nswrap/examples/subclass/ns"
)
func c1release(self ns.C1, super ns.C1Supermethods) {
fmt.Printf("c1release()\n")
super.Release()
fmt.Printf("c1release() done\n")
}
func c2myMethod(self ns.C2) {
fmt.Printf("c2myMethod()\n")
}
func main() {
fmt.Printf("Starting\n")
c1 := ns.C1Alloc()
c1.ReleaseCallback(c1release)
c1.Release()
c2 := ns.C2Alloc()
c2.MyMethodCallback(c2myMethod)
c2.Release()
fmt.Printf("Done\n")
}

View File

@ -0,0 +1,58 @@
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 C1Dealloc
func C1Dealloc(o unsafe.Pointer) {
C1Mux.RLock()
cb := C1Lookup[o].Dealloc
C1Mux.RUnlock()
if cb == nil { return }
self := C1{}
self.ptr = o
super := C1Supermethods{
self.SuperDealloc,
self.SuperRelease,
}
cb(self, super)
}
//export C1Release
func C1Release(o unsafe.Pointer) {
C1Mux.RLock()
cb := C1Lookup[o].Release
C1Mux.RUnlock()
if cb == nil { return }
self := C1{}
self.ptr = o
super := C1Supermethods{
self.SuperDealloc,
self.SuperRelease,
}
cb(self, super)
}
//export C2MyMethod
func C2MyMethod(o unsafe.Pointer) {
C2Mux.RLock()
cb := C2Lookup[o].MyMethod
C2Mux.RUnlock()
if cb == nil { return }
self := C2{}
self.ptr = o
cb(self)
}

9042
examples/subclass/ns/main.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
inputfiles: [ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h ]
classes:
- NSObject
- NSString
subclasses:
c1:
NSObject:
- dealloc
- release
c2:
NSObject:
- -(void)myMethod
# c3:
# NSObject:
# - -(void)myMethod:(int)i
# c4:
# NSObject:
# - release
# - -(int)myMethod:(int)i
# c5:
# NSObject:
# - release
# - -(void)myMethod
frameworks: [ Foundation ]
pragma: [ clang diagnostic ignored "-Wformat-security" ]

BIN
examples/subclass/subclass Executable file

Binary file not shown.

66
main.go
View File

@ -12,7 +12,10 @@ import (
"strings" "strings"
"git.wow.st/gmp/nswrap/ast" "git.wow.st/gmp/nswrap/ast"
"git.wow.st/gmp/nswrap/types"
"git.wow.st/gmp/nswrap/wrap" "git.wow.st/gmp/nswrap/wrap"
"github.com/a8m/envsubst"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
@ -26,22 +29,26 @@ var autoadd = []string{
} }
type conf struct { type conf struct {
Positions bool Positions bool
Package string Package string
Inputfiles []string Inputfiles []string
Astfile string Astfile string
Debugast bool Debugast bool
Classes []string Classes []string
Functions []string Functions []string
Enums []string FunctionIgnore []string
Delegates map[string]map[string][]string Enums []string
Subclasses map[string]map[string][]string Delegates map[string]map[string][]string
Frameworks []string Subclasses map[string]map[string][]string
Frameworkdirs []string Frameworks []string
Imports []string Libraries []string
Sysimports []string Frameworkdirs []string
Pragma []string Imports []string
Vaargs int Sysimports []string
Pragma []string
Typesubs map[string]string
Vaargs int
Clang string
//Arc flag for debugging only, builds will break //Arc flag for debugging only, builds will break
Arc bool Arc bool
Autorelease bool Autorelease bool
@ -233,7 +240,12 @@ func Start() (err error) {
} }
cargs = append(cargs, Config.Inputfiles...) cargs = append(cargs, Config.Inputfiles...)
fmt.Printf("Generating AST\n") fmt.Printf("Generating AST\n")
astPP, err = exec.Command("clang", cargs...).Output() clang := "clang"
if Config.Clang != "" {
clang = Config.Clang
}
fmt.Printf("%s %s\n", clang, strings.Join(cargs, " "))
astPP, err = exec.Command(clang, cargs...).Output()
if err != nil { if err != nil {
// If clang fails it still prints out the AST, so we have to run it // If clang fails it still prints out the AST, so we have to run it
// again to get the real error. // again to get the real error.
@ -281,12 +293,14 @@ func Start() (err error) {
w := wrap.NewWrapper(Debug) w := wrap.NewWrapper(Debug)
w.Package = Config.Package w.Package = Config.Package
w.Frameworks = Config.Frameworks w.Frameworks = Config.Frameworks
w.Libraries = Config.Libraries
w.Frameworkdirs = Config.Frameworkdirs w.Frameworkdirs = Config.Frameworkdirs
w.Import(Config.Imports) w.Import(Config.Imports)
w.SysImport(Config.Sysimports) w.SysImport(Config.Sysimports)
w.Pragmas = Config.Pragma w.Pragmas = Config.Pragma
w.Delegate(Config.Delegates) w.Delegate(Config.Delegates)
w.Subclass(Config.Subclasses) w.Subclass(Config.Subclasses)
types.Typesubs = Config.Typesubs
if Config.Vaargs == 0 { if Config.Vaargs == 0 {
Config.Vaargs = 16 Config.Vaargs = 16
} }
@ -305,7 +319,7 @@ func Start() (err error) {
} }
} }
if matches(x.Name, autoadd) { if matches(x.Name, autoadd) {
Config.Classes = append(Config.Classes,x.Name) Config.Classes = append(Config.Classes, x.Name)
} }
case *ast.ObjCCategoryDecl: case *ast.ObjCCategoryDecl:
w.AddCategory(x) w.AddCategory(x)
@ -314,7 +328,8 @@ func Start() (err error) {
w.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) &&
!matches(x.Name, Config.FunctionIgnore) {
w.AddFunction(x) w.AddFunction(x)
} }
case *ast.ObjCProtocolDecl: case *ast.ObjCProtocolDecl:
@ -341,9 +356,18 @@ func main() {
defer pprof.StopCPUProfile() defer pprof.StopCPUProfile()
} }
confbytes, err := ioutil.ReadFile("nswrap.yaml") conffile := "nswrap.yaml"
if len(os.Args) > 1 {
conffile = os.Args[1]
}
confbytes, err := ioutil.ReadFile(conffile)
if err != nil { if err != nil {
fmt.Printf("%s\n\nFATAL ERROR: Configuration file must be present in directory where nswrap\nis invoked.\n", err) fmt.Printf("%s\n\nFATAL ERROR: Configuration file not found (default: nswrap.yaml)\n", err)
os.Exit(-1)
}
confbytes, err = envsubst.Bytes(confbytes)
if err != nil {
fmt.Printf("FATAL ERROR: Shell string variable substitution faled: %s\n", err)
os.Exit(-1) os.Exit(-1)
} }
if err = yaml.UnmarshalStrict(confbytes, &Config); err != nil { if err = yaml.UnmarshalStrict(confbytes, &Config); err != nil {

View File

@ -42,7 +42,7 @@ func ChildOf(ret *Node, p Parser) Parser {
} }
} }
//Children takes a parser returns a parser that adds the children of its //Children takes a parser and returns a parser that adds the children of its
//output node to the tree. If multiple parsers are passed in, they are //output node to the tree. If multiple parsers are passed in, they are
//passed to Seq(...) //passed to Seq(...)
func Children(ps ...Parser) Parser { func Children(ps ...Parser) Parser {

View File

@ -8,6 +8,7 @@ import (
) )
var Gogc bool var Gogc bool
var Typesubs map[string]string
//super is a map recording which class is the parent of each other class //super is a map recording which class is the parent of each other class
var super map[string]string var super map[string]string
@ -201,25 +202,45 @@ func (t *Type) GoType() string {
return _goType(t.CType()) return _goType(t.CType())
} }
func typeSub(gt string) string {
if Typesubs == nil {
return gt
}
i := 0
for ; i < len(gt); i++ {
if gt[i] != '*' {
break
}
}
gtp := gt[:i]
gte := gt[i:]
for k, v := range Typesubs {
if gte == k {
return gtp + v
}
}
return gt
}
func _goType(ct string) string { func _goType(ct string) string {
ct = strings.Title(ct) ct = strings.Title(ct)
ct = strings.ReplaceAll(ct, " ", "") ct = strings.ReplaceAll(ct, " ", "")
ct = strings.TrimPrefix(ct, "Struct") ct = strings.TrimPrefix(ct, "Struct")
ct = swapstars(ct) ct = swapstars(ct)
if len(ct) > 0 && ct[0] == '*' && IsGoInterface(ct[1:]) { if len(ct) > 0 && ct[0] == '*' && IsGoInterface(ct[1:]) {
return ct return typeSub(ct)
} }
if ct == "Id" { if ct == "Id" {
ct = "*Id" ct = "*Id"
} }
if ShouldWrap(ct) { if ShouldWrap(ct) {
return ct return typeSub(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"
} }
return ct return typeSub(ct)
} }
func (t *Type) CType() string { func (t *Type) CType() string {
@ -271,20 +292,32 @@ func (t *Type) GoTypeDecl(fin bool) string {
type %s = %s type %s = %s
`, gt, tdgt) `, gt, tdgt)
} }
cgt := td.CGoType()
eq := ""
if len(cgt) > 9 && cgt[:9] == "C.struct_" {
//cgt = "C." + cgt[9:]
eq = "= "
}
return fmt.Sprintf(` return fmt.Sprintf(`
type %s %s type %s %s%s
`, gt, td.CGoType()) `, gt, eq, cgt)
} }
if Debug { if Debug {
fmt.Printf(" writing GoTypeDecl for %s\n",gt) fmt.Printf(" writing GoTypeDecl for %s\n", gt)
} }
switch gt { switch gt {
case "", "Void": case "", "Void":
return "" return ""
default: default:
cgt := t.CGoType()
eq := ""
if len(cgt) > 9 && cgt[:9] == "C.struct_" {
//cgt = "C." + cgt[9:]
eq = "= "
}
return fmt.Sprintf(` return fmt.Sprintf(`
type %s %s type %s %s%s
`, gt, t.CGoType()) `, gt, eq, cgt)
} }
} }
@ -292,12 +325,12 @@ func (t *Type) GoInterfaceDecl(fin bool) string {
ct := t.CType() ct := t.CType()
gt := t.GoType() gt := t.GoType()
if Debug { if Debug {
fmt.Printf(" writing GoInterfaceDecl for %s\n",gt) fmt.Printf(" writing GoInterfaceDecl for %s\n", gt)
} }
if gt[0] == '*' { if gt[0] == '*' {
gt = gt[1:] // dereference wrapped types gt = gt[1:] // dereference wrapped types
ct = ct[:len(ct)-1] ct = ct[:len(ct)-1]
fmt.Printf(" dereferenced %s\n",gt) //fmt.Printf(" dereferenced %s\n", gt)
} }
super := Super(ct) super := Super(ct)
if super == "" { if super == "" {
@ -384,7 +417,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(sname, name string, pnames, snames []string, rtype *Type, ptypes []*Type, fun, fin bool, cm bool) string { func GoToC(sname, name string, pnames, snames []string, rtype *Type, ptypes []*Type, fun, fin bool, cm bool, goImports map[string]bool) string {
if rtype == nil { if rtype == nil {
//fmt.Println("nil sent to GoToC") //fmt.Println("nil sent to GoToC")
return "" return ""
@ -407,7 +440,7 @@ func GoToC(sname, name string, pnames, snames []string, rtype *Type, ptypes []*T
rtgt = "*Id" rtgt = "*Id"
} }
ret.WriteString(fmt.Sprintf( ret.WriteString(fmt.Sprintf(
`ret := &%s{} `ret := &%s{}
ret.ptr = unsafe.Pointer(`, rtgt[1:])) ret.ptr = unsafe.Pointer(`, rtgt[1:]))
case TypedefShouldWrap(rtgt): case TypedefShouldWrap(rtgt):
isptr = true isptr = true
@ -416,7 +449,7 @@ func GoToC(sname, name string, pnames, snames []string, rtype *Type, ptypes []*T
rtgt = "*Id" rtgt = "*Id"
} }
ret.WriteString(fmt.Sprintf( ret.WriteString(fmt.Sprintf(
`ret := &%s{} `ret := &%s{}
ret.ptr = unsafe.Pointer(`, rtgt[1:])) ret.ptr = unsafe.Pointer(`, rtgt[1:]))
default: default:
if rtgt == "BOOL" { if rtgt == "BOOL" {
@ -444,7 +477,11 @@ func GoToC(sname, name string, pnames, snames []string, rtype *Type, ptypes []*T
case TypedefShouldWrap(ptgt) && !pt.Variadic && !fun: case TypedefShouldWrap(ptgt) && !pt.Variadic && !fun:
p = pn + ".Ptr()" p = pn + ".Ptr()"
case snames[i] != "": case snames[i] != "":
p = "(*unsafe.Pointer)(unsafe.Pointer(&" + snames[i] + "[0]))" cast := pt.CGoType()
if len(ptgt) > 2 && ptgt[:1] == "*" && PtrShouldWrap(ptgt[1:]) {
cast = "*unsafe.Pointer"
}
p = fmt.Sprintf("(%s)(unsafe.Pointer(&%s[0]))", cast, snames[i])
case pt.Variadic: case pt.Variadic:
p = "unsafe.Pointer(&" + p + ")" p = "unsafe.Pointer(&" + p + ")"
case pt.IsPointer() && !fun: case pt.IsPointer() && !fun:
@ -472,8 +509,11 @@ func GoToC(sname, name string, pnames, snames []string, rtype *Type, ptypes []*T
continue continue
} }
ptgt := ptypes[i].GoType() ptgt := ptypes[i].GoType()
if !(len(ptgt) > 2 && ptgt[:1] == "*" && PtrShouldWrap(ptgt[1:])) {
continue
}
if len(ptgt) < 2 { if len(ptgt) < 2 {
fmt.Printf("Error in function translation -- argument %s to %s should be pointer to pointer\n",pnames[i],name) fmt.Printf("Error in function translation -- argument %s to %s should be pointer to pointer\n", pnames[i], name)
os.Exit(-1) os.Exit(-1)
} }
ptgt = ptgt[2:] ptgt = ptgt[2:]
@ -482,6 +522,7 @@ func GoToC(sname, name string, pnames, snames []string, rtype *Type, ptypes []*T
} }
dogc := "" dogc := ""
if Gogc { if Gogc {
goImports["runtime"] = true
dogc = fmt.Sprintf(` dogc = fmt.Sprintf(`
runtime.SetFinalizer((*%s)[i], func(o *%s) { runtime.SetFinalizer((*%s)[i], func(o *%s) {
o.Release() o.Release()
@ -503,12 +544,17 @@ func GoToC(sname, name string, pnames, snames []string, rtype *Type, ptypes []*T
if rt != "void" { if rt != "void" {
cmp := "" cmp := ""
if sw { if sw {
ka := ""
if !cm {
goImports["runtime"] = true
ka = "runtime.KeepAlive(o); "
}
if !cm && sname != "copy" && sname != "mutableCopy" { if !cm && sname != "copy" && sname != "mutableCopy" {
cmp = fmt.Sprintf(` cmp = fmt.Sprintf(`
if ret.ptr == o.ptr { return (%s)(unsafe.Pointer(o)) }`,rtgt) if ret.ptr == o.ptr { %sreturn (%s)(unsafe.Pointer(o)) }`, ka, rtgt)
} }
ret.WriteString(fmt.Sprintf(` ret.WriteString(fmt.Sprintf(`
if ret.ptr == nil { return ret }%s`,cmp)) if ret.ptr == nil { %sreturn ret }%s`, ka, cmp))
} }
if fin { if fin {
dbg := "" dbg := ""
@ -519,13 +565,25 @@ func GoToC(sname, name string, pnames, snames []string, rtype *Type, ptypes []*T
dbg2 = fmt.Sprintf(`fmt.Printf("Finalizer (%s): release %%p -> %%p\n", o, o.ptr) dbg2 = fmt.Sprintf(`fmt.Printf("Finalizer (%s): release %%p -> %%p\n", o, o.ptr)
`, rtgt) `, rtgt)
} }
goImports["runtime"] = true
ret.WriteString(fmt.Sprintf(` ret.WriteString(fmt.Sprintf(`
%sruntime.SetFinalizer(ret, func(o %s) { %sruntime.SetFinalizer(ret, func(o %s) {
%so.Release() %so.Release()
})`, dbg, rtgt, dbg2)) })`, dbg, rtgt, dbg2))
}
if !cm {
goImports["runtime"] = true
ret.WriteString(`
runtime.KeepAlive(o)`)
} }
ret.WriteString(` ret.WriteString(`
return ret`) return ret`)
} else {
if !cm {
goImports["runtime"] = true
ret.WriteString(`
runtime.KeepAlive(o)`)
}
} }
return ret.String() return ret.String()
} }

View File

@ -72,8 +72,8 @@ func TestType(t *testing.T) {
str = "NSString**" str = "NSString**"
n = &Node{"TypeName", "", []*Node{ n = &Node{"TypeName", "", []*Node{
&Node{"TypedefName", "NSString", []*Node{}}, &Node{"TypedefName", "NSString", []*Node{}},
&Node{"Pointer", "*", []*Node{}}, &Node{"Pointer", "*", []*Node{}},
&Node{"Pointer", "*", []*Node{}}}} &Node{"Pointer", "*", []*Node{}}}}
chk_newtype() chk_newtype()
chk(tp.IsPointer(), true) chk(tp.IsPointer(), true)
chk(tp.Typedef(), nil) chk(tp.Typedef(), nil)
@ -82,8 +82,8 @@ func TestType(t *testing.T) {
str = "NSObject**" str = "NSObject**"
n = &Node{"TypeName", "", []*Node{ n = &Node{"TypeName", "", []*Node{
&Node{"TypedefName", "NSObject", []*Node{}}, &Node{"TypedefName", "NSObject", []*Node{}},
&Node{"Pointer", "*", []*Node{}}, &Node{"Pointer", "*", []*Node{}},
&Node{"Pointer", "*", []*Node{}}}} &Node{"Pointer", "*", []*Node{}}}}
chk_newtype() chk_newtype()
chk(tp.IsPointer(), true) chk(tp.IsPointer(), true)
nsopp := tp nsopp := tp
@ -272,40 +272,46 @@ func (o *Id) NSString() *NSString {
ptypes := []*Type{nsop, nstp, tint, voidpp} ptypes := []*Type{nsop, nstp, tint, voidpp}
pnames := []string{"p1", "p2", "p3", "p4"} pnames := []string{"p1", "p2", "p3", "p4"}
snames := []string{"", "", "", ""} snames := []string{"", "", "", ""}
goImports := make(map[string]bool)
chk_gotoc := func(expected string) { chk_gotoc := func(expected string) {
chk(GoToC("myFun", "myFun", pnames, snames, rtype, ptypes, false, false, false), expected) chk(GoToC("myFun", "myFun", pnames, snames, rtype, ptypes, false, false, false, goImports), expected)
} }
chk_gotoc("") chk_gotoc("")
rtype = void rtype = void
chk_gotoc(`C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))`) chk_gotoc(`C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))
runtime.KeepAlive(o)`)
rtype = bl rtype = bl
chk_gotoc( chk_gotoc(
`ret := (C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))) != 0 `ret := (C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))) != 0
runtime.KeepAlive(o)
return ret`) return ret`)
rtype = voidpp rtype = voidpp
chk_gotoc( chk_gotoc(
`ret := (*unsafe.Pointer)(unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4)))) `ret := (*unsafe.Pointer)(unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))))
runtime.KeepAlive(o)
return ret`) return ret`)
rtype = nstp rtype = nstp
chk_gotoc( chk_gotoc(
`ret := &NSString{} `ret := &NSString{}
ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))) ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4)))
if ret.ptr == nil { return ret } if ret.ptr == nil { runtime.KeepAlive(o); return ret }
if ret.ptr == o.ptr { return (*NSString)(unsafe.Pointer(o)) } if ret.ptr == o.ptr { runtime.KeepAlive(o); return (*NSString)(unsafe.Pointer(o)) }
runtime.KeepAlive(o)
return ret`) return ret`)
rtype = nsop rtype = nsop
chk_gotoc( chk_gotoc(
`ret := &Id{} `ret := &Id{}
ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))) ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4)))
if ret.ptr == nil { return ret } if ret.ptr == nil { runtime.KeepAlive(o); return ret }
if ret.ptr == o.ptr { return (*Id)(unsafe.Pointer(o)) } if ret.ptr == o.ptr { runtime.KeepAlive(o); return (*Id)(unsafe.Pointer(o)) }
runtime.KeepAlive(o)
return ret`) return ret`)
ptypes[1].Variadic = true ptypes[1].Variadic = true
@ -313,8 +319,9 @@ func (o *Id) NSString() *NSString {
chk_gotoc( chk_gotoc(
`ret := &Id{} `ret := &Id{}
ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), unsafe.Pointer(&p2), (C.int)(p3), unsafe.Pointer(p4))) ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), unsafe.Pointer(&p2), (C.int)(p3), unsafe.Pointer(p4)))
if ret.ptr == nil { return ret } if ret.ptr == nil { runtime.KeepAlive(o); return ret }
if ret.ptr == o.ptr { return (*Id)(unsafe.Pointer(o)) } if ret.ptr == o.ptr { runtime.KeepAlive(o); return (*Id)(unsafe.Pointer(o)) }
runtime.KeepAlive(o)
return ret`) return ret`)
ptypes[1].Variadic = false ptypes[1].Variadic = false
@ -334,8 +341,9 @@ func (o *Id) NSString() *NSString {
} }
(*p2)[i].ptr = p2p[i] (*p2)[i].ptr = p2p[i]
} }
if ret.ptr == nil { return ret } if ret.ptr == nil { runtime.KeepAlive(o); return ret }
if ret.ptr == o.ptr { return (*Id)(unsafe.Pointer(o)) } if ret.ptr == o.ptr { runtime.KeepAlive(o); return (*Id)(unsafe.Pointer(o)) }
runtime.KeepAlive(o)
return ret`) return ret`)
snames[1] = "" snames[1] = ""
snames[2] = "p3p" snames[2] = "p3p"
@ -355,11 +363,12 @@ func (o *Id) NSString() *NSString {
} }
(*p3)[i].ptr = p3p[i] (*p3)[i].ptr = p3p[i]
} }
if ret.ptr == nil { return ret } if ret.ptr == nil { runtime.KeepAlive(o); return ret }
if ret.ptr == o.ptr { return (*Id)(unsafe.Pointer(o)) } if ret.ptr == o.ptr { runtime.KeepAlive(o); return (*Id)(unsafe.Pointer(o)) }
runtime.KeepAlive(o)
return ret`) return ret`)
chk(GoToC("myFun", "myFun", pnames, snames, rtype, ptypes, true, false, false), chk(GoToC("myFun", "myFun", pnames, snames, rtype, ptypes, true, false, false, goImports),
`ret := &Id{} `ret := &Id{}
ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (*unsafe.Pointer)(unsafe.Pointer(&p3p[0])), p4)) ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (*unsafe.Pointer)(unsafe.Pointer(&p3p[0])), p4))
(*p3) = (*p3)[:cap(*p3)] (*p3) = (*p3)[:cap(*p3)]
@ -373,7 +382,8 @@ func (o *Id) NSString() *NSString {
} }
(*p3)[i].ptr = p3p[i] (*p3)[i].ptr = p3p[i]
} }
if ret.ptr == nil { return ret } if ret.ptr == nil { runtime.KeepAlive(o); return ret }
if ret.ptr == o.ptr { return (*Id)(unsafe.Pointer(o)) } if ret.ptr == o.ptr { runtime.KeepAlive(o); return (*Id)(unsafe.Pointer(o)) }
runtime.KeepAlive(o)
return ret`) return ret`)
} }

View File

@ -112,11 +112,27 @@ func ArrayDeclarator(s string, n *Node) (string, *Node) {
} }
func FunctionDeclarator(s string, n *Node) (string, *Node) { func FunctionDeclarator(s string, n *Node) (string, *Node) {
return ChildOf(NewNode("Function"), return ChildOf(NewNode("Function"), Seq(
Parenthesized(Opt(ParameterList)), Parenthesized(Opt(ParameterList)),
ZeroOrMore(Attribute),
))(s, n)
}
func Attribute(s string, n *Node) (string, *Node) {
return Seq(
Word("__attribute__"),
ChildOf(NewNode("parens"), Parenthesized(Parenthesized(
Attr,
))),
)(s, n) )(s, n)
} }
func Attr(s string, n *Node) (string, *Node) {
return NodeNamed("Attribute", OneOf(
Word("noreturn"),
))(s, n)
}
func DirectAbstractDeclarator(s string, n *Node) (string, *Node) { func DirectAbstractDeclarator(s string, n *Node) (string, *Node) {
return OneOf( return OneOf(
ParenAbstractDeclarator, ParenAbstractDeclarator,

File diff suppressed because it is too large Load Diff