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.Wrap([]string{"ClassOne"})
w.Wrap([]string{"NSString"})
return nil
}

View File

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

View File

@ -30,6 +30,7 @@ func AbstractDeclarator(s string, n *Node) (string, *Node) {
Opt(Pointer),
OneOrMore(DirectAbstractDeclarator)),
Pointer,
Block,
)(s,n)
}
@ -134,6 +135,7 @@ func NullableAnnotation(s string, n *Node) (string, *Node) {
Word("_Null_unspecified"),
))(s,n)
}
func Pointer(s string, n *Node) (string, *Node) {
return Seq(
NodeNamed("Pointer",Lit("*")),
@ -143,6 +145,14 @@ func Pointer(s string, n *Node) (string, *Node) {
)(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) {
return OneOrMore(TypeQualifier)(s,n)
}

View File

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