Author: Armin Rigo <ar...@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) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit