[pypy-commit] cffi cffi-1.0: Small refactoring to make a new test pass

arigo noreply at buildbot.pypy.org
Sun May 3 10:21:20 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1905:47ef4ec2a64c
Date: 2015-05-03 10:21 +0200
http://bitbucket.org/cffi/cffi/changeset/47ef4ec2a64c/

Log:	Small refactoring to make a new test pass

diff --git a/_cffi1/ffi_obj.c b/_cffi1/ffi_obj.c
--- a/_cffi1/ffi_obj.c
+++ b/_cffi1/ffi_obj.c
@@ -110,51 +110,47 @@
        Does not return a new reference!
     */
     if ((accept & ACCEPT_STRING) && PyText_Check(arg)) {
-        int index, err;
-        char *input_text;
-        CTypeDescrObject *ct;
         PyObject *types_dict = ffi->types_builder->types_dict;
         PyObject *x = PyDict_GetItem(types_dict, arg);
-        if (x != NULL) {
-            assert(CTypeDescr_Check(x));
-            return (CTypeDescrObject *)x;
+
+        if (x == NULL) {
+            char *input_text = PyText_AS_UTF8(arg);
+            int err, index = parse_c_type(&ffi->info, input_text);
+            if (index < 0) {
+                size_t num_spaces = ffi->info.error_location;
+                char *spaces = alloca(num_spaces + 1);
+                memset(spaces, ' ', num_spaces);
+                spaces[num_spaces] = '\0';
+                PyErr_Format(FFIError, "%s\n%s\n%s^", ffi->info.error_message,
+                             input_text, spaces);
+                return NULL;
+            }
+            x = realize_c_type_or_func(ffi->types_builder,
+                                       ffi->info.output, index);
+            if (x == NULL)
+                return NULL;
+
+            /* Cache under the name given by 'arg', in addition to the
+               fact that the same ct is probably already cached under
+               its standardized name.  In a few cases, it is not, e.g.
+               if it is a primitive; for the purpose of this function,
+               the important point is the following line, which makes
+               sure that in any case the next _ffi_type() with the same
+               'arg' will succeed early, in PyDict_GetItem() above.
+            */
+            err = PyDict_SetItem(types_dict, arg, x);
+            Py_DECREF(x); /* we know it was written in types_dict (unless out
+                             of mem), so there is at least that ref left */
+            if (err < 0)
+                return NULL;
         }
 
-        input_text = PyText_AS_UTF8(arg);
-        index = parse_c_type(&ffi->info, input_text);
-        if (index < 0) {
-            size_t num_spaces = ffi->info.error_location;
-            char *spaces = alloca(num_spaces + 1);
-            memset(spaces, ' ', num_spaces);
-            spaces[num_spaces] = '\0';
-            PyErr_Format(FFIError, "%s\n%s\n%s^", ffi->info.error_message,
-                         input_text, spaces);
-            return NULL;
-        }
-        if (accept & CONSIDER_FN_AS_FNPTR) {
-            ct = realize_c_type_fn_as_fnptr(ffi->types_builder,
-                                            ffi->info.output, index);
-        }
-        else {
-            ct = realize_c_type(ffi->types_builder, ffi->info.output, index);
-        }
-        if (ct == NULL)
-            return NULL;
-
-        /* Cache under the name given by 'arg', in addition to the
-           fact that the same ct is probably already cached under
-           its standardized name.  In a few cases, it is not, e.g.
-           if it is a primitive; for the purpose of this function,
-           the important point is the following line, which makes
-           sure that in any case the next _ffi_type() with the same
-           'arg' will succeed early, in PyDict_GetItem() above.
-        */
-        err = PyDict_SetItem(types_dict, arg, (PyObject *)ct);
-        Py_DECREF(ct);   /* we know it was written in types_dict (unless we got
-                     out of memory), so there is at least this reference left */
-        if (err < 0)
-            return NULL;
-        return ct;
+        if (CTypeDescr_Check(x))
+            return (CTypeDescrObject *)x;
+        else if (accept & CONSIDER_FN_AS_FNPTR)
+            return unwrap_fn_as_fnptr(x);
+        else
+            return unexpected_fn_type(x);
     }
     else if ((accept & ACCEPT_CTYPE) && CTypeDescr_Check(arg)) {
         return (CTypeDescrObject *)arg;
diff --git a/_cffi1/lib_obj.c b/_cffi1/lib_obj.c
--- a/_cffi1/lib_obj.c
+++ b/_cffi1/lib_obj.c
@@ -48,9 +48,9 @@
     PyErr_Clear();
 
     lib = (LibObject *)PyCFunction_GET_SELF(x);
-    tuple = _realize_c_type_or_func(lib->l_types_builder,
-                                    lib->l_types_builder->ctx.types,
-                                    exf->type_index);
+    tuple = realize_c_type_or_func(lib->l_types_builder,
+                                   lib->l_types_builder->ctx.types,
+                                   exf->type_index);
     if (tuple == NULL)
         return NULL;
 
diff --git a/_cffi1/realize_c_type.c b/_cffi1/realize_c_type.c
--- a/_cffi1/realize_c_type.c
+++ b/_cffi1/realize_c_type.c
@@ -219,9 +219,30 @@
     return NULL;
 }
 
+static CTypeDescrObject *
+unwrap_fn_as_fnptr(PyObject *x)
+{
+    assert(PyTuple_Check(x));
+    return (CTypeDescrObject *)PyTuple_GET_ITEM(x, 0);
+}
+
+static CTypeDescrObject *
+unexpected_fn_type(PyObject *x)
+{
+    CTypeDescrObject *ct = unwrap_fn_as_fnptr(x);
+    char *text1 = ct->ct_name;
+    char *text2 = text1 + ct->ct_name_position + 1;
+    assert(text2[-3] == '(');
+    text2[-3] = '\0';
+    PyErr_Format(FFIError, "the type '%s%s' is a function type, not a "
+                           "pointer-to-function type", text1, text2);
+    text2[-3] = '(';
+    return NULL;
+}
+
 static PyObject *
-_realize_c_type_or_func(builder_c_t *builder,
-                        _cffi_opcode_t opcodes[], int index);  /* forward */
+realize_c_type_or_func(builder_c_t *builder,
+                       _cffi_opcode_t opcodes[], int index);  /* forward */
 
 
 /* Interpret an opcodes[] array.  If opcodes == ctx->types, store all
@@ -231,46 +252,11 @@
 static CTypeDescrObject *
 realize_c_type(builder_c_t *builder, _cffi_opcode_t opcodes[], int index)
 {
-    PyObject *x = _realize_c_type_or_func(builder, opcodes, index);
-    if (x == NULL || CTypeDescr_Check(x)) {
+    PyObject *x = realize_c_type_or_func(builder, opcodes, index);
+    if (x == NULL || CTypeDescr_Check(x))
         return (CTypeDescrObject *)x;
-    }
-    else {
-        char *text1, *text2;
-        PyObject *y;
-        assert(PyTuple_Check(x));
-        y = PyTuple_GET_ITEM(x, 0);
-        text1 = ((CTypeDescrObject *)y)->ct_name;
-        text2 = text1 + ((CTypeDescrObject *)y)->ct_name_position + 1;
-        assert(text2[-3] == '(');
-        text2[-3] = '\0';
-        PyErr_Format(FFIError, "the type '%s%s' is a function type, not a "
-                               "pointer-to-function type", text1, text2);
-        text2[-3] = '(';
-        Py_DECREF(x);
-        return NULL;
-    }
-}
-
-/* Same as realize_c_type(), but if it's a function type, return the
-   corresponding function pointer ctype instead of complaining.
-*/
-static CTypeDescrObject *
-realize_c_type_fn_as_fnptr(builder_c_t *builder,
-                           _cffi_opcode_t opcodes[], int index)
-{
-    PyObject *x = _realize_c_type_or_func(builder, opcodes, index);
-    if (x == NULL || CTypeDescr_Check(x)) {
-        return (CTypeDescrObject *)x;
-    }
-    else {
-        PyObject *y;
-        assert(PyTuple_Check(x));
-        y = PyTuple_GET_ITEM(x, 0);
-        Py_INCREF(y);
-        Py_DECREF(x);
-        return (CTypeDescrObject *)y;
-    }
+    else
+        return unexpected_fn_type(x);
 }
 
 static void _realize_name(char *target, const char *prefix, const char *srcname)
@@ -379,7 +365,7 @@
 }
 
 static PyObject *
-_realize_c_type_or_func(builder_c_t *builder,
+realize_c_type_or_func(builder_c_t *builder,
                         _cffi_opcode_t opcodes[], int index)
 {
     PyObject *x, *y, *z;
@@ -400,7 +386,7 @@
         break;
 
     case _CFFI_OP_POINTER:
-        y = _realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op));
+        y = realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op));
         if (y == NULL)
             return NULL;
         if (CTypeDescr_Check(y)) {
@@ -572,7 +558,7 @@
     }
 
     case _CFFI_OP_NOOP:
-        x = _realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op));
+        x = realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op));
         break;
 
     case _CFFI_OP_TYPENAME:
@@ -581,7 +567,7 @@
            up in the 'ctx->typenames' array, but it does so in 'ctx->types'
            instead of in 'opcodes'! */
         int type_index = builder->ctx.typenames[_CFFI_GETARG(op)].type_index;
-        x = _realize_c_type_or_func(builder, builder->ctx.types, type_index);
+        x = realize_c_type_or_func(builder, builder->ctx.types, type_index);
         break;
     }
 
diff --git a/_cffi1/test_ffi_obj.py b/_cffi1/test_ffi_obj.py
--- a/_cffi1/test_ffi_obj.py
+++ b/_cffi1/test_ffi_obj.py
@@ -136,3 +136,9 @@
     assert ffi.from_handle(xp) is x
     yp = ffi.new_handle([6, 4, 2])
     assert ffi.from_handle(yp) == [6, 4, 2]
+
+def test_ffi_cast():
+    ffi = _cffi1_backend.FFI()
+    assert ffi.cast("int(*)(int)", 0) == ffi.NULL
+    ffi.callback("int(int)")      # side-effect of registering this string
+    py.test.raises(ffi.error, ffi.cast, "int(int)", 0)


More information about the pypy-commit mailing list