GNU Emacs 32.0.50 (9008bf64c3) のマニュアルを PLaMo 翻訳で機械翻訳したものです。誤訳を含むことがあります。原文: https://www.gnu.org/software/emacs/manual/html_node/elisp/Module-Nonlocal.html ・ emacs-doc.conao3.com

E.7.6 モジュールにおける非局所脱出

Emacs Lispは非局所脱出をサポートしており、これによりプログラムの制御がプログラム内のある地点から別の遠隔地点へと転送されます。非局所脱出を参照してください。したがって、モジュールから呼び出されるLisp関数がsignalやthrowを呼び出すことで非局所脱出する場合があり、モジュールの関数はこうした非局所脱出を適切に処理する必要があります。C言語のプログラムでは、このような場合にリソースの解放やその他のクリーンアップを自動的に行わないため、モジュールのコード自身で処理を行う必要があります。モジュールのAPIにはそのための機能が用意されており、本サブセクションで説明します。これらの機能は一般的にEmacs 25以降で利用可能です。後続のリリースで利用可能になった機能については、APIの一部となった最初のEmacsバージョンが明記されています。

モジュール関数によって呼び出されたLispコードがエラーをシグナルしたりスローしたりすると、非ローカルな終了がトラップされ、保留中の終了とそれに関連するデータが環境に格納されます。環境に非ローカルな終了が保留されている間は、その環境へのポインタを用いて呼び出されたあらゆるモジュールのAPI関数は、いかなる処理も行わずに直ちに戻ります(関数non_local_exit_check、non_local_exit_get、およびnon_local_exit_clearはこのルールの例外です)。その後、モジュール関数が何も行わずにEmacsに戻った場合、保留中の非ローカルな終了によってEmacsがそれに対応し、エラーをシグナルするか、対応するcatchをスローします。

したがって、モジュール関数における非局所的な脱出の最もシンプルな「処理」とは、特別な操作を行わず、残りのコードを何事もなかったかのように実行させることです。しかし、これにより2種類の問題が発生する可能性があります:

したがって、お使いのモジュールの関数では、以下に説明する関数を用いて、nonlocal の終了条件をチェックし、そこから復帰することを推奨します。

関数: enum emacs_funcall_exit non_local_exit_check (emacs_env *env)

この関数は、env に格納されている nonlocal の終了条件の種類を返します。取り得る値は以下の通りです:

emacs_funcall_exit_return

最後のAPI関数が正常に終了しました。

emacs_funcall_exit_signal

最後のAPI関数がエラーを報告しました。

emacs_funcall_exit_throw

最後のAPI関数がthrow経由で終了しました。

関数: enum emacs_funcall_exit non_local_exit_get (emacs_env *env, emacs_value *symbol, emacs_value *data)

この関数は、non_local_exit_check と同様に env に格納されている非ローカル終了条件の種類を返しますが、非ローカル終了に関する詳細情報(もしあれば)も併せて返します。戻り値が emacs_funcall_exit_signal の場合、関数はエラーシンボルを *symbol に、エラーデータを *data に格納します(エラーの通知方法 を参照)。戻り値が emacs_funcall_exit_throw の場合、関数は catch タグシンボルを *symbol に、throw の値を *data に格納します。戻り値が emacs_funcall_exit_return の場合、関数はこれらの引数が指すメモリ領域に何も格納しません。関数が symbol または data の記憶領域を確保できなかった場合は、シンボル module-out-of-memory を表す値を *symbol に、nil を表す値を *data に格納し、emacs_funcall_exit_signal を返します。

重要な箇所では、nonlocalの終了条件を確認すべきです。具体的には、リソースを割り当てる前や、解放が必要になる可能性のあるリソースを割り当てた後、あるいは失敗によって以降の処理が不可能または実行不能になる場合などが挙げられます。

モジュール関数が nonlocal による終了が待機中であることを検知すると、(必要なローカルクリーンアップを行った上で)Emacs に戻るか、あるいは nonlocal による終了からの復旧を試みることができます。以下の API 関数がこれらの処理に役立ちます。

関数: void non_local_exit_clear (emacs_env *env)

この関数は、env から保留中の nonlocal 終了条件およびデータをクリアします。この関数を呼び出した後、モジュールの API 関数は正常に動作するようになります。モジュールの関数が、呼び出し先の Lisp 関数の nonlocal 終了から回復して処理を継続できる場合、および以下の 2 つの関数(または、nonlocal 終了が保留されている際に意図した処理を行わせたいその他の API 関数)を呼び出す前に、この関数を使用してください。

関数: void non_local_exit_throw (emacs_env *env, emacs_value tag, emacs_value value)

この関数は、tag で表される Lisp のシンボル catch に対して例外をスローし、戻り値として value を渡します。通常、モジュールの関数はこの関数を呼び出した後、すぐに処理を終了させるべきです。この関数の用途の一つとして、呼び出された API や Lisp 関数のいずれかから非ローカルな終了を再度スローしたい場合が挙げられます。

関数: void non_local_exit_signal (emacs_env *env, emacs_value symbol, emacs_value data)

この関数は、エラーシンボル symbol で表されるエラーを、指定されたエラーデータ data とともに通知します。モジュール関数は、この関数を呼び出した後速やかに復帰する必要があります。この関数は、例えばモジュール関数からのエラーを Emacs に通知する場合などに有用です。