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"
2019-04-23 15:48:11 -04:00
"gitlab.wow.st/gmp/clast/types"
2019-04-09 11:52:21 -04:00
)
2019-04-10 14:00:48 -04:00
var (
Debug = false
)
2019-04-23 15:48:11 -04:00
type cStruct struct {
goName , cName string
}
2019-04-09 11:52:21 -04:00
type Wrapper struct {
2019-04-09 23:19:49 -04:00
Interfaces map [ string ] Interface
2019-04-26 09:04:53 -04:00
Tps map [ string ] * types . Node
2019-04-09 23:19:49 -04:00
Types map [ string ] string
2019-04-23 15:48:11 -04:00
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
2019-04-26 14:08:43 -04:00
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
2019-04-10 14:00:48 -04:00
Processed map [ string ] bool
2019-04-26 10:07:34 -04:00
Processed2 map [ string ] bool
2019-04-09 23:19:49 -04:00
}
2019-04-10 14:00:48 -04:00
var gobuiltinTypes map [ string ] bool = map [ string ] bool {
"byte" : true ,
"int" : true ,
2019-04-11 13:09:02 -04:00
"float64" : true ,
2019-04-10 14:00:48 -04:00
}
2019-04-23 15:48:11 -04:00
// translate C builtin types to CGo
2019-04-09 23:19:49 -04:00
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" ,
2019-04-23 15:48:11 -04:00
}
2019-04-09 23:19:49 -04:00
2019-04-23 15:48:11 -04:00
//AddType registers a type that needs a Go wrapper struct
func ( w * Wrapper ) AddType ( t , class string ) {
//fmt.Printf("Type: %s\n",t)
2019-04-10 14:00:48 -04:00
if _ , ok := builtinTypes [ t ] ; ok {
return
}
2019-04-23 15:48:11 -04:00
nt := w . goType ( t , class )
2019-04-18 09:38:46 -04:00
if Debug {
2019-04-23 15:48:11 -04:00
fmt . Printf ( "AddType(): (%s) -> %s\n" , t , nt )
2019-04-18 09:38:46 -04:00
}
2019-04-23 15:48:11 -04:00
if nt == "" {
return
}
if _ , ok := w . Interfaces [ nt ] ; ! ok { // not an interface
2019-04-10 14:00:48 -04:00
return
}
}
2019-04-23 15:48:11 -04:00
func ( w * Wrapper ) goType ( t , class string ) string {
2019-04-26 09:04:53 -04:00
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 + " *" }
}
2019-04-23 15:48:11 -04:00
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 )
2019-04-26 09:04:53 -04:00
ret = "[]" + w . goType ( pt , class )
2019-04-23 15:48:11 -04:00
//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
2019-04-26 09:04:53 -04:00
w . Types [ ct ] = t
2019-04-23 15:48:11 -04:00
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
2019-04-09 11:52:21 -04:00
}
2019-04-11 11:46:24 -04:00
func NewWrapper ( debug bool ) * Wrapper {
Debug = debug
if Debug { fmt . Println ( "// Debug mode" ) }
2019-04-09 23:19:49 -04:00
return & Wrapper {
Interfaces : map [ string ] Interface { } ,
Types : map [ string ] string { } ,
2019-04-23 15:48:11 -04:00
gtMap : map [ string ] string { } ,
ctMap : map [ string ] * types . Node { } ,
goStructTypes : map [ string ] cStruct { } ,
Processed : map [ string ] bool { } ,
2019-04-26 10:07:34 -04:00
Processed2 : map [ string ] bool { } ,
2019-04-09 23:19:49 -04:00
}
}
type Property struct {
2019-04-23 15:48:11 -04:00
Name , Type , Attr string
2019-04-26 09:04:53 -04:00
Tp * types . Type
2019-04-09 23:19:49 -04:00
}
type Parameter struct {
2019-04-23 15:48:11 -04:00
Pname , Vname , Type string
2019-04-26 09:04:53 -04:00
Tp * types . Type
2019-04-09 23:19:49 -04:00
}
type Method struct {
2019-04-23 15:48:11 -04:00
Name , Type , Class string
2019-04-26 09:04:53 -04:00
Tp * types . Type
2019-04-11 17:00:36 -04:00
ClassMethod bool
2019-04-11 11:46:24 -04:00
Parameters [ ] Parameter
2019-04-09 23:19:49 -04:00
}
2019-04-10 14:00:48 -04:00
func ( m Method ) isVoid ( ) bool {
2019-04-23 15:48:11 -04:00
return m . Type == "void"
2019-04-10 14:00:48 -04:00
}
2019-04-26 14:08:43 -04:00
//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 ( ) {
return true
}
}
return false
}
2019-04-11 13:09:02 -04:00
func ( w Wrapper ) isObject ( tp string ) bool { // takes a goType
2019-04-11 12:00:10 -04:00
if _ , ok := w . Interfaces [ tp ] ; ok {
2019-04-11 11:46:24 -04:00
return true
}
return false
}
2019-04-11 13:09:02 -04:00
func ( w Wrapper ) cparamlist ( m Method ) string {
2019-04-11 17:00:36 -04:00
ret := make ( [ ] string , 0 )
if ! m . ClassMethod {
ret = append ( ret , "void* obj" )
}
2019-04-11 11:46:24 -04:00
for _ , p := range m . Parameters {
2019-04-26 14:08:43 -04:00
var tp string
if p . Tp . Node . IsPointer ( ) {
2019-04-11 13:09:02 -04:00
tp = "void*"
2019-04-26 14:08:43 -04:00
} else {
tp = p . Tp . CType ( )
2019-04-11 13:09:02 -04:00
}
ret = append ( ret , fmt . Sprintf ( "%s %s" , tp , p . Vname ) )
2019-04-10 14:00:48 -04:00
}
return strings . Join ( ret , ", " )
}
2019-04-23 15:48:11 -04:00
func ( w Wrapper ) objcparamlist ( m Method ) string {
2019-04-10 14:00:48 -04:00
if len ( m . Parameters ) == 0 {
return m . Name
}
2019-04-11 11:46:24 -04:00
first := true
ret := [ ] string { }
for _ , p := range m . Parameters {
if first {
ret = append ( ret , m . Name + ":" + p . Vname )
first = false
} else {
ret = append ( ret , p . Pname + ":" + p . Vname )
}
2019-04-10 14:00:48 -04:00
}
return strings . Join ( ret , " " )
}
2019-04-23 15:48:11 -04:00
//goreserved is a map telling whether a word is a go reserved word that is not
//also a C/Objective-C reserved word.
2019-04-11 11:46:24 -04:00
var goreserved map [ string ] bool = map [ string ] bool {
"range" : true ,
}
2019-04-26 10:56:00 -04:00
func ( m * Method ) gpntp ( ) ( [ ] string , [ ] * types . Type , string ) {
2019-04-26 09:04:53 -04:00
ns := [ ] string { }
tps := [ ] * types . Type { }
2019-04-26 10:56:00 -04:00
if ! m . ClassMethod {
ns = append ( ns , "o" )
tps = append ( tps , types . NewTypeFromString ( m . Class + "*" , "" ) )
}
2019-04-26 09:04:53 -04:00
for _ , p := range m . Parameters {
gname := p . Vname
if goreserved [ gname ] {
gname = gname + "_"
}
ns = append ( ns , gname )
tps = append ( tps , p . Tp )
}
2019-04-26 10:56:00 -04:00
ret := [ ] string { }
i := 0
if ! m . ClassMethod { i = 1 }
for ; i < len ( ns ) ; i ++ {
2019-04-26 14:08:43 -04:00
gt := tps [ i ] . GoType ( )
if gt == "*Void" {
gt = "unsafe.Pointer"
}
ret = append ( ret , ns [ i ] + " " + gt )
2019-04-26 10:56:00 -04:00
}
return ns , tps , strings . Join ( ret , ", " )
2019-04-26 09:04:53 -04:00
}
2019-04-11 13:09:02 -04:00
func ( w Wrapper ) goparamlist ( m Method ) ( string , [ ] string , bool ) {
2019-04-10 14:00:48 -04:00
ret := [ ] string { }
tps := [ ] string { }
2019-04-11 11:46:24 -04:00
for _ , p := range m . Parameters {
gname := p . Vname
2019-04-23 15:48:11 -04:00
w . AddType ( p . Type , m . Class )
tp := w . goType ( p . Type , m . Class )
if tp == "" {
2019-04-11 11:46:24 -04:00
return "UNSUPPORTED TYPE" , [ ] string { } , false
}
2019-04-11 13:09:02 -04:00
if w . isObject ( tp ) {
tp = "*" + tp
}
2019-04-11 11:46:24 -04:00
if goreserved [ gname ] {
gname = gname + "_"
2019-04-10 14:00:48 -04:00
}
tps = append ( tps , tp )
2019-04-11 11:46:24 -04:00
ret = append ( ret , fmt . Sprintf ( "%s %s" , gname , tp ) )
2019-04-10 14:00:48 -04:00
}
2019-04-11 11:46:24 -04:00
return strings . Join ( ret , ", " ) , tps , true
2019-04-10 14:00:48 -04:00
}
2019-04-11 13:09:02 -04:00
func ( w Wrapper ) goparamnames ( m Method ) string {
2019-04-11 17:00:36 -04:00
ret := make ( [ ] string , 0 )
if ! m . ClassMethod {
ret = append ( ret , "o.ptr" )
}
2019-04-11 11:46:24 -04:00
for _ , p := range m . Parameters {
gname := p . Vname
if goreserved [ gname ] {
gname = gname + "_"
}
2019-04-23 15:48:11 -04:00
gt := w . goType ( p . Type , m . Class )
if gt == "" {
return "UNSUPPORTED TYPE " + p . Type
}
2019-04-11 13:09:02 -04:00
if w . isObject ( gt ) {
gname = gname + ".ptr"
2019-04-23 15:48:11 -04:00
} 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 + ")"
2019-04-11 13:09:02 -04:00
}
2019-04-11 11:46:24 -04:00
ret = append ( ret , gname )
2019-04-10 14:00:48 -04:00
}
return strings . Join ( ret , ", " )
}
2019-04-09 23:19:49 -04:00
type Interface struct {
2019-04-10 14:00:48 -04:00
Name , Super string
2019-04-09 23:19:49 -04:00
Properties map [ string ] Property
Methods map [ string ] Method
}
2019-04-10 14:00:48 -04:00
func ( i Interface ) IsRoot ( ) bool {
if i . Super == "" || i . Super == i . Name {
return true
}
return false
}
2019-04-09 23:19:49 -04:00
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 ( )
2019-04-23 15:48:11 -04:00
if len ( ns ) > 0 {
switch x := ns [ 0 ] . ( type ) {
case * ast . ObjCInterface :
w . add ( x . Name , ns [ 1 : ] )
return
}
2019-04-09 23:19:49 -04:00
}
2019-04-23 15:48:11 -04:00
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 { } ,
}
2019-04-26 09:04:53 -04:00
w . AddType ( name , name ) // need this?
2019-04-09 23:19:49 -04:00
}
2019-04-26 10:07:34 -04:00
tp := types . NewTypeFromString ( name , name )
2019-04-26 14:08:43 -04:00
types . Wrap ( tp . GoType ( ) )
2019-04-11 11:46:24 -04:00
var avail bool
2019-04-09 23:19:49 -04:00
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 :
2019-04-11 11:46:24 -04:00
//fmt.Printf("ObjCPropertyDecl: %s\n",x.Name)
2019-04-09 23:19:49 -04:00
p := Property {
Name : x . Name ,
Type : x . Type ,
2019-04-26 09:04:53 -04:00
Tp : types . NewTypeFromString ( x . Type , name ) ,
2019-04-09 23:19:49 -04:00
}
2019-04-11 11:46:24 -04:00
//_,avail = w.GetParms(x,name) // TODO
//if avail {
2019-04-23 15:48:11 -04:00
// w.AddType(x.Type,name)
2019-04-11 11:46:24 -04:00
i . Properties [ p . Name ] = p
//}
2019-04-09 11:52:21 -04:00
case * ast . ObjCMethodDecl :
2019-04-10 14:00:48 -04:00
//fmt.Printf("ObjCMethodDecl: %s\n",x.Name)
2019-04-09 23:19:49 -04:00
m := Method {
Name : x . Name ,
Type : x . Type ,
2019-04-26 09:04:53 -04:00
Tp : types . NewTypeFromString ( x . Type , name ) ,
2019-04-11 11:46:24 -04:00
Class : name ,
2019-04-11 17:00:36 -04:00
ClassMethod : x . ClassMethod ,
2019-04-11 11:46:24 -04:00
}
m . Parameters , avail = w . GetParms ( x , name )
if avail {
2019-04-23 15:48:11 -04:00
// w.AddType(x.Type,name)
2019-04-11 11:46:24 -04:00
i . Methods [ m . Name ] = m
2019-04-09 23:19:49 -04:00
}
case * ast . ObjCProtocol :
//fmt.Printf("ast.ObjCProtocol: %s\n",x.Name)
case * ast . ObjCInterface :
2019-04-10 14:00:48 -04:00
if x . Super {
//fmt.Printf("ast.ObjCInterface: %s inherits from %s\n",name,x.Name)
i . Super = x . Name
2019-04-26 09:04:53 -04:00
types . SetSuper ( name , x . Name )
2019-04-10 14:00:48 -04:00
}
2019-04-09 23:19:49 -04:00
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))
}
}
2019-04-23 15:48:11 -04:00
//fmt.Println("Add interface ",i.Name)
2019-04-09 23:19:49 -04:00
w . Interfaces [ i . Name ] = i
}
2019-04-11 11:46:24 -04:00
type AvailAttr struct {
OS , Version string
Deprecated bool
}
2019-04-23 15:48:11 -04:00
//GetParms returns the parameters of a method declaration and a bool
//indicating whether the given method is available on MacOS and not
//deprecated.
2019-04-11 11:46:24 -04:00
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 ( ) {
2019-04-09 23:19:49 -04:00
switch x := c . ( type ) {
case * ast . ParmVarDecl :
p := Parameter {
2019-04-11 11:46:24 -04:00
Pname : n . Parameters [ j ] ,
Vname : x . Name ,
2019-04-09 23:19:49 -04:00
Type : x . Type ,
2019-04-26 10:07:34 -04:00
Tp : types . NewTypeFromString ( x . Type , class ) ,
2019-04-09 23:19:49 -04:00
}
2019-04-11 11:46:24 -04:00
ret = append ( ret , p )
j ++
2019-04-09 23:19:49 -04:00
case * ast . AvailabilityAttr :
2019-04-11 11:46:24 -04:00
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 ) }
2019-04-09 23:19:49 -04:00
}
}
2019-04-18 09:38:46 -04:00
// check that the method is available for this OS and not deprecated
2019-04-11 11:46:24 -04:00
a := func ( ) bool {
if len ( avail ) == 0 {
2019-04-09 23:19:49 -04:00
return true
}
2019-04-11 11:46:24 -04:00
for _ , x := range avail {
if x . OS == "macos" && x . Deprecated == false {
2019-04-09 23:19:49 -04:00
return true
}
}
return false
2019-04-11 11:46:24 -04:00
} ( )
if ! a {
return nil , false
2019-04-09 23:19:49 -04:00
}
2019-04-18 09:38:46 -04:00
// check that we found the right number of parameters
2019-04-11 11:46:24 -04:00
if len ( ret ) != 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 ) , len ( ret ) )
2019-04-09 23:19:49 -04:00
}
2019-04-11 11:46:24 -04:00
return ret , true
2019-04-09 23:19:49 -04:00
}
2019-04-26 10:07:34 -04:00
// new version of ProcessType
func ( w * Wrapper ) pt2 ( tps ... * types . Type ) {
switch len ( tps ) {
case 0 :
return
case 1 :
2019-04-26 14:08:43 -04:00
w . _pt2 ( tps [ 0 ] )
2019-04-26 10:07:34 -04:00
default :
for _ , tp := range tps {
w . pt2 ( tp )
}
return
}
2019-04-26 14:08:43 -04:00
}
func ( w * Wrapper ) _pt2 ( tp * types . Type ) {
bt := tp . BaseType ( )
if w . Processed2 [ bt . GoType ( ) ] { return }
w . Processed2 [ bt . GoType ( ) ] = true
if bt . Node . IsFunction ( ) {
2019-04-26 10:07:34 -04:00
return
}
2019-04-26 14:08:43 -04:00
w . goTypes . WriteString ( tp . GoTypeDecl ( ) )
if tp . GoType ( ) == "*Char" {
w . CharHelpers ( )
}
super := types . Super ( bt . GoType ( ) )
if super != "" {
types . Wrap ( super )
pt := types . NewTypeFromString ( super + "*" , "" )
w . _pt2 ( pt )
}
}
func ( w * Wrapper ) CharHelpers ( ) {
w . goHelpers . WriteString ( `
func CharFromString ( s string ) * Char {
return ( * Char ) ( unsafe . Pointer ( C . CString ( s ) ) )
}
func CharFromBytes ( b [ ] byte ) * Char {
return ( * Char ) ( unsafe . Pointer ( C . CString ( string ( b ) ) ) )
}
func ( c * Char ) String ( ) string {
return C . GoString ( ( * C . char ) ( c ) )
}
` )
2019-04-26 10:07:34 -04:00
}
2019-04-10 14:00:48 -04:00
func ( w * Wrapper ) ProcessType ( gotype string ) {
if gotype == "" {
return
}
2019-04-11 13:09:02 -04:00
if gotype [ 0 ] == '*' {
gotype = gotype [ 1 : ]
}
2019-04-26 09:04:53 -04:00
if w . Processed [ gotype ] {
return
}
w . Processed [ gotype ] = true
2019-04-10 14:00:48 -04:00
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 )
}
2019-04-23 15:48:11 -04:00
var fields string
2019-04-10 14:00:48 -04:00
// if there is an Interface known for this type, decide if it is the
// root object and if so give it a pointer element:
2019-04-23 15:48:11 -04:00
if i . IsRoot ( ) {
fields = "ptr unsafe.Pointer"
} else {
fields = i . Super // embed superclass
}
w . goTypes . WriteString ( fmt . Sprintf ( `
2019-04-09 23:19:49 -04:00
// %s
2019-04-10 14:00:48 -04:00
type % s struct { % s }
` , ctype , gotype , fields ) )
2019-04-23 15:48:11 -04:00
}
if s , ok := w . goStructTypes [ gotype ] ; ok {
ct := strings . ReplaceAll ( s . cName , " " , "_" )
w . goTypes . WriteString ( fmt . Sprintf ( `
type % s % s
` , s . goName , "C." + ct ) )
}
2019-04-10 14:00:48 -04:00
}
func ( w * Wrapper ) ProcessTypes ( tps [ ] string ) {
for _ , tp := range tps {
w . ProcessType ( tp )
2019-04-09 23:19:49 -04:00
}
2019-04-10 14:00:48 -04:00
}
2019-04-23 15:48:11 -04:00
func ( w * Wrapper ) Wrap ( toproc [ ] string ) {
2019-04-10 14:00:48 -04:00
w . cCode . WriteString ( ` / *
# cgo CFLAGS : - x objective - c
2019-04-11 11:46:24 -04:00
# cgo LDFLAGS : - framework Foundation
# import < Foundation / Foundation . h >
2019-04-10 14:00:48 -04:00
` )
2019-04-23 15:48:11 -04:00
pInterfaces := map [ string ] Interface { }
for _ , iface := range toproc {
pInterfaces [ iface ] = w . Interfaces [ iface ]
}
for iname , i := range pInterfaces {
2019-04-10 14:00:48 -04:00
if Debug {
fmt . Printf ( "Interface %s: %d properties, %d methods\n" ,
2019-04-23 15:48:11 -04:00
iname , len ( i . Properties ) , len ( i . Methods ) )
2019-04-10 14:00:48 -04:00
}
w . goCode . WriteString ( fmt . Sprintf ( `
func New % s ( ) * % s {
ret := & % s { }
ret . ptr = unsafe . Pointer ( C . New % s ( ) )
2019-04-23 15:48:11 -04:00
ret = ret . Init ( )
2019-04-10 14:00:48 -04:00
return ret
}
2019-04-23 15:48:11 -04:00
` , i . Name , i . Name , i . Name , i . Name ) )
2019-04-10 14:00:48 -04:00
w . cCode . WriteString ( fmt . Sprintf ( `
% s *
New % s ( ) {
2019-04-11 17:00:36 -04:00
return [ % s alloc ] ;
2019-04-10 14:00:48 -04:00
}
2019-04-23 15:48:11 -04:00
` , i . Name , i . Name , i . Name ) )
2019-04-10 14:00:48 -04:00
2019-04-23 15:48:11 -04:00
for _ , p := range i . Properties {
2019-04-10 14:00:48 -04:00
if Debug {
2019-04-23 15:48:11 -04:00
fmt . Printf ( " property: %s (%s)\n" , p . Name , p . Type )
2019-04-10 14:00:48 -04:00
}
2019-04-23 15:48:11 -04:00
w . AddType ( p . Type , i . Name )
2019-04-09 23:19:49 -04:00
}
2019-04-23 15:48:11 -04:00
for _ , m := range i . Methods {
2019-04-10 14:00:48 -04:00
if Debug {
2019-04-23 15:48:11 -04:00
fmt . Printf ( " method: %s (%s)\n" , m . Name , m . Type )
2019-04-10 14:00:48 -04:00
}
2019-04-26 10:07:34 -04:00
if m . Tp . Node . IsFunction ( ) {
continue
}
2019-04-26 14:08:43 -04:00
if m . hasFunctionParam ( ) {
continue
}
2019-04-23 15:48:11 -04:00
gname := strings . Title ( m . Name )
2019-04-26 10:07:34 -04:00
cname := i . Name + "_" + m . Name
2019-04-10 14:00:48 -04:00
2019-04-23 15:48:11 -04:00
w . AddType ( m . Type , i . Name )
2019-04-26 10:07:34 -04:00
//cmtype := w.ctMap[w.goType(m.Type,i.Name)].CtypeSimplified()
cmtype := m . Tp . CType ( )
2019-04-26 10:56:00 -04:00
ns , tps , gplist := m . gpntp ( )
2019-04-26 10:07:34 -04:00
w . pt2 ( tps ... )
w . pt2 ( m . Tp )
2019-04-26 14:08:43 -04:00
grtype := m . Tp . GoType ( )
if grtype == "Void" {
grtype = ""
}
2019-04-10 14:00:48 -04:00
w . goCode . WriteString ( fmt . Sprintf ( `
2019-04-26 09:04:53 -04:00
func ( o * % s ) % s ( % s ) % s {
2019-04-26 14:08:43 -04:00
` , i . Name , gname , gplist , grtype ) )
2019-04-26 10:07:34 -04:00
w . goCode . WriteString (
2019-04-26 10:56:00 -04:00
types . GoToC ( cname , ns , m . Tp , tps ) + "}\n\n" )
2019-04-10 14:00:48 -04:00
cret := ""
2019-04-23 15:48:11 -04:00
if ! m . isVoid ( ) {
2019-04-10 14:00:48 -04:00
cret = "return "
}
2019-04-11 17:00:36 -04:00
var cobj string
2019-04-23 15:48:11 -04:00
if m . ClassMethod {
cobj = i . Name
2019-04-11 17:00:36 -04:00
} else {
cobj = "(id)obj"
}
2019-04-10 14:00:48 -04:00
w . cCode . WriteString ( fmt . Sprintf ( `
% s
2019-04-26 10:07:34 -04:00
% s ( % s ) {
2019-04-11 17:00:36 -04:00
% s [ % s % s ] ;
2019-04-26 10:07:34 -04:00
} ` , cmtype , cname , w . cparamlist ( m ) , cret , cobj , w . objcparamlist ( m ) ) )
2019-04-09 11:52:21 -04:00
}
}
2019-04-10 14:00:48 -04:00
fmt . Println ( ` package main
` )
fmt . Println ( w . cCode . String ( ) )
fmt . Println ( `
* /
import "C"
import (
"unsafe"
)
` )
fmt . Println ( w . goTypes . String ( ) )
2019-04-26 14:08:43 -04:00
fmt . Println ( w . goHelpers . String ( ) )
2019-04-10 14:00:48 -04:00
fmt . Println ( w . goCode . String ( ) )
2019-04-09 11:52:21 -04:00
}