[pypy-svn] r30853 - in pypy/dist/pypy: lib module/_stackless objspace/cclp objspace/test

auc at codespeak.net auc at codespeak.net
Tue Aug 1 17:37:41 CEST 2006


Author: auc
Date: Tue Aug  1 17:37:37 2006
New Revision: 30853

Modified:
   pypy/dist/pypy/lib/_exceptions.py
   pypy/dist/pypy/module/_stackless/clonable.py
   pypy/dist/pypy/module/_stackless/interp_clonable.py
   pypy/dist/pypy/objspace/cclp/scheduler.py
   pypy/dist/pypy/objspace/cclp/types.py
   pypy/dist/pypy/objspace/cclp/variable.py
   pypy/dist/pypy/objspace/test/test_logicobjspace.py
Log:
proper exceptions types are now raised
futures read-onlyness more correctly enforced


Modified: pypy/dist/pypy/lib/_exceptions.py
==============================================================================
--- pypy/dist/pypy/lib/_exceptions.py	(original)
+++ pypy/dist/pypy/lib/_exceptions.py	Tue Aug  1 17:37:37 2006
@@ -436,3 +436,16 @@
                      badchar, self.start, self.reason)
         return "%r codec can't encode characters in position %d-%d: %s" % (
             self.encoding, self.start, self.end - 1, self.reason)
+
+
+
+#-- Logic object space specific stuff
+#XXX conditionalize me on '-o logic'
+
+class LOError(Exception): pass
+
+class UnificationError(LOError): pass
+class RebindingError(LOError): pass
+class FutureBindingError(LOError): pass
+
+class AllBlockedError(LOError): pass

Modified: pypy/dist/pypy/module/_stackless/clonable.py
==============================================================================
--- pypy/dist/pypy/module/_stackless/clonable.py	(original)
+++ pypy/dist/pypy/module/_stackless/clonable.py	Tue Aug  1 17:37:37 2006
@@ -57,7 +57,7 @@
             raise OperationError(space.w_ValueError, space.wrap(
                 "cannot switch to an unbound Coroutine"))
         self.switch()
-        rstack.resume_point("w_switch", self, space)
+        #rstack.resume_point("w_switch", self, space)
         state = self.costate
         w_ret, state.w_tempval = state.w_tempval, space.w_None
         return w_ret

Modified: pypy/dist/pypy/module/_stackless/interp_clonable.py
==============================================================================
--- pypy/dist/pypy/module/_stackless/interp_clonable.py	(original)
+++ pypy/dist/pypy/module/_stackless/interp_clonable.py	Tue Aug  1 17:37:37 2006
@@ -4,7 +4,6 @@
 
 from pypy.interpreter.error import OperationError
 
-from pypy.rpython import rstack # for resume points
 from pypy.tool import stdlib_opcode as pythonopcode
 
 class InterpClonableCoroutine(Coroutine):

Modified: pypy/dist/pypy/objspace/cclp/scheduler.py
==============================================================================
--- pypy/dist/pypy/objspace/cclp/scheduler.py	(original)
+++ pypy/dist/pypy/objspace/cclp/scheduler.py	Tue Aug  1 17:37:37 2006
@@ -126,7 +126,7 @@
                 self._init_head(self._main)
                 self._init_blocked()
                 w(".. SCHEDULER reinitialized")
-                raise OperationError(self.space.w_RuntimeError,
+                raise OperationError(self.space.w_AllBlockedError,
                                      self.space.wrap("can't schedule, possible deadlock in sight"))
         return to_be_run
 

Modified: pypy/dist/pypy/objspace/cclp/types.py
==============================================================================
--- pypy/dist/pypy/objspace/cclp/types.py	(original)
+++ pypy/dist/pypy/objspace/cclp/types.py	Tue Aug  1 17:37:37 2006
@@ -1,10 +1,10 @@
-from pypy.interpreter import baseobjspace
+from pypy.interpreter import baseobjspace, typedef
 
 from pypy.objspace.cclp.misc import w, ClonableCoroutine
 
 W_Root = baseobjspace.W_Root
 
-#-- Types --------------------------------------------------
+#-- Variables types ----------------------------------------
 
 class W_Var(W_Root):
     def __init__(w_self, space):
@@ -27,15 +27,16 @@
         w_self.client = ClonableCoroutine.w_getcurrent(space)
         w("FUT", str(w_self))
 
+#-- Exception types ----------------------------------------
 
-class W_FailedValue(W_Root, object):
+class W_FailedValue(W_Root):
     """wraps an exception raised in some coro, to be re-raised in
        some dependant coro sometime later
     """
     def __init__(w_self, exc):
         w_self.exc = exc
 
-#-- Misc ----------------------------------------------------
+#-- Misc ---------------------------------------------------
 
 def deref(space, w_var):
     #XXX kill me ?

Modified: pypy/dist/pypy/objspace/cclp/variable.py
==============================================================================
--- pypy/dist/pypy/objspace/cclp/variable.py	(original)
+++ pypy/dist/pypy/objspace/cclp/variable.py	Tue Aug  1 17:37:37 2006
@@ -55,7 +55,7 @@
         scheduler[0].add_to_blocked_byneed(w_var, ClonableCoroutine.w_getcurrent(space))
         scheduler[0].schedule()
     else:
-        raise OperationError(space.w_RuntimeError,
+        raise OperationError(space.w_TypeError,
                              space.wrap("wait_needed only supported on unbound variables"))
 
 def wait_needed(space, w_var):
@@ -140,18 +140,21 @@
         w_curr = w_next
 
 
-def fail(space, w_obj1, w_obj2):
+def raise_unification_failure(space):
     """raises a specific exception for bind/unify
        should fail the current comp. space at some point"""
-    #FIXME : really raise some specific exception
-    assert isinstance(w_obj1, W_Root)
-    assert isinstance(w_obj2, W_Root)
-    raise OperationError(space.w_RuntimeError,
+    raise OperationError(space.w_UnificationError,
                          space.wrap("Unification failure"))
 
+# to signal a future binding exception
+def raise_future_binding(space):
+    raise OperationError(space.w_FutureBindingError,
+                         space.wrap("This future is read-only for you, pal"))
+
 
 #-- BIND -----------------------------
 
+
 def bind(space, w_var, w_obj):
     """1. aliasing of unbound variables
        2. assign bound var to unbound var
@@ -170,15 +173,15 @@
         return _assign(space, w_var, w_obj)
     if space.is_true(space.eq(w_var.w_bound_to, w_obj)):
         return
-    raise OperationError(space.w_RuntimeError,
-                         space.wrap("Cannot bind twice"))
+    raise OperationError(space.w_RebindingError,
+                         space.wrap("Cannot bind twice but two identical values"))
+
 
 def bind__Future_Root(space, w_fut, w_obj):
     #v("future val", str(id(w_fut)))
     if w_fut.client == ClonableCoroutine.w_getcurrent(space):
-        raise OperationError(space.w_RuntimeError,
-                             space.wrap("This future is read-only for you, pal"))
-    bind__Var_Root(space, w_fut, w_obj) # call-next-method ?
+        raise_future_binding(space)
+    return bind__Var_Root(space, w_fut, w_obj) # call-next-method ?
 
 def bind__Var_Var(space, w_v1, w_v2):
     #w("var var")
@@ -199,17 +202,20 @@
 def bind__Future_Var(space, w_fut, w_var):
     #v("future var")
     if w_fut.client == ClonableCoroutine.w_getcurrent(space):
-        raise OperationError(space.w_RuntimeError,
-                             space.wrap("This future is read-only for you, pal"))
-    bind__Var_Var(space, w_fut, w_var)
+        raise_future_binding(space)
+    return bind__Var_Var(space, w_fut, w_var)
 
-#XXX Var_Future would just alias or assign, this is ok
+def bind__Var_Future(space, w_var, w_fut):
+    if space.is_true(space.is_bound(w_fut)):
+        return bind__Var_Root(w_var, w_fut.w_bound_to)
+    raise_future_binding(space)
     
 bind_mm = StdObjSpaceMultiMethod('bind', 2)
 bind_mm.register(bind__Var_Root, W_Var, W_Root)
 bind_mm.register(bind__Var_Var, W_Var, W_Var)
 bind_mm.register(bind__Future_Root, W_Future, W_Root)
 bind_mm.register(bind__Future_Var, W_Future, W_Var)
+bind_mm.register(bind__Var_Future, W_Var, W_Future)
 all_mms['bind'] = bind_mm
 
 def _assign(space, w_var, w_val):
@@ -281,7 +287,7 @@
         w_d1 = w_x.getdict() #returns wrapped dict or unwrapped None ...
         w_d2 = w_y.getdict()
         if None in [w_d1, w_d2]:
-            fail(space, w_x, w_y)
+            raise_unification_failure(space)
         else:
             return space.unify(w_d1, w_d2)
     return space.w_None
@@ -308,7 +314,7 @@
 
 def unify__Tuple_Tuple(space, w_i1, w_i2):
     if len(w_i1.wrappeditems) != len(w_i2.wrappeditems):
-        fail(space, w_i1, w_i2)
+        raise_unification_failure(space)
     idx, top = (-1, space.int_w(space.len(w_i1))-1)
     while idx < top:
         idx += 1
@@ -321,7 +327,7 @@
 
 def unify__List_List(space, w_i1, w_i2):
     if len(w_i1.wrappeditems) != len(w_i2.wrappeditems):
-        fail(space, w_i1, w_i2)
+        raise_unification_failure(space)
     idx, top = (-1, space.int_w(space.len(w_i1))-1)
     while idx < top:
         idx += 1

Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py
==============================================================================
--- pypy/dist/pypy/objspace/test/test_logicobjspace.py	(original)
+++ pypy/dist/pypy/objspace/test/test_logicobjspace.py	Tue Aug  1 17:37:37 2006
@@ -17,7 +17,7 @@
         assert is_bound(1)
         # FIXME : propagate proper
         #         FailureException
-        raises(Exception, bind, X, 2)
+        raises(RebindingError, bind, X, 2)
 
     def test_bind_to_self(self):
         X = newvar()
@@ -51,7 +51,6 @@
         assert alias_of(X, Y)
         assert alias_of(X, Y)
         unify(X, 1)
-        # what about is_alias, then ?
         assert X == 1
         assert Y == 1
 
@@ -131,7 +130,7 @@
         X = newvar()
         def f(x):
             return x + 1
-        raises(Exception, f, X)
+        raises(AllBlockedError, f, X)
 
     def test_eq_unifies_simple(self):
         X = newvar()
@@ -171,7 +170,7 @@
         unify(X, (1, (2, None)))
         assert X == (1, (2, None))
         unify(X, (1, (2, None)))
-        raises(Exception, unify, X, (1, 2))
+        raises(UnificationError, unify, X, (1, 2))
 
     def test_unify_dict(self):
         Z, W = newvar(), newvar()
@@ -193,7 +192,7 @@
         assert alias_of(f1.b, f2.b)
         unify(f2.b, 'foo')
         assert f1.b == f2.b == 'foo'
-        raises(Exception, unify, f1.b, 24)
+        raises(UnificationError, unify, f1.b, 24)
 
 
 class AppTest_LogicFutures(object):
@@ -202,8 +201,6 @@
         cls.space = gettestobjspace('logic', usemodules=("_stackless",))
 
     def test_future_value(self):
-        print "future value", sched_info()
-
         def poop(X):
             return X + 1
 
@@ -214,22 +211,18 @@
 
         X = newvar()
         T = future(poop, X)
-        raises(Exception, unify, T, 42)
+        raises(FutureBindingError, unify, T, 42)
         bind(X, 42); schedule() # helps the gc
 
-        X, Y = newvar(), newvar()
+        X, Y, Z = newvar(), newvar(), newvar()
+        bind(Z, 42)
         T = future(poop, X)
-        raises(Exception, unify, T, Y)
+        raises(FutureBindingError, unify, T, Z)
+        raises(FutureBindingError, unify, Z, T)
+        raises(FutureBindingError, unify, Y, T)
+        raises(FutureBindingError, unify, T, Y)
         bind(X, 42); schedule() # gc ...
 
-        assert is_free(Y)
-        X = newvar()
-        T = future(poop, X)
-        unify(Y, T)
-        unify(X, 42)
-        assert Y == 43
-        bind(X, 42); schedule()
-
     def test_one_future_exception(self):
         print "one future exception", sched_info()
         class FooException(Exception): pass
@@ -340,22 +333,26 @@
     def test_eager_producer_consummer(self):
         print "eager_producer_consummer", sched_info()
 
-        def generate(n, limit):
+        def generate(n, limit, R):
             if n < limit:
-                return (n, generate(n + 1, limit))
-            return None
+                Tail = newvar()
+                unify(R, (n, Tail))
+                return generate(n + 1, limit, Tail)
+            bind(R, None)
+            return
 
-        def sum(L, a):
+        def sum(L, a, R):
             Head, Tail = newvar(), newvar()
             unify(L, (Head, Tail))
             if Tail != None:
-                return sum(Tail, Head + a)
-            return a + Head
+                return sum(Tail, Head + a, R)
+            bind(R, a + Head)
+            return
 
         X = newvar()
         S = newvar()
-        unify(S, future(sum, X, 0))
-        unify(X, future(generate, 0, 10))
+        stacklet(sum, X, 0, S)
+        stacklet(generate, 0, 10, X)
         assert S == 45
 
 
@@ -365,28 +362,32 @@
         def lgenerate(n, L):
             """wait-needed version of generate"""
             #XXX how is this ever collected ?
+            #    should be when L becomes unreferenced from
+            #    outside this thread ... But this can't
+            #    happen right now because we keep
+            #    references also of this thread in the
+            #    scheduler.
             wait_needed(L)
             Tail = newvar()
             bind(L, (n, Tail))
             lgenerate(n+1, Tail)
 
-        def lsum(L, a, limit):
+        def lsum(L, a, limit, R):
             """this summer controls the generator"""
             if limit > 0:
                 Head, Tail = newvar(), newvar()
-                wait(L)
+                wait(L) # send needed signal to generator
                 unify(L, (Head, Tail))
-                return lsum(Tail, a+Head, limit-1)
+                return lsum(Tail, a+Head, limit-1, R)
             else:
-                return a
+                bind(R, a)
 
         Y = newvar()
         T = newvar()
 
         future(lgenerate, 0, Y)
-        unify(T, future(lsum, Y, 0, 10))
+        stacklet(lsum, Y, 0, 10, T)
 
-        wait(T)
         assert T == 45
         assert len(sched_info()['blocked_byneed']) == 1
         reset_scheduler()



More information about the Pypy-commit mailing list