Handle Objective-C methods with variadic arguments.

This commit is contained in:
Greg 2019-04-29 16:14:45 -04:00
parent 57232548fa
commit d78e055008
6 changed files with 93 additions and 12 deletions

View File

@ -298,10 +298,10 @@ func Parse(fullline string) Node {
return parseWeakAttr(line) return parseWeakAttr(line)
case "WhileStmt": case "WhileStmt":
return parseWhileStmt(line) return parseWhileStmt(line)
case "...":
return parseVariadic(line)
case "NullStmt": case "NullStmt":
return nil return nil
case "...": // FIXME for variadic functions
return nil
default: default:
return parseUnknown(nodeName,line) return parseUnknown(nodeName,line)
} }

35
ast/variadic.go Normal file
View File

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

View File

@ -11,6 +11,8 @@ func main() {
c1 := n1.CapitalizedString() c1 := n1.CapitalizedString()
gs := c1.UTF8String().String() gs := c1.UTF8String().String()
fmt.Println(gs) fmt.Println(gs)
a := ns.ArrayWithObjects(n1) n2 := ns.StringWithUTF8String(ns.CharFromString("hi world"))
_ = a n3 := ns.StringWithUTF8String(ns.CharFromString("ok bye"))
a := ns.ArrayWithObjects(n1,n2,n3)
fmt.Println("Length(a) = ",a.Count())
} }

View File

@ -22,6 +22,7 @@ type conf struct {
Imports []string Imports []string
SysImports []string SysImports []string
Pragma []string Pragma []string
VaArgs int
} }
var Config conf var Config conf
@ -171,6 +172,9 @@ func Start() (err error) {
w.Import(Config.Imports) w.Import(Config.Imports)
w.SysImport(Config.SysImports) w.SysImport(Config.SysImports)
w.Pragma(Config.Pragma) w.Pragma(Config.Pragma)
if Config.VaArgs == 0 {
w.VaArgs = 16
}
for _, u := range tree { for _, u := range tree {
for _, n := range(u.Children()) { for _, n := range(u.Children()) {
switch x := n.(type) { switch x := n.(type) {

View File

@ -66,6 +66,7 @@ type Type struct {
Node *Node Node *Node
Class string Class string
ctype string ctype string
Variadic bool
} }
func NewType(n *Node, c string) *Type { 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++ { for i := 0; i < len(pnames); i++ {
pn,pt := pnames[i],ptypes[i] pn,pt := pnames[i],ptypes[i]
p := pn p := pn
if shouldWrap(pt.GoType()) || isGoInterface(pt.GoType()) { if (shouldWrap(pt.GoType()) || isGoInterface(pt.GoType())) && !pt.Variadic {
p = pn + ".Ptr()" p = pn + ".Ptr()"
} else { } else {
if pt.Node.IsPointer() { switch {
case pt.Variadic:
p = "unsafe.Pointer(&" + p + ")"
case pt.Node.IsPointer():
p = "unsafe.Pointer(" + pn + ")" p = "unsafe.Pointer(" + pn + ")"
} else { default:
p = "(" + pt.CGoType() + ")(" + pn + ")" p = "(" + pt.CGoType() + ")(" + pn + ")"
} }
} }

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"path" "path"
"strconv"
"strings" "strings"
"gitlab.wow.st/gmp/nswrap/ast" "gitlab.wow.st/gmp/nswrap/ast"
@ -23,6 +24,7 @@ type Wrapper struct {
goCode strings.Builder // put Go code here goCode strings.Builder // put Go code here
goHelpers strings.Builder // put Go helper functions here goHelpers strings.Builder // put Go helper functions here
Processed map[string]bool Processed map[string]bool
VaArgs int
} }
func NewWrapper(debug bool) *Wrapper { func NewWrapper(debug bool) *Wrapper {
@ -31,6 +33,7 @@ func NewWrapper(debug bool) *Wrapper {
ret := &Wrapper{ ret := &Wrapper{
Interfaces: map[string]Interface{}, Interfaces: map[string]Interface{},
Processed: map[string]bool{}, Processed: map[string]bool{},
VaArgs: 16,
} }
ret.cCode.WriteString(`/* ret.cCode.WriteString(`/*
#cgo CFLAGS: -x objective-c #cgo CFLAGS: -x objective-c
@ -102,7 +105,7 @@ func (w Wrapper) cparamlist(m Method) string {
} }
for _,p := range m.Parameters { for _,p := range m.Parameters {
var tp string var tp string
if p.Type.Node.IsPointer() { if p.Type.Node.IsPointer() || p.Type.Variadic {
tp = "void*" tp = "void*"
} else { } else {
tp = p.Type.CType() tp = p.Type.CType()
@ -119,13 +122,22 @@ func (w Wrapper) objcparamlist(m Method) string {
first := true first := true
ret := []string{} ret := []string{}
for _,p := range m.Parameters { for _,p := range m.Parameters {
if first { if first && !p.Type.Variadic {
ret = append(ret,m.Name + ":" + p.Vname) ret = append(ret,m.Name + ":" + p.Vname)
first = false first = false
} else {
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 { } else {
ret = append(ret, p.Pname + ":" + p.Vname) ret = append(ret, p.Pname + ":" + p.Vname)
} }
} }
}
return strings.Join(ret," ") return strings.Join(ret," ")
} }
@ -158,6 +170,10 @@ func (m *Method) gpntp() ([]string,[]*types.Type,string) {
if gt == "*Void" { if gt == "*Void" {
gt = "unsafe.Pointer" gt = "unsafe.Pointer"
} }
if tps[i].Variadic {
gt = "..." + gt
ns[i] = ns[i] + "s"
}
ret = append(ret,ns[i] + " " + gt) ret = append(ret,ns[i] + " " + gt)
} }
return ns, tps, strings.Join(ret,", ") 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) ret = append(ret,p)
j++ j++
case *ast.Variadic:
ret[j-1].Type.Variadic = true
case *ast.AvailabilityAttr: case *ast.AvailabilityAttr:
avail = append(avail, avail = append(avail,
AvailAttr{ AvailAttr{
@ -432,6 +450,18 @@ New%s() {
w.goCode.WriteString(fmt.Sprintf(` w.goCode.WriteString(fmt.Sprintf(`
func %s(%s) %s { func %s(%s) %s {
`,gname,gplist,grtype)) `,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( w.goCode.WriteString(
types.GoToC(cname,ns,m.Type,tps) + "}\n\n") types.GoToC(cname,ns,m.Type,tps) + "}\n\n")
@ -448,8 +478,14 @@ func %s(%s) %s {
w.cCode.WriteString(fmt.Sprintf(` w.cCode.WriteString(fmt.Sprintf(`
%s %s
%s(%s) { %s(%s) {
%s[%s %s]; `, cmtype, cname, w.cparamlist(m)))
}`, cmtype, cname, w.cparamlist(m), cret, cobj, w.objcparamlist(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") of.WriteString("package " + w.Package + "\n\n")