Make a Go Interface instead of a struct for top level objects.

Use a new struct Id as a concrete version of that type.
This commit is contained in:
Greg 2019-04-29 11:46:48 -04:00
parent c0c17e88d1
commit c03e37bd54
8 changed files with 94 additions and 19 deletions

2
.gitignore vendored
View File

@ -5,4 +5,4 @@ program
examples/foundation/foundation examples/foundation/foundation
examples/foundation/ns examples/foundation/ns
examples/simple/simple examples/simple/simple
examples/simple/simple/ClassOne examples/simple/ClassOne

View File

@ -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
}

View File

@ -18,5 +18,11 @@ struct stru {int a,b;};
- (int) hi2:(struct stru*)in; - (int) hi2:(struct stru*)in;
- (struct stru) nstru1; - (struct stru) nstru1;
- (struct stru*) nstru2; - (struct stru*) nstru2;
- (void) hi:(id)in;
- (void) hi3:(id)in;
@end @end
@interface ClassTwo : ClassOne
{ }
- (ClassTwo*) init;
@end

View File

@ -54,6 +54,19 @@
ret->b = 10; ret->b = 10;
return ret; return ret;
} }
- (void) hi:(id)in
{
NSLog(@"hi");
}
- (void) hi3:(id)in
{
NSLog(@"hi");
}
@end @end
@implementation ClassTwo
- (ClassTwo*) init
{
return [super init];
}
@end

View File

@ -1,4 +1,4 @@
Package = "ClassOne" Package = "ClassOne"
InputFiles = [ "ClassOne/simple.h" ] InputFiles = [ "ClassOne/simple.h" ]
Classes = [ "ClassOne" ] Classes = [ "ClassOne","ClassTwo" ]
Imports = [ "simple.h" ] Imports = [ "simple.h" ]

View File

@ -153,9 +153,9 @@ func Start() (err error) {
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.
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) lines := readAST(astPP)

View File

@ -12,6 +12,26 @@ var super map[string]string
//go struct. //go struct.
var wrapped map[string]bool 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 //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
@ -109,9 +129,6 @@ func (t *Type) BaseType() *Type {
t.Node.BaseType(), t.Node.BaseType(),
t.Class, t.Class,
) )
// if ret.CType() == ret.Class + " *" { // "instancename"
// ret.ctype = ret.Class
// }
return ret return ret
} }
@ -141,6 +158,9 @@ func _goType(ct string) string {
ct = strings.Title(ct) ct = strings.Title(ct)
ct = strings.ReplaceAll(ct," ","") ct = strings.ReplaceAll(ct," ","")
ct = strings.ReplaceAll(ct,"Struct","") ct = strings.ReplaceAll(ct,"Struct","")
if len(ct) > 0 && ct[0] == '*' && isGoInterface(ct[1:]) {
return ct[1:]
}
return ct return ct
} }
@ -208,13 +228,26 @@ func (t *Type) GoInterfaceDecl() string {
gt = gt[1:] // dereference wrapped types gt = gt[1:] // dereference wrapped types
} }
super := Super(gt) super := Super(gt)
if goInterfaces == nil {
goInterfaces = make(map[string]bool)
}
if super == "" { 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(` return fmt.Sprintf(`
//%s (%s) //%s (%s)
type %s struct { %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 { 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 { func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type) string {
var ret strings.Builder var ret strings.Builder
rt := rtype.CType() rt := rtype.CType()
wrap := func(gt string) bool {
return gt != "" && gt[0] == '*' && wrapped[gt[1:]]
}
if rt != "void" { if rt != "void" {
if wrap(rtype.GoType()) { rtgt := rtype.GoType()
ret.WriteString(" ret := &" + rtype.GoType()[1:] + "{}\n") 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(") ret.WriteString(" ret.ptr = unsafe.Pointer(")
} else { } else {
ret.WriteString(" return (" + rtype.GoType() + ")(") 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++ { for i := 0; i < len(pnames); i++ {
pn,pt := pnames[i],ptypes[i] pn,pt := pnames[i],ptypes[i]
p := pn p := pn
if wrap(pt.GoType()) { if shouldWrap(pt.GoType()) || isGoInterface(pt.GoType()) {
p = pn + ".ptr" p = pn + ".Ptr()"
} else { } else {
if pt.Node.IsPointer() { if pt.Node.IsPointer() {
p = "unsafe.Pointer(" + pn + ")" 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(strings.Join(parms,", "))
ret.WriteString(")") ret.WriteString(")")
if rt != "void" { if rt != "void" {
if wrap(rtype.GoType()) { if shouldWrap(rtype.GoType()) || isGoInterface(rtype.GoType()) {
ret.WriteString(`) ret.WriteString(`)
return ret return ret
`) `)

View File

@ -35,6 +35,10 @@ func NewWrapper(debug bool) *Wrapper {
ret.cCode.WriteString(`/* ret.cCode.WriteString(`/*
#cgo CFLAGS: -x objective-c #cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation #cgo LDFLAGS: -framework Foundation
`)
ret.goTypes.WriteString(`
type Id struct { ptr unsafe.Pointer }
func (o *Id) Ptr() unsafe.Pointer { return o.ptr }
`) `)
return ret return ret
} }
@ -331,12 +335,12 @@ func (w *Wrapper) processType(tp *types.Type) {
if bt.IsFunction() { if bt.IsFunction() {
return return
} }
w.goTypes.WriteString(bt.GoTypeDecl())
super := types.Super(gt) super := types.Super(gt)
if super != "" { if super != "" {
types.Wrap(super) types.Wrap(super)
w.processType(types.NewTypeFromString(super,"")) w.processType(types.NewTypeFromString(super,""))
} }
w.goTypes.WriteString(bt.GoTypeDecl())
} }
func (w *Wrapper) CharHelpers() { func (w *Wrapper) CharHelpers() {