Add type conversion functions to types package. Start moving the

wrapper to the new type system. Intermediate commit before I rip
out the old stuff, not working yet.
This commit is contained in:
Greg 2019-04-26 09:04:53 -04:00
parent 885658b67b
commit fb21881a8b
5 changed files with 231 additions and 15 deletions

179
types/convert.go Normal file
View File

@ -0,0 +1,179 @@
package types
import (
"fmt"
"strings"
)
var super map[string]string
func Super(c string) string {
if super == nil {
super = make(map[string]string)
}
return super[c]
}
func SetSuper(c, p string) {
if super == nil {
super = make(map[string]string)
}
super[c] = p
}
type Type struct {
Node *Node
Class string
ctype string
wrapped bool
}
func NewType(n *Node, c string) *Type {
return &Type{
Node: n,
Class: c,
ctype: "",
}
}
func NewTypeFromString(t,c string) *Type {
n,err := Parse(t)
if err != nil {
return &Type{}
}
return &Type{
Node: n,
Class: c,
ctype: "",
}
}
func (t *Type) String() string {
return t.Node.String()
}
func (t *Type) Wrap() *Type {
t.wrapped = true
return t
}
func (t *Type) BaseType() *Type {
ret := NewType(
t.Node.BaseType(),
t.Class,
)
if ret.CType() == ret.Class + " *" { // "instancename"
ret.ctype = ret.Class
}
return ret
}
func swapstars(s string) string {
for i := len(s) - 1; i > 0 && s[i] == '*'; {
s = "*" + s[:i]
}
return strings.TrimSpace(s)
}
func (t *Type) CGoType() string {
ct := swapstars("C." + t.CType())
ct = strings.ReplaceAll(ct," ","_")
return ct
}
func (t *Type) GoType() string {
ct := swapstars(t.CType())
ct = strings.Title(ct)
ct = strings.ReplaceAll(ct," ","")
ct = strings.ReplaceAll(ct,"Struct","")
return ct
}
func (t *Type) CType() string {
if t.ctype != "" { // cache
return t.ctype
}
ct := t.Node.CtypeSimplified()
ct = strings.ReplaceAll(ct,"instancename",t.Class)
ct = strings.ReplaceAll(ct,"instancetype",t.Class + " *")
if len(ct) > 1 && ct[:2] == "id" {
ct = "NSObject *" + ct[2:]
}
if len(ct) > 11 {
if ct[:12] == "instancename" { ct = t.Class }
if ct[:12] == "instancetype" { ct = t.Class + " *" }
}
t.ctype = ct
return ct
}
func (t *Type) GoTypeDecl() string {
if t.wrapped {
return t.GoInterfaceDecl()
}
return fmt.Sprintf(`
type %s %s
`,t.GoType(),t.CGoType())
}
func (t *Type) GoInterfaceDecl() string {
super := Super(t.Class)
if super == "" {
super = "ptr unsafe.Pointer"
}
return fmt.Sprintf(`
type %s struct { %s }
`,t.GoType(), super)
}
func (t *Type) CToGo(cval string) string { // cast C value to CGo
if t.Node.IsPointer() {
cval = "unsafe.Pointer(" + cval + ")"
}
return fmt.Sprintf("(%s)(%s)",t.GoType(),cval)
}
// Call a C function from Go with a given return type and parameter types
func GoToC(name string, pnames []string, rtype *Type, ptypes []*Type) string {
var ret strings.Builder
rt := rtype.CType()
if rt != "void" {
if rtype.wrapped {
ret.WriteString("ret := &" + rtype.GoType()[1:] + "{}\n")
ret.WriteString("ret.ptr = unsafe.Pointer(")
} else {
ret.WriteString("return (" + rtype.GoType() + ")(")
if rtype.Node.IsPointer() {
ret.WriteString("unsafe.Pointer(")
}
}
}
ret.WriteString("C." + name + "(")
parms := []string{}
for i := 0; i < len(pnames); i++ {
pn,pt := pnames[i],ptypes[i]
p := pn
if pt.wrapped {
p = pn + ".ptr"
} else {
p = "(" + pt.CGoType() + ")(" + pn + ")"
}
parms = append(parms,p)
}
ret.WriteString(strings.Join(parms,", "))
ret.WriteString(")")
if rt != "void" {
if rtype.wrapped {
ret.WriteString(`)
return ret
`)
} else {
ret.WriteString(")")
if rtype.Node.IsPointer() {
ret.WriteString(")")
}
}
}
return ret.String()
}

View File

@ -96,7 +96,7 @@ func (n *Node) PointsTo() *Node {
//IsPointer returns true if the node is a pointer //IsPointer returns true if the node is a pointer
func (n *Node) IsPointer() bool { func (n *Node) IsPointer() bool {
return n.PointsTo != nil return n.PointsTo() != nil
} }
//ArrayOf, when called on an array node returns a node describing the type //ArrayOf, when called on an array node returns a node describing the type

View File

@ -86,8 +86,8 @@ func (n *Node) _Ctype(ignore map[string]bool) string {
} }
var ret strings.Builder var ret strings.Builder
childStrings := func(n *Node) []string { childStrings := func(n *Node) []string {
if n == nil { return []string{} }
ret := []string{} ret := []string{}
if n == nil { return ret }
for _,c := range n.Children { for _,c := range n.Children {
if x := c._Ctype(ignore); x != "" { if x := c._Ctype(ignore); x != "" {
ret = append(ret, x) ret = append(ret, x)

View File

@ -19,6 +19,7 @@ type cStruct struct {
type Wrapper struct { type Wrapper struct {
Interfaces map[string]Interface Interfaces map[string]Interface
Tps map[string]*types.Node
Types map[string]string Types map[string]string
gtMap map[string]string gtMap map[string]string
ctMap map[string]*types.Node // map from go type as a string. ctMap map[string]*types.Node // map from go type as a string.
@ -72,10 +73,14 @@ func (w *Wrapper) AddType(t, class string) {
if _,ok := w.Interfaces[nt]; !ok { // not an interface if _,ok := w.Interfaces[nt]; !ok { // not an interface
return return
} }
w.Types[nt] = t
} }
func (w *Wrapper) goType(t,class string) string { func (w *Wrapper) goType(t,class string) string {
if len(t) > 1 && t[:2] == "id" { t = "NSObject *" }
if len(t) > 11 {
if t[:12] == "instancename" { t = class }
if t[:12] == "instancetype" { t = class + " *" }
}
n,err := types.Parse(t) n,err := types.Parse(t)
if err != nil { if err != nil {
//fmt.Printf("Cannot parse type %s\n",t) //fmt.Printf("Cannot parse type %s\n",t)
@ -117,14 +122,12 @@ func (w *Wrapper) goType(t,class string) string {
if x := n.ArrayOf(); x != nil { if x := n.ArrayOf(); x != nil {
pt := x.CtypeSimplified() pt := x.CtypeSimplified()
w.AddType(pt,class) w.AddType(pt,class)
ret = w.goType(pt,class) + "Arr" ret = "[]" + w.goType(pt,class)
//fmt.Printf("goType(): %s -> %s\n",t,ret) //fmt.Printf("goType(): %s -> %s\n",t,ret)
w.gtMap[ct] = ret w.gtMap[ct] = ret
w.ctMap[ret] = n w.ctMap[ret] = n
return ret return ret
} }
if ct == "id" { ct = "NSObject" }
if ct == "instancename" { ct = class }
if bt,ok := builtinTypes[ct]; ok { if bt,ok := builtinTypes[ct]; ok {
ct = bt ct = bt
} }
@ -134,6 +137,7 @@ func (w *Wrapper) goType(t,class string) string {
w.gtMap[ct] = ct w.gtMap[ct] = ct
w.goInterfaceTypes = append(w.goInterfaceTypes,ct) w.goInterfaceTypes = append(w.goInterfaceTypes,ct)
w.ctMap[ct] = n w.ctMap[ct] = n
w.Types[ct] = t
return ct return ct
} }
if n.IsStruct() { if n.IsStruct() {
@ -183,14 +187,17 @@ func NewWrapper(debug bool) *Wrapper {
type Property struct { type Property struct {
Name, Type, Attr string Name, Type, Attr string
Tp *types.Type
} }
type Parameter struct { type Parameter struct {
Pname, Vname, Type string Pname, Vname, Type string
Tp *types.Type
} }
type Method struct { type Method struct {
Name, Type, Class string Name, Type, Class string
Tp *types.Type
ClassMethod bool ClassMethod bool
Parameters []Parameter Parameters []Parameter
} }
@ -246,6 +253,20 @@ var goreserved map[string]bool = map[string]bool{
"range": true, "range": true,
} }
func gpntp(m Method) ([]string,[]*types.Type) {
ns := []string{}
tps := []*types.Type{}
for _,p := range m.Parameters {
gname := p.Vname
if goreserved[gname] {
gname = gname + "_"
}
ns = append(ns,gname)
tps = append(tps,p.Tp)
}
return ns,tps
}
func (w Wrapper) goparamlist(m Method) (string,[]string,bool) { func (w Wrapper) goparamlist(m Method) (string,[]string,bool) {
ret := []string{} ret := []string{}
tps := []string{} tps := []string{}
@ -344,7 +365,7 @@ func (w *Wrapper) add(name string, ns []ast.Node) {
Properties: map[string]Property{}, Properties: map[string]Property{},
Methods: map[string]Method{}, Methods: map[string]Method{},
} }
w.AddType(name,name) w.AddType(name,name) // need this?
} }
var avail bool var avail bool
for _,c := range ns { for _,c := range ns {
@ -354,6 +375,7 @@ func (w *Wrapper) add(name string, ns []ast.Node) {
p := Property{ p := Property{
Name: x.Name, Name: x.Name,
Type: x.Type, Type: x.Type,
Tp: types.NewTypeFromString(x.Type,name),
} }
//_,avail = w.GetParms(x,name) // TODO //_,avail = w.GetParms(x,name) // TODO
//if avail { //if avail {
@ -365,6 +387,7 @@ func (w *Wrapper) add(name string, ns []ast.Node) {
m := Method{ m := Method{
Name: x.Name, Name: x.Name,
Type: x.Type, Type: x.Type,
Tp: types.NewTypeFromString(x.Type,name),
Class: name, Class: name,
ClassMethod: x.ClassMethod, ClassMethod: x.ClassMethod,
} }
@ -379,6 +402,7 @@ func (w *Wrapper) add(name string, ns []ast.Node) {
if x.Super { if x.Super {
//fmt.Printf("ast.ObjCInterface: %s inherits from %s\n",name,x.Name) //fmt.Printf("ast.ObjCInterface: %s inherits from %s\n",name,x.Name)
i.Super = x.Name i.Super = x.Name
types.SetSuper(name,x.Name)
} }
case *ast.Unknown: case *ast.Unknown:
//fmt.Printf("(*ast.Unkonwn %s: %s)\n",x.Name,x.Content) //fmt.Printf("(*ast.Unkonwn %s: %s)\n",x.Name,x.Content)
@ -409,6 +433,7 @@ func (w *Wrapper) GetParms(n *ast.ObjCMethodDecl,class string) ([]Parameter,bool
Pname: n.Parameters[j], Pname: n.Parameters[j],
Vname: x.Name, Vname: x.Name,
Type: x.Type, Type: x.Type,
Tp: types.NewTypeFromString(x.Name,class),
} }
ret = append(ret,p) ret = append(ret,p)
j++ j++
@ -456,6 +481,10 @@ func (w *Wrapper) ProcessType(gotype string) {
if gotype[0] == '*' { if gotype[0] == '*' {
gotype = gotype[1:] gotype = gotype[1:]
} }
if w.Processed[gotype] {
return
}
w.Processed[gotype] = true
if _,ok := gobuiltinTypes[gotype]; ok { if _,ok := gobuiltinTypes[gotype]; ok {
return return
} }
@ -466,9 +495,6 @@ func (w *Wrapper) ProcessType(gotype string) {
if Debug { if Debug {
fmt.Printf("Processing %s (%s)\n",gotype,ctype) fmt.Printf("Processing %s (%s)\n",gotype,ctype)
} }
if w.Processed[gotype] {
return
}
if i,ok := w.Interfaces[gotype]; ok { if i,ok := w.Interfaces[gotype]; ok {
if Debug { if Debug {
fmt.Printf("Have interface for %s. super = %s\n",gotype,i.Super) fmt.Printf("Have interface for %s. super = %s\n",gotype,i.Super)
@ -488,14 +514,12 @@ func (w *Wrapper) ProcessType(gotype string) {
// %s // %s
type %s struct { %s } type %s struct { %s }
`,ctype, gotype, fields)) `,ctype, gotype, fields))
w.Processed[gotype] = true
} }
if s,ok := w.goStructTypes[gotype]; ok { if s,ok := w.goStructTypes[gotype]; ok {
ct := strings.ReplaceAll(s.cName," ","_") ct := strings.ReplaceAll(s.cName," ","_")
w.goTypes.WriteString(fmt.Sprintf(` w.goTypes.WriteString(fmt.Sprintf(`
type %s %s type %s %s
`,s.goName,"C." + ct)) `,s.goName,"C." + ct))
w.Processed[gotype] = true
} }
} }
@ -554,8 +578,10 @@ New%s() {
grtype := "" grtype := ""
grptr := "" grptr := ""
_ = grptr
w.AddType(m.Type,i.Name) w.AddType(m.Type,i.Name)
cmtype := cType(m.Type,i.Name) //cmtype := cType(m.Type,i.Name)
cmtype := w.ctMap[w.goType(m.Type,i.Name)].CtypeSimplified()
if !m.isVoid() { if !m.isVoid() {
grtype = w.goType(cmtype,i.Name) grtype = w.goType(cmtype,i.Name)
if grtype == "" { if grtype == "" {
@ -565,6 +591,8 @@ New%s() {
} }
gcast := "" gcast := ""
gcast2 := "" gcast2 := ""
_ = gcast
_ = gcast2
if grtype != "" { if grtype != "" {
if grtype[0] == '*' { // pointer return type if grtype[0] == '*' { // pointer return type
if _,ok := w.Interfaces[grtype[1:]]; ok { if _,ok := w.Interfaces[grtype[1:]]; ok {
@ -585,14 +613,23 @@ New%s() {
} }
w.ProcessType(grtype) w.ProcessType(grtype)
gplist, gptypes, ok := w.goparamlist(m) gplist, gptypes, ok := w.goparamlist(m)
_ = gplist
if !ok { if !ok {
continue continue
} }
w.ProcessTypes(gptypes) w.ProcessTypes(gptypes)
ns,tps := gpntp(m)
w.goCode.WriteString(fmt.Sprintf(` w.goCode.WriteString(fmt.Sprintf(`
func (o *%s) %s(%s) %s%s { func (o *%s) %s(%s) %s {
`,i.Name,gname,gplist,m.Tp.GoType()))
w.goCode.WriteString(types.GoToC(gname,ns,m.Tp,tps))
w.goCode.WriteString(`
}
`)
/*w.goCode.WriteString(fmt.Sprintf(`
%sC.%s_%s(%s)%s %sC.%s_%s(%s)%s
}`,i.Name, gname, gplist, grptr, grtype, gcast, i.Name, m.Name, w.goparamnames(m),gcast2)) }`,i.Name, gname, gplist, grptr, grtype, gcast, i.Name, m.Name, w.goparamnames(m),gcast2))*/
cret := "" cret := ""
if !m.isVoid() { if !m.isVoid() {