[pypy-commit] pypy rffi-parser-2: Add a way to create API functions using C declarations; try to use it

rlamy pypy.commits at gmail.com
Thu Jan 12 11:41:54 EST 2017


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: rffi-parser-2
Changeset: r89520:05b94a8b7e3d
Date: 2017-01-12 16:40 +0000
http://bitbucket.org/pypy/pypy/changeset/05b94a8b7e3d/

Log:	Add a way to create API functions using C declarations; try to use
	it

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -246,13 +246,15 @@
 
 class ApiFunction(object):
     def __init__(self, argtypes, restype, callable, error=CANNOT_FAIL,
-                 c_name=None, gil=None, result_borrowed=False, result_is_ll=False):
+                 c_name=None, cdecl=None, gil=None,
+                 result_borrowed=False, result_is_ll=False):
         self.argtypes = argtypes
         self.restype = restype
         self.functype = lltype.Ptr(lltype.FuncType(argtypes, restype))
         self.callable = callable
         self.error_value = error
         self.c_name = c_name
+        self.cdecl = cdecl
 
         # extract the signature from the (CPython-level) code object
         from pypy.interpreter import pycode
@@ -371,6 +373,8 @@
         return unwrapper
 
     def get_c_restype(self, c_writer):
+        if self.cdecl:
+            return self.cdecl.split(self.c_name)[0].strip()
         return c_writer.gettype(self.restype).replace('@', '').strip()
 
     def get_c_args(self, c_writer):
@@ -470,6 +474,20 @@
         return unwrapper
     return decorate
 
+def api_decl(cdecl, cts, error=_NOT_SPECIFIED, header=DEFAULT_HEADER):
+    def decorate(func):
+        func._always_inline_ = 'try'
+        name, FUNC = cts.parse_func(cdecl)
+        api_function = ApiFunction(
+            FUNC.ARGS, FUNC.RESULT, func,
+            error=_compute_error(error, FUNC.RESULT), cdecl=cdecl)
+        FUNCTIONS_BY_HEADER[header][name] = api_function
+        unwrapper = api_function.get_unwrapper()
+        unwrapper.func = func
+        unwrapper.api_func = api_function
+        return unwrapper
+    return decorate
+
 def slot_function(argtypes, restype, error=_NOT_SPECIFIED):
     def decorate(func):
         func._always_inline_ = 'try'
diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -11,12 +11,10 @@
     CONST_STRING, METH_CLASS, METH_COEXIST, METH_KEYWORDS, METH_NOARGS, METH_O,
     METH_STATIC, METH_VARARGS, PyObject, PyObjectFields, bootstrap_function,
     build_type_checkers, cpython_api, cpython_struct, generic_cpy_call,
-    PyTypeObjectPtr, slot_function, object_h)
+    PyTypeObjectPtr, slot_function, object_h, api_decl)
 from pypy.module.cpyext.pyobject import (
     Py_DecRef, from_ref, make_ref, as_pyobj, make_typedescr)
 
-PyCFunction_typedef = rffi.COpaquePtr(typedef='PyCFunction')
-
 PyMethodDef = object_h.gettype('PyMethodDef')
 PyCFunction = object_h.gettype('PyCFunction')
 PyCFunctionKwArgs = object_h.gettype('PyCFunctionWithKeywords')
@@ -284,7 +282,7 @@
 def PyCFunction_NewEx(space, ml, w_self, w_name):
     return space.wrap(W_PyCFunctionObject(space, ml, w_self, w_name))
 
- at cpython_api([PyObject], PyCFunction_typedef)
+ at api_decl("PyCFunction PyCFunction_GetFunction(PyObject *)", object_h)
 def PyCFunction_GetFunction(space, w_obj):
     try:
         cfunction = space.interp_w(W_PyCFunctionObject, w_obj)
diff --git a/pypy/module/cpyext/test/test_methodobject.py b/pypy/module/cpyext/test/test_methodobject.py
--- a/pypy/module/cpyext/test/test_methodobject.py
+++ b/pypy/module/cpyext/test/test_methodobject.py
@@ -4,7 +4,7 @@
 from pypy.module.cpyext.api import ApiFunction
 from pypy.module.cpyext.pyobject import PyObject, make_ref, Py_DecRef
 from pypy.module.cpyext.methodobject import (
-    PyDescr_NewMethod, PyCFunction_typedef)
+    PyDescr_NewMethod, PyCFunction)
 from rpython.rtyper.lltypesystem import rffi, lltype
 
 class AppTestMethodObject(AppTestCpythonExtensionBase):
@@ -67,7 +67,7 @@
              '''
              PyCFunction ptr = PyCFunction_GetFunction(args);
              if (!ptr) return NULL;
-             if (ptr == MyModule_getarg_O)
+             if (ptr == (PyCFunction)MyModule_getarg_O)
                  Py_RETURN_TRUE;
              else
                  Py_RETURN_FALSE;
@@ -105,8 +105,7 @@
         ml = lltype.malloc(PyMethodDef, flavor='raw', zero=True)
         namebuf = rffi.cast(rffi.CONST_CCHARP, rffi.str2charp('func'))
         ml.c_ml_name = namebuf
-        ml.c_ml_meth = rffi.cast(PyCFunction_typedef,
-                                 c_func.get_llhelper(space))
+        ml.c_ml_meth = rffi.cast(PyCFunction, c_func.get_llhelper(space))
 
         method = api.PyDescr_NewMethod(space.w_str, ml)
         assert repr(method).startswith(
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -19,7 +19,7 @@
     Py_TPFLAGS_HAVE_NEWBUFFER, Py_TPFLAGS_CHECKTYPES,
     Py_TPFLAGS_HAVE_INPLACEOPS)
 from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject,
-    W_PyCWrapperObject, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef,
+    W_PyCWrapperObject, PyCFunction_NewEx, PyCFunction, PyMethodDef,
     W_PyCMethodObject, W_PyCFunctionObject)
 from pypy.module.cpyext.modsupport import convert_method_defs
 from pypy.module.cpyext.pyobject import (
@@ -386,8 +386,7 @@
 
 def setup_new_method_def(space):
     ptr = get_new_method_def(space)
-    ptr.c_ml_meth = rffi.cast(
-        PyCFunction_typedef, llslot(space, tp_new_wrapper))
+    ptr.c_ml_meth = rffi.cast(PyCFunction, llslot(space, tp_new_wrapper))
 
 def add_tp_new_wrapper(space, dict_w, pto):
     if "__new__" in dict_w:


More information about the pypy-commit mailing list