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