handler-case
expression
[[{!error-clause}* | !no-error-clause]] ⇒ {result}*
clause | ::= | !error-clause | !no-error-clause |
error-clause | ::= | (typespec ([ var] ) {declaration}* {form}*)
|
no-error-clause | ::= | (:no-error lambda-list {declaration}* {form}*)
|
expression | a form. |
typespec | a type specifier. |
var | a variable name. |
lambda-list | an ordinary lambda list. |
declaration | a declare expression; not evaluated. |
form | a form. |
results | In the normal situation, the values returned are those that result from the evaluation of expression; in the exceptional situation when control is transferred to a clause, the value of the last form in that clause is returned. |
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.
(defun assess-condition (condition)
(handler-case (signal condition)
(warning () "Lots of smoke, but no fire.")
((or arithmetic-error control-error cell-error stream-error)
(condition)
(format nil "~S looks especially bad." condition))
(serious-condition (condition)
(format nil "~S looks serious." condition))
(condition () "Hardly worth mentioning.")))
⇒ ASSESS-CONDITION
(assess-condition (make-condition 'stream-error :stream *terminal-io*))
⇒ "#<STREAM-ERROR 12352256> looks especially bad."
(define-condition random-condition (condition) ()
(:report (lambda (condition stream)
(declare (ignore condition))
(princ "Yow" stream))))
⇒ RANDOM-CONDITION
(assess-condition (make-condition 'random-condition))
⇒ "Hardly worth mentioning."
(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) ...)))))