[pypy-svn] r31116 - in pypy/dist/pypy: annotation rpython/rctypes rpython/rctypes/test
arigo at codespeak.net
arigo at codespeak.net
Mon Aug 7 16:54:10 CEST 2006
Author: arigo
Date: Mon Aug 7 16:54:08 2006
New Revision: 31116
Added:
pypy/dist/pypy/rpython/rctypes/rfunc.py (contents, props changed)
Modified:
pypy/dist/pypy/annotation/unaryop.py
pypy/dist/pypy/rpython/rctypes/afunc.py
pypy/dist/pypy/rpython/rctypes/avoid_p.py
pypy/dist/pypy/rpython/rctypes/rmodel.py
pypy/dist/pypy/rpython/rctypes/test/_rctypes_test.c
pypy/dist/pypy/rpython/rctypes/test/test_ctypes.py
pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py
pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py
pypy/dist/pypy/rpython/rctypes/test/test_rvoid_p.py
Log:
rctypes support for passing ctypes function pointers around, calling
them generically and casting between them and 'void*'.
Modified: pypy/dist/pypy/annotation/unaryop.py
==============================================================================
--- pypy/dist/pypy/annotation/unaryop.py (original)
+++ pypy/dist/pypy/annotation/unaryop.py Mon Aug 7 16:54:08 2006
@@ -701,6 +701,11 @@
def is_true(cto):
return SomeBool()
+ def simple_call(cto, *args_s):
+ # for variables containing ctypes function pointers
+ entry = extregistry.lookup_type(cto.knowntype)
+ return entry.compute_result_annotation(*args_s)
+
#_________________________________________
# memory addresses
Modified: pypy/dist/pypy/rpython/rctypes/afunc.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/afunc.py (original)
+++ pypy/dist/pypy/rpython/rctypes/afunc.py Mon Aug 7 16:54:08 2006
@@ -1,5 +1,6 @@
from pypy.annotation.model import SomeCTypesObject
from pypy.annotation import model as annmodel
+from pypy.annotation.pairtype import pairtype
from pypy.rpython.error import TyperError
from pypy.rpython.rctypes.implementation import CTypesEntry
from pypy.rpython.lltypesystem import lltype
@@ -10,17 +11,75 @@
CFuncPtrType = type(ctypes.CFUNCTYPE(None))
+class SomeCTypesFunc(annmodel.SomeBuiltin):
+ """Stands for a known constant ctypes function. Variables containing
+ potentially multiple ctypes functions are regular SomeCTypesObjects.
+ This is a separate annotation because some features are only supported
+ for calls to constant functions, like _rctypes_pyerrchecker_ and
+ functions with no declared argtypes. It also produces better code:
+ a direct_call instead of an indirect_call.
+ """
+ def normalized(self):
+ ctype = normalized_func_ctype(self.const)
+ return cto_union(ctype, ctype) # -> SomeCTypesObject
+
+class __extend__(pairtype(SomeCTypesFunc, SomeCTypesFunc)):
+ def union((ctf1, ctf2)):
+ ctype1 = normalized_func_ctype(ctf1.const)
+ ctype2 = normalized_func_ctype(ctf2.const)
+ return cto_union(ctype1, ctype2)
+
+class __extend__(pairtype(SomeCTypesFunc, SomeCTypesObject)):
+ def union((ctf1, cto2)):
+ ctype1 = normalized_func_ctype(ctf1.const)
+ return cto_union(ctype1, cto2.knowntype)
+
+class __extend__(pairtype(SomeCTypesObject, SomeCTypesFunc)):
+ def union((cto1, ctf2)):
+ ctype2 = normalized_func_ctype(ctf2.const)
+ return cto_union(cto1.knowntype, ctype2)
+
+
+def normalized_func_ctype(cfuncptr):
+ if getattr(cfuncptr, 'argtypes', None) is None:
+ raise annmodel.UnionError("cannot merge two ctypes functions "
+ "without declared argtypes")
+ return ctypes.CFUNCTYPE(cfuncptr.restype,
+ *cfuncptr.argtypes)
+
+def cto_union(ctype1, ctype2):
+ if ctype1 != ctype2:
+ raise annmodel.UnionError("a ctypes function object can only be "
+ "merged with another function with the same "
+ "signature")
+ return SomeCTypesObject(ctype1, ownsmemory=True)
+
+
class CallEntry(CTypesEntry):
"""Annotation and rtyping of calls to external functions
declared with ctypes.
"""
_metatype_ = CFuncPtrType
+ def compute_annotation(self):
+ #self.ctype_object_discovered()
+ func = self.instance
+ analyser = self.compute_result_annotation
+ methodname = getattr(func, '__name__', None)
+ return SomeCTypesFunc(analyser, methodname=methodname)
+
+ def get_instance_sample(self):
+ if self.instance is not None:
+ return self.instance
+ else:
+ return self.type() # a sample NULL function object
+
def compute_result_annotation(self, *args_s):
"""
Answer the annotation of the external function's result
"""
- result_ctype = self.instance.restype
+ cfuncptr = self.get_instance_sample()
+ result_ctype = cfuncptr.restype
if result_ctype is None:
return None
if result_ctype is ctypes.py_object:
@@ -61,98 +120,15 @@
## s_res))
def specialize_call(self, hop):
- from pypy.rpython.rctypes.rmodel import CTypesValueRepr
+ from pypy.rpython.rctypes.rfunc import get_funcptr_constant
+ from pypy.rpython.rctypes.rfunc import rtype_funcptr_call
cfuncptr = self.instance
- fnname = cfuncptr.__name__
-
- def repr_for_ctype(ctype):
- s = SomeCTypesObject(ctype, ownsmemory=False)
- r = hop.rtyper.getrepr(s)
- return r
-
- args_r = []
- if getattr(cfuncptr, 'argtypes', None) is not None:
- for ctype in cfuncptr.argtypes:
- args_r.append(repr_for_ctype(ctype))
- else:
- # unspecified argtypes: use ctypes rules for arguments
- for s_arg, r_arg in zip(hop.args_s, hop.args_r):
- if not isinstance(s_arg, SomeCTypesObject):
- # accept integers, strings, or None
- if isinstance(s_arg, annmodel.SomeInteger):
- r_arg = repr_for_ctype(ctypes.c_long)
- elif (isinstance(s_arg, annmodel.SomeString)
- or s_arg == annmodel.s_None):
- r_arg = repr_for_ctype(ctypes.c_char_p)
- else:
- raise TyperError("call with no argtypes: don't know "
- "how to convert argument %r"%(s_arg,))
- args_r.append(r_arg)
-
- hop.rtyper.call_all_setups()
- vlist = hop.inputargs(*args_r)
- unwrapped_args_v = []
- ARGTYPES = []
- for r_arg, v in zip(args_r, vlist):
- if isinstance(r_arg, CTypesValueRepr):
- # ValueRepr case
- unwrapped_args_v.append(r_arg.getvalue(hop.llops, v))
- ARGTYPES.append(r_arg.ll_type)
- else:
- # RefRepr case -- i.e. the function argument that we pass by
- # value is e.g. a complete struct; we pass a pointer to it
- # in the low-level graphs and it's up to the back-end to
- # generate the correct dereferencing
- unwrapped_args_v.append(r_arg.get_c_data(hop.llops, v))
- ARGTYPES.append(r_arg.c_data_type)
- if cfuncptr.restype is not None:
- s_res = SomeCTypesObject(cfuncptr.restype, ownsmemory=True)
- r_res = hop.rtyper.getrepr(s_res)
- RESTYPE = r_res.ll_type
- else:
- RESTYPE = lltype.Void
-
- kwds = {}
- if hasattr(cfuncptr, 'llinterp_friendly_version'):
- kwds['_callable'] = cfuncptr.llinterp_friendly_version
- suppress_pyerr_occurred = False
- if (cfuncptr._flags_ & ctypes._FUNCFLAG_PYTHONAPI) == 0:
- suppress_pyerr_occurred = True
- if hasattr(cfuncptr, '_rctypes_pyerrchecker_'):
- suppress_pyerr_occurred = True
- if suppress_pyerr_occurred:
- kwds['includes'] = getattr(cfuncptr, 'includes', ())
- kwds['libraries'] = getattr(cfuncptr, 'libraries', ())
- #else:
- # no 'includes': hack to trigger in GenC a PyErr_Occurred() check
-
- hop.exception_cannot_occur()
- v_result = hop.llops.gencapicall(fnname, unwrapped_args_v,
- resulttype = RESTYPE,
- **kwds)
- # XXX hack! hack! temporary! I promize!
- FUNCTYPE = lltype.FuncType(ARGTYPES, RESTYPE)
- last_op = hop.llops[-1]
- assert last_op.opname == 'direct_call'
- last_op.args[0].concretetype = lltype.Ptr(FUNCTYPE)
- last_op.args[0].value._set_TYPE(last_op.args[0].concretetype)
- last_op.args[0].value._set_T(FUNCTYPE)
- last_op.args[0].value._obj._TYPE = FUNCTYPE
-
- if getattr(cfuncptr, '_rctypes_pyerrchecker_', None):
- # special extension to support the CPyObjSpace
- # XXX hackish: someone else -- like the annotator policy --
- # must ensure that this extra function has been annotated
- from pypy.translator.translator import graphof
- func = cfuncptr._rctypes_pyerrchecker_
- graph = graphof(hop.rtyper.annotator.translator, func)
- hop.llops.record_extra_call(graph)
- # build the 'direct_call' operation
- f = hop.rtyper.getcallable(graph)
- c = hop.inputconst(lltype.typeOf(f), f)
- hop.genop('direct_call', [c])
-
- if RESTYPE is lltype.Void:
- return None
- else:
- return r_res.return_value(hop.llops, v_result)
+ v_funcptr, args_r, r_res = get_funcptr_constant(hop.rtyper, cfuncptr,
+ hop.args_s)
+ pyerrchecker = getattr(cfuncptr, '_rctypes_pyerrchecker_', None)
+ return rtype_funcptr_call(hop, v_funcptr, args_r, r_res, pyerrchecker)
+
+ def get_repr(self, rtyper, s_funcptr):
+ # for variables containing ctypes function pointers
+ from pypy.rpython.rctypes.rfunc import CFuncPtrRepr
+ return CFuncPtrRepr(rtyper, s_funcptr)
Modified: pypy/dist/pypy/rpython/rctypes/avoid_p.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/avoid_p.py (original)
+++ pypy/dist/pypy/rpython/rctypes/avoid_p.py Mon Aug 7 16:54:08 2006
@@ -4,6 +4,7 @@
from ctypes import c_void_p, c_int, POINTER, cast, c_char, c_char_p
from pypy.rpython.rctypes.astringbuf import StringBufferType
+from pypy.rpython.rctypes.afunc import CFuncPtrType, SomeCTypesFunc
PointerType = type(POINTER(c_int))
@@ -34,7 +35,8 @@
_about_ = cast
def checkptr(self, ctype):
- assert isinstance(ctype, PointerType) or ctype == c_void_p, (
+ assert (isinstance(ctype, PointerType) or ctype == c_void_p or
+ isinstance(ctype, CFuncPtrType)), (
"cast(): can only cast between pointers so far, not %r" % (ctype,))
def compute_result_annotation(self, s_arg, s_type):
@@ -42,7 +44,8 @@
"cast(p, %r): argument 2 must be constant" % (s_type,))
type = s_type.const
self.checkptr(type)
- if s_arg.knowntype == StringBufferType:
+ if (s_arg.knowntype == StringBufferType or
+ isinstance(s_arg, SomeCTypesFunc)):
pass
else:
self.checkptr(s_arg.knowntype)
@@ -52,16 +55,23 @@
from pypy.rpython.rctypes.rpointer import PointerRepr
from pypy.rpython.rctypes.rvoid_p import CVoidPRepr
from pypy.rpython.rctypes.rstringbuf import StringBufRepr
+ from pypy.rpython.rctypes.rfunc import CFuncPtrRepr
from pypy.rpython.lltypesystem import lltype, llmemory
- assert isinstance(hop.args_r[0], (PointerRepr, CVoidPRepr,
- StringBufRepr))
+ r_arg = hop.args_r[0]
+ if isinstance(hop.args_s[0], SomeCTypesFunc):
+ # cast(const_cfuncptr, c_void_p): force the const_cfuncptr
+ # to become a general non-constant SomeCTypesObject
+ s_arg = hop.args_s[0].normalized()
+ r_arg = hop.rtyper.getrepr(s_arg)
+ assert isinstance(r_arg, (PointerRepr, CVoidPRepr,
+ StringBufRepr, CFuncPtrRepr))
targetctype = hop.args_s[1].const
- v_box, c_targetctype = hop.inputargs(hop.args_r[0], lltype.Void)
- if isinstance(hop.args_r[0], StringBufRepr):
+ v_box, c_targetctype = hop.inputargs(r_arg, lltype.Void)
+ if isinstance(r_arg, StringBufRepr):
v_index = hop.inputconst(lltype.Signed, 0)
- v_adr = hop.args_r[0].get_c_data_of_item(hop.llops, v_box, v_index)
+ v_adr = r_arg.get_c_data_of_item(hop.llops, v_box, v_index)
else:
- v_adr = hop.args_r[0].getvalue(hop.llops, v_box)
+ v_adr = r_arg.getvalue(hop.llops, v_box)
if v_adr.concretetype != llmemory.Address:
v_adr = hop.genop('cast_ptr_to_adr', [v_adr],
resulttype = llmemory.Address)
Added: pypy/dist/pypy/rpython/rctypes/rfunc.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/rctypes/rfunc.py Mon Aug 7 16:54:08 2006
@@ -0,0 +1,194 @@
+from pypy.rpython.rtyper import inputconst
+from pypy.rpython.rctypes.rmodel import CTypesValueRepr, CTypesRefRepr
+from pypy.rpython.rctypes.afunc import CFuncPtrType
+from pypy.rpython.error import TyperError
+from pypy.rpython.lltypesystem import lltype
+from pypy.annotation import model as annmodel
+from pypy.annotation.model import SomeCTypesObject
+from pypy.objspace.flow.model import Constant
+
+import ctypes
+
+
+class CFuncPtrRepr(CTypesValueRepr):
+
+ def __init__(self, rtyper, s_funcptr):
+ # For recursive types, getting the args_r and r_result is delayed
+ # until _setup_repr().
+ ll_contents = lltype.Ptr(lltype.ForwardReference())
+ super(CFuncPtrRepr, self).__init__(rtyper, s_funcptr, ll_contents)
+ self.sample = self.ctype()
+ self.argtypes = self.sample.argtypes
+ self.restype = self.sample.restype
+ if self.argtypes is None:
+ raise TyperError("cannot handle yet function pointers with "
+ "unspecified argument types")
+
+ def _setup_repr(self):
+ # Find the repr and low-level type of the arguments and return value
+ rtyper = self.rtyper
+ args_r = []
+ for arg_ctype in self.argtypes:
+ r = rtyper.getrepr(SomeCTypesObject(arg_ctype,
+ ownsmemory=False))
+ args_r.append(r)
+ r_result = rtyper.getrepr(SomeCTypesObject(self.restype,
+ ownsmemory=True))
+ if isinstance(self.ll_type.TO, lltype.ForwardReference):
+ FUNCTYPE = get_funcptr_type(args_r, r_result)
+ self.ll_type.TO.become(FUNCTYPE)
+ self.args_r = args_r
+ self.r_result = r_result
+
+ def ctypecheck(self, value):
+ return (isinstance(value.__class__, CFuncPtrType) and
+ list(value.argtypes) == list(self.argtypes) and
+ value.restype == self.restype)
+
+ def initialize_const(self, p, cfuncptr):
+ if not cfuncptr: # passed as arg to functions expecting func pointers
+ return
+ c, args_r, r_res = get_funcptr_constant(self.rtyper, cfuncptr, None)
+ p.c_data[0] = c.value
+
+ def rtype_simple_call(self, hop):
+ v_box = hop.inputarg(self, arg=0)
+ v_funcptr = self.getvalue(hop.llops, v_box)
+ hop2 = hop.copy()
+ hop2.r_s_popfirstarg()
+ return rtype_funcptr_call(hop2, v_funcptr, self.args_r, self.r_result)
+
+
+# ____________________________________________________________
+
+
+def get_funcptr_constant(rtyper, cfuncptr, args_s):
+ """Get a Constant ll function pointer from a ctypes function object.
+ """
+ fnname = cfuncptr.__name__
+ args_r, r_res = get_arg_res_repr(rtyper, cfuncptr, args_s)
+ FUNCTYPE = get_funcptr_type(args_r, r_res)
+ flags = get_funcptr_flags(cfuncptr)
+ f = lltype.functionptr(FUNCTYPE, fnname, **flags)
+ return inputconst(lltype.typeOf(f), f), args_r, r_res
+
+
+def get_arg_res_repr(rtyper, cfuncptr, args_s):
+ """Get the reprs to use for the arguments and the return value of a
+ ctypes function call. The args_s annotations are used to guess the
+ argument types if they are not specified by cfuncptr.argtypes.
+ """
+ def repr_for_ctype(ctype):
+ s = SomeCTypesObject(ctype, ownsmemory=False)
+ r = rtyper.getrepr(s)
+ return r
+
+ args_r = []
+ if getattr(cfuncptr, 'argtypes', None) is not None:
+ for ctype in cfuncptr.argtypes:
+ args_r.append(repr_for_ctype(ctype))
+ else:
+ # unspecified argtypes: use ctypes rules for arguments,
+ # accepting integers, strings, or None
+ for s_arg in args_s:
+ if isinstance(s_arg, SomeCTypesObject):
+ r_arg = rtyper.getrepr(s_arg)
+ elif isinstance(s_arg, annmodel.SomeInteger):
+ r_arg = repr_for_ctype(ctypes.c_long)
+ elif (isinstance(s_arg, annmodel.SomeString)
+ or s_arg == annmodel.s_None):
+ r_arg = repr_for_ctype(ctypes.c_char_p)
+ else:
+ raise TyperError("call with no argtypes: don't know "
+ "how to convert argument %r" % (s_arg,))
+ args_r.append(r_arg)
+ if cfuncptr.restype is not None:
+ s_res = SomeCTypesObject(cfuncptr.restype, ownsmemory=True)
+ r_res = rtyper.getrepr(s_res)
+ else:
+ r_res = None
+ return args_r, r_res
+
+
+def get_funcptr_type(args_r, r_res):
+ """Get the lltype FUNCTYPE to use for a ctypes function call.
+ """
+ ARGTYPES = []
+ for r_arg in args_r:
+ if isinstance(r_arg, CTypesValueRepr):
+ # ValueRepr case
+ ARGTYPES.append(r_arg.ll_type)
+ else:
+ # RefRepr case -- i.e. the function argument that we pass by
+ # value is e.g. a complete struct
+ ARGTYPES.append(r_arg.c_data_type)
+ if r_res is not None:
+ RESTYPE = r_res.ll_type
+ else:
+ RESTYPE = lltype.Void
+ return lltype.FuncType(ARGTYPES, RESTYPE)
+
+
+def get_funcptr_flags(cfuncptr):
+ """Get the fnptr flags to use for the given concrete ctypes function.
+ """
+ kwds = {'external': 'C'}
+ if hasattr(cfuncptr, 'llinterp_friendly_version'):
+ kwds['_callable'] = cfuncptr.llinterp_friendly_version
+ suppress_pyerr_occurred = False
+ if (cfuncptr._flags_ & ctypes._FUNCFLAG_PYTHONAPI) == 0:
+ suppress_pyerr_occurred = True
+ if hasattr(cfuncptr, '_rctypes_pyerrchecker_'):
+ suppress_pyerr_occurred = True
+ if suppress_pyerr_occurred:
+ kwds['includes'] = getattr(cfuncptr, 'includes', ())
+ kwds['libraries'] = getattr(cfuncptr, 'libraries', ())
+ #else:
+ # no 'includes': hack to trigger in GenC a PyErr_Occurred() check
+ return kwds
+
+
+def rtype_funcptr_call(hop, v_funcptr, args_r, r_res, pyerrchecker=None):
+ """Generate a call to the given ll function pointer.
+ """
+ hop.rtyper.call_all_setups()
+ vlist = hop.inputargs(*args_r)
+ unwrapped_args_v = []
+ for r_arg, v in zip(args_r, vlist):
+ if isinstance(r_arg, CTypesValueRepr):
+ # ValueRepr case
+ unwrapped_args_v.append(r_arg.getvalue(hop.llops, v))
+ elif isinstance(r_arg, CTypesRefRepr):
+ # RefRepr case -- i.e. the function argument that we pass by
+ # value is e.g. a complete struct; we pass a pointer to it
+ # in the low-level graphs and it's up to the back-end to
+ # generate the correct dereferencing
+ unwrapped_args_v.append(r_arg.get_c_data(hop.llops, v))
+ else:
+ assert 0, "ctypes func call got a non-ctypes arg repr"
+
+ FUNCTYPE = v_funcptr.concretetype.TO
+ hop.exception_cannot_occur()
+ if isinstance(v_funcptr, Constant):
+ opname = 'direct_call'
+ else:
+ unwrapped_args_v.append(inputconst(lltype.Void, None))
+ opname = 'indirect_call'
+ v_result = hop.genop(opname, [v_funcptr]+unwrapped_args_v,
+ resulttype = FUNCTYPE.RESULT)
+
+ if pyerrchecker is not None:
+ # special extension to support the CPyObjSpace
+ # XXX hackish: someone else -- like the annotator policy --
+ # must ensure that this extra function has been annotated
+ from pypy.translator.translator import graphof
+ graph = graphof(hop.rtyper.annotator.translator, pyerrchecker)
+ hop.llops.record_extra_call(graph)
+ # build the 'direct_call' operation
+ f = hop.rtyper.getcallable(graph)
+ c = hop.inputconst(lltype.typeOf(f), f)
+ hop.genop('direct_call', [c])
+
+ if r_res is not None:
+ v_result = r_res.return_value(hop.llops, v_result)
+ return v_result
Modified: pypy/dist/pypy/rpython/rctypes/rmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/rmodel.py (original)
+++ pypy/dist/pypy/rpython/rctypes/rmodel.py Mon Aug 7 16:54:08 2006
@@ -69,8 +69,11 @@
of this object."""
return None
+ def ctypecheck(self, value):
+ return isinstance(value, self.ctype)
+
def convert_const(self, value):
- if isinstance(value, self.ctype):
+ if self.ctypecheck(value):
key = "by_id", id(value)
keepalive = value
else:
@@ -82,6 +85,7 @@
try:
return self.const_cache[key][0]
except KeyError:
+ self.setup()
p = lltype.malloc(self.r_memoryowner.lowleveltype.TO)
self.initialize_const(p, value)
if self.ownsmemory:
@@ -229,7 +233,7 @@
get_c_data_or_value = getvalue
def initialize_const(self, p, value):
- if isinstance(value, self.ctype):
+ if self.ctypecheck(value):
value = value.value
p.c_data[0] = value
Modified: pypy/dist/pypy/rpython/rctypes/test/_rctypes_test.c
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/_rctypes_test.c (original)
+++ pypy/dist/pypy/rpython/rctypes/test/_rctypes_test.c Mon Aug 7 16:54:08 2006
@@ -61,6 +61,13 @@
return (void *)&p;
}
+typedef int (*fnptr_t)(point);
+
+EXPORT(fnptr_t) _testfunc_get_func(void)
+{
+ return _testfunc_struct;
+}
+
DL_EXPORT(void)
init_rctypes_test(void)
{
Modified: pypy/dist/pypy/rpython/rctypes/test/test_ctypes.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_ctypes.py (original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_ctypes.py Mon Aug 7 16:54:08 2006
@@ -227,3 +227,9 @@
for i, c in enumerate(struct.pack("l", 12345678)):
p.contents[i] = ord(c)
assert x.value == 12345678
+
+def test_cfunctype_inspection():
+ T = CFUNCTYPE(c_int, c_ubyte)
+ # T.argtypes and T.restype don't work, must use a dummy instance
+ assert list(T().argtypes) == [c_ubyte]
+ assert T().restype == c_int
Modified: pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py (original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Mon Aug 7 16:54:08 2006
@@ -17,6 +17,7 @@
from ctypes import cdll
from ctypes import POINTER, Structure, c_int, byref, pointer, c_void_p
+from ctypes import CFUNCTYPE
# __________ compile and load our local test C file __________
@@ -102,6 +103,12 @@
testfunc_erase_type.restype = c_void_p
testfunc_erase_type.argtypes = []
+# _testfunc_get_func
+testfunc_get_func = _rctypes_test._testfunc_get_func
+testfunc_get_func.restype = CFUNCTYPE(c_int, tagpoint)
+testfunc_get_func.argtypes = []
+testfunc_get_func.includes = includes
+
def test_testfunc_struct():
in_point = tagpoint()
@@ -142,6 +149,15 @@
assert pt._z == 100
return pt.x - pt.y # this test function is reused below
+def test_testfunc_get_func():
+ in_point = tagpoint()
+ in_point.x = -9171831
+ in_point.y = 9171873
+ fn = testfunc_get_func()
+ res = fn(in_point)
+ assert res == 42
+ return res # this test function is reused below
+
class Test_annotation:
def test_annotate_struct(self):
t = TranslationContext()
@@ -195,3 +211,7 @@
def test_compile_swap(self):
fn = compile(test_testfunc_swap, [])
assert fn() == 4
+
+ def test_compile_get_func(self):
+ fn = compile(test_testfunc_get_func, [])
+ assert fn() == 42
Modified: pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py (original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py Mon Aug 7 16:54:08 2006
@@ -5,6 +5,7 @@
import py
import sys
import pypy.rpython.rctypes.implementation
+from pypy.annotation import model as annmodel
from pypy.annotation.annrpython import RPythonAnnotator
from pypy.translator.translator import TranslationContext, graphof
from pypy.rpython.test.test_llinterp import interpret
@@ -48,6 +49,15 @@
return result
atoi.llinterp_friendly_version = ll_atoi
+atol = mylib.atol
+atol.restype = c_long
+atol.argtypes = [c_char_p]
+atol.llinterp_friendly_version = ll_atoi
+
+strlen = mylib.strlen
+strlen.restype = c_long
+strlen.argtypes = [c_char_p]
+
time_ = mylib.time
time_.restype = c_long # should rather use ctypes_platform.getsimpletype()
time_.argtypes = [POINTER(c_long)]
@@ -218,6 +228,23 @@
## assert a.binding(v1).knowntype == int
## assert a.binding(v2).knowntype == int
+ def test_annotate_indirect_call(self):
+ s = '442'
+ def f(n):
+ if n > 0:
+ f = strlen
+ else:
+ f = atol
+ return f
+ a = RPythonAnnotator()
+ s = a.build_types(f, [int])
+ if conftest.option.view:
+ a.translator.view()
+ assert isinstance(s, annmodel.SomeCTypesObject)
+ sample = s.knowntype()
+ assert list(sample.argtypes) == [c_char_p]
+ assert sample.restype == c_long
+
class Test_specialization:
def test_specialize_labs(self):
res = interpret(test_labs, [-11])
@@ -397,3 +424,14 @@
fn = compile(f, [])
assert fn() == string
+ def test_compile_indirect_call(self):
+ s = '442'
+ def f(n):
+ if n > 0:
+ f = strlen
+ else:
+ f = atol
+ return f(s)
+ fn = compile(f, [int])
+ assert fn(1) == 3
+ assert fn(0) == 442
Modified: pypy/dist/pypy/rpython/rctypes/test/test_rvoid_p.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_rvoid_p.py (original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_rvoid_p.py Mon Aug 7 16:54:08 2006
@@ -11,7 +11,7 @@
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.rpython.test.test_llinterp import interpret
-from ctypes import c_void_p, c_int, cast, pointer, POINTER
+from ctypes import c_void_p, c_int, c_long, cast, pointer, POINTER
from ctypes import c_char, c_byte, c_char_p, create_string_buffer, CFUNCTYPE
class Test_annotation:
@@ -92,3 +92,21 @@
fn = compile(func, [])
assert fn() == 12
+
+ def test_compile_funcptr_as_void_p(self):
+ from pypy.rpython.rctypes.test.test_rfunc import labs
+ UNARYFN = CFUNCTYPE(c_long, c_long)
+ def func(n):
+ if n < -100:
+ p1 = c_void_p() # NULL void pointer - don't try!
+ else:
+ p1 = cast(labs, c_void_p)
+ p2 = cast(p1, UNARYFN)
+ return p2(n)
+
+ assert func(-41) == 41
+ assert func(72) == 72
+
+ fn = compile(func, [int])
+ assert fn(-42) == 42
+ assert fn(71) == 71
More information about the Pypy-commit
mailing list