Author: Armin Rigo <[email protected]>
Branch: stacklet
Changeset: r46617:2f596f87d840
Date: 2011-08-18 21:54 +0200
http://bitbucket.org/pypy/pypy/changeset/2f596f87d840/

Log:    continulet.throw()

diff --git a/pypy/module/_continuation/interp_continuation.py 
b/pypy/module/_continuation/interp_continuation.py
--- a/pypy/module/_continuation/interp_continuation.py
+++ b/pypy/module/_continuation/interp_continuation.py
@@ -28,6 +28,7 @@
     def check_sthread(self):
         ec = self.space.getexecutioncontext()
         if ec.stacklet_thread is not self.sthread:
+            start_state.clear()
             raise geterror(self.space, "inter-thread support is missing")
         return ec
 
@@ -47,17 +48,15 @@
             start_state.clear()
             raise getmemoryerror(self.space)
 
-    def descr_switch(self, w_value=None, w_to=None):
-        to = self.space.interp_w(W_Continulet, w_to, can_be_None=True)
+    def switch(self, to=None):
         if self.sthread is None:
+            start_state.clear()
             raise geterror(self.space, "continulet not initialized yet")
         if self.sthread.is_empty_handle(self.h):
+            start_state.clear()
             raise geterror(self.space, "continulet already finished")
         ec = self.check_sthread()
-        if self is to:    # double-switch to myself: no-op
-            return w_value
         saved_topframeref = ec.topframeref
-        start_state.w_value = w_value
         #
         start_state.origin = self
         if to is None:
@@ -84,6 +83,28 @@
         start_state.w_value = None
         return w_value
 
+    def descr_switch(self, w_value=None, w_to=None):
+        to = self.space.interp_w(W_Continulet, w_to, can_be_None=True)
+        if self is to:    # double-switch to myself: no-op
+            return w_value
+        start_state.w_value = w_value
+        return self.switch(to)
+
+    def descr_throw(self, w_type, w_val=None, w_tb=None):
+        from pypy.interpreter.pytraceback import check_traceback
+        space = self.space
+        #
+        msg = "throw() third argument must be a traceback object"
+        if space.is_w(w_tb, space.w_None):
+            tb = None
+        else:
+            tb = check_traceback(space, w_tb, msg)
+        #
+        operr = OperationError(w_type, w_val, tb)
+        operr.normalize_exception(space)
+        start_state.propagate_exception = operr
+        return self.switch()
+
     def descr_is_pending(self):
         valid = (self.sthread is not None
                  and not self.sthread.is_empty_handle(self.h))
@@ -102,6 +123,7 @@
     __new__     = interp2app(W_Continulet___new__),
     __init__    = interp2app(W_Continulet.descr_init),
     switch      = interp2app(W_Continulet.descr_switch),
+    throw       = interp2app(W_Continulet.descr_throw),
     is_pending  = interp2app(W_Continulet.descr_is_pending),
     )
 
diff --git a/pypy/module/_continuation/test/test_stacklet.py 
b/pypy/module/_continuation/test/test_stacklet.py
--- a/pypy/module/_continuation/test/test_stacklet.py
+++ b/pypy/module/_continuation/test/test_stacklet.py
@@ -487,6 +487,61 @@
         assert res == 'z'
         raises(TypeError, c1.switch, to=c2)  # "can't send non-None value"
 
+    def test_throw(self):
+        import sys
+        from _continuation import continulet
+        #
+        def f1(c1):
+            try:
+                c1.switch()
+            except KeyError:
+                res = "got keyerror"
+            try:
+                c1.switch(res)
+            except IndexError, e:
+                pass
+            try:
+                c1.switch(e)
+            except IndexError, e2:
+                pass
+            try:
+                c1.switch(e2)
+            except IndexError:
+                c1.throw(*sys.exc_info())
+            should_never_reach_here
+        #
+        c1 = continulet(f1)
+        c1.switch()
+        res = c1.throw(KeyError)
+        assert res == "got keyerror"
+        class FooError(IndexError):
+            pass
+        foo = FooError()
+        res = c1.throw(foo)
+        assert res is foo
+        res = c1.throw(IndexError, foo)
+        assert res is foo
+        #
+        def main():
+            def do_raise():
+                raise foo
+            try:
+                do_raise()
+            except IndexError:
+                tb = sys.exc_info()[2]
+            try:
+                c1.throw(IndexError, foo, tb)
+            except IndexError:
+                tb = sys.exc_info()[2]
+            return tb
+        #
+        tb = main()
+        assert tb.tb_frame.f_code.co_name == 'main'
+        assert tb.tb_next.tb_frame.f_code.co_name == 'f1'
+        assert tb.tb_next.tb_next.tb_frame.f_code.co_name == 'main'
+        assert tb.tb_next.tb_next.tb_next.tb_frame.f_code.co_name == 'do_raise'
+        assert tb.tb_next.tb_next.tb_next.tb_next is None
+
     def test_various_depths(self):
         skip("may fail on top of CPython")
         # run it from test_translated, but not while being actually translated
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to