mirror of https://github.com/go-python/gopy.git
python callback fully implemented -- one last thing is dealing with return values properly..
This commit is contained in:
parent
179e37fa2d
commit
697577b7f4
|
@ -8,13 +8,20 @@ import "fmt"
|
||||||
|
|
||||||
type FunStruct struct {
|
type FunStruct struct {
|
||||||
FieldI int
|
FieldI int
|
||||||
|
FieldS string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FunStruct) CallBack(arg1 int, fun func(a1 int)) {
|
func (fs *FunStruct) CallBack(arg1 int, fun func(afs *FunStruct, a1 int, s1 string)) {
|
||||||
fun(arg1)
|
fun(fs, arg1, fs.FieldS)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FunStruct) CallBackIf(arg1 int, fun func(afs *FunStruct, a1 int, if1 interface{})) {
|
||||||
|
fun(fs, arg1, fs.FieldS)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FunStruct) OtherMeth(arg1 int, args string) {
|
func (fs *FunStruct) OtherMeth(arg1 int, args string) {
|
||||||
|
fs.FieldI = arg1
|
||||||
|
fs.FieldS = args
|
||||||
fmt.Printf("arg1: %d args: %s\n", arg1, args)
|
fmt.Printf("arg1: %d args: %s\n", arg1, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,23 +7,33 @@ from __future__ import print_function
|
||||||
|
|
||||||
from funcs import go, funcs
|
from funcs import go, funcs
|
||||||
|
|
||||||
def cbfun(val):
|
def cbfun(afs, ival, sval):
|
||||||
print("in python cbfun: val", val)
|
tfs = funcs.FunStruct(handle=afs)
|
||||||
|
print("in python cbfun: FieldI: ", tfs.FieldI, " FieldS: ", tfs.FieldS, " ival: ", ival, " sval: ", sval)
|
||||||
|
|
||||||
|
def cbfunif(afs, ival, ifval):
|
||||||
|
tfs = funcs.FunStruct(handle=afs)
|
||||||
|
print("in python cbfunif: FieldI: ", tfs.FieldI, " FieldS: ", tfs.FieldS, " ival: ", ival, " ifval: ", ifval)
|
||||||
|
|
||||||
class MyClass(object):
|
class MyClass(object):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.misc = 2
|
self.misc = 2
|
||||||
|
|
||||||
def ClassFun(self, val):
|
def ClassFun(self, afs, ival, sval):
|
||||||
print("in python class fun: val", val)
|
tfs = funcs.FunStruct(handle=afs)
|
||||||
|
print("in python class fun: FieldI: ", tfs.FieldI, " FieldS: ", tfs.FieldS, " ival: ", ival, " sval: ", sval)
|
||||||
|
|
||||||
|
|
||||||
fs = funcs.FunStruct()
|
fs = funcs.FunStruct()
|
||||||
|
fs.FieldS = "str field"
|
||||||
|
fs.FieldI = 42
|
||||||
fs.CallBack(22, cbfun)
|
fs.CallBack(22, cbfun)
|
||||||
|
|
||||||
|
fs.CallBackIf(22, cbfunif)
|
||||||
|
|
||||||
cls = MyClass()
|
cls = MyClass()
|
||||||
|
|
||||||
fs.CallBack(22, cls.ClassFun)
|
fs.CallBack(32, cls.ClassFun)
|
||||||
|
|
||||||
# print("funcs.GetF1()...")
|
# print("funcs.GetF1()...")
|
||||||
# f1 = funcs.GetF1()
|
# f1 = funcs.GetF1()
|
||||||
|
|
14
bind/gen.go
14
bind/gen.go
|
@ -44,14 +44,20 @@ package main
|
||||||
// btw, static inline is trick for avoiding need for extra .c file
|
// btw, static inline is trick for avoiding need for extra .c file
|
||||||
// the following are used for build value -- switch on reflect.Kind
|
// the following are used for build value -- switch on reflect.Kind
|
||||||
// or the types equivalent
|
// or the types equivalent
|
||||||
static inline PyObject* py_build_int64(int64_t val) {
|
static inline PyObject* gopy_build_bool(uint8_t val) {
|
||||||
|
return Py_BuildValue("b", val);
|
||||||
|
}
|
||||||
|
static inline PyObject* gopy_build_int64(int64_t val) {
|
||||||
return Py_BuildValue("k", val);
|
return Py_BuildValue("k", val);
|
||||||
}
|
}
|
||||||
static inline PyObject* py_build_float64(double val) {
|
static inline PyObject* gopy_build_uint64(uint64_t val) {
|
||||||
|
return Py_BuildValue("K", val);
|
||||||
|
}
|
||||||
|
static inline PyObject* gopy_build_float64(double val) {
|
||||||
return Py_BuildValue("d", val);
|
return Py_BuildValue("d", val);
|
||||||
}
|
}
|
||||||
static inline PyObject* py_build_string(const char* val) {
|
static inline PyObject* gopy_build_string(const char* val) {
|
||||||
return Py_BuildValue("d", val);
|
return Py_BuildValue("s", val);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
|
@ -12,6 +12,9 @@ func (g *pyGen) genConst(c *Const) {
|
||||||
if isPyCompatVar(c.sym) != nil {
|
if isPyCompatVar(c.sym) != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if c.sym.isSignature() {
|
||||||
|
return
|
||||||
|
}
|
||||||
g.genConstValue(c)
|
g.genConstValue(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +22,9 @@ func (g *pyGen) genVar(v *Var) {
|
||||||
if isPyCompatVar(v.sym) != nil {
|
if isPyCompatVar(v.sym) != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if v.sym.isSignature() {
|
||||||
|
return
|
||||||
|
}
|
||||||
g.genVarGetter(v)
|
g.genVarGetter(v)
|
||||||
if !v.sym.isArray() {
|
if !v.sym.isArray() {
|
||||||
g.genVarSetter(v)
|
g.genVarSetter(v)
|
||||||
|
|
|
@ -320,7 +320,7 @@ func stdBasicTypes() map[string]*symbol {
|
||||||
go2py: "C.CString",
|
go2py: "C.CString",
|
||||||
py2go: "C.GoString",
|
py2go: "C.GoString",
|
||||||
zval: `""`,
|
zval: `""`,
|
||||||
pyfmt: "O&",
|
pyfmt: "s",
|
||||||
},
|
},
|
||||||
|
|
||||||
"rune": { // FIXME(sbinet) py2/py3
|
"rune": { // FIXME(sbinet) py2/py3
|
||||||
|
|
124
bind/symbols.go
124
bind/symbols.go
|
@ -100,9 +100,6 @@ func isPyCompatVar(v *symbol) error {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return fmt.Errorf("gopy: var symbol not found")
|
return fmt.Errorf("gopy: var symbol not found")
|
||||||
}
|
}
|
||||||
// if v.isSignature() {
|
|
||||||
// return fmt.Errorf("gopy: var is function signature")
|
|
||||||
// }
|
|
||||||
if v.isPointer() && v.isBasic() {
|
if v.isPointer() && v.isBasic() {
|
||||||
return fmt.Errorf("gopy: var is pointer to basic type")
|
return fmt.Errorf("gopy: var is pointer to basic type")
|
||||||
}
|
}
|
||||||
|
@ -120,9 +117,7 @@ func isPyCompatVar(v *symbol) error {
|
||||||
|
|
||||||
// isPyCompatType checks if type is compatible with python
|
// isPyCompatType checks if type is compatible with python
|
||||||
func isPyCompatType(typ types.Type) error {
|
func isPyCompatType(typ types.Type) error {
|
||||||
// if _, isSig := typ.(*types.Signature); isSig {
|
typ = typ.Underlying()
|
||||||
// return fmt.Errorf("gopy: type is function signature")
|
|
||||||
// }
|
|
||||||
if ptyp, isPtr := typ.(*types.Pointer); isPtr {
|
if ptyp, isPtr := typ.(*types.Pointer); isPtr {
|
||||||
if _, isBasic := ptyp.Elem().(*types.Basic); isBasic {
|
if _, isBasic := ptyp.Elem().(*types.Basic); isBasic {
|
||||||
return fmt.Errorf("gopy: type is pointer to basic type")
|
return fmt.Errorf("gopy: type is pointer to basic type")
|
||||||
|
@ -146,6 +141,9 @@ func isPyCompatField(f *types.Var) (error, *symbol) {
|
||||||
return fmt.Errorf("gopy: field not exported or is embedded"), nil
|
return fmt.Errorf("gopy: field not exported or is embedded"), nil
|
||||||
}
|
}
|
||||||
ftyp := current.symtype(f.Type())
|
ftyp := current.symtype(f.Type())
|
||||||
|
if _, isSig := f.Type().Underlying().(*types.Signature); isSig {
|
||||||
|
return fmt.Errorf("gopy: type is function signature"), nil
|
||||||
|
}
|
||||||
return isPyCompatVar(ftyp), ftyp
|
return isPyCompatVar(ftyp), ftyp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +187,9 @@ func isPyCompatFunc(sig *types.Signature) (err error, ret types.Type, haserr, ha
|
||||||
if err = isPyCompatType(ret); err != nil {
|
if err = isPyCompatType(ret); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if _, isSig := ret.Underlying().(*types.Signature); isSig {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
args := sig.Params()
|
args := sig.Params()
|
||||||
|
@ -199,7 +200,7 @@ func isPyCompatFunc(sig *types.Signature) (err error, ret types.Type, haserr, ha
|
||||||
if err = isPyCompatType(argt); err != nil {
|
if err = isPyCompatType(argt); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, isSig := argt.(*types.Signature); isSig {
|
if _, isSig := argt.Underlying().(*types.Signature); isSig {
|
||||||
if !hasfun {
|
if !hasfun {
|
||||||
hasfun = true
|
hasfun = true
|
||||||
} else {
|
} else {
|
||||||
|
@ -554,6 +555,7 @@ func (sym *symtab) addSymbol(obj types.Object) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// processTuple ensures that all types in a tuple are in sym table
|
||||||
func (sym *symtab) processTuple(tuple *types.Tuple) error {
|
func (sym *symtab) processTuple(tuple *types.Tuple) error {
|
||||||
if tuple == nil {
|
if tuple == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -572,6 +574,55 @@ func (sym *symtab) processTuple(tuple *types.Tuple) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// buildTuple returns a string of Go code that builds a PyTuple
|
||||||
|
// for the given tuple (e.g., function args).
|
||||||
|
// varnm is the name of the local variable for the built tuple
|
||||||
|
func (sym *symtab) buildTuple(tuple *types.Tuple, varnm string) (string, error) {
|
||||||
|
sz := tuple.Len()
|
||||||
|
if sz == 0 {
|
||||||
|
return "", fmt.Errorf("buildTuple: no elements")
|
||||||
|
}
|
||||||
|
bstr := fmt.Sprintf("%s := C.PyTuple_New(%d); ", varnm, sz)
|
||||||
|
for i := 0; i < sz; i++ {
|
||||||
|
v := tuple.At(i)
|
||||||
|
typ := v.Type()
|
||||||
|
anm := pySafeArg(v.Name(), i)
|
||||||
|
vsym := sym.symtype(typ)
|
||||||
|
if vsym == nil {
|
||||||
|
err := sym.addType(v, typ)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
vsym = sym.symtype(typ)
|
||||||
|
if vsym == nil {
|
||||||
|
return "", fmt.Errorf("buildTuple: type still not found: %s", typ.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bt, isb := typ.Underlying().(*types.Basic)
|
||||||
|
switch {
|
||||||
|
case vsym.hasHandle(): // note: assuming int64 handles
|
||||||
|
bstr += fmt.Sprintf("C.PyTuple_SetItem(%s, %d, C.gopy_build_int64(C.int64_t(%s(%s)%s))); ", varnm, i, vsym.go2py, anm, vsym.go2pyParenEx)
|
||||||
|
case isb:
|
||||||
|
bk := bt.Kind()
|
||||||
|
switch {
|
||||||
|
case bk >= types.Int && bk <= types.Int64:
|
||||||
|
bstr += fmt.Sprintf("C.PyTuple_SetItem(%s, %d, C.gopy_build_int64(C.int64_t(%s))); ", varnm, i, anm)
|
||||||
|
case bk >= types.Uint && bk <= types.Uintptr:
|
||||||
|
bstr += fmt.Sprintf("C.PyTuple_SetItem(%s, %d, C.gopy_build_uint64(C.uint64_t(%s))); ", varnm, i, anm)
|
||||||
|
case bk >= types.Float32 && bk <= types.Float64:
|
||||||
|
bstr += fmt.Sprintf("C.PyTuple_SetItem(%s, %d, C.gopy_build_float64(C.double(%s))); ", varnm, i, anm)
|
||||||
|
case bk == types.String:
|
||||||
|
bstr += fmt.Sprintf("C.PyTuple_SetItem(%s, %d, C.gopy_build_string(C.CString(%s))); ", varnm, i, anm)
|
||||||
|
case bk == types.Bool:
|
||||||
|
bstr += fmt.Sprintf("C.PyTuple_SetItem(%s, %d, C.gopy_build_bool(C.uint8_t(boolGoToPy(%s)))); ", varnm, i, anm)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("buildTuple: type not handled: %s", typ.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bstr, nil
|
||||||
|
}
|
||||||
|
|
||||||
// typeNamePkg gets the goname and package for a given types.Type -- deals with
|
// typeNamePkg gets the goname and package for a given types.Type -- deals with
|
||||||
// naming for types in other packages, and adds those packages to imports paths.
|
// naming for types in other packages, and adds those packages to imports paths.
|
||||||
// Falls back on sym.pkg if no other package info avail.
|
// Falls back on sym.pkg if no other package info avail.
|
||||||
|
@ -879,44 +930,43 @@ func (sym *symtab) addStructType(pkg *types.Package, obj types.Object, t types.T
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sym *symtab) addSignatureType(pkg *types.Package, obj types.Object, t types.Type, kind symkind, id, n string) error {
|
func (sym *symtab) addSignatureType(pkg *types.Package, obj types.Object, t types.Type, kind symkind, id, n string) error {
|
||||||
fn := sym.fullTypeString(t)
|
fn := sym.fullTypeString(t.Underlying())
|
||||||
kind |= skSignature
|
kind |= skSignature
|
||||||
// if (kind & skNamed) == 0 {
|
|
||||||
// id = hash(id)
|
|
||||||
// }
|
|
||||||
|
|
||||||
py2g := fmt.Sprintf("%s { ", fn)
|
py2g := fmt.Sprintf("%s { ", n)
|
||||||
|
|
||||||
sig := t.(*types.Signature)
|
sig := t.Underlying().(*types.Signature)
|
||||||
args := sig.Params()
|
args := sig.Params()
|
||||||
|
rets := sig.Results()
|
||||||
|
if rets.Len() > 0 { // todo 1
|
||||||
|
return fmt.Errorf("multiple return values not supported")
|
||||||
|
}
|
||||||
|
retstr := ""
|
||||||
|
if rets.Len() == 1 {
|
||||||
|
retstr = "_fcret := "
|
||||||
|
}
|
||||||
nargs := args.Len()
|
nargs := args.Len()
|
||||||
// todo: this va_list thing is when you're in a var arg function
|
|
||||||
// inside of c -- not for building dynamically
|
|
||||||
// need to use the ... var args version in C -- need to put
|
|
||||||
// all this arg building code into c.. :(
|
|
||||||
if nargs > 0 {
|
if nargs > 0 {
|
||||||
py2g += fmt.Sprintf("_fcargs := C.PyTuple_New(%d); ", nargs)
|
bstr, err := sym.buildTuple(args, "_fcargs")
|
||||||
for i := 0; i < nargs; i++ {
|
if err != nil {
|
||||||
arg := args.At(i)
|
return err
|
||||||
argt := arg.Type()
|
|
||||||
anm := pySafeArg(arg.Name(), i)
|
|
||||||
asym := sym.symtype(argt)
|
|
||||||
if asym == nil {
|
|
||||||
err := sym.addType(arg, argt)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
asym = sym.symtype(argt)
|
|
||||||
if asym == nil {
|
|
||||||
return fmt.Errorf("type still not found: %s", argt.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// todo: switch on type
|
|
||||||
py2g += fmt.Sprintf("C.PyTuple_SetItem(_fcargs, %d, C.py_build_int64(C.int64_t(%s))); ", i, anm)
|
|
||||||
}
|
}
|
||||||
py2g += fmt.Sprintf("C.PyObject_CallObject(_fun_arg, _fcargs) ")
|
py2g += bstr + retstr
|
||||||
|
py2g += fmt.Sprintf("C.PyObject_CallObject(_fun_arg, _fcargs); ")
|
||||||
} else {
|
} else {
|
||||||
py2g += "C.PyObject_CallObject(_fun_arg, nil) "
|
py2g += retstr + "C.PyObject_CallObject(_fun_arg, nil); "
|
||||||
|
}
|
||||||
|
if rets.Len() == 1 {
|
||||||
|
ret := rets.At(0)
|
||||||
|
rsym := sym.symtype(ret.Type())
|
||||||
|
if rsym == nil {
|
||||||
|
return fmt.Errorf("return type not supported: %s", n)
|
||||||
|
}
|
||||||
|
if rsym.py2go != "" {
|
||||||
|
py2g += fmt.Sprintf("return %s(_fcret)%s", rsym.py2go, rsym.py2goParenEx)
|
||||||
|
} else {
|
||||||
|
py2g += "return _fcret"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
py2g += "}"
|
py2g += "}"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue