Sorry for the delay in replying, but I was busy with other things and I
wanted to give other people a chance to reply. Since noone has, might it
be possible to get the attached patches committed? I'm not familiar with
the protocol for such things so, again, I'm sorry if I've got it wrong.

Ben

--- S04-control.pod.orig	2009-08-11 08:43:36.000000000 +0100
+++ S04-control.pod	2009-08-11 09:03:42.000000000 +0100
@@ -1232,6 +1232,21 @@
 before C<BEGIN>, C<CHECK>, or C<INIT>, since those are done at compile or
 process initialization time).
 
+If an exception is thrown through a block without a C<CATCH> block, the
+C<LEAVE>, C<UNDO> and C<POST> blocks will be run at that point, with
+C<$!> set to the in-flight exception.  If there is no in-flight
+exception when these blocks are run, C<$!> will be C<undef>.  The last
+exception caught in the outer block is available as C<< OUTER::<$!> >>,
+as usual. 
+
+An exception thrown from an C<ENTER> block will abort the C<ENTER>
+queue, but one thrown from a C<LEAVE> block will not.  The exceptions
+thrown by failing C<PRE> and C<POST> blocks cannot be caught by a
+C<CATCH> in the same block, which implies that C<POST> blocks are not
+run if a C<PRE> block fails.  If a C<POST> fails while an exception is in
+flight the C<POST> failure doesn't replace C<$!> but goes straight into
+C<$!.pending>.
+
 For blocks such as C<KEEP> and C<POST> that are run when exiting a
 scope normally, the return value (if any) from that scope is available
 as the current topic.  (It is presented as a C<Capture> object.)
Index: S04-closure-traits/enter-leave.t
===================================================================
--- S04-closure-traits/enter-leave.t	(revision 27955)
+++ S04-closure-traits/enter-leave.t	(working copy)
@@ -2,7 +2,7 @@
 
 use Test;
 
-plan 11;
+plan 19;
 
 # L<S04/Closure traits/ENTER "at every block entry time">
 # L<S04/Closure traits/LEAVE "at every block exit time">
@@ -92,4 +92,92 @@
     }), 1, 'leave triggers LEAVE {}';
 }
 
+{
+    my $str;
+    try {
+        ENTER { $str ~= '(' }
+        LEAVE { $str ~= ')' }
+        $str ~= 'x';
+        die 'foo';
+    }
+    is $str, '(x)', 'die calls LEAVE blocks';
+}
+
+{
+    my $str;
+    try {
+        LEAVE { $str ~= $! // '<undef>' }
+        die 'foo';
+    }
+    is $str, 'foo', '$! set in LEAVE if exception thrown';
+}
+
+{
+    my $str;
+    {
+        LEAVE { $str ~= (defined $! ? 'yes' : 'no') }
+        try { die 'foo' }
+        $str ~= (defined $! ? 'aye' : 'nay');
+    }
+    is $str, 'ayeno', '$! not set in LEAVE if exception not thrown';
+}
+
+{
+    my $str;
+    try {
+        $str ~= '(';
+        try {
+            ENTER { die 'foo' }
+            $str ~= 'x';
+        }
+        $str ~= ')';
+    }
+    is $str, '()', 'die in ENTER caught by try';
+}
+
+{
+    my $str;
+    try {
+        $str ~= '(';
+        try {
+            LEAVE { die 'foo' }
+            $str ~= 'x';
+        }
+        $str ~= ')';
+    }
+    is $str, '(x)', 'die in LEAVE caught by try';
+}
+
+{
+    my $str;
+    try {
+        $str ~= '(';
+        try {
+            ENTER { $str ~= '['; die 'foo' }
+            LEAVE { $str ~= ']' }
+            $str ~= 'x';
+        }
+        $str ~= ')';
+    }
+    is $str, '([])', 'die in ENTER calls LEAVE';
+}
+
+{
+    my $str;
+    try {
+        ENTER { $str ~= '1'; die 'foo' }
+        ENTER { $str ~= '2' }
+    }
+    is $str, '1', 'die aborts ENTER queue';
+}
+
+{
+    my $str;
+    try {
+        LEAVE { $str ~= '1' }
+        LEAVE { $str ~= '2'; die 'foo' }
+    }
+    is $str, '21', 'die doesn\'t abort LEAVE queue';
+}
+
 # vim: ft=perl6
Index: S04-closure-traits/pre-post.t
===================================================================
--- S04-closure-traits/pre-post.t	(revision 27955)
+++ S04-closure-traits/pre-post.t	(working copy)
@@ -9,7 +9,7 @@
 # TODO: 
 #  * Multiple inheritance + PRE/POST blocks
 
-plan 18;
+plan 25;
 
 sub foo(Num $i) {
     PRE {
@@ -125,4 +125,82 @@
 lives_ok { $pt.test(2) }, 'POST receives return value as $_ (succeess)';
 dies_ok  { $pt.test(1) }, 'POST receives return value as $_ (failure)';
 
+{
+    my $str;
+    {
+        PRE  { $str ~= '('; 1 }
+        POST { $str ~= ')'; 1 }
+        $str ~= 'x';
+    }
+    is $str, '(x)', 'PRE and POST run on ordinary blocks';
+}
+
+{
+    my $str;
+    {
+        POST  { $str ~= ')'; 1 }
+        LEAVE { $str ~= ']' }
+        ENTER { $str ~= '[' }
+        PRE   { $str ~= '('; 1 }
+        $str ~= 'x';
+    }
+    is $str, '([x])', 'PRE/POST run outside ENTER/LEAVE';
+}
+
+{
+    my $str;
+    try {
+        {
+            PRE     { $str ~= '('; 0 }
+            PRE     { $str ~= '*'; 1 }
+            ENTER   { $str ~= '[' }
+            $str ~= 'x';
+            LEAVE   { $str ~= ']' }
+            POST    { $str ~= ')'; 1 }
+        }
+    }
+    is $str, '(', 'failing PRE runs nothing else';
+}
+
+{
+    my $str;
+    try {
+        {
+            POST  { $str ~= 'x'; 0 }
+            LEAVE { $str ~= 'y' }
+            POST  { $str ~= 'z'; 1 }
+        }
+    }
+    is $str, 'yx', 'failing POST runs LEAVE but not more POSTs';
+}
+
+{
+    my $str;
+    try {
+        POST { $str ~= $! // '<undef>'; 1 }
+        die 'foo';
+    }
+    is $str, 'foo', 'POST runs on exception, with correct $!';
+}
+
+{
+    my $str;
+    try {
+        POST { $str ~= (defined $! ? 'yes' : 'no'); 1 }
+        try { die 'foo' }
+        $str ~= (defined $! ? 'aye' : 'nay');
+    }
+    is $str, 'ayeno', 'POST has undef $! on no exception';
+}
+
+{
+    try {
+        POST { 0 }
+        die 'foo';
+    }
+    is $!, 'foo', 'failing POST on exception doesn\'t replace $!';
+    # XXX
+    # is $!.pending.[-1], 'a POST exception', 'does push onto $!.pending';
+}
+
 # vim: ft=perl6

Reply via email to