handler-case executes expression in a dynamic environment where
various handlers are active. Each error-clause specifies how to
handle a condition matching the indicated typespec.
A no-error-clause allows the specification of a particular action
if control returns normally.
If a condition is signaled for which there is an appropriate
error-clause during the execution of expression
(i.e., one for which (typep condition 'typespec)
returns true) and if there is no intervening handler for a
condition of that type, then control is transferred to
the body of the relevant error-clause. In this case, the
dynamic state is unwound appropriately (so that the handlers established
around the expression are no longer active), and var is bound to
the condition that had been signaled.
If more than one case is provided, those cases are made accessible
in parallel. That is, in
(handler-case form
(typespec1 (var1) form1)
(typespec2 (var2) form2))
if the first clause (containing form1) has been selected,
the handler for the second is no longer visible (or vice versa).
The clauses
are searched sequentially from top to bottom. If there is type
overlap between typespecs,
the earlier of the clauses is selected.
If var
is not needed, it can be omitted. That is, a clause such as:
(typespec (var) (declare (ignore var)) form)
can be written
(typespec () form).
If there are no forms in a selected clause, the case, and therefore
handler-case, returns nil.
If execution of expression
returns normally and no no-error-clause
exists, the values returned by
expression are returned by handler-case.
If execution of
expression returns normally and a no-error-clause
does exist, the values returned are used as arguments to the function
described by constructing
(lambda lambda-list {form}*)
from the no-error-clause, and the values of that function call are
returned by handler-case.
The handlers which were established around the expression are no longer active at the time of this call.
(handler-case form
(type1 (var1) . body1)
(type2 (var2) . body2) ...)
is approximately equivalent to:
(block #1=#:g0001
(let ((#2=#:g0002 nil))
(tagbody
(handler-bind ((type1 #'(lambda (temp)
(setq #1# temp)
(go #3=#:g0003)))
(type2 #'(lambda (temp)
(setq #2# temp)
(go #4=#:g0004))) ...)
(return-from #1# form))
#3# (return-from #1# (let ((var1 #2#)) . body1))
#4# (return-from #1# (let ((var2 #2#)) . body2)) ...)))
(handler-case form
(type1 (var1) . body1)
...
(:no-error (varN-1 varN-2 ...) . bodyN))
is approximately equivalent to:
(block #1=#:error-return
(multiple-value-call #'(lambda (varN-1 varN-2 ...) . bodyN)
(block #2=#:normal-return
(return-from #1#
(handler-case (return-from #2# form)
(type1 (var1) . body1) ...)))))