SYS-EXCEPTION(2)
NAME
Exception, raise, rescue, rescued, unrescue − exception handling
SYNOPSIS
include "sys.m"; sys := load Sys Sys->PATH;
Exception: adt {
name: string; # name of exception
mod: string; # module
pc: int; # program counter };
raise: fn(s: string); rescue: fn(s: string, e: ref Exception): int; rescued: fn(flag: int, s: string); unrescue: fn();
DESCRIPTION
These functions provide exception handling in Limbo.
Exception communicates the nature of the exception. Exception.pc is the virtual machine program counter at the point of the raised exception, relative to the start of the module.
Raise throws an exception with the name s, and sets the error string for sys-print(2) (the value of the format %r) to s.
Rescue installs a rescue block for exceptions matched by s. If a matching exception occurs, rescue will return Sys->EXCEPTION; otherwise it returns Sys->HANDLER. S matches an exception name when the two are equal, or s is a string (the prefix) followed by *, which matches any exception name starting with the same prefix. In particular, "*" matches all exceptions. Rescue blocks can only handle exceptions that are raised in the same thread. If an exception needs to be handled in a spawned thread, a rescue block must be installed there.
if(sys->rescue("fail:*", e) == Sys->EXCEPTION) { # exception handling code ... sys->rescued(Sys->EXIT, nil); }
Rescued tells the system what to do after an exception has been handled, as specified by flag:
ACTIVE
Leave the handler installed; execution continues.
RAISE
Re-raise this exception or raise a different one. If s is nil, the current exception is re-raised; otherwise, exception s is raised instead.
EXIT The thread exits.
ONCE
Remove the handler; execution continues. For example:
if(sys->rescue("an exception", e) == Sys->HANDLER) { # normal execution code here } else { # handler code here sys->rescued(Sys->ONCE, nil); # removes the handler }
Unrescue removes the most recently installed handler and continues execution.
EXAMPLES
The first example removes the handler if normal execution completes:
if(sys->rescue("an exception", e) == Sys->HANDLER) { # normal execution code here sys->unrescue(); } else { # exception handling code here }
The next example is a complete program that demonstrates the behaviour of exception handling by executing both the normal execution code and the handler code.
implement Excep; include "sys.m"; sys: Sys; include "draw.m"; Excep: module { init: fn(ctxt: ref Draw->Context, argv: list of string); }; init(ctxt: ref Draw->Context, argv: list of string) {
sys = load Sys Sys->PATH;
e := ref sys->Exception;
if(sys->rescue("an exception", e) == Sys->EXCEPTION) { sys->print("rescue: exception\n"); sys->print("e.name = %s\ne.mod = %s\ne.pc = %d\n", e.name, e.mod, e.pc); sys->rescued(Sys->ONCE, nil);
} else { sys->print("rescue: normal execution\n"); sys->raise("an exception");
}
sys->print("raise: %r\n");
sys->raise("nasty thing");# won’t be handled }