Macro HANDLER-CASE
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 - フォーム
typespec - 型指定子
var - 変数名
lambda-list - 通常のラムダリスト
declaration - 宣言式。評価されません。
form - フォーム
result - 通常の状況ではexpressionの評価による結果が返却されます。 例外的な状況では制御がclauseに遷移したときに、 clause内の最後のformの値が返却されます。
handler-case
は 様々なハンドラーがアクティブになっている動的環境下で expressionを実行します。 各error-clauseは、 どのようなコンディションを捕捉するのか、 typespecでマッチされたものとして指定します。 no-error-clauseは、制御が通常の返却をしたときに 特定のアクションを指定することが許されます。
もしexpressionが実行中に error-clauseに適用できるコンディションが通知されたとき (例えば、(typep condition 'typespec)
がtrueになるような 何らかのcondition)、 さらにその型のコンディションが介入できるハンドラーがないときは、 関係するerror-clauseの ボディ部に制御が遷移します。 このような場合、動的な状態を適切に巻き戻し、 (つまりexpression周りに確立されたハンドラーは もうアクティブではありません)、 varに通知されたコンディションを束縛します。 もし複数の場合が提供されたときは、 そのような場合は並列にアクセスされます。 例えば次のような場合、
handler-case form
(
(typespec1 (var1) form1) (typespec2 (var2) form2))
もし最初のclauseが(form1が含まれているもの)選ばれたとき、 2番目のハンドラーは見ることができません(そしてその反対も同様)。
clauseは上から下に順番に検索されます。 もしtypespec間で重複する型があるときは、 classeの早い方が選択されます。
もしvarが必要ないときは、それは省略できます。 つまりclauseは次のようなもの
declare (ignore var)) form) (typespec (var) (
これを(typespec () form)
のように書くことができます。
もしformがないclauseが選択されたとき、 このような場合はhandler-case
はnil
を返却します。 もしexpressionの実行が普通に返却され、 no-error-clauseがないときは、 handler-case
はexpressionの結果が返却されます。 もしexpressionの実行が普通に返却され、 no-error-clauseがあるときは、 返却値はno-error-clauseから(lambda lambda-list form*)
の 生成によって定義された関数の引数として使用され、 その関数の呼び出しの値がhandler-case
による返却値になります。 この呼び出しの時点では、expression周りに確立されたハンドラーは もうアクティブではありません。
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
make-condition 'stream-error :stream *terminal-io*))
(assess-condition (=> "#<STREAM-ERROR 12352256> looks especially bad."
define-condition random-condition (condition) ()
(lambda (condition stream)
(:report (declare (ignore condition))
(princ "Yow" stream))))
(=> RANDOM-CONDITION
make-condition 'random-condition))
(assess-condition (=> "Hardly worth mentioning."
なし。
なし。
handler-bind
, ignore-errors
, 9.1. コンディションシステムの説明
handler-case form
(
(type1 (var1) . body1) (type2 (var2) . body2) ...)
上記の式はおおよそ下記のものと同等です。
block #1=#:g0001
(let ((#2=#:g0002 nil))
(tagbody
(handler-bind ((type1 #'(lambda (temp)
(setq #1# temp)
(go #3=#:g0003)))
(lambda (temp)
(type2 #'(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)
...-1 varN-2 ...) . bodyN)) (:no-error (varN
上記の式はおおよそ下記のものと同等です。
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) ...)))))