Warning: This is the manual of the legacy Guile 2.0 series. You may want to read the manual of the current stable series instead.
Next: Throw Handlers, Previous: Exception Terminology, Up: Exceptions [Contents][Index]
catch
is used to set up a target for a possible non-local jump.
The arguments of a catch
expression are a key, which
restricts the set of exceptions to which this catch
applies, a
thunk that specifies the code to execute and one or two handler
procedures that say what to do if an exception is thrown while executing
the code. If the execution thunk executes normally, which means
without throwing any exceptions, the handler procedures are not called
at all.
When an exception is thrown using the throw
function, the first
argument of the throw
is a symbol that indicates the type of the
exception. For example, Guile throws an exception using the symbol
numerical-overflow
to indicate numerical overflow errors such as
division by zero:
(/ 1 0) ⇒ ABORT: (numerical-overflow)
The key argument in a catch
expression corresponds to this
symbol. key may be a specific symbol, such as
numerical-overflow
, in which case the catch
applies
specifically to exceptions of that type; or it may be #t
, which
means that the catch
applies to all exceptions, irrespective of
their type.
The second argument of a catch
expression should be a thunk
(i.e. a procedure that accepts no arguments) that specifies the normal
case code. The catch
is active for the execution of this thunk,
including any code called directly or indirectly by the thunk’s body.
Evaluation of the catch
expression activates the catch and then
calls this thunk.
The third argument of a catch
expression is a handler procedure.
If an exception is thrown, this procedure is called with exactly the
arguments specified by the throw
. Therefore, the handler
procedure must be designed to accept a number of arguments that
corresponds to the number of arguments in all throw
expressions
that can be caught by this catch
.
The fourth, optional argument of a catch
expression is another
handler procedure, called the pre-unwind handler. It differs from
the third argument in that if an exception is thrown, it is called,
before the third argument handler, in exactly the dynamic context
of the throw
expression that threw the exception. This means
that it is useful for capturing or displaying the stack at the point of
the throw
, or for examining other aspects of the dynamic context,
such as fluid values, before the context is unwound back to that of the
prevailing catch
.
Invoke thunk in the dynamic context of handler for exceptions matching key. If thunk throws to the symbol key, then handler is invoked this way:
(handler key args ...)
key is a symbol or #t
.
thunk takes no arguments. If thunk returns
normally, that is the return value of catch
.
Handler is invoked outside the scope of its own catch
.
If handler again throws to the same key, a new handler
from further up the call chain is invoked.
If the key is #t
, then a throw to any symbol will
match this call to catch
.
If a pre-unwind-handler is given and thunk throws
an exception that matches key, Guile calls the
pre-unwind-handler before unwinding the dynamic state and
invoking the main handler. pre-unwind-handler should
be a procedure with the same signature as handler, that
is (lambda (key . args))
. It is typically used to save
the stack at the point where the exception occurred, but can also
query other parts of the dynamic state at that point, such as
fluid values.
A pre-unwind-handler can exit either normally or non-locally. If it exits normally, Guile unwinds the stack and dynamic context and then calls the normal (third argument) handler. If it exits non-locally, that exit determines the continuation.
If a handler procedure needs to match a variety of throw
expressions with varying numbers of arguments, you should write it like
this:
(lambda (key . args) …)
The key argument is guaranteed always to be present, because a
throw
without a key is not valid. The number and
interpretation of the args varies from one type of exception to
another, but should be specified by the documentation for each exception
type.
Note that, once the normal (post-unwind) handler procedure is invoked, the catch that led to the handler procedure being called is no longer active. Therefore, if the handler procedure itself throws an exception, that exception can only be caught by another active catch higher up the call stack, if there is one.
The above scm_catch_with_pre_unwind_handler
and scm_catch
take Scheme procedures as body and handler arguments.
scm_c_catch
and scm_internal_catch
are equivalents taking
C functions.
body is called as body (body_data)
with a catch
on exceptions of the given tag type. If an exception is caught,
pre_unwind_handler and handler are called as
handler (handler_data, key, args)
.
key and args are the SCM
key and argument list from
the throw
.
body and handler should have the following prototypes.
scm_t_catch_body
and scm_t_catch_handler
are pointer
typedefs for these.
SCM body (void *data); SCM handler (void *data, SCM key, SCM args);
The body_data and handler_data parameters are passed to the respective calls so an application can communicate extra information to those functions.
If the data consists of an SCM
object, care should be taken
that it isn’t garbage collected while still required. If the
SCM
is a local C variable, one way to protect it is to pass a
pointer to that variable as the data parameter, since the C compiler
will then know the value must be held on the stack. Another way is to
use scm_remember_upto_here_1
(see Remembering During Operations).
Next: Throw Handlers, Previous: Exception Terminology, Up: Exceptions [Contents][Index]