diff --git a/.gitignore b/.gitignore index 50f89a4..3e9c3fe 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ program examples/foundation/foundation examples/foundation/ns examples/simple/simple -examples/simple/simple/ClassOne +examples/simple/ClassOne diff --git a/examples/foundation/main.go b/examples/foundation/main.go new file mode 100644 index 0000000..9db7d22 --- /dev/null +++ b/examples/foundation/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + + "gitlab.wow.st/gmp/nswrap/examples/foundation/ns" +) + +func main() { + n1 := ns.StringWithUTF8String(ns.CharFromString("hi there")) + c1 := n1.CapitalizedString() + gs := c1.UTF8String().String() + fmt.Println(gs) + a := ns.ArrayWithObjects(n1) + _ = a +} diff --git a/examples/simple/ClassOne/simple.h b/examples/simple/ClassOne/simple.h index 52a0acb..67cb248 100644 --- a/examples/simple/ClassOne/simple.h +++ b/examples/simple/ClassOne/simple.h @@ -18,5 +18,11 @@ struct stru {int a,b;}; - (int) hi2:(struct stru*)in; - (struct stru) nstru1; - (struct stru*) nstru2; +- (void) hi:(id)in; +- (void) hi3:(id)in; @end +@interface ClassTwo : ClassOne +{ } +- (ClassTwo*) init; +@end diff --git a/examples/simple/ClassOne/simple.m b/examples/simple/ClassOne/simple.m index 6273f92..9570ffa 100644 --- a/examples/simple/ClassOne/simple.m +++ b/examples/simple/ClassOne/simple.m @@ -54,6 +54,19 @@ ret->b = 10; return ret; } - +- (void) hi:(id)in +{ + NSLog(@"hi"); +} +- (void) hi3:(id)in +{ + NSLog(@"hi"); +} @end +@implementation ClassTwo +- (ClassTwo*) init +{ + return [super init]; +} +@end diff --git a/examples/simple/nswrap.toml b/examples/simple/nswrap.toml index dde6dcb..e28fd80 100644 --- a/examples/simple/nswrap.toml +++ b/examples/simple/nswrap.toml @@ -1,4 +1,4 @@ Package = "ClassOne" InputFiles = [ "ClassOne/simple.h" ] -Classes = [ "ClassOne" ] +Classes = [ "ClassOne","ClassTwo" ] Imports = [ "simple.h" ] diff --git a/main.go b/main.go index e3eb108..30cce57 100644 --- a/main.go +++ b/main.go @@ -153,9 +153,9 @@ func Start() (err error) { if err != nil { // If clang fails it still prints out the AST, so we have to run it // again to get the real error. - errBody, _ := exec.Command("clang", cargs...).CombinedOutput() +// errBody, _ := exec.Command("clang", cargs...).CombinedOutput() - panic("clang failed: " + err.Error() + ":\n\n" + string(errBody)) + panic("clang failed: " + err.Error() + ":\n\n") } lines := readAST(astPP) diff --git a/types/convert.go b/types/convert.go index a623689..3f76d70 100644 --- a/types/convert.go +++ b/types/convert.go @@ -12,6 +12,26 @@ var super map[string]string //go struct. var wrapped map[string]bool +func shouldWrap(gt string) bool { + if wrapped == nil { + wrapped = make(map[string]bool) + return false + } + return gt != "" && gt[0] == '*' && wrapped[gt[1:]] +} + +//goInterfaces records the names of top level Go interfaces. Pointers to these +//are dereferenced to bare interface names. +var goInterfaces map[string]bool + +func isGoInterface(gt string) bool { + if goInterfaces == nil { + goInterfaces = make(map[string]bool) + return false + } + return goInterfaces[gt] +} + //TypeParameters maps, for each class, a TypedefName to a type, representing //the Objective-C type parameters for that class var TypeParameters map[string]map[string]string @@ -109,9 +129,6 @@ func (t *Type) BaseType() *Type { t.Node.BaseType(), t.Class, ) -// if ret.CType() == ret.Class + " *" { // "instancename" -// ret.ctype = ret.Class -// } return ret } @@ -141,6 +158,9 @@ func _goType(ct string) string { ct = strings.Title(ct) ct = strings.ReplaceAll(ct," ","") ct = strings.ReplaceAll(ct,"Struct","") + if len(ct) > 0 && ct[0] == '*' && isGoInterface(ct[1:]) { + return ct[1:] + } return ct } @@ -208,13 +228,26 @@ func (t *Type) GoInterfaceDecl() string { gt = gt[1:] // dereference wrapped types } super := Super(gt) + if goInterfaces == nil { + goInterfaces = make(map[string]bool) + } if super == "" { - super = "ptr unsafe.Pointer" + goInterfaces[gt] = true + return fmt.Sprintf(` +//%s (%s) +type %s interface { + Ptr() unsafe.Pointer +} +`,t.Node.Ctype(),t.BaseType().GoType(),gt) + } + if isGoInterface(super) { + super = "Id" } return fmt.Sprintf(` //%s (%s) type %s struct { %s } -`,t.Node.Ctype(),t.BaseType().GoType(),gt,super) +func (o *%s) Ptr() unsafe.Pointer { return o.ptr } +`,t.Node.Ctype(),t.BaseType().GoType(),gt,super,gt) } func (t *Type) IsFunction() bool { @@ -242,12 +275,15 @@ func (t *Type) CToGo(cval string) string { // cast C value to CGo func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type) string { var ret strings.Builder rt := rtype.CType() - wrap := func(gt string) bool { - return gt != "" && gt[0] == '*' && wrapped[gt[1:]] - } if rt != "void" { - if wrap(rtype.GoType()) { - ret.WriteString(" ret := &" + rtype.GoType()[1:] + "{}\n") + rtgt := rtype.GoType() + if shouldWrap(rtgt) || isGoInterface(rtgt) { + if isGoInterface(rtgt) { + rtgt = "Id" + } else { + rtgt = rtgt[1:] + } + ret.WriteString(" ret := &" + rtgt + "{}\n") ret.WriteString(" ret.ptr = unsafe.Pointer(") } else { ret.WriteString(" return (" + rtype.GoType() + ")(") @@ -261,8 +297,8 @@ func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type) string { for i := 0; i < len(pnames); i++ { pn,pt := pnames[i],ptypes[i] p := pn - if wrap(pt.GoType()) { - p = pn + ".ptr" + if shouldWrap(pt.GoType()) || isGoInterface(pt.GoType()) { + p = pn + ".Ptr()" } else { if pt.Node.IsPointer() { p = "unsafe.Pointer(" + pn + ")" @@ -275,7 +311,7 @@ func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type) string { ret.WriteString(strings.Join(parms,", ")) ret.WriteString(")") if rt != "void" { - if wrap(rtype.GoType()) { + if shouldWrap(rtype.GoType()) || isGoInterface(rtype.GoType()) { ret.WriteString(`) return ret `) diff --git a/wrap/main.go b/wrap/main.go index 0dbffeb..d2346ec 100644 --- a/wrap/main.go +++ b/wrap/main.go @@ -35,6 +35,10 @@ func NewWrapper(debug bool) *Wrapper { ret.cCode.WriteString(`/* #cgo CFLAGS: -x objective-c #cgo LDFLAGS: -framework Foundation +`) + ret.goTypes.WriteString(` +type Id struct { ptr unsafe.Pointer } +func (o *Id) Ptr() unsafe.Pointer { return o.ptr } `) return ret } @@ -331,12 +335,12 @@ func (w *Wrapper) processType(tp *types.Type) { if bt.IsFunction() { return } - w.goTypes.WriteString(bt.GoTypeDecl()) super := types.Super(gt) if super != "" { types.Wrap(super) w.processType(types.NewTypeFromString(super,"")) } + w.goTypes.WriteString(bt.GoTypeDecl()) } func (w *Wrapper) CharHelpers() {