Improved type handling.

This commit is contained in:
Greg 2019-04-11 11:46:24 -04:00
parent 2fbd9134a0
commit 74f4073d35
5 changed files with 195 additions and 75 deletions

View File

@ -191,13 +191,13 @@ func Parse(fullline string) Node {
case "ObjCImplementation": case "ObjCImplementation":
return parseObjCImplementation(line) return parseObjCImplementation(line)
case "ObjCInterface": case "ObjCInterface":
return parseObjCInterface(line) return parseObjCInterface(line,false)
case "ObjCInterfaceType":
return parseObjCInterfaceType(line)
case "super ObjCInterface": case "super ObjCInterface":
return parseSuperObjCInterface(line) return parseObjCInterface(line,true)
case "ObjCInterfaceDecl": case "ObjCInterfaceDecl":
return parseObjCInterfaceDecl(line) return parseObjCInterfaceDecl(line)
case "ObjCInterfaceType":
return parseObjCInterfaceType(line)
case "getter ObjCMethod": case "getter ObjCMethod":
return parseObjCMethod(line) return parseObjCMethod(line)
case "ObjCMethod": case "ObjCMethod":
@ -272,6 +272,8 @@ func Parse(fullline string) Node {
return parseUnaryExprOrTypeTraitExpr(line) return parseUnaryExprOrTypeTraitExpr(line)
case "UnaryOperator": case "UnaryOperator":
return parseUnaryOperator(line) return parseUnaryOperator(line)
case "UnavailableAttr":
return parseUnavailableAttr(line)
case "UnusedAttr": case "UnusedAttr":
return parseUnusedAttr(line) return parseUnusedAttr(line)
case "VAArgExpr": case "VAArgExpr":

View File

@ -8,13 +8,7 @@ type ObjCInterface struct {
ChildNodes []Node ChildNodes []Node
} }
func parseSuperObjCInterface(line string) *ObjCInterface { func parseObjCInterface(line string, super bool) *ObjCInterface {
ret := parseObjCInterface(line)
ret.Super = true
return ret
}
func parseObjCInterface(line string) *ObjCInterface {
groups := groupsFromRegex( groups := groupsFromRegex(
"'(?P<name>.*)'", "'(?P<name>.*)'",
line, line,
@ -23,7 +17,7 @@ func parseObjCInterface(line string) *ObjCInterface {
return &ObjCInterface{ return &ObjCInterface{
Addr: ParseAddress(groups["address"]), Addr: ParseAddress(groups["address"]),
Name: groups["name"], Name: groups["name"],
Super: false, Super: super,
ChildNodes: []Node{}, ChildNodes: []Node{},
} }
} }

55
ast/unavailable_attr.go Normal file
View File

@ -0,0 +1,55 @@
package ast
import (
"strings"
)
// UnavailableAttr is node represents an unavailable attribute.
type UnavailableAttr struct {
Addr Address
Pos Position
Position2 string
Content string
ChildNodes []Node
}
func parseUnavailableAttr(line string) *UnavailableAttr {
groups := groupsFromRegex(
`(?:prev (?P<prev>0x[0-9a-f]+) )?
<(?P<position><invalid sloc>|.*?)>
(?P<position2> <invalid sloc>| col:\d+| line:\d+:\d+)?
(?P<content>.*)`,
line,
)
return &UnavailableAttr{
Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]),
Position2: strings.TrimSpace(groups["position2"]),
Content: strings.TrimSpace(groups["content"]),
ChildNodes: []Node{},
}
}
// AddChild adds a new child node. Child nodes can then be accessed with the
// Children attribute.
func (n *UnavailableAttr) 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 *UnavailableAttr) Address() Address {
return n.Addr
}
// 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 *UnavailableAttr) Children() []Node {
return n.ChildNodes
}
// Position returns the position in the original source code.
func (n *UnavailableAttr) Position() Position {
return n.Pos
}

View File

@ -203,7 +203,7 @@ func Start(args ProgramArgs) (err error) {
} }
tree := buildTree(nodes, 0) tree := buildTree(nodes, 0)
unit := tree[0] unit := tree[0]
w := wrap.NewWrapper() w := wrap.NewWrapper(*debugFlag)
for _, n := range(unit.Children()) { for _, n := range(unit.Children()) {
switch x := n.(type) { switch x := n.(type) {
case *ast.ObjCInterfaceDecl: case *ast.ObjCInterfaceDecl:
@ -212,7 +212,7 @@ func Start(args ProgramArgs) (err error) {
w.AddCategory(x) w.AddCategory(x)
} }
} }
w.Wrap("ClassOne") w.Wrap("NSString")
return nil return nil
} }
@ -241,6 +241,7 @@ var (
versionFlag = flag.Bool("v", false, "print the version and exit") versionFlag = flag.Bool("v", false, "print the version and exit")
wrapCommand = flag.NewFlagSet("wrap", flag.ContinueOnError) wrapCommand = flag.NewFlagSet("wrap", flag.ContinueOnError)
verboseFlag = wrapCommand.Bool("V", false, "print progress as comments") verboseFlag = wrapCommand.Bool("V", false, "print progress as comments")
debugFlag = wrapCommand.Bool("d", false, "print debug information as comments")
outputFlag = wrapCommand.String("o", "", "output Go generated code to the specified file") outputFlag = wrapCommand.String("o", "", "output Go generated code to the specified file")
packageFlag = wrapCommand.String("p", "main", "set the name of the generated package") packageFlag = wrapCommand.String("p", "main", "set the name of the generated package")
wrapHelpFlag = wrapCommand.Bool("h", false, "print help information") wrapHelpFlag = wrapCommand.Bool("h", false, "print help information")

View File

@ -65,23 +65,28 @@ var builtinTypes map[string]string = map[string]string{
"complex double": "C.complexdouble", "complex double": "C.complexdouble",
}*/ }*/
func (w *Wrapper) AddType(t string) { func (w *Wrapper) AddType(t,class string) {
if _,ok := builtinTypes[t]; ok { if _,ok := builtinTypes[t]; ok {
return return
} }
nt, err := goType(t) nt, err := goType(t,class)
if err != nil { if err != nil {
return return
} }
w.Types[nt] = t w.Types[nt] = t
} }
func goType(t string) (string, error) { func goType(t,class string) (string, error) {
// strip off pointers, < > and blank space // strip off pointers, < > and blank space
nt := strings.ReplaceAll(t,"*","") nt := strings.ReplaceAll(t,"*","")
if len(nt) > 3 && nt[0:3] == "id<" { if len(nt) > 3 && nt[0:3] == "id<" {
nt = t[3:len(t)-1] nt = t[3:len(t)-1]
} }
nt = strings.ReplaceAll(nt," _Nullable","")
nt = strings.ReplaceAll(nt," _Nonnull","")
if t == "instancetype" {
return class, nil
}
nt = strings.ReplaceAll(nt,"<","__") nt = strings.ReplaceAll(nt,"<","__")
nt = strings.ReplaceAll(nt,">","__") nt = strings.ReplaceAll(nt,">","__")
nt = strings.ReplaceAll(nt,",","_") nt = strings.ReplaceAll(nt,",","_")
@ -101,7 +106,18 @@ func goType(t string) (string, error) {
return nt, nil return nt, nil
} }
func NewWrapper() *Wrapper { func cType(t, class string) string {
nt := strings.ReplaceAll(t," _Nullable","")
nt = strings.ReplaceAll(nt," _Nonnull","")
if nt == "instancetype" {
return class + " *"
}
return nt
}
func NewWrapper(debug bool) *Wrapper {
Debug = debug
if Debug { fmt.Println("// Debug mode") }
return &Wrapper{ return &Wrapper{
Interfaces: map[string]Interface{}, Interfaces: map[string]Interface{},
Types: map[string]string{}, Types: map[string]string{},
@ -113,22 +129,30 @@ type Property struct {
} }
type Parameter struct { type Parameter struct {
Name, Type, Type2 string Pname, Vname, Type, Type2 string
} }
type Method struct { type Method struct {
Name, Type, Type2 string Name, Type, Type2, Class string
Parameters map[string]Parameter Parameters []Parameter
} }
func (m Method) isVoid() bool { func (m Method) isVoid() bool {
return typeOrType2(m.Type,m.Type2) == "void" return typeOrType2(m.Type,m.Type2) == "void"
} }
func (m Method) isObject() bool { // FIXME
tp := typeOrType2(m.Type,m.Type2)
if len(tp) > 1 && tp[0:2] == "NS" {
return true
}
return false
}
func (m Method) cparamlist() string { func (m Method) cparamlist() string {
ret := []string{"void* obj"} ret := []string{"void* obj"}
for k,v := range m.Parameters { for _,p := range m.Parameters {
ret = append(ret,fmt.Sprintf("%s %s",typeOrType2(v.Type,v.Type2),k)) ret = append(ret,fmt.Sprintf("%s %s",typeOrType2(p.Type,p.Type2),p.Vname))
} }
return strings.Join(ret,", ") return strings.Join(ret,", ")
} }
@ -137,31 +161,49 @@ func (m Method) objcparamlist() string {
if len(m.Parameters) == 0 { if len(m.Parameters) == 0 {
return m.Name return m.Name
} }
ret := []string{fmt.Sprintf("%s:",m.Name)} first := true
for k,_ := range m.Parameters { ret := []string{}
ret = append(ret, fmt.Sprintf("%s:%s",k,k)) for _,p := range m.Parameters {
if first {
ret = append(ret,m.Name + ":" + p.Vname)
first = false
} else {
ret = append(ret, p.Pname + ":" + p.Vname)
}
} }
return strings.Join(ret," ") return strings.Join(ret," ")
} }
func (m Method) goparamlist() (string,[]string) { var goreserved map[string]bool = map[string]bool{
"range": true,
}
func (m Method) goparamlist() (string,[]string,bool) {
ret := []string{} ret := []string{}
tps := []string{} tps := []string{}
for k,v := range m.Parameters { for _,p := range m.Parameters {
tp,err := goType(typeOrType2(v.Type,v.Type2)) gname := p.Vname
tp,err := goType(typeOrType2(p.Type,p.Type2),m.Class)
if err != nil { if err != nil {
return "UNSUPPORTED TYPE", []string{} return "UNSUPPORTED TYPE", []string{},false
}
if goreserved[gname] {
gname = gname + "_"
} }
tps = append(tps,tp) tps = append(tps,tp)
ret = append(ret,fmt.Sprintf("%s %s",k,tp)) ret = append(ret,fmt.Sprintf("%s %s",gname,tp))
} }
return strings.Join(ret,", "),tps return strings.Join(ret,", "),tps,true
} }
func (m Method) goparamnames() string { func (m Method) goparamnames() string {
ret := []string{"o.ptr"} ret := []string{"o.ptr"}
for k,_ := range m.Parameters { for _,p := range m.Parameters {
ret = append(ret,k) gname := p.Vname
if goreserved[gname] {
gname = gname + "_"
}
ret = append(ret,gname)
} }
return strings.Join(ret, ", ") return strings.Join(ret, ", ")
} }
@ -203,28 +245,36 @@ 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) w.AddType(name,name)
} }
var avail bool
for _,c := range ns { for _,c := range ns {
switch x := c.(type) { switch x := c.(type) {
case *ast.ObjCPropertyDecl: case *ast.ObjCPropertyDecl:
//fmt.Printf("ObjCPropertyDecl: %s\n",x.Name)
p := Property{ p := Property{
Name: x.Name, Name: x.Name,
Type: x.Type, Type: x.Type,
Type2: x.Type2, Type2: x.Type2,
} }
w.AddType(typeOrType2(x.Type,x.Type2)) //_,avail = w.GetParms(x,name) // TODO
i.Properties[p.Name] = p //if avail {
w.AddType(typeOrType2(x.Type,x.Type2),name)
i.Properties[p.Name] = p
//}
case *ast.ObjCMethodDecl: case *ast.ObjCMethodDecl:
//fmt.Printf("ObjCMethodDecl: %s\n",x.Name) //fmt.Printf("ObjCMethodDecl: %s\n",x.Name)
m := Method{ m := Method{
Name: x.Name, Name: x.Name,
Type: x.Type, Type: x.Type,
Type2: x.Type2, Type2: x.Type2,
Class: name,
}
m.Parameters, avail = w.GetParms(x,name)
if avail {
w.AddType(typeOrType2(x.Type,x.Type2),name)
i.Methods[m.Name] = m
} }
w.AddType(typeOrType2(x.Type,x.Type2))
m.Parameters = w.GetParms(x)
i.Methods[m.Name] = m
case *ast.ObjCProtocol: case *ast.ObjCProtocol:
//fmt.Printf("ast.ObjCProtocol: %s\n",x.Name) //fmt.Printf("ast.ObjCProtocol: %s\n",x.Name)
case *ast.ObjCInterface: case *ast.ObjCInterface:
@ -241,55 +291,63 @@ func (w *Wrapper) add(name string, ns []ast.Node) {
w.Interfaces[i.Name] = i w.Interfaces[i.Name] = i
} }
func (w *Wrapper) GetParms(n *ast.ObjCMethodDecl) map[string]Parameter { type AvailAttr struct {
ps := make([]Parameter,0) OS, Version string
avail := make([][]string,len(n.Children())) Deprecated bool
var c ast.Node }
i := -1
for i,c = range n.Children() { func (w *Wrapper) GetParms(n *ast.ObjCMethodDecl,class string) ([]Parameter,bool) {
ret := make([]Parameter,0)
avail := make([]AvailAttr,0)
j := 0
for _,c := range n.Children() {
switch x := c.(type) { switch x := c.(type) {
case *ast.ParmVarDecl: case *ast.ParmVarDecl:
i++
p := Parameter{ p := Parameter{
Pname: n.Parameters[j],
Vname: x.Name,
Type: x.Type, Type: x.Type,
Type2: x.Type2, Type2: x.Type2,
} }
ps = append(ps,p) ret = append(ret,p)
avail = append(avail,[]string{}) j++
case *ast.AvailabilityAttr: case *ast.AvailabilityAttr:
avail[i] = append(avail[i],x.OS) avail = append(avail,
AvailAttr{
OS: x.OS,
Version: x.Version,
Deprecated: x.Unknown1 != "0",
})
//fmt.Println("AvailAttr ",avail,x)
case *ast.UnavailableAttr:
avail = append(avail,
AvailAttr{ OS: "macos", Deprecated: true })
case *ast.Unknown:
if Debug { fmt.Printf("GetParms(): ast.Unknown: %s\n",x.Name) }
} }
} }
isAvail := func(l []string) bool { a := func() bool {
if len(l) == 0 { if len(avail) == 0 {
return true return true
} }
for _,x := range l { for _,x := range avail {
if x == "macos" { if x.OS == "macos" && x.Deprecated == false {
return true return true
} }
} }
return false return false
}()
if !a {
return nil, false
} }
ret := make(map[string]Parameter) if len(ret) != len(n.Parameters) {
j := 0 fmt.Printf("Error in method declaration %s: Wrong number of ParmVarDecl children: %d parameters but %d ParmVarDecl children\n",n.Name,len(n.Parameters),len(ret))
for i,p := range ps {
if isAvail(avail[i]) {
ret[n.Parameters[j]] = p
j++
}
} }
for _,p := range ret { return ret, true
w.AddType(typeOrType2(p.Type,p.Type2))
}
if j != len(n.Parameters) {
fmt.Printf("Error in method declaration %s: Wrong number of ParmVarDecl children: %d parameters but %d ParmVarDecl children\n",n.Name,len(n.Parameters),i)
}
return ret
} }
func typeOrType2(t1, t2 string) string { func typeOrType2(t1, t2 string) string {
if t2 != "" { if t2 != "" && t2 != "id" {
return t2 return t2
} }
return t1 return t1
@ -347,7 +405,9 @@ func (w *Wrapper) Wrap(toproc string) {
w.cCode.WriteString(`/* w.cCode.WriteString(`/*
#cgo CFLAGS: -x objective-c #cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation -framework CoreBluetooth #cgo LDFLAGS: -framework Foundation
#import <Foundation/Foundation.h>
`) `)
pInterfaces := map[string]Interface {toproc: w.Interfaces[toproc]} pInterfaces := map[string]Interface {toproc: w.Interfaces[toproc]}
@ -385,12 +445,13 @@ New%s() {
grtype := "" grtype := ""
grptr := "" grptr := ""
cmtype := typeOrType2(y.Type,y.Type2) cmtype := cType(typeOrType2(y.Type,y.Type2),v.Name)
if !y.isVoid() { if !y.isVoid() {
var err error var err error
grtype,err = goType(cmtype) grtype,err = goType(cmtype,v.Name)
if err != nil { if err != nil {
grtype = fmt.Sprintf("// goType(%s): NOT IMPLEMENTED\n",cmtype) grtype = fmt.Sprintf("// goType(%s): NOT IMPLEMENTED\n",cmtype)
continue
} }
} }
gcast := "" gcast := ""
@ -406,7 +467,10 @@ New%s() {
} }
} }
w.ProcessType(grtype) w.ProcessType(grtype)
gplist, gptypes := y.goparamlist() gplist, gptypes,ok := y.goparamlist()
if !ok {
continue
}
w.ProcessTypes(gptypes) w.ProcessTypes(gptypes)
w.goCode.WriteString(fmt.Sprintf(` w.goCode.WriteString(fmt.Sprintf(`
func (o *%s) %s(%s) %s%s { func (o *%s) %s(%s) %s%s {
@ -417,11 +481,15 @@ func (o *%s) %s(%s) %s%s {
if !y.isVoid() { if !y.isVoid() {
cret = "return " cret = "return "
} }
ccast := ""
if y.isObject() {
cret = "(id)"
}
w.cCode.WriteString(fmt.Sprintf(` w.cCode.WriteString(fmt.Sprintf(`
%s %s
%s_%s(%s) { %s_%s(%s) {
%s[(id)obj %s]; %s[%sobj %s];
}`, cmtype, v.Name, y.Name, y.cparamlist(), cret, y.objcparamlist())) }`, cmtype, v.Name, y.Name, y.cparamlist(), cret, ccast, y.objcparamlist()))
} }
} }
fmt.Println(`package main fmt.Println(`package main