// 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)) }