diff --git a/types/convert.go b/types/convert.go index 4db8451..172384a 100644 --- a/types/convert.go +++ b/types/convert.go @@ -109,20 +109,37 @@ func _goType(ct string) string { func (t *Type) CType() string { + return t._CType(false) +} + +func (t *Type) CTypeAttrib() string { + return t._CType(true) +} + +func (t *Type) _CType(attrib bool) string { if t.ctype != "" { // cache return t.ctype } - ct := t.Node.CtypeSimplified() + var ct string + if attrib { + ct = t.Node.Ctype() + } else { + 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 + " *" } + if ct[:12] == "instancename" { ct = t.Class + ct[12:] } + if ct[:12] == "instancetype" { ct = t.Class + ct[12:] + " *" } + } + if attrib { + t._CType(false) + } else { + t.ctype = ct } - t.ctype = ct return ct } diff --git a/wrap/main.go b/wrap/main.go index afae6d8..fc4c551 100644 --- a/wrap/main.go +++ b/wrap/main.go @@ -2,7 +2,6 @@ package wrap import ( "fmt" - //"reflect" "strings" "gitlab.wow.st/gmp/clast/ast" @@ -13,148 +12,14 @@ var ( Debug = false ) -type cStruct struct { - goName, cName string -} - type Wrapper struct { Interfaces map[string]Interface - Tps map[string]*types.Node - Types map[string]string - gtMap map[string]string - ctMap map[string]*types.Node // map from go type as a string. - 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 goHelpers strings.Builder // put Go helper functions here Processed map[string]bool - Processed2 map[string]bool -} - -var gobuiltinTypes map[string]bool = map[string]bool{ - "byte": true, - "int": true, - "float64": true, -} - -// translate C builtin types to CGo -var builtinTypes map[string]string = map[string]string{ - "char": "C.char", - "signed char": "C.schar", - "unsigned char": "C.uchar", - "short": "C.short", - "unsigned short": "C.ushort", - "int": "C.int", - "unsigned int": "C.uint", - "long": "C.long", - "unsigned long": "C.ulong", - "long long": "C.longlong", - "unsigned long long": "C.ulonglong", - "float": "C.float", - "double": "C.double", - "complex float": "C.complexfloat", - "complex double": "C.complexdouble", -} - -//AddType registers a type that needs a Go wrapper struct -func (w *Wrapper) AddType(t, class string) { - //fmt.Printf("Type: %s\n",t) - if _,ok := builtinTypes[t]; ok { - return - } - nt := w.goType(t,class) - if Debug { - fmt.Printf("AddType(): (%s) -> %s\n",t,nt) - } - if nt == "" { - return - } - if _,ok := w.Interfaces[nt]; !ok { // not an interface - return - } -} - -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) - if err != nil { - //fmt.Printf("Cannot parse type %s\n",t) - return "" - } - if n.HasFunc() { - //fmt.Printf("Function types not supported (%s)\n",t) - return "" - } - ct := n.CtypeSimplified() - ret := "" - if nt, ok := w.gtMap[ct]; ok { // we already know this type - return nt - } - if x := n.PointsTo(); x != nil { - pt := x.CtypeSimplified() -// if _,ok := w.Interfaces[pt]; ok { -// // pointer to Objective-C interface, stop here -// //fmt.Printf("goType(): %s -> %s\n",t,pt) -// w.gtMap[ct] = pt -// w.goInterfaceTypes = append(w.goInterfaceTypes,pt) -// return pt -// } -// pt = x.BaseType().CtypeSimplified() -// if _,ok := w.Interfaces[pt]; ok { -// // ultimately points to an interface, so need a wrapper -// w.AddType(pt,class) -// ret = w.goType(pt,class) + "Ptr" -// //fmt.Printf("goType(): %s -> %s\n",t,ret) -// w.gtMap[ct] = ret -// return ret -// } - // pointer to non-interface type - ret = "*" + w.goType(pt,class) - w.gtMap[ct] = ret - w.ctMap[ret] = n - return ret - } - if x := n.ArrayOf(); x != nil { - pt := x.CtypeSimplified() - w.AddType(pt,class) - ret = "[]" + w.goType(pt,class) - //fmt.Printf("goType(): %s -> %s\n",t,ret) - w.gtMap[ct] = ret - w.ctMap[ret] = n - return ret - } - if bt,ok := builtinTypes[ct]; ok { - ct = bt - } - if _,ok := w.Interfaces[ct]; ok { - // pointer to Objective-C interface, stop here - //fmt.Printf("goType(): %s -> %s\n",t,pt) - w.gtMap[ct] = ct - w.goInterfaceTypes = append(w.goInterfaceTypes,ct) - w.ctMap[ct] = n - w.Types[ct] = t - return ct - } - if n.IsStruct() { - gt := strings.Title(ct) - gt = strings.ReplaceAll(gt, " ", "") - w.gtMap[ct] = gt - w.goStructTypes[gt] = cStruct{ goName: gt, cName: ct } - //fmt.Printf("goType(): %s -> %s\n",t,gt) - w.ctMap[gt] = n - return gt - } - //fmt.Printf("goType(): %s -> %s\n",t,ct) - w.gtMap[ct] = ct - w.ctMap[ct] = n - return ct } func NewWrapper(debug bool) *Wrapper { @@ -162,53 +27,42 @@ func NewWrapper(debug bool) *Wrapper { if Debug { fmt.Println("// Debug mode") } return &Wrapper{ Interfaces: map[string]Interface{}, - Types: map[string]string{}, - gtMap: map[string]string{}, - ctMap: map[string]*types.Node{}, - goStructTypes: map[string]cStruct{}, Processed: map[string]bool{}, - Processed2: map[string]bool{}, } } type Property struct { - Name, Type, Attr string - Tp *types.Type + Name, Attr string + Type *types.Type } type Parameter struct { - Pname, Vname, Type string - Tp *types.Type + Pname, Vname string + Type *types.Type } type Method struct { - Name, Type, Class string - Tp *types.Type + Name, Class string + Type *types.Type ClassMethod bool Parameters []Parameter } +//isVoid() returns true if the method has no return value. func (m Method) isVoid() bool { - return m.Type == "void" + return m.Type.CType() == "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() { + if p.Type.Node.IsFunction() { return true } } return false } -func (w Wrapper) isObject(tp string) bool { // takes a goType - if _,ok := w.Interfaces[tp]; ok { - return true - } - return false -} - func (w Wrapper) cparamlist(m Method) string { ret := make([]string,0) if !m.ClassMethod { @@ -216,10 +70,10 @@ func (w Wrapper) cparamlist(m Method) string { } for _,p := range m.Parameters { var tp string - if p.Tp.Node.IsPointer() { + if p.Type.Node.IsPointer() { tp = "void*" } else { - tp = p.Tp.CType() + tp = p.Type.CType() } ret = append(ret,fmt.Sprintf("%s %s",tp,p.Vname)) } @@ -262,7 +116,7 @@ func (m *Method) gpntp() ([]string,[]*types.Type,string) { gname = gname + "_" } ns = append(ns,gname) - tps = append(tps,p.Tp) + tps = append(tps,p.Type) } ret := []string{} i := 0 @@ -277,78 +131,13 @@ func (m *Method) gpntp() ([]string,[]*types.Type,string) { return ns, tps, strings.Join(ret,", ") } -func (w Wrapper) goparamlist(m Method) (string,[]string,bool) { - ret := []string{} - tps := []string{} - for _,p := range m.Parameters { - gname := p.Vname - w.AddType(p.Type,m.Class) - tp := w.goType(p.Type,m.Class) - if tp == "" { - return "UNSUPPORTED TYPE", []string{},false - } - if w.isObject(tp) { - tp = "*" + tp - } - if goreserved[gname] { - gname = gname + "_" - } - tps = append(tps,tp) - ret = append(ret,fmt.Sprintf("%s %s",gname,tp)) - } - return strings.Join(ret,", "),tps,true -} - -func (w Wrapper) goparamnames(m Method) string { - ret := make([]string,0) - if !m.ClassMethod { - ret = append(ret,"o.ptr") - } - for _,p := range m.Parameters { - gname := p.Vname - if goreserved[gname] { - gname = gname + "_" - } - gt := w.goType(p.Type,m.Class) - if gt == "" { - return "UNSUPPORTED TYPE " + p.Type - } - if w.isObject(gt) { - gname = gname + ".ptr" - } else { - n := w.ctMap[gt] - star := "" - for pt := n.PointsTo(); pt != nil; pt = pt.PointsTo() { - star = star + "*" - } - ct := n.BaseType().CtypeSimplified() - if n.IsStruct() { - ct = strings.ReplaceAll(ct,"struct ","") - ct = "struct_" + ct - } - if gt[0] == '*' { // wrap pointers in unsafe.Pointer() - gname = "unsafe.Pointer(" + gname + ")" - } - gname = "(" + star + "C." + ct + ")(" + gname + ")" - } - ret = append(ret,gname) - } - return strings.Join(ret, ", ") -} type Interface struct { - Name, Super string + Name string Properties map[string]Property Methods map[string]Method } -func (i Interface) IsRoot() bool { - if i.Super == "" || i.Super == i.Name { - return true - } - return false -} - func (w *Wrapper) AddInterface(n *ast.ObjCInterfaceDecl) { //fmt.Printf("ast.ObjCInterfaceDecl: %s\n",n.Name) w.add(n.Name, n.Children()) @@ -375,7 +164,6 @@ func (w *Wrapper) add(name string, ns []ast.Node) { Properties: map[string]Property{}, Methods: map[string]Method{}, } - w.AddType(name,name) // need this? } tp := types.NewTypeFromString(name,name) types.Wrap(tp.GoType()) @@ -386,26 +174,22 @@ func (w *Wrapper) add(name string, ns []ast.Node) { //fmt.Printf("ObjCPropertyDecl: %s\n",x.Name) p := Property{ Name: x.Name, - Type: x.Type, - Tp: types.NewTypeFromString(x.Type,name), + Type: types.NewTypeFromString(x.Type,name), } //_,avail = w.GetParms(x,name) // TODO //if avail { -// w.AddType(x.Type,name) i.Properties[p.Name] = p //} case *ast.ObjCMethodDecl: //fmt.Printf("ObjCMethodDecl: %s\n",x.Name) m := Method{ Name: x.Name, - Type: x.Type, - Tp: types.NewTypeFromString(x.Type,name), + Type: types.NewTypeFromString(x.Type,name), Class: name, ClassMethod: x.ClassMethod, } m.Parameters, avail = w.GetParms(x,name) if avail { -// w.AddType(x.Type,name) i.Methods[m.Name] = m } case *ast.ObjCProtocol: @@ -413,7 +197,6 @@ func (w *Wrapper) add(name string, ns []ast.Node) { case *ast.ObjCInterface: if x.Super { //fmt.Printf("ast.ObjCInterface: %s inherits from %s\n",name,x.Name) - i.Super = x.Name types.SetSuper(name,x.Name) } case *ast.Unknown: @@ -444,8 +227,7 @@ func (w *Wrapper) GetParms(n *ast.ObjCMethodDecl,class string) ([]Parameter,bool p := Parameter{ Pname: n.Parameters[j], Vname: x.Name, - Type: x.Type, - Tp: types.NewTypeFromString(x.Type,class), + Type: types.NewTypeFromString(x.Type,class), } ret = append(ret,p) j++ @@ -487,24 +269,24 @@ func (w *Wrapper) GetParms(n *ast.ObjCMethodDecl,class string) ([]Parameter,bool } // new version of ProcessType -func (w *Wrapper) pt2(tps ...*types.Type) { +func (w *Wrapper) processTypes(tps []*types.Type) { switch len(tps) { case 0: return case 1: - w._pt2(tps[0]) + w.processType(tps[0]) default: for _,tp := range tps { - w.pt2(tp) + w.processType(tp) } return } } -func (w *Wrapper) _pt2(tp *types.Type) { +func (w *Wrapper) processType(tp *types.Type) { bt := tp.BaseType() - if w.Processed2[bt.GoType()] { return } - w.Processed2[bt.GoType()] = true + if w.Processed[bt.GoType()] { return } + w.Processed[bt.GoType()] = true if bt.Node.IsFunction() { return } @@ -516,7 +298,7 @@ func (w *Wrapper) _pt2(tp *types.Type) { if super != "" { types.Wrap(super) pt := types.NewTypeFromString(super + "*","") - w._pt2(pt) + w.processType(pt) } } @@ -536,60 +318,6 @@ func (c *Char) String() string { `) } -func (w *Wrapper) ProcessType(gotype string) { - if gotype == "" { - return - } - if gotype[0] == '*' { - gotype = gotype[1:] - } - if w.Processed[gotype] { - return - } - w.Processed[gotype] = true - if _,ok := gobuiltinTypes[gotype]; ok { - return - } - ctype := w.Types[gotype] - if _,ok := builtinTypes[ctype]; ok { - return - } - if Debug { - fmt.Printf("Processing %s (%s)\n",gotype,ctype) - } - if i,ok := w.Interfaces[gotype]; ok { - if Debug { - fmt.Printf("Have interface for %s. super = %s\n",gotype,i.Super) - } - if i.Name != i.Super { - w.ProcessType(i.Super) - } - var fields string -// if there is an Interface known for this type, decide if it is the -// root object and if so give it a pointer element: - if i.IsRoot() { - fields = "ptr unsafe.Pointer" - } else { - fields = i.Super // embed superclass - } - w.goTypes.WriteString(fmt.Sprintf(` -// %s -type %s struct { %s } -`,ctype, gotype, fields)) - } - if s,ok := w.goStructTypes[gotype]; ok { - ct := strings.ReplaceAll(s.cName," ","_") - w.goTypes.WriteString(fmt.Sprintf(` -type %s %s -`,s.goName,"C." + ct)) - } -} - -func (w *Wrapper) ProcessTypes(tps []string) { - for _,tp := range tps { - w.ProcessType(tp) - } -} func (w *Wrapper) Wrap(toproc []string) { @@ -604,13 +332,14 @@ func (w *Wrapper) Wrap(toproc []string) { for _,iface := range toproc { pInterfaces[iface] = w.Interfaces[iface] } + //FIXME: sort pInterfaces for iname,i := range pInterfaces { if Debug { fmt.Printf("Interface %s: %d properties, %d methods\n", iname, len(i.Properties), len(i.Methods)) } - w.goCode.WriteString(fmt.Sprintf(` + /*w.goCode.WriteString(fmt.Sprintf(` func New%s() *%s { ret := &%s{} ret.ptr = unsafe.Pointer(C.New%s()) @@ -624,42 +353,46 @@ func New%s() *%s { New%s() { return [%s alloc]; } -`, i.Name, i.Name, i.Name)) +`, i.Name, i.Name, i.Name))*/ + //FIXME: sort properties for _,p := range i.Properties { if Debug { - fmt.Printf(" property: %s (%s)\n", p.Name, p.Type) + fmt.Printf(" property: %s (%s)\n", p.Name, p.Type.CType()) } - w.AddType(p.Type,i.Name) } + //FIXME: sort methods for _,m := range i.Methods { if Debug { fmt.Printf(" method: %s (%s)\n", m.Name, m.Type) } - if m.Tp.Node.IsFunction() { + if m.Type.Node.IsFunction() { continue } if m.hasFunctionParam() { continue } gname := strings.Title(m.Name) + if m.ClassMethod { + gname = i.Name + gname + } else { + gname = "(o *" + i.Name + ") " + gname + } cname := i.Name + "_" + m.Name - w.AddType(m.Type,i.Name) - //cmtype := w.ctMap[w.goType(m.Type,i.Name)].CtypeSimplified() - cmtype := m.Tp.CType() + cmtype := m.Type.CTypeAttrib() ns,tps,gplist := m.gpntp() - w.pt2(tps...) - w.pt2(m.Tp) - grtype := m.Tp.GoType() + w.processTypes(tps) + w.processType(m.Type) + grtype := m.Type.GoType() if grtype == "Void" { grtype = "" } w.goCode.WriteString(fmt.Sprintf(` -func (o *%s) %s(%s) %s { -`,i.Name,gname,gplist,grtype)) +func %s(%s) %s { +`,gname,gplist,grtype)) w.goCode.WriteString( - types.GoToC(cname,ns,m.Tp,tps) + "}\n\n") + types.GoToC(cname,ns,m.Type,tps) + "}\n\n") cret := "" if !m.isVoid() {