Create GoString helper methods for anything that has a "WithString"

method. Multiple bug fixes in type system, fixed parsing of id,
instancename and instancetype, allow NullableAnnotations after
generic lists (e.g. "id<ObjectType> _Nullable"). Helper function
to identify types that are function pointers.
This commit is contained in:
Greg 2019-05-03 13:14:30 -04:00
parent 8ea3d57cf0
commit eced251710
9 changed files with 103 additions and 33 deletions

View File

@ -11,7 +11,8 @@ func main() {
fmt.Println("LE capable:",cd.IsLECapableHardware())
time.Sleep(time.Second * 1)
fmt.Println("LE capable:",cd.IsLECapableHardware())
uuid := ble.CBUUIDWithString(ble.NSStringWithUTF8String(ble.CharFromString("180d")))
uuid := ble.CBUUIDWithGoString("180d")
cd.ScanFor(uuid)
time.Sleep(time.Second * 15)
select { }
}

View File

@ -8,12 +8,12 @@ import (
)
func main() {
n1 := ns.NSStringWithUTF8String(ns.CharFromString("hi there"))
n1 := ns.NSStringWithUTF8String(ns.CharWithGoString("hi there"))
c1 := n1.CapitalizedString()
gs := c1.UTF8String().String()
fmt.Println(gs)
n2 := ns.NSStringWithUTF8String(ns.CharFromString("hi world"))
n3 := ns.NSStringWithUTF8String(ns.CharFromString("ok bye"))
n2 := ns.NSStringWithGoString("hi world")
n3 := ns.NSStringWithGoString("ok bye")
a := ns.NSMutableArrayWithObjects(n1,n2,n3)
fmt.Println("Length(a) = ",a.Count())
fmt.Println("is n2 in a?",a.ContainsObject(n2))

View File

@ -22,6 +22,6 @@ Functions = [
Enums = [
"CF.*",
]
SysImports = [ "Foundation/Foundation.h" ]
Frameworks = [ "Foundation" ]
Pragma = [ 'clang diagnostic ignored "-Wformat-security"' ]
VaArgs = 32

View File

@ -2,3 +2,4 @@ Package = "ClassOne"
InputFiles = [ "ClassOne/simple.h" ]
Classes = [ "ClassOne","ClassTwo" ]
Imports = [ "simple.h" ]
Frameworks = [ "Foundation" ]

View File

@ -149,7 +149,6 @@ func matches(x string, rs []string) bool {
// Start begins transpiling an input file.
func Start() (err error) {
// 1. Compile it first (checking for errors)
for _, in := range Config.InputFiles {
_, err := os.Stat(in)
if err != nil {
@ -159,10 +158,11 @@ func Start() (err error) {
// 2. Preprocess NOT DONE
// 3. Generate JSON from AST
// 3. Generate AST
cargs := []string{"-xobjective-c", "-Xclang", "-ast-dump",
"-fsyntax-only","-fno-color-diagnostics"}
cargs = append(cargs,Config.InputFiles...)
fmt.Printf("Generating AST\n")
astPP, err := exec.Command("clang",cargs...).Output()
if err != nil {
// If clang fails it still prints out the AST, so we have to run it
@ -175,9 +175,11 @@ func Start() (err error) {
lines := readAST(astPP)
// Converting to nodes
fmt.Printf("Building nodes\n")
nodes := convertLinesToNodesParallel(lines)
// build tree
fmt.Printf("Assembling tree\n")
tree := buildTree(nodes, 0)
w := wrap.NewWrapper(Debug)
w.Package = Config.Package
@ -190,6 +192,7 @@ func Start() (err error) {
}
w.VaArgs = Config.VaArgs
for _, u := range tree {
fmt.Printf("--processing translation unit\n")
for _, n := range(u.Children()) {
switch x := n.(type) {
case *ast.ObjCInterfaceDecl:

View File

@ -50,7 +50,7 @@ func init() {
TypeParameters = make(map[string]map[string]string)
typedefs = make(map[string]*Type)
r_id = regexp.MustCompile("\bid\b")
r_id = regexp.MustCompile(`\bid\b`)
r_instancename = regexp.MustCompile(`\binstancename\b`)
r_instancetype = regexp.MustCompile(`\binstancetype\b`)
}
@ -117,7 +117,6 @@ func NewType(n *Node, c string) *Type {
return &Type{
Node: n2,
Class: c,
//ctype: "",
}
}
@ -125,19 +124,16 @@ func NewTypeFromString(t,c string) *Type {
//fmt.Printf("t/c: %s/%s\n",t,c)
n,err := Parse(t)
//fmt.Printf("%p %s",n,n.String())
if n.IsId() {
n,err = Parse("NSObject*")
}
if err != nil {
return &Type{}
}
if n2,ok := clean(n, c); ok {
//found type parameters, re-parse
return NewTypeFromString(n2.Ctype(),c)
}
return &Type{
Node: n,
Class: c,
//ctype: "",
}
}
@ -219,9 +215,9 @@ func (t *Type) _CType(attrib bool) string {
//fmt.Println("nil sent to _CType()")
return ""
}
if !attrib && t.ctype != "" { // cache
return t.ctype
}
//if !attrib && t.ctype != "" { // cache
// return t.ctype
//}
var ct string
if attrib {
ignore := map[string]bool { "GenericList": true }
@ -296,6 +292,19 @@ func (o *Id) %s() *%s { return (*%s)(unsafe.Pointer(o)) }
`,t.Node.Ctype(),t.BaseType().GoType(),gt,super,gt,gt,gt,gt)
}
func (t *Type) IsFunctionPtr() bool {
if t == nil {
return false
}
if td := t.Typedef(); td != nil {
return td.IsFunctionPtr()
}
for pt := t.PointsTo(); pt != nil; pt = pt.PointsTo() {
return pt.IsFunction()
}
return false
}
func (t *Type) IsFunction() bool {
if t == nil {
fmt.Println("nil sent to IsFunction()")

View File

@ -81,21 +81,31 @@ digit:
[0-9]
*/
import (
"regexp"
)
var TypeName func(s string, n *Node) (string, *Node)
func init() {
instancename := regexp.MustCompile("instancename")
instancetype := regexp.MustCompile("instancetype")
cacheable := func(s string) bool {
return !instancetype.MatchString(s) && !instancename.MatchString(s)
}
cache := map[string]*Node{}
TypeName = func(s string, n *Node) (string, *Node) {
if n2,ok := cache[s]; ok {
return "",n2
}
s2,n2 := _TypeName(s,n)
if s2 == "" {
if s2 == "" && cacheable(s) {
cache[s] = n2
}
return s2,n2
}
TypeName = _TypeName
//TypeName = _TypeName
}
func _TypeName(s string, n *Node) (string, *Node) {
@ -318,10 +328,10 @@ func BareTypedefName(s string, n *Node) (string, *Node) {
}
func TypedefName(s string, n *Node) (string, *Node) {
return OneOf(
Seq(BareTypedefName, AngBracketed(GenericList)),
Seq(BareTypedefName, NullableAnnotation),
return Seq(
BareTypedefName,
Opt(AngBracketed(GenericList)),
Opt(NullableAnnotation),
)(s,n)
}

View File

@ -53,7 +53,7 @@ func (n *Node) stripAbstract(k string) *Node {
return nil
}
ret := NewNode(n.Kind)
cs := n.Children[:]
cs := append([]*Node{},n.Children...)
dbg("stripAbstract(): i = %d\n",i)
//Scan backwords skipping TypeQualifier and NullableAnnotation tags
@ -97,7 +97,10 @@ func (n *Node) PointsTo() *Node {
//IsPointer returns true if the node is a pointer
func (n *Node) IsPointer() bool {
return n.IsId() || n.IsInstancetype() || n.PointsTo() != nil
if pt := n.PointsTo(); pt != nil {
return true
}
return n.IsInstancetype() || n.IsId()
}
//ArrayOf, when called on an array node returns a node describing the type
@ -124,6 +127,9 @@ func (n *Node) IsFunction() bool {
if n == nil || len(n.Children) < 1 {
return false
}
if pt := n.PointsTo(); pt != nil {
return false
}
return n.Children[len(n.Children)-1].Kind == "Function"
}
@ -140,7 +146,8 @@ func (n *Node) IsId() bool {
if n == nil || len(n.Children) < 1 {
return false
}
return n.Children[0].Kind == "TypedefName" &&
return !n.IsFunction() &&
n.Children[0].Kind == "TypedefName" &&
n.Children[0].Content == "id"
}

View File

@ -113,7 +113,7 @@ func (m Method) isVoid() bool {
//hasFunctionParam() returns true if a method has a function as a parameter.
func (m Method) hasFunctionParam() bool {
for _,p := range m.Parameters {
if p.Type.IsFunction() {
if p.Type.IsFunction() || p.Type.IsFunctionPtr() {
return true
}
}
@ -521,7 +521,7 @@ func (w *Wrapper) processType(tp *types.Type) {
if gt == "NSEnumerator" {
w.EnumeratorHelpers()
}
if bt.IsFunction() {
if bt.IsFunction() || bt.IsFunctionPtr() {
return
}
super := types.Super(gt)
@ -535,7 +535,7 @@ func (w *Wrapper) processType(tp *types.Type) {
func (w *Wrapper) CharHelpers() {
w.goHelpers.WriteString(`
func CharFromString(s string) *Char {
func CharWithGoString(s string) *Char {
return (*Char)(unsafe.Pointer(C.CString(s)))
}
@ -555,7 +555,8 @@ func (e *NSEnumerator) ForIn(f func(*Id) bool) {
for o := e.NextObject(); o != nil; o = e.NextObject() {
if !f(o) { break }
}
}`)
}
`)
}
func (w *Wrapper) ProcessMethod(m *Method) {
@ -570,13 +571,12 @@ func (w *Wrapper) _processMethod(m *Method,fun bool) {
if Debug {
fmt.Printf(" method: %s (%s)\n", m.Name, m.Type)
}
if m.Type.IsFunction() || m.hasFunctionParam() {
if m.Type.IsFunction() || m.Type.IsFunctionPtr() || m.hasFunctionParam() {
return
}
gname := strings.Title(m.Name)
switch {
case !m.ClassMethod:
gname = "(o *" + m.GoClass + ") " + gname
case m.Type.GoType() != "*" + m.GoClass:
gname = m.GoClass + gname
default:
@ -592,6 +592,10 @@ func (w *Wrapper) _processMethod(m *Method,fun bool) {
gname = m.GoClass + gname[lens1-i:]
}
}
receiver := ""
if !m.ClassMethod {
receiver = "(o *" + m.GoClass + ") "
}
cname := m.Name
if m.Class != "" {
cname = m.Class + "_" + cname
@ -611,8 +615,8 @@ func (w *Wrapper) _processMethod(m *Method,fun bool) {
}
w.goCode.WriteString(fmt.Sprintf(`
//%s
func %s(%s) %s {
`,m.Type.CType(),gname,gplist,grtype))
func %s%s(%s) %s {
`,m.Type.CType(),receiver,gname,gplist,grtype))
lparm := len(tps)-1
if len(tps) > 0 && tps[lparm].Variadic {
vn := ns[lparm]
@ -659,7 +663,42 @@ func %s(%s) %s {
w.cCode.WriteString(fmt.Sprintf(` %s[%s %s];
}`, cret, cobj, w.objcparamlist(m)))
}
// create GoString helper method
if ok,_ := regexp.MatchString("WithString$",m.Name); ok {
//fmt.Printf("--%s\n",gname)
gname2 := gname[:len(gname)-6] + "GoString"
gps := []string{}
i := 0
if !m.ClassMethod { i = 1 }
for ; i < len(ns); i++ {
gt := tps[i].GoType()
//fmt.Printf(" %s\n",gt)
ns2 := ns[i]
if gt == "*NSString" {
gt = "string"
ns[i] = gStringToNsstring(ns[i])
}
gps = append(gps,ns2 + " " + gt)
}
gplist = strings.Join(gps,", ")
obj := ""
if !m.ClassMethod {
obj = "o."
ns = ns[1:]
}
w.goCode.WriteString(fmt.Sprintf(`
func %s%s(%s) %s {
return %s%s(%s)
}
`,receiver,gname2,gplist,grtype,obj,gname,strings.Join(ns,", ")))
}
}
func gStringToNsstring(s string) string {
return fmt.Sprintf("NSStringWithUTF8String(CharWithGoString(%s))",s)
}
func (w *Wrapper) ProcessEnum(e *Enum) {
gtp := ""