From d78e0550089b5f68396da113028bdf7153107c22 Mon Sep 17 00:00:00 2001 From: Greg Date: Mon, 29 Apr 2019 16:14:45 -0400 Subject: [PATCH] Handle Objective-C methods with variadic arguments. --- ast/ast.go | 4 ++-- ast/variadic.go | 35 ++++++++++++++++++++++++++++ examples/foundation/main.go | 6 +++-- main.go | 4 ++++ types/convert.go | 10 +++++--- wrap/main.go | 46 +++++++++++++++++++++++++++++++++---- 6 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 ast/variadic.go diff --git a/ast/ast.go b/ast/ast.go index 19a6dfc..c8fec79 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -298,10 +298,10 @@ func Parse(fullline string) Node { return parseWeakAttr(line) case "WhileStmt": return parseWhileStmt(line) + case "...": + return parseVariadic(line) case "NullStmt": return nil - case "...": // FIXME for variadic functions - return nil default: return parseUnknown(nodeName,line) } diff --git a/ast/variadic.go b/ast/variadic.go new file mode 100644 index 0000000..9df7875 --- /dev/null +++ b/ast/variadic.go @@ -0,0 +1,35 @@ +package ast + +// Variadic node indicates an ellipsis (...) in the Clang AST. +type Variadic struct { + ChildNodes []Node +} + +func parseVariadic(line string) *Variadic { + return &Variadic{ + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *Variadic) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *Variadic) Address() Address { + return Address(0) +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *Variadic) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *Variadic) Position() Position { + return Position{} +} diff --git a/examples/foundation/main.go b/examples/foundation/main.go index 9db7d22..552cd1a 100644 --- a/examples/foundation/main.go +++ b/examples/foundation/main.go @@ -11,6 +11,8 @@ func main() { c1 := n1.CapitalizedString() gs := c1.UTF8String().String() fmt.Println(gs) - a := ns.ArrayWithObjects(n1) - _ = a + n2 := ns.StringWithUTF8String(ns.CharFromString("hi world")) + n3 := ns.StringWithUTF8String(ns.CharFromString("ok bye")) + a := ns.ArrayWithObjects(n1,n2,n3) + fmt.Println("Length(a) = ",a.Count()) } diff --git a/main.go b/main.go index 30cce57..8694f2b 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,7 @@ type conf struct { Imports []string SysImports []string Pragma []string + VaArgs int } var Config conf @@ -171,6 +172,9 @@ func Start() (err error) { w.Import(Config.Imports) w.SysImport(Config.SysImports) w.Pragma(Config.Pragma) + if Config.VaArgs == 0 { + w.VaArgs = 16 + } for _, u := range tree { for _, n := range(u.Children()) { switch x := n.(type) { diff --git a/types/convert.go b/types/convert.go index 008ac38..5bbb156 100644 --- a/types/convert.go +++ b/types/convert.go @@ -66,6 +66,7 @@ type Type struct { Node *Node Class string ctype string + Variadic bool } func NewType(n *Node, c string) *Type { @@ -292,12 +293,15 @@ 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 shouldWrap(pt.GoType()) || isGoInterface(pt.GoType()) { + if (shouldWrap(pt.GoType()) || isGoInterface(pt.GoType())) && !pt.Variadic { p = pn + ".Ptr()" } else { - if pt.Node.IsPointer() { + switch { + case pt.Variadic: + p = "unsafe.Pointer(&" + p + ")" + case pt.Node.IsPointer(): p = "unsafe.Pointer(" + pn + ")" - } else { + default: p = "(" + pt.CGoType() + ")(" + pn + ")" } } diff --git a/wrap/main.go b/wrap/main.go index d2346ec..93e1eaa 100644 --- a/wrap/main.go +++ b/wrap/main.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "path" + "strconv" "strings" "gitlab.wow.st/gmp/nswrap/ast" @@ -23,6 +24,7 @@ type Wrapper struct { goCode strings.Builder // put Go code here goHelpers strings.Builder // put Go helper functions here Processed map[string]bool + VaArgs int } func NewWrapper(debug bool) *Wrapper { @@ -31,6 +33,7 @@ func NewWrapper(debug bool) *Wrapper { ret := &Wrapper{ Interfaces: map[string]Interface{}, Processed: map[string]bool{}, + VaArgs: 16, } ret.cCode.WriteString(`/* #cgo CFLAGS: -x objective-c @@ -102,7 +105,7 @@ func (w Wrapper) cparamlist(m Method) string { } for _,p := range m.Parameters { var tp string - if p.Type.Node.IsPointer() { + if p.Type.Node.IsPointer() || p.Type.Variadic { tp = "void*" } else { tp = p.Type.CType() @@ -119,11 +122,20 @@ func (w Wrapper) objcparamlist(m Method) string { first := true ret := []string{} for _,p := range m.Parameters { - if first { + if first && !p.Type.Variadic { ret = append(ret,m.Name + ":" + p.Vname) first = false } else { - ret = append(ret, p.Pname + ":" + p.Vname) + if p.Type.Variadic { + str := []string{m.Name + ":arr[0]"} + for i := 1; i < w.VaArgs; i++ { + str = append(str,"arr["+strconv.Itoa(i)+"]") + } + str = append(str,"nil") + ret = append(ret, strings.Join(str,", ")) + } else { + ret = append(ret, p.Pname + ":" + p.Vname) + } } } return strings.Join(ret," ") @@ -158,6 +170,10 @@ func (m *Method) gpntp() ([]string,[]*types.Type,string) { if gt == "*Void" { gt = "unsafe.Pointer" } + if tps[i].Variadic { + gt = "..." + gt + ns[i] = ns[i] + "s" + } ret = append(ret,ns[i] + " " + gt) } return ns, tps, strings.Join(ret,", ") @@ -266,6 +282,8 @@ func (w *Wrapper) GetParms(n *ast.ObjCMethodDecl,class string) ([]Parameter,bool } ret = append(ret,p) j++ + case *ast.Variadic: + ret[j-1].Type.Variadic = true case *ast.AvailabilityAttr: avail = append(avail, AvailAttr{ @@ -432,6 +450,18 @@ New%s() { w.goCode.WriteString(fmt.Sprintf(` func %s(%s) %s { `,gname,gplist,grtype)) + lparm := len(tps)-1 + if len(tps) > 0 && tps[lparm].Variadic { + vn := ns[lparm] + vn = vn[:len(vn)-1] + ns[lparm] = vn + w.goCode.WriteString(fmt.Sprintf( +` var %s [%d]unsafe.Pointer + for i,o := range %ss { + %s[i] = o.Ptr() + } +`,vn,w.VaArgs,vn,vn)) + } w.goCode.WriteString( types.GoToC(cname,ns,m.Type,tps) + "}\n\n") @@ -448,8 +478,14 @@ func %s(%s) %s { w.cCode.WriteString(fmt.Sprintf(` %s %s(%s) { - %s[%s %s]; -}`, cmtype, cname, w.cparamlist(m), cret, cobj, w.objcparamlist(m))) +`, cmtype, cname, w.cparamlist(m))) + if len(tps) > 0 && tps[lparm].Variadic { + w.cCode.WriteString(fmt.Sprintf( +` %s* arr = %s; +`, tps[lparm].CType(), ns[lparm])) + } + w.cCode.WriteString(fmt.Sprintf(` %s[%s %s]; +}`, cret, cobj, w.objcparamlist(m))) } } of.WriteString("package " + w.Package + "\n\n")