2019-04-09 11:52:21 -04:00
package wrap
import (
"fmt"
2019-04-09 23:19:49 -04:00
//"reflect"
"strings"
2019-04-09 11:52:21 -04:00
"gitlab.wow.st/gmp/clast/ast"
)
type Wrapper struct {
2019-04-09 23:19:49 -04:00
Interfaces map [ string ] Interface
Types map [ string ] string
}
// 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" ,
}
func ( w * Wrapper ) AddType ( t string ) {
// only for objects and pointers?
// strip off pointers, < > and blank space
nt := strings . ReplaceAll ( t , "*" , "" )
if len ( nt ) > 3 && nt [ 0 : 3 ] == "id<" {
nt = t [ 3 : len ( t ) - 1 ]
}
nt = strings . ReplaceAll ( nt , "<" , "_" )
nt = strings . ReplaceAll ( nt , ">" , "_" )
if _ , ok := builtinTypes [ nt ] ; ok { // do not add builtin types
return
}
if len ( nt ) > 5 && nt [ 0 : 5 ] == "enum " { // FIXME: deal with enums?
return
}
nt = strings . ReplaceAll ( nt , " " , "" )
if nt == "void" {
return
}
w . Types [ nt ] = t
2019-04-09 11:52:21 -04:00
}
func NewWrapper ( ) * Wrapper {
2019-04-09 23:19:49 -04:00
return & Wrapper {
Interfaces : map [ string ] Interface { } ,
Types : map [ string ] string { } ,
}
}
type Property struct {
Name , Type , Type2 , Attr string
}
type Parameter struct {
Name , Type , Type2 string
}
type Method struct {
Name , Type , Type2 string
Parameters map [ string ] Parameter
}
type Interface struct {
Name string
Properties map [ string ] Property
Methods map [ string ] Method
}
func ( w * Wrapper ) AddInterface ( n * ast . ObjCInterfaceDecl ) {
//fmt.Printf("ast.ObjCInterfaceDecl: %s\n",n.Name)
w . add ( n . Name , n . Children ( ) )
}
func ( w * Wrapper ) AddCategory ( n * ast . ObjCCategoryDecl ) {
ns := n . Children ( )
switch x := ns [ 0 ] . ( type ) {
case * ast . ObjCInterface :
w . add ( x . Name , ns [ 1 : ] )
default :
fmt . Printf ( "Not adding methods for %s: interface name not found in first child node of category defclaration\n" , n . Name )
}
2019-04-09 11:52:21 -04:00
}
2019-04-09 23:19:49 -04:00
func ( w * Wrapper ) add ( name string , ns [ ] ast . Node ) {
var i Interface
var ok bool
if i , ok = w . Interfaces [ name ] ; ! ok {
i = Interface {
Name : name ,
Properties : map [ string ] Property { } ,
Methods : map [ string ] Method { } ,
}
}
for _ , c := range ns {
2019-04-09 11:52:21 -04:00
switch x := c . ( type ) {
2019-04-09 23:19:49 -04:00
case * ast . ObjCPropertyDecl :
p := Property {
Name : x . Name ,
Type : x . Type ,
Type2 : x . Type2 ,
}
w . AddType ( typeOrType2 ( x . Type , x . Type2 ) )
i . Properties [ p . Name ] = p
2019-04-09 11:52:21 -04:00
case * ast . ObjCMethodDecl :
2019-04-09 23:19:49 -04:00
fmt . Printf ( "ObjcMethodDecl: %s\n" , x . Name )
m := Method {
Name : x . Name ,
Type : x . Type ,
Type2 : x . Type2 ,
}
w . AddType ( typeOrType2 ( x . Type , x . Type2 ) )
m . Parameters = w . GetParms ( x )
i . Methods [ m . Name ] = m
case * ast . ObjCProtocol :
//fmt.Printf("ast.ObjCProtocol: %s\n",x.Name)
case * ast . ObjCInterface :
//fmt.Printf("ast.ObjCInterface: %s\n",x.Name)
case * ast . Unknown :
//fmt.Printf("(*ast.Unkonwn %s: %s)\n",x.Name,x.Content)
2019-04-09 11:52:21 -04:00
default :
2019-04-09 23:19:49 -04:00
//fmt.Println(reflect.TypeOf(x))
}
}
w . Interfaces [ i . Name ] = i
}
func ( w * Wrapper ) GetParms ( n * ast . ObjCMethodDecl ) map [ string ] Parameter {
ps := make ( [ ] Parameter , 0 )
avail := make ( [ ] [ ] string , len ( n . Children ( ) ) )
var c ast . Node
i := - 1
for i , c = range n . Children ( ) {
switch x := c . ( type ) {
case * ast . ParmVarDecl :
i ++
p := Parameter {
Type : x . Type ,
Type2 : x . Type2 ,
}
ps = append ( ps , p )
avail = append ( avail , [ ] string { } )
case * ast . AvailabilityAttr :
avail [ i ] = append ( avail [ i ] , x . OS )
}
}
isAvail := func ( l [ ] string ) bool {
if len ( l ) == 0 {
return true
}
for _ , x := range l {
if x == "macos" {
return true
}
}
return false
}
ret := make ( map [ string ] Parameter )
j := 0
for i , p := range ps {
if isAvail ( avail [ i ] ) {
ret [ n . Parameters [ j ] ] = p
j ++
}
}
for _ , p := range ret {
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 {
if t2 != "" {
return t2
}
return t1
}
func ( w * Wrapper ) Wrap ( ) {
//var cCode strings.Builder
var goCode strings . Builder
for k , t := range w . Types { // FIXME: SORT FIRST
w := fmt . Sprintf ( `
// %s
type % s struct { ptr unsafe . Pointer }
` , t , k )
goCode . WriteString ( w )
}
for k , v := range w . Interfaces {
fmt . Printf ( "Interface %s: %d properties, %d methods\n" ,
k , len ( v . Properties ) , len ( v . Methods ) )
for _ , y := range v . Properties {
fmt . Printf ( " property: %s (%s)\n" , y . Name , typeOrType2 ( y . Type , y . Type2 ) )
}
for _ , y := range v . Methods {
fmt . Printf ( " method: %s (%s)\n" , y . Name , typeOrType2 ( y . Type , y . Type2 ) )
for _ , z := range y . Parameters {
fmt . Printf ( " %s:%s\n" , z . Name , typeOrType2 ( z . Type , z . Type2 ) )
}
2019-04-09 11:52:21 -04:00
}
}
2019-04-09 23:19:49 -04:00
fmt . Println ( goCode . String ( ) )
2019-04-09 11:52:21 -04:00
}