Author: Armin Rigo <ar...@tunes.org> Branch: cffi-1.0 Changeset: r77293:abb305ea8684 Date: 2015-05-11 15:55 +0200 http://bitbucket.org/pypy/pypy/changeset/abb305ea8684/
Log: ffi.addressof(lib, "var") diff --git a/pypy/module/_cffi_backend/cglob.py b/pypy/module/_cffi_backend/cglob.py --- a/pypy/module/_cffi_backend/cglob.py +++ b/pypy/module/_cffi_backend/cglob.py @@ -1,6 +1,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.typedef import TypeDef from pypy.module._cffi_backend.cdataobj import W_CData +from pypy.module._cffi_backend import newtype class W_GlobSupport(W_Root): @@ -15,5 +16,9 @@ def write_global_var(self, w_newvalue): self.w_ctype.convert_from_object(self.ptr, w_newvalue) + def address(self): + w_ctypeptr = newtype.new_pointer_type(self.space, self.w_ctype) + return W_CData(self.space, self.ptr, w_ctypeptr) + W_GlobSupport.typedef = TypeDef("FFIGlobSupport") W_GlobSupport.typedef.acceptable_as_base_class = False diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py --- a/pypy/module/_cffi_backend/ffi_obj.py +++ b/pypy/module/_cffi_backend/ffi_obj.py @@ -145,20 +145,34 @@ def descr_addressof(self, w_arg, args_w): """\ -With a single arg, return the address of a <cdata 'struct-or-union'>. -If 'fields_or_indexes' are given, returns the address of that field or -array item in the structure or array, recursively in case of nested -structures.""" +Limited equivalent to the '&' operator in C: + +1. ffi.addressof(<cdata 'struct-or-union'>) returns a cdata that is a +pointer to this struct or union. + +2. ffi.addressof(<cdata>, field-or-index...) returns the address of a +field or array item inside the given structure or array, recursively +in case of nested structures or arrays. + +3. ffi.addressof(<library>, "name") returns the address of the named +global variable.""" + # + from pypy.module._cffi_backend.lib_obj import W_LibObject + space = self.space + if isinstance(w_arg, W_LibObject) and len(args_w) == 1: + # case 3 in the docstring + return w_arg.address_of_global_var(space.str_w(args_w[0])) # w_ctype = self.ffi_type(w_arg, ACCEPT_CDATA) - space = self.space if len(args_w) == 0: + # case 1 in the docstring if (not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion) and not isinstance(w_ctype, ctypearray.W_CTypeArray)): raise oefmt(space.w_TypeError, "expected a cdata struct/union/array object") offset = 0 else: + # case 2 in the docstring if (not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion) and not isinstance(w_ctype, ctypearray.W_CTypeArray) and not isinstance(w_ctype, ctypeptr.W_CTypePointer)): diff --git a/pypy/module/_cffi_backend/lib_obj.py b/pypy/module/_cffi_backend/lib_obj.py --- a/pypy/module/_cffi_backend/lib_obj.py +++ b/pypy/module/_cffi_backend/lib_obj.py @@ -10,6 +10,7 @@ from pypy.module._cffi_backend import cffi_opcode, cglob from pypy.module._cffi_backend.realize_c_type import getop, getarg from pypy.module._cffi_backend.cdataobj import W_CData +from pypy.module._cffi_backend.ctypefunc import W_CTypeFunc from pypy.module._cffi_backend.structwrapper import W_StructWrapper @@ -173,6 +174,24 @@ for i in range(total)] return space.newlist(names_w) + def address_of_global_var(self, varname): + # rebuild a string object from 'varname', to do typechecks and + # to force a unicode back to a plain string + space = self.space + w_value = self._get_attr(space.wrap(varname)) + if isinstance(w_value, cglob.W_GlobSupport): + # regular case: a global variable + return w_value.address() + # + if ((isinstance(w_value, W_CData) and + isinstance(w_value.ctype, W_CTypeFunc)) + or isinstance(w_value, W_StructWrapper)): + # '&func' is 'func' in C, for a constant function 'func' + return w_value + # + raise oefmt(space.w_AttributeError, + "cannot take the address of the constant '%s'", varname) + W_LibObject.typedef = TypeDef( 'CompiledLib', diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py --- a/pypy/module/_cffi_backend/test/test_recompiler.py +++ b/pypy/module/_cffi_backend/test/test_recompiler.py @@ -695,3 +695,37 @@ assert repr(ffi.typeof("foo_t")) == "<ctype 'foo_t'>" assert repr(ffi.typeof("bar_p")) == "<ctype 'struct $1 *'>" assert repr(ffi.typeof("baz_pp")) == "<ctype 'struct $2 * *'>" + + def test_address_of_global_var(self): + ffi, lib = self.prepare(""" + long bottom, bottoms[2]; + long FetchRectBottom(void); + long FetchRectBottoms1(void); + #define FOOBAR 42 + """, "test_address_of_global_var", """ + long bottom, bottoms[2]; + long FetchRectBottom(void) { return bottom; } + long FetchRectBottoms1(void) { return bottoms[1]; } + #define FOOBAR 42 + """) + lib.bottom = 300 + assert lib.FetchRectBottom() == 300 + lib.bottom += 1 + assert lib.FetchRectBottom() == 301 + lib.bottoms[1] = 500 + assert lib.FetchRectBottoms1() == 500 + lib.bottoms[1] += 2 + assert lib.FetchRectBottoms1() == 502 + # + p = ffi.addressof(lib, 'bottom') + assert ffi.typeof(p) == ffi.typeof("long *") + assert p[0] == 301 + p[0] += 1 + assert lib.FetchRectBottom() == 302 + p = ffi.addressof(lib, 'bottoms') + assert ffi.typeof(p) == ffi.typeof("long(*)[2]") + assert p[0] == lib.bottoms + # + raises(AttributeError, ffi.addressof, lib, 'unknown_var') + raises(AttributeError, ffi.addressof, lib, "FOOBAR") + assert ffi.addressof(lib, 'FetchRectBottom') == lib.FetchRectBottom _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit