[pypy-svn] r12216 - in pypy/dist/pypy/rpython: . test

pedronis at codespeak.net pedronis at codespeak.net
Thu May 12 14:44:07 CEST 2005


Author: pedronis
Date: Thu May 12 14:44:07 2005
New Revision: 12216

Modified:
   pypy/dist/pypy/rpython/lltypes.py
   pypy/dist/pypy/rpython/test/test_lltypes.py
Log:
support for expressing functions&function pointers



Modified: pypy/dist/pypy/rpython/lltypes.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypes.py	(original)
+++ pypy/dist/pypy/rpython/lltypes.py	Thu May 12 14:44:07 2005
@@ -33,9 +33,13 @@
     def _freeze_(self):
         return True
 
+    def _inline_is_varsize(self, last):
+        return False
+
 
 class ContainerType(LowLevelType):
-    pass
+    def _inline_is_varsize(self, last):
+        raise TypeError, "%r cannot be inlined in structure" % self
 
 
 class Struct(ContainerType):
@@ -52,20 +56,23 @@
             if name in flds:
                 raise TypeError("%s: repeated field name" % self._name)
             flds[name] = typ
-            if isinstance(typ, Struct) and typ._arrayfld:
-                raise TypeError("cannot inline a var-sized struct "
-                                "inside another struct")
+ 
         # look if we have an inlined variable-sized array as the last field
         if fields:
             for name, typ in fields[:-1]:
-                if isinstance(typ, Array):
-                    raise TypeError("%s: array field must be last")
+                typ._inline_is_varsize(False)
             name, typ = fields[-1]
-            if isinstance(typ, Array):
+            if typ._inline_is_varsize(True):
                 self._arrayfld = name
         self._flds = frozendict(flds)
         self._names = tuple(names)
 
+    def _inline_is_varsize(self, last):
+        if self._arrayfld:
+            raise TypeError("cannot inline a var-sized struct "
+                            "inside another struct")
+        return False
+
     def __getattr__(self, name):
         try:
             return self._flds[name]
@@ -96,12 +103,36 @@
         if self.OF._arrayfld is not None:
             raise TypeError("array cannot contain an inlined array")
 
+    def _inline_is_varsize(self, last):
+        if not last:
+            raise TypeError("array field must be last")
+        return True
+
     def __str__(self):
         return "Array of { %s }" % (self.OF._str_fields(),)
 
     def _container_example(self):
         return _array(self, 1)
 
+class FuncType(ContainerType):
+    def __init__(self, args, result):
+        for arg in args:
+            if isinstance(arg, ContainerType):
+                raise TypeError, "function arguments can only be primitives or pointers"
+        self.ARGS = tuple(args)
+        if isinstance(result, ContainerType):
+            raise TypeError, "function result can only be primitive or pointer"
+        self.RESULT = result
+
+    def __str__(self):
+        args = ', '.join(map(str, self.ARGS))
+        return "Func ( %s ) -> %s" % (args, self.RESULT)
+
+    def _container_example(self):
+        def ex(*args):
+            return self.RESULT._example()
+        return _func(self, _callable=ex)
+       
 
 class Primitive(LowLevelType):
     def __init__(self, name, default):
@@ -127,10 +158,12 @@
 class _PtrType(LowLevelType):
     def __init__(self, TO, **flags):
         if not isinstance(TO, ContainerType):
-            raise TypeError, ("can only point to a Struct or an Array, "
+            raise TypeError, ("can only point to a Struct or an Array or a FuncType, "
                               "not to %s" % (TO,))
         self.TO = TO
         self.flags = frozendict(flags)
+        if isinstance(TO, FuncType) and 'gc' in self.flags:
+            raise TypeError, "function pointers are not gc-able"
 
     def _str_flags(self):
         flags = self.flags.keys()
@@ -231,6 +264,7 @@
     """XXX A nice docstring here"""
     T = typeOf(val)
     if isinstance(T, ContainerType):
+        assert not isinstance(T, FuncType), "functions cannot be substructures"
         if can_have_gc and isinstance(T, Struct):
             val = _ptr(GcPtr(T), val)
         else:
@@ -321,6 +355,17 @@
     def __str__(self):
         return '%s to %s' % (self._TYPE.__class__.__name__.lower(), self._obj)
 
+    def __call__(self, *args):
+        if isinstance(self._T, FuncType):
+            self._check()
+            if len(args) != len(self._T.ARGS):
+                raise TypeError,"calling %r with wrong argument number: %r" % (self._T, args)
+            for a, ARG in zip(args, self._T.ARGS):
+                if typeOf(a) != ARG:
+                    raise TypeError,"calling %r with wrong argument types: %r" % (self._T, args)
+            return self._obj._callable(*args)
+        raise TypeError("%r instance is not a function" % (self._T,))
+            
 
 class _struct(object):
     _wrparent = None
@@ -402,6 +447,22 @@
         return 'array [ %s ]' % (', '.join(['{%s}' % item._str_fields()
                                             for item in self.items]),)
 
+class _func(object):
+    def __init__(self, TYPE, **attrs):
+        self._TYPE = TYPE
+        self._name = "?"
+        self._callable = None
+        self.__dict__.update(attrs)
+
+    def _check(self):
+        if self._callable is None:
+            raise RuntimeError,"calling undefined function"
+
+    def __repr__(self):
+        return '<%s>' % (self,)
+
+    def __str__(self):
+        return "func %s" % self._name
 
 def malloc(T, n=None):
     if isinstance(T, Struct):

Modified: pypy/dist/pypy/rpython/test/test_lltypes.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_lltypes.py	(original)
+++ pypy/dist/pypy/rpython/test/test_lltypes.py	Thu May 12 14:44:07 2005
@@ -209,3 +209,14 @@
     assert ex_ps.v == 0
     assert ex_pst.v == 0
     assert ex_pst.trail[0].v == 0
+
+def test_functions():
+    F = FuncType((Signed,), Signed)
+    py.test.raises(TypeError, "Struct('x', ('x', F))")
+
+    PF = NonGcPtr(F)
+    pf = PF._example()
+    assert pf(0) == 0
+    py.test.raises(TypeError, pf, 0, 0)
+    py.test.raises(TypeError, pf, 'a')
+



More information about the Pypy-commit mailing list