handler-bind
(handler-bind ((type handler)...) body...)
ハンドラを確立して body... を評価します。本体の中でコンディションが通知されると — error、signal、warn、cerror によって — マッチする各ハンドラがシグナル点で、巻き戻しの前に、コンディションオブジェクトを唯一の引数として呼ばれます。ここが handler-case との違いです: シグナル元とハンドラの間のスタックはまだ生きているため、ハンドラは本体の内側の restart-case が確立したリスタートを invoke-restart してそこへ制御を移せます。正常にリターンしたハンドラは辞退したことになり、探索は外側のハンドラへ続きます。誰も処理しなかった error は handler-bind がなかった場合とまったく同様に中断します(あるいは外側の handler-case に捕捉されます)。type には handler-case の節の型がすべて使えます(define-condition のクラスと、組み込みエラーが持つクラス(type-error、division-by-zero など。handler-case を参照)を含む)。ハンドラ式は handler-bind に入るときに評価されます。
--no-gc を除くすべてのバックエンドでサポートされます。リスタートシステムを使うプログラムは wasm-GC バックエンドでは EH モードでコンパイルされるため、wasmtime run/wasmtime serve に -W exceptions=y を追加してください。組み込みが起こすエラー((car 5) のような型エラー、範囲外の aref、未定義関数)でもハンドラは実行されます: インタプリタは通知されたコンディションと同じくシグナル点で実行し、コンパイルバックエンドはエラーが handler-bind 自身を越えて巻き戻るときに実行します — その時点では本体の内側で確立されたリスタートは消えており、間にある unwind-protect のクリーンアップも実行済みです(通知されたコンディションはどのバックエンドでも正確なシグナル点セマンティクスを保ちます)。wasm-GC バックエンドでは、通知ではなくトラップになる失敗((car 5) はキャスト失敗にコンパイルされます。整数のゼロ除算も同様)は従来どおりハンドラを実行せずにプログラムを終了させます — ハンドラに届くのはコンディションチャネルに乗るもの(通知されたコンディション、未定義関数の呼び出し)だけです。
リターンしたハンドラは辞退し、エラーは伝播を続けます:
ハンドラは内側から順に実行され、本体の内側で確立された handler-case もそのひとつです: それにマッチするコンディションはそこで処理され、外側のハンドラは呼ばれません。内側の handler-case のどの節にもマッチしなかったときにだけ、探索は外側のハンドラに届きます。
組み込みが起こすエラーでもハンドラは実行されます — テストフレームワークが壊れたテスト本体を実行の中断ではなく失敗の記録に変える仕組みです: