Okay, here's a quick sketch of how exceptions are going to look.

First, we're going to treat them as essentially a sort of 
upwards-only continuation. (Which they really are, so that's fine)

Exceptions are semi-fatal--they are *not* resumable. Too much 
trouble. Maybe we'll lift that restriction later, though there are 
issues with it. (Resuming low-level exceptions are a major pain, 
though it's easier at the parrot level)

At the interpreter level, we're throwing exceptions, *all* 
exceptions, with the system-local exception mechanism. This will be 
setjmp and longjmp for most everwhere, but if a system's got 
something better we'll use it. Yeah, this means a certain amount of 
Macro Hell. I don't much like it, but this is one of the spots where 
we need it.

Exceptions have four parts:

    Language
    Severity
    Class
    ID

Language is the language throwing the exception. (Ruby, Scheme, Perl, 
Python, Brainf*ck, unlamda, whatever)

Severity ranges from informational to "Help the world is ending!" 
There'll be fields in the interpreter to note at which level 
exceptions are ignored, and at which level they just throw a message 
to stderr.

Class is stuff like IO, Math, or Internal, which gives a 
classification of sorts to the exception.

ID gives an identifier to the exception. There'll be a name to ID 
mapping table somewhere.


When we set an exception handler, we take a continuation. This means 
we remember the state of all the stacks (*and* we save off the 
current register state). This involves walking the stack frames 
upwards and marking them all COW, but we'll get to that in more 
detail with continuations. (That'll be another mail message) That 
exception handler gets pushed onto the control stack.

When we get an exception, we unwind the control stack until we get to 
a handler that can handle the exception. If we find one we invoke the 
continuation that is responsible for dealing with the exception and 
let it go from there. The exception handler may, if it chooses, 
rethrow the exception.

Internal/doomed exceptions are somewhat different. We do *not* walk 
anything. There may be a single internal/doomed exception handler, 
and all it may do is a bit of last-gasp processing. When it exits the 
interpreter is destroyed.


When throwing an exception, code may also throw an object with it. If 
so, the object is passed in as a parameter to the exception handler.


C code *may*, if it chooses, install a generic exception override, 
and we'll have a routine for this. Something like:

      EXCEPTION_OVERRIDE(&exception_frame);
      EXCEPTION_RELEASE(&exception_frame);

but with a bit more thought involved. All it'll do is install a 
different setjmp destination in the interpreter and later remove it, 
but it'll take care of the whole linked-list stuff so they'll nest 
and restore properly. Your code will be 100% responsible for handling 
*all* exceptions, though it may choose to de-install itself and 
rethrow. That's OK.


Finally, *all* fatal errors will be dealt with by throwing 
exceptions. The whole "Return 0/NULL on error" thing's too much of a 
hassle--either we succeed, or we freak out. I'll update the vtable 
PDD accordingly. This will mean that you may have to do a little more 
work in those few cases where 'fatal' errors are acceptable, but that 
should be a tiny minority, so I think this'll be a win.
-- 
                                         Dan

--------------------------------------"it's like this"-------------------
Dan Sugalski                          even samurai
[EMAIL PROTECTED]                         have teddy bears and even
Perl class: stemsystems.com/class     teddy bears get drunk

Reply via email to