[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