[pypy-svn] pypy default: Issue652 (kleptog) new lltype.Typedef, which allows to give different

amauryfa commits-noreply at bitbucket.org
Fri Apr 15 00:36:31 CEST 2011


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: 
Changeset: r43375:d381cb2c140b
Date: 2011-04-15 00:36 +0200
http://bitbucket.org/pypy/pypy/changeset/d381cb2c140b/

Log:	Issue652 (kleptog) new lltype.Typedef, which allows to give
	different names (in the C backend) to the same type.

	Use it in cpyext to have "real" Py_ssize_t parameters

diff --git a/pypy/translator/c/test/test_database.py b/pypy/translator/c/test/test_database.py
--- a/pypy/translator/c/test/test_database.py
+++ b/pypy/translator/c/test/test_database.py
@@ -5,7 +5,7 @@
 from pypy.objspace.flow.model import Constant, Variable, SpaceOperation
 from pypy.objspace.flow.model import Block, Link, FunctionGraph
 from pypy.rpython.typesystem import getfunctionptr
-from pypy.rpython.lltypesystem.rffi import VOIDP, INT_real, INT
+from pypy.rpython.lltypesystem.rffi import VOIDP, INT_real, INT, CArrayPtr
 
 
 def dump_on_stdout(database):
@@ -244,3 +244,15 @@
     db.get(p)
     db.complete()
     dump_on_stdout(db)
+
+def test_typedef():
+    A = Typedef(Signed, 'test4')
+    db = LowLevelDatabase()
+    assert db.gettype(A) == "test4 @"
+
+    PA = CArrayPtr(A)
+    assert db.gettype(PA) == "test4 *@"
+
+    F = FuncType((A,), A)
+    assert db.gettype(F) == "test4 (@)(test4)"
+

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -37,7 +37,7 @@
 DEBUG_WRAPPER = True
 
 # update these for other platforms
-Py_ssize_t = lltype.Signed
+Py_ssize_t = lltype.Typedef(rffi.SSIZE_T, 'Py_ssize_t')
 Py_ssize_tP = rffi.CArrayPtr(Py_ssize_t)
 size_t = rffi.ULONG
 ADDR = lltype.Signed
@@ -192,14 +192,19 @@
     - set `external` to False to get a C function pointer, but not exported by
       the API headers.
     """
+    if isinstance(restype, lltype.Typedef):
+        real_restype = restype.OF
+    else:
+        real_restype = restype
+
     if error is _NOT_SPECIFIED:
-        if isinstance(restype, lltype.Ptr):
-            error = lltype.nullptr(restype.TO)
-        elif restype is lltype.Void:
+        if isinstance(real_restype, lltype.Ptr):
+            error = lltype.nullptr(real_restype.TO)
+        elif real_restype is lltype.Void:
             error = CANNOT_FAIL
     if type(error) is int:
-        error = rffi.cast(restype, error)
-    expect_integer = (isinstance(restype, lltype.Primitive) and
+        error = rffi.cast(real_restype, error)
+    expect_integer = (isinstance(real_restype, lltype.Primitive) and
                       rffi.cast(restype, 0) == 0)
 
     def decorate(func):

diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
--- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
@@ -1000,6 +1000,13 @@
         p = ctypes2lltype(lltype.Ptr(NODE), ctypes.pointer(pc))
         assert p.pong.ping == p
 
+    def test_typedef(self):
+        assert ctypes2lltype(lltype.Typedef(lltype.Signed, 'test'), 6) == 6
+        assert ctypes2lltype(lltype.Typedef(lltype.Float, 'test2'), 3.4) == 3.4
+
+        assert get_ctypes_type(lltype.Signed) == get_ctypes_type(
+            lltype.Typedef(lltype.Signed, 'test3'))
+
     def test_cast_adr_to_int(self):
         class someaddr(object):
             def _cast_to_int(self):

diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py
--- a/pypy/rpython/lltypesystem/rffi.py
+++ b/pypy/rpython/lltypesystem/rffi.py
@@ -818,6 +818,8 @@
     """Similar to llmemory.sizeof() but tries hard to return a integer
     instead of a symbolic value.
     """
+    if isinstance(tp, lltype.Typedef):
+        tp = tp.OF
     if isinstance(tp, lltype.FixedSizeArray):
         return sizeof(tp.OF) * tp.length
     if isinstance(tp, lltype.Struct):

diff --git a/pypy/module/cpyext/test/test_api.py b/pypy/module/cpyext/test/test_api.py
--- a/pypy/module/cpyext/test/test_api.py
+++ b/pypy/module/cpyext/test/test_api.py
@@ -70,11 +70,35 @@
         if self.check_and_print_leaks():
             assert False, "Test leaks or loses object(s)."
 
+ at api.cpython_api([api.Py_ssize_t], api.Py_ssize_t, error=-1)
+def PyPy_TypedefTest1(space, arg):
+    assert lltype.typeOf(arg) == api.Py_ssize_t
+    return 0
+
+ at api.cpython_api([api.Py_ssize_tP], api.Py_ssize_tP)
+def PyPy_TypedefTest2(space, arg):
+    assert lltype.typeOf(arg) == api.Py_ssize_tP
+    return None
+
 class TestConversion(BaseApiTest):
     def test_conversions(self, space, api):
         api.PyPy_GetWrapped(space.w_None)
         api.PyPy_GetReference(space.w_None)
 
+    def test_typedef(self, space):
+        from pypy.translator.c.database import LowLevelDatabase
+        db = LowLevelDatabase()
+        assert (api.c_function_signature(db, api.FUNCTIONS['PyPy_TypedefTest1'])
+                == ('Py_ssize_t', 'Py_ssize_t arg0'))
+        assert (api.c_function_signature(db, api.FUNCTIONS['PyPy_TypedefTest2'])
+                == ('Py_ssize_t *', 'Py_ssize_t *arg0'))
+
+        PyPy_TypedefTest1(space, 0)
+        ppos = lltype.malloc(api.Py_ssize_tP.TO, 1, flavor='raw')
+        ppos[0] = 0
+        PyPy_TypedefTest2(space, ppos)
+        lltype.free(ppos, flavor='raw')
+
 
 def test_copy_header_files(tmpdir):
     api.copy_header_files(tmpdir)

diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -255,6 +255,9 @@
         return cls
 
 def build_new_ctypes_type(T, delayed_builders):
+    if isinstance(T, lltype.Typedef):
+        T = T.OF
+
     if isinstance(T, lltype.Ptr):
         if isinstance(T.TO, lltype.FuncType):
             argtypes = [get_ctypes_type(ARG) for ARG in T.TO.ARGS
@@ -758,6 +761,8 @@
     """
     if T is lltype.Void:
         return None
+    if isinstance(T, lltype.Typedef):
+        T = T.OF
     if isinstance(T, lltype.Ptr):
         if not cobj or not ctypes.cast(cobj, ctypes.c_void_p).value:   # NULL pointer
             # CFunctionType.__nonzero__ is broken before Python 2.6

diff --git a/pypy/rpython/lltypesystem/test/test_rffi.py b/pypy/rpython/lltypesystem/test/test_rffi.py
--- a/pypy/rpython/lltypesystem/test/test_rffi.py
+++ b/pypy/rpython/lltypesystem/test/test_rffi.py
@@ -728,6 +728,7 @@
     
         for ll, ctp in cache.items():
             assert sizeof(ll) == ctypes.sizeof(ctp)
+            assert sizeof(lltype.Typedef(ll, 'test')) == sizeof(ll)
         assert not size_and_sign(lltype.Signed)[1]
         assert not size_and_sign(lltype.Char)[1]
         assert not size_and_sign(lltype.UniChar)[1]

diff --git a/pypy/annotation/model.py b/pypy/annotation/model.py
--- a/pypy/annotation/model.py
+++ b/pypy/annotation/model.py
@@ -641,6 +641,8 @@
     except TypeError:
         s = None    # unhashable T, e.g. a Ptr(GcForwardReference())
     if s is None:
+        if isinstance(T, lltype.Typedef):
+            return lltype_to_annotation(T.OF)
         if isinstance(T, lltype.Number):
             return SomeInteger(knowntype=T._type)
         if isinstance(T, (ootype.Instance, ootype.BuiltinType)):

diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py
--- a/pypy/rpython/lltypesystem/lltype.py
+++ b/pypy/rpython/lltypesystem/lltype.py
@@ -95,6 +95,8 @@
     __slots__ = ['__dict__', '__cached_hash']
 
     def __eq__(self, other):
+        if isinstance(other, Typedef):
+            return other.__eq__(self)
         return self.__class__ is other.__class__ and (
             self is other or safe_equal(self.__dict__, other.__dict__))
 
@@ -194,6 +196,36 @@
         raise NotImplementedError
 
 
+class Typedef(LowLevelType):
+    """A typedef is just another name for an existing type"""
+    def __init__(self, OF, c_name):
+        """
+        @param OF: the equivalent rffi type
+        @param c_name: the name we want in C code
+        """
+        assert isinstance(OF, LowLevelType)
+        # Look through typedefs, so other places don't have to
+        if isinstance(OF, Typedef):
+            OF = OF.OF # haha
+        self.OF = OF
+        self.c_name = c_name
+
+    def __repr__(self):
+        return '<Typedef "%s" of %r>' % (self.c_name, self.OF)
+
+    def __eq__(self, other):
+        return other == self.OF
+
+    def __getattr__(self, name):
+        return self.OF.get(name)
+
+    def _defl(self, parent=None, parentindex=None):
+        return self.OF._defl()
+
+    def _allocate(self, initialization, parent=None, parentindex=None):
+        return self.OF._allocate(initialization, parent, parentindex)
+
+
 class Struct(ContainerType):
     _gckind = 'raw'
 

diff --git a/pypy/translator/c/database.py b/pypy/translator/c/database.py
--- a/pypy/translator/c/database.py
+++ b/pypy/translator/c/database.py
@@ -1,7 +1,7 @@
-from pypy.rpython.lltypesystem.lltype import \
-     Primitive, Ptr, typeOf, RuntimeTypeInfo, \
-     Struct, Array, FuncType, PyObject, Void, \
-     ContainerType, OpaqueType, FixedSizeArray, _uninitialized
+
+from pypy.rpython.lltypesystem.lltype import (
+    Primitive, Ptr, typeOf, RuntimeTypeInfo, Struct, Array, FuncType, PyObject,
+    Void, ContainerType, OpaqueType, FixedSizeArray, _uninitialized, Typedef)
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.rpython.lltypesystem.llmemory import WeakRef, _WeakRefType, GCREF
 from pypy.rpython.lltypesystem.rffi import CConstant
@@ -100,6 +100,8 @@
     def gettype(self, T, varlength=1, who_asks=None, argnames=[]):
         if isinstance(T, Primitive) or T == GCREF:
             return PrimitiveType[T]
+        elif isinstance(T, Typedef):
+            return '%s @' % T.c_name
         elif isinstance(T, Ptr):
             if (isinstance(T.TO, OpaqueType) and
                 T.TO.hints.get('c_pointer_typedef') is not None):

diff --git a/pypy/rpython/lltypesystem/test/test_lltype.py b/pypy/rpython/lltypesystem/test/test_lltype.py
--- a/pypy/rpython/lltypesystem/test/test_lltype.py
+++ b/pypy/rpython/lltypesystem/test/test_lltype.py
@@ -804,6 +804,21 @@
                  hints={'immutable_fields': FieldListAccessor({'x':'[*]'})})
     assert S._immutable_field('x') == '[*]'
 
+def test_typedef():
+    T = Typedef(Signed, 'T')
+    assert T == Signed
+    assert Signed == T
+    T2 = Typedef(T, 'T2')
+    assert T2 == T
+    assert T2.OF is Signed
+    py.test.raises(TypeError, Ptr, T)
+    assert rffi.CArrayPtr(T) == rffi.CArrayPtr(Signed)
+    assert rffi.CArrayPtr(Signed) == rffi.CArrayPtr(T)
+
+    F = FuncType((T,), T)
+    assert F.RESULT == Signed
+    assert F.ARGS == (Signed,)
+
 
 class TestTrackAllocation:
     def test_automatic_tracking(self):


More information about the Pypy-commit mailing list