Author: allison
Date: Tue Jul  4 10:43:19 2006
New Revision: 13151

Modified:
   trunk/docs/pdds/pdd23_exceptions.pod

Changes in other areas also in this revision:
Modified:
   trunk/   (props changed)

Log:
[pdds]: Review and revise the Exceptions PDD.


Modified: trunk/docs/pdds/pdd23_exceptions.pod
==============================================================================
--- trunk/docs/pdds/pdd23_exceptions.pod        (original)
+++ trunk/docs/pdds/pdd23_exceptions.pod        Tue Jul  4 10:43:19 2006
@@ -42,9 +42,9 @@
 
 =over
 
-=item B<< push_eh I<SUB_LABEL> >>
+=item B<push_eh I<SUB_LABEL>>
 
-=item B<< push_eh I<INVOCABLE_PMC> >>
+=item B<push_eh I<INVOCABLE_PMC>>
 
 Push an invocable PMC -- usually a closure or, in rarer cases, a subroutine --
 onto the exception handler stack.
@@ -58,15 +58,13 @@
 exception (i.e. the call stack is I<not> unwound first).  See below for more
 detail.
 
-=item B<< pop_eh >>
+=item B<pop_eh>
 
 Pop the most recently pushed exception handler off the control stack.
 
-{{ TODO: should we provide a "pop_eh $P0" variant returning the address, since
-it's easy and somebody might find it useful?  Or is it more important to
-provide generic control stack introspection?  Probably the latter.  }}
+{{ TODO: Provide control stack introspection. }}
 
-=item B<< throw I<EXCEPTION> >>
+=item B<throw I<EXCEPTION>>
 
 Throw an exception consisting of the given I<EXCEPTION> PMC.  Active exception
 handlers (if any) will be invoked with I<EXCEPTION> as the only parameter.
@@ -78,21 +76,22 @@
 Any type of PMC can be thrown as an exception.  However, if there's any chance
 of cross-language calls -- and in a Parrot environment, cross-language
 operations are kind of the point -- then you should be prepared to catch
-object of classes you would never have thrown yourself.
+exception classes you would never have thrown yourself.
 
 That said, it is I<VERY STRONGLY RECOMMENDED> that any thrown PMC that can
 possibly escape your private sandbox should meet the minimal interface
 requirements of the C<parrot;exception> class, described below.
 
-=item B<< throwcc I<EXCEPTION> >>
+=item B<throwcc I<EXCEPTION> [ , I<CONTINUATION> ]>
 
-Throw an exception consisting of the given I<EXCEPTION> PMC after taking a
-continuation at the next opcode.  Active exception handlers (if any) will be
+Throw an exception consisting of the given I<EXCEPTION> PMC after taking
+a continuation at the next opcode.  When a I<CONTINUATION> is passed in,
+it will use that instead. Active exception handlers (if any) will be
 invoked with I<EXCEPTION> and the given continuation as parameters.
 
-Except for its taking of a continuation which is then passed to exception
-handlers, C<throwcc> is just like C<throw>.  This opcode is useful for
-exceptions that are more like warnings or notices than errors.
+Except for the continuation which is passed to exception handlers,
+C<throwcc> is just like C<throw>.  This opcode is useful for exceptions
+that are more like warnings or notices than errors.
 
 Exception handlers can resume execution immediately after the C<throwcc>
 opcode by executing the C<handled> opcode, and then invoking the given
@@ -100,21 +99,26 @@
 invoked with no parameters; in other words, C<throwcc> may I<not> return a
 value.
 
-=item B<< die [ I<MESSAGE> ] >>
+{{ TODO: Resuming immediately after the C<throw> opcode isn't quite
+flexible enough. Perl 6, for example, resumes control flow after the end
+of the block in which the exception was thrown. }}
+
+=item B<die [ I<MESSAGE> ]>
 
 The C<die> opcode throws an exception of type C<exception;death> with a
 payload of I<MESSAGE>.  If I<MESSAGE> is a string register, the exception
 payload is a C<String> PMC containing I<MESSAGE>; if I<MESSAGE> is a PMC, it
 is used directly as the exception payload.
 
-{{ TODO: What is the default when no I<MESSAGE> is given? }}
+{{ TODO: What is the default when no I<MESSAGE> is given? Something like
+"Fatal exception at LINE in FILE." followed by a backtrace. }}
 
 If this exception is not handled, it results in Parrot returning an error
 indication and the stringification of I<MESSAGE> to its embedding environment.
 When running standalone, this means writing the stringification of I<MESSAGE>
-to the standard error and executing the standard C function C<exit(1)>.
+to standard error and executing the standard C function C<exit(1)>.
 
-=item B<< exit [ I<EXITCODE> ] >>
+=item B<exit [ I<EXITCODE> ]>
 
 Throw an exception of type C<exception;exit> with a payload of I<EXITCODE>,
 which defaults to zero, as an Integer PMC.
@@ -123,7 +127,7 @@
 as a status to its embedded environment, or when running standalone,
 to execute the C function C<exit(I<EXITCODE>)>.
 
-=item B<< handled >>
+=item B<handled I<EXCEPTION>>
 
 While handling an exception, tell Parrot that the exception has been handled
 and should be removed from the stack of active exceptions.  This opcode is an
@@ -133,38 +137,65 @@
 
 =head2 Order of Operations in Exception Handling
 
-=over 4
+When B<throw> or B<throwcc> is called, for all active exception
+handlers, in LIFO order:
+
+=over
+
+=item 1
+Find the topmost exception handler
+
+=item 2
+Push an exception record somewhere, presumably on the control stack.
+The exception record contains a pointer to an exception handler block
+and an exception PMC (and possibly a continuation)
+
+=item 3
+Invoke the handler (note: this is still in the thrower's dynamic
+context)
+
+=back
+
+If the handler returns normally:
+
+=over
+
+=item 1
+Find the "exception handling in progress" record
 
-=item B<throw> or B<throwcc>
+=item 2
+Find the next exception handler
 
-   For all active exception handlers, in LIFO order:
-      find the topmost exception handler
-      push Exception Record somewhere,
-         presumably on the control stack,
-         containing pointer to exception handler block
-            and exception PMC
-            (and possibly a continuation)
-      invoke the handler
-        (note: this is still in the thrower's dynamic context)
-
-=item if the handler returns normally:
-
-   find the "exception handling in progress" record
-   find the next exception handler
-   if found,
-      invoke it
-   else if there is a continuation in the Exception Record
-        (because the throwing opcode was C<throwcc>),
-      invoke the ER's continuation (i.e. resume execution)
-   else,
-      terminate program a la C<die>
+=item 3
+If the handler is found, invoke it
 
-=item C<handled> opcode
+=item 4
+Or if there is a continuation in the exception record
+(because the throwing opcode was C<throwcc>),
+invoke the ER's continuation (i.e. resume execution)
 
-   pop and destroy Exception Record
+=item 5
+Otherwise terminate program a la C<die>
 
 =back
 
+{{ TODO: this isn't right, another option is a) invoke the handler, b)
+the handler calls handled, and c) invoke the continuation to resume
+because the exception was handled. The question of whether to resume or
+die when an exception is never handled is determined by the severity of
+the exception, not by the simple fact of having a continuation. }}
+
+
+When the C<handled> opcode is called:
+
+=over
+
+=item 1
+Pop and destroy exception record
+
+=back
+
+
 =head1 STANDARD EXCEPTIONS
 
 =head2 Universal Exception Object Interface [Advisory]
@@ -220,7 +251,9 @@
 C<set_inner_exception()> method to store that previous exception
 as part of the exception object.
 
-{{ TODO: Should we use properties instead? }}
+{{ TODO: Should we use properties instead? ANR: I'm not sure what you
+mean by "an exception is a consequence of a previous exception".
+Example? }}
 
 =back
 
@@ -252,6 +285,8 @@
 
 =item B<exception;domain>
 
+{{ TODO: How about calling these B<exception;input>? }}
+
 Generic base class for miscellaneous domain (input value) errors.  Payload is
 an array, the first element of which is the operation that failed (e.g. the
 opcode name); subsequent elements depend on the value of the first element.
@@ -321,8 +356,8 @@
 C<store_lex> is likely to succeed every time, as creating new lexicals at
 runtime is OK in Tcl.)
 
-{{ FIXME - Is it true that more opcodes throw exceptions?  If so, they should
-be listed here. }}
+{{ TODO: List any other opcodes that currently throw exceptions and
+general categories of opcodes that should throw exceptions. }}
 
 Other opcodes respond to an C<errorson> setting to decide whether to
 throw an exception or return an error value. C<find_global> throws an
@@ -331,8 +366,32 @@
 name requested doesn't exist in a lexical, current, global, or built-in
 namespace.
 
-{{ FIXME - "erroron" as specified is dynamically rather than lexically
-scoped; is this good? }}
+{{ FIXME - "errorson" as specified is dynamically rather than lexically
+scoped; is this good? ANR: There are a couple of different factors here.
+One is the ability to globally define the severity of certain exceptions
+or categories of exceptions without needing to define a handler for each
+one. (e.g. Perl 6 may have pragmas to set how severe type-checking
+errors are. A simple "incompatible type" error may be fatal under one
+pragma, a resumable warning under another pragma, and completely silent
+under a third pragma.) Another is the ability to "defang" opcodes so
+they return error codes instead of throwing exceptions. We might provide
+a very simple interface to catch an exception and capture its payload
+without the full complexity of manually defining exception handlers
+(though it would still be implemented as an exception handler
+internally). Something like:
+
+  .local pmc error_code
+  .capture_start error_code
+  $P1 = find_lex 'foo'
+  .capture_end
+
+  # error_code contains what would have been the "error" return value
+
+This could eliminate the need for "defanging" because it would be almost
+as easy to use as error codes. It could be implemented once for all
+exceptional opcodes, instead of needing to be defined for each one. And,
+it still keeps the error information out-of-band, instead of mixing the
+error in with normal return values. }}
 
 It's a little odd that so few opcodes throw exceptions (these are the
 ones that are documented, but a few others throw exceptions internally
@@ -344,7 +403,7 @@
 for exception-based or non-exception-based implementations, rather than
 forcing one or the other.]
 
-=head2 
+=head2 Resuming after Exceptions
 
 Exceptions thrown by standard Parrot opcodes (like the one thrown by
 C<find_global> above or by the C<throw> opcode) are always resumable,
@@ -358,11 +417,20 @@
   $P1 = new ['parrot';'exception'], $P0  # create new exception object
   throw $P1                              # throw it
 
+=head2 Consequenses
+
 Exceptions are designed to work with the Parrot calling conventions.
 Since the return addresses of C<bsr> subroutine calls and exception
 handlers are both pushed onto the control stack, it's generally a bad
 idea to combine the two.
 
+{{ TODO: If this continues to be true, then we need a way to turn off
+all exceptions. A number of built-in opcodes throw exceptions. If there
+is no way to prevent this, then it is never safe to use the control
+stack for anything other than exceptions. Alternatively, we leave the
+control stack safe for more primitive control flow, and pick another
+strategy for exceptions. }}
+
 =head1 ATTACHMENTS
 
 None.

Reply via email to