Fix handling of id and void* types. Add helper functions to convert

char* to and from Go strings. Parse block (^) types. Skip methods
with functions as parameters. Fix passing pointers go C code.
This commit is contained in:
Greg 2019-04-26 14:08:43 -04:00
parent 98e19ca726
commit 4f260dda0e
4 changed files with 104 additions and 32 deletions

View File

@ -212,7 +212,7 @@ func Start(args ProgramArgs) (err error) {
w.AddCategory(x) w.AddCategory(x)
} }
} }
w.Wrap([]string{"ClassOne"}) w.Wrap([]string{"NSString"})
return nil return nil
} }

View File

@ -42,6 +42,9 @@ func NewType(n *Node, c string) *Type {
func NewTypeFromString(t,c string) *Type { func NewTypeFromString(t,c string) *Type {
n,err := Parse(t) n,err := Parse(t)
if n.CtypeSimplified() == "id" {
n,err = Parse("NSObject*")
}
if err != nil { if err != nil {
return &Type{} return &Type{}
} }
@ -56,12 +59,12 @@ func (t *Type) String() string {
return t.Node.String() return t.Node.String()
} }
func (t *Type) Wrap() { func Wrap(s string) {
if wrapped == nil { if wrapped == nil {
wrapped = make(map[string]bool) wrapped = make(map[string]bool)
} }
// it is the pointers to this type that get wrapped // it is the pointers to this type that get wrapped
wrapped["*" + t.GoType()] = true wrapped["*" + s] = true
} }
func (t *Type) BaseType() *Type { func (t *Type) BaseType() *Type {
@ -85,6 +88,9 @@ func swapstars(s string) string {
func (t *Type) CGoType() string { func (t *Type) CGoType() string {
ct := swapstars("C." + t.CType()) ct := swapstars("C." + t.CType())
ct = strings.ReplaceAll(ct," ","_") ct = strings.ReplaceAll(ct," ","_")
if ct == "C.long_long" {
ct = "C.long" // FIXME why?
}
return ct return ct
} }
@ -124,29 +130,30 @@ func (t *Type) GoTypeDecl() string {
return t.GoInterfaceDecl() return t.GoInterfaceDecl()
} }
tp := t.BaseType() tp := t.BaseType()
return fmt.Sprintf(` gt := tp.GoType()
switch gt {
case "", "Void":
return ""
default:
return fmt.Sprintf(`
type %s %s type %s %s
`,tp.GoType(),tp.CGoType()) `,gt,tp.CGoType())
}
} }
func (t *Type) GoInterfaceDecl() string { func (t *Type) GoInterfaceDecl() string {
return _goInterfaceDecl(t.GoType()) gt := t.GoType()
} if gt[0] == '*' {
gt = gt[1:] // dereference wrapped types
func _goInterfaceDecl(c string) string {
if c[0] == '*' {
c = c[1:] // dereference wrapped types
} }
x := "" x := ""
super := Super(c) super := Super(gt)
if super == "" { if super == "" {
super = "ptr unsafe.Pointer" super = "ptr unsafe.Pointer"
} else {
x = _goInterfaceDecl(super) + "\n"
} }
return fmt.Sprintf(` return fmt.Sprintf(`
%stype %s struct { %s } %stype %s struct { %s }
`,x,c,super) `,x,gt,super)
} }
func (t *Type) CToGo(cval string) string { // cast C value to CGo func (t *Type) CToGo(cval string) string { // cast C value to CGo
@ -179,7 +186,11 @@ func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type) string {
if wrapped[pt.GoType()] { if wrapped[pt.GoType()] {
p = pn + ".ptr" p = pn + ".ptr"
} else { } else {
p = "(" + pt.CGoType() + ")(" + pn + ")" if pt.Node.IsPointer() {
p = "unsafe.Pointer(" + pn + ")"
} else {
p = "(" + pt.CGoType() + ")(" + pn + ")"
}
} }
parms = append(parms,p) parms = append(parms,p)
} }

View File

@ -30,6 +30,7 @@ func AbstractDeclarator(s string, n *Node) (string, *Node) {
Opt(Pointer), Opt(Pointer),
OneOrMore(DirectAbstractDeclarator)), OneOrMore(DirectAbstractDeclarator)),
Pointer, Pointer,
Block,
)(s,n) )(s,n)
} }
@ -134,6 +135,7 @@ func NullableAnnotation(s string, n *Node) (string, *Node) {
Word("_Null_unspecified"), Word("_Null_unspecified"),
))(s,n) ))(s,n)
} }
func Pointer(s string, n *Node) (string, *Node) { func Pointer(s string, n *Node) (string, *Node) {
return Seq( return Seq(
NodeNamed("Pointer",Lit("*")), NodeNamed("Pointer",Lit("*")),
@ -143,6 +145,14 @@ func Pointer(s string, n *Node) (string, *Node) {
)(s,n) )(s,n)
} }
//FIXME: not sure how correct this is...
func Block(s string, n *Node) (string, *Node) {
return Seq(
NodeNamed("Block",Lit("^")),
Opt(NullableAnnotation),
)(s,n)
}
func TypeQualifierList(s string, n *Node) (string, *Node) { func TypeQualifierList(s string, n *Node) (string, *Node) {
return OneOrMore(TypeQualifier)(s,n) return OneOrMore(TypeQualifier)(s,n)
} }

View File

@ -26,9 +26,10 @@ type Wrapper struct {
goStructTypes map[string]cStruct // map from gotype to struct descr. goStructTypes map[string]cStruct // map from gotype to struct descr.
goInterfaceTypes []string goInterfaceTypes []string
cCode strings.Builder // put cGo code here cCode strings.Builder // put cGo code here
goTypes strings.Builder // put Go type declarations here goTypes strings.Builder // put Go type declarations here
goCode strings.Builder // put Go code here goCode strings.Builder // put Go code here
goHelpers strings.Builder // put Go helper functions here
Processed map[string]bool Processed map[string]bool
Processed2 map[string]bool Processed2 map[string]bool
} }
@ -191,6 +192,16 @@ func (m Method) isVoid() bool {
return m.Type == "void" return m.Type == "void"
} }
//hasFunctionParam() returns true if a method has a function as a parameter.
func (m Method) hasFunctionParam() bool {
for _,p := range m.Parameters {
if p.Tp.Node.IsFunction() {
return true
}
}
return false
}
func (w Wrapper) isObject(tp string) bool { // takes a goType func (w Wrapper) isObject(tp string) bool { // takes a goType
if _,ok := w.Interfaces[tp]; ok { if _,ok := w.Interfaces[tp]; ok {
return true return true
@ -204,11 +215,11 @@ func (w Wrapper) cparamlist(m Method) string {
ret = append(ret,"void* obj") ret = append(ret,"void* obj")
} }
for _,p := range m.Parameters { for _,p := range m.Parameters {
tp := p.Type var tp string
gtp := w.goType(tp,m.Class) if p.Tp.Node.IsPointer() {
//w.goType(tp,m.Class)
if w.isObject(gtp) {
tp = "void*" tp = "void*"
} else {
tp = p.Tp.CType()
} }
ret = append(ret,fmt.Sprintf("%s %s",tp,p.Vname)) ret = append(ret,fmt.Sprintf("%s %s",tp,p.Vname))
} }
@ -257,7 +268,11 @@ func (m *Method) gpntp() ([]string,[]*types.Type,string) {
i := 0 i := 0
if !m.ClassMethod { i = 1 } if !m.ClassMethod { i = 1 }
for ; i < len(ns); i++ { for ; i < len(ns); i++ {
ret = append(ret,ns[i] + " " + tps[i].GoType()) gt := tps[i].GoType()
if gt == "*Void" {
gt = "unsafe.Pointer"
}
ret = append(ret,ns[i] + " " + gt)
} }
return ns, tps, strings.Join(ret,", ") return ns, tps, strings.Join(ret,", ")
} }
@ -363,7 +378,7 @@ func (w *Wrapper) add(name string, ns []ast.Node) {
w.AddType(name,name) // need this? w.AddType(name,name) // need this?
} }
tp := types.NewTypeFromString(name,name) tp := types.NewTypeFromString(name,name)
tp.Wrap() types.Wrap(tp.GoType())
var avail bool var avail bool
for _,c := range ns { for _,c := range ns {
switch x := c.(type) { switch x := c.(type) {
@ -477,20 +492,48 @@ func (w *Wrapper) pt2(tps ...*types.Type) {
case 0: case 0:
return return
case 1: case 1:
break w._pt2(tps[0])
default: default:
for _,tp := range tps { for _,tp := range tps {
w.pt2(tp) w.pt2(tp)
} }
return return
} }
tp := tps[0].BaseType() }
if w.Processed2[tp.GoType()] { return }
w.Processed2[tp.GoType()] = true func (w *Wrapper) _pt2(tp *types.Type) {
if tp.Node.IsFunction() { bt := tp.BaseType()
if w.Processed2[bt.GoType()] { return }
w.Processed2[bt.GoType()] = true
if bt.Node.IsFunction() {
return return
} }
w.goTypes.WriteString(tps[0].GoTypeDecl()) w.goTypes.WriteString(tp.GoTypeDecl())
if tp.GoType() == "*Char" {
w.CharHelpers()
}
super := types.Super(bt.GoType())
if super != "" {
types.Wrap(super)
pt := types.NewTypeFromString(super + "*","")
w._pt2(pt)
}
}
func (w *Wrapper) CharHelpers() {
w.goHelpers.WriteString(`
func CharFromString(s string) *Char {
return (*Char)(unsafe.Pointer(C.CString(s)))
}
func CharFromBytes(b []byte) *Char {
return (*Char)(unsafe.Pointer(C.CString(string(b))))
}
func (c *Char) String() string {
return C.GoString((*C.char)(c))
}
`)
} }
func (w *Wrapper) ProcessType(gotype string) { func (w *Wrapper) ProcessType(gotype string) {
@ -596,6 +639,9 @@ New%s() {
if m.Tp.Node.IsFunction() { if m.Tp.Node.IsFunction() {
continue continue
} }
if m.hasFunctionParam() {
continue
}
gname := strings.Title(m.Name) gname := strings.Title(m.Name)
cname := i.Name + "_" + m.Name cname := i.Name + "_" + m.Name
@ -605,9 +651,13 @@ New%s() {
ns,tps,gplist := m.gpntp() ns,tps,gplist := m.gpntp()
w.pt2(tps...) w.pt2(tps...)
w.pt2(m.Tp) w.pt2(m.Tp)
grtype := m.Tp.GoType()
if grtype == "Void" {
grtype = ""
}
w.goCode.WriteString(fmt.Sprintf(` w.goCode.WriteString(fmt.Sprintf(`
func (o *%s) %s(%s) %s { func (o *%s) %s(%s) %s {
`,i.Name,gname,gplist,m.Tp.GoType())) `,i.Name,gname,gplist,grtype))
w.goCode.WriteString( w.goCode.WriteString(
types.GoToC(cname,ns,m.Tp,tps) + "}\n\n") types.GoToC(cname,ns,m.Tp,tps) + "}\n\n")
@ -640,5 +690,6 @@ import (
) )
`) `)
fmt.Println(w.goTypes.String()) fmt.Println(w.goTypes.String())
fmt.Println(w.goHelpers.String())
fmt.Println(w.goCode.String()) fmt.Println(w.goCode.String())
} }