gopy/bind/gencpy.go

349 lines
7.6 KiB
Go

// Copyright 2015 The go-python Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bind
import (
"go/token"
"path/filepath"
)
const (
cPreamble = `/*
C stubs for package %[1]q.
gopy gen -lang=python %[1]s
File is generated by gopy gen. Do not edit.
*/
#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#include "Python.h"
#include "structmember.h"
#include "memoryobject.h"
#include "bufferobject.h"
// cpy-seq support
#include "cgopy_seq_cpy.h"
#include "_cgopy_seq_export.h"
// header exported from 'go tool cgo'
#include "%[3]s.h"
#if PY_VERSION_HEX > 0x03000000
#error "Python-3 is not yet supported by gopy"
#endif
// descriptor for calls placed to the wrapped go package
#define cgopy_seq_pkg_Descriptor %[1]q
// --- gopy object model ---
struct _gopy_object;
// empty interface converter
typedef GoInterface (*gopy_efacefunc)(struct _gopy_object *);
// proxy for all go values
struct _gopy_object {
PyObject_HEAD
int32_t cgopy; /* handle to a go value */
gopy_efacefunc eface;
};
typedef struct _gopy_object gopy_object;
// --- gopy object model ---
// helpers for cgopy
#define def_cnv(name, c2py, py2c, gotype) \
static int \
cgopy_cnv_py2c_ ## name(PyObject *o, gotype *addr) { \
*addr = py2c(o); \
return 1; \
} \
\
static PyObject* \
cgopy_cnv_c2py_ ## name(gotype *addr) { \
return c2py(*addr); \
}
#if (GOINTBITS == 4)
def_cnv( int, PyLong_FromLong, PyLong_AsLong, GoInt)
def_cnv(uint, PyLong_FromUnsignedLong, PyLong_AsUnsignedLong, GoUint)
#else
def_cnv( int, PyInt_FromLong, PyInt_AsLong, GoInt)
def_cnv(uint, PyInt_FromLong, PyInt_AsLong, GoUint)
#endif
def_cnv( int8, PyInt_FromLong, PyInt_AsLong, GoInt8)
def_cnv( int16, PyInt_FromLong, PyInt_AsLong, GoInt16)
def_cnv( int32, PyInt_FromLong, PyInt_AsLong, GoInt32)
def_cnv( int64, PyLong_FromLong, PyLong_AsLong, GoInt64)
def_cnv(uint8, PyInt_FromLong, PyInt_AsLong, GoUint8)
def_cnv(uint16, PyInt_FromLong, PyInt_AsLong, GoUint16)
def_cnv(uint32, PyInt_FromLong, PyInt_AsLong, GoUint32)
def_cnv(uint64, PyLong_FromUnsignedLong, PyLong_AsUnsignedLong, GoUint64)
def_cnv(float64, PyFloat_FromDouble, PyFloat_AsDouble, GoFloat64)
#undef def_cnv
static int
cgopy_cnv_py2c_bool(PyObject *o, GoUint8 *addr) {
*addr = (o == Py_True) ? 1 : 0;
return 1;
}
static PyObject*
cgopy_cnv_c2py_bool(GoUint8 *addr) {
long v = *addr;
return PyBool_FromLong(v);
}
static int
cgopy_cnv_py2c_string(PyObject *o, cgopy_seq_bytearray *addr) {
const char *str = PyString_AsString(o);
if (str == NULL) {
return 0;
}
Py_ssize_t len = PyString_Size(o);
*addr = cgopy_seq_bytearray_new(len);
addr->Data = (uint8_t*)strncpy((char*)(addr->Data), str, (size_t)(len));
return 1;
}
static PyObject*
cgopy_cnv_c2py_string(cgopy_seq_bytearray *addr) {
uint8_t *data = addr->Data;
int64_t len = addr->Len;
PyObject *pystr = PyString_FromStringAndSize((const char*)(data), (Py_ssize_t)(len));
return pystr;
}
static int
cgopy_cnv_py2c_float32(PyObject *o, GoFloat32 *addr) {
GoFloat32 v = PyFloat_AsDouble(o);
*addr = v;
return 1;
}
static PyObject*
cgopy_cnv_c2py_float32(GoFloat32 *addr) {
GoFloat64 v = *addr;
return PyFloat_FromDouble(v);
}
static int
cgopy_cnv_py2c_complex64(PyObject *o, GoComplex64 *addr) {
Py_complex v = PyComplex_AsCComplex(o);
*addr = v.real + v.imag * _Complex_I;
return 1;
}
static PyObject*
cgopy_cnv_c2py_complex64(GoComplex64 *addr) {
return PyComplex_FromDoubles(creal(*addr), cimag(*addr));
}
static int
cgopy_cnv_py2c_complex128(PyObject *o, GoComplex128 *addr) {
Py_complex v = PyComplex_AsCComplex(o);
*addr = v.real + v.imag * _Complex_I;
return 1;
}
static PyObject*
cgopy_cnv_c2py_complex128(GoComplex128 *addr) {
return PyComplex_FromDoubles(creal(*addr), cimag(*addr));
}
`
)
type cpyGen struct {
decl *printer
impl *printer
fset *token.FileSet
pkg *Package
err ErrorList
lang int // c-python api version (2,3)
}
func (g *cpyGen) gen() error {
g.genPreamble()
// first, process types
for _, t := range g.pkg.types {
sym := t.sym
if !sym.isType() {
continue
}
g.genType(t)
}
// expose ctors at module level
for _, t := range g.pkg.types {
for _, ctor := range t.ctors {
g.genFunc(ctor)
}
}
for _, f := range g.pkg.funcs {
g.genFunc(f)
}
for _, c := range g.pkg.consts {
g.genConst(c)
}
for _, v := range g.pkg.vars {
g.genVar(v)
}
g.impl.Printf("\n/* functions for package %s */\n", g.pkg.pkg.Name())
g.impl.Printf("static PyMethodDef cpy_%s_methods[] = {\n", g.pkg.pkg.Name())
g.impl.Indent()
for _, f := range g.pkg.funcs {
name := f.GoName()
//obj := scope.Lookup(name)
g.impl.Printf("{%[1]q, %[2]s, METH_VARARGS, %[3]q},\n",
name, "cpy_func_"+f.ID(), f.Doc(),
)
}
// expose ctors at module level
// FIXME(sbinet): attach them to types/structs?
// -> problem is if one has 2 or more ctors with exactly the same signature.
for _, t := range g.pkg.types {
for _, f := range t.ctors {
name := f.GoName()
//obj := scope.Lookup(name)
g.impl.Printf("{%[1]q, %[2]s, METH_VARARGS, %[3]q},\n",
name, "cpy_func_"+f.ID(), f.Doc(),
)
}
}
for _, c := range g.pkg.consts {
name := c.GoName()
g.impl.Printf("{%[1]q, %[2]s, METH_VARARGS, %[3]q},\n",
"Get"+name, "cpy_func_"+c.id+"_get", c.Doc(),
)
}
for _, v := range g.pkg.vars {
name := v.Name()
g.impl.Printf("{%[1]q, %[2]s, METH_VARARGS, %[3]q},\n",
"Get"+name, "cpy_func_"+v.id+"_get", v.doc,
)
g.impl.Printf("{%[1]q, %[2]s, METH_VARARGS, %[3]q},\n",
"Set"+name, "cpy_func_"+v.id+"_set", v.doc,
)
}
g.impl.Printf("{NULL, NULL, 0, NULL} /* Sentinel */\n")
g.impl.Outdent()
g.impl.Printf("};\n\n")
g.impl.Printf("PyMODINIT_FUNC\ninit%[1]s(void)\n{\n", g.pkg.pkg.Name())
g.impl.Indent()
g.impl.Printf("PyObject *module = NULL;\n\n")
g.impl.Printf("/* make sure Cgo is loaded and initialized */\n")
g.impl.Printf("cgo_pkg_%[1]s_init();\n\n", g.pkg.pkg.Name())
for _, n := range g.pkg.syms.names() {
sym := g.pkg.syms.sym(n)
if !sym.isType() {
continue
}
g.impl.Printf(
"if (PyType_Ready(&%sType) < 0) { return; }\n",
sym.cpyname,
)
}
g.impl.Printf("module = Py_InitModule3(%[1]q, cpy_%[1]s_methods, %[2]q);\n\n",
g.pkg.pkg.Name(),
g.pkg.doc.Doc,
)
for _, n := range g.pkg.syms.names() {
sym := g.pkg.syms.sym(n)
if !sym.isType() {
continue
}
g.impl.Printf("Py_INCREF(&%sType);\n", sym.cpyname)
g.impl.Printf("PyModule_AddObject(module, %q, (PyObject*)&%sType);\n\n",
sym.goname,
sym.cpyname,
)
}
g.impl.Outdent()
g.impl.Printf("}\n\n")
if len(g.err) > 0 {
return g.err
}
return nil
}
func (g *cpyGen) genConst(o Const) {
g.genFunc(o.f)
}
func (g *cpyGen) genVar(v Var) {
desc := g.pkg.ImportPath() + "." + v.Name()
id := g.pkg.Name() + "_" + v.Name()
doc := v.doc
{
res := []*Var{newVar(g.pkg, v.GoType(), "ret", v.Name(), doc)}
sig := newSignature(g.pkg, nil, nil, res)
fget := Func{
pkg: g.pkg,
sig: sig,
typ: nil,
name: v.Name(),
desc: desc + ".get",
id: id + "_get",
doc: "returns " + g.pkg.Name() + "." + v.Name(),
ret: v.GoType(),
err: false,
}
g.genFunc(fget)
}
{
params := []*Var{newVar(g.pkg, v.GoType(), "arg", v.Name(), doc)}
sig := newSignature(g.pkg, nil, params, nil)
fset := Func{
pkg: g.pkg,
sig: sig,
typ: nil,
name: v.Name(),
desc: desc + ".set",
id: id + "_set",
doc: "sets " + g.pkg.Name() + "." + v.Name(),
ret: nil,
err: false,
}
g.genFunc(fset)
}
}
func (g *cpyGen) genPreamble() {
n := g.pkg.pkg.Name()
g.decl.Printf(cPreamble, g.pkg.ImportPath(), g.pkg.pkg.Path(), filepath.Base(n))
}