Emacs Lisp поддерживает нелокальные выходы, когда управление программой передаётся из одной точки программы в другую удалённую точку.
См. Нелокальные выходы. Таким образом, функции Lisp, вызванные вашим модулем,
могут выйти нелокально через вызов signal или throw, и
функции вашего модуля должны правильно обрабатывать такие нелокальные выходы. Такая
обработка необходима, потому что программы на C не будут автоматически освобождать ресурсы и выполнять другие действия по очистке в этих случаях; код вашего модуля
должен сделать это сам. Модульный API предоставляет для этого средства,
описанные в этом подразделе. Они доступны, начиная с Emacs 25; те из них, которые стали доступны в более поздних версиях,
явно указывают первую версию Emacs, в которой они вошли в состав API.
Когда некий код Lisp, вызванный функцией модуля, сигнализирует об ошибке или
выполняет throw, нелокальный выход перехватывается, и ожидающий выхода и его
связанные данные сохраняются в окружении. Всякий раз, когда в окружении ожидает нелокальный
выход, любая функция модульного API, вызванная с указателем на это окружение, немедленно вернёт управление
без какой-либо обработки (функции non_local_exit_check,
non_local_exit_get и non_local_exit_clear являются
исключением из этого правила). Если ваша функция модуля затем ничего не делает
и возвращает управление в Emacs, ожидающий нелокальный выход заставит Emacs
отреагировать на него: сигнализировать об ошибке или выполнить throw в соответствующий catch.
Таким образом, простейшая «обработка» нелокальных выходов в функциях модуля — это ничего не делать специально и позволить остальному коду работать так, как будто ничего не произошло. Однако это может привести к двум типам проблем:
Поэтому мы рекомендуем, чтобы ваши функции модуля проверяли условия нелокального выхода и восстанавливались после них, используя функции, описанные ниже.
enum emacs_funcall_exit non_local_exit_check (emacs_env *env) ¶Эта функция возвращает вид условия нелокального выхода, сохранённого в env. Возможные значения:
enum emacs_funcall_exit non_local_exit_get (emacs_env *env, emacs_value *symbol, emacs_value *data) ¶Эта функция возвращает вид условия нелокального выхода, сохранённого в
env, как и non_local_exit_check, но также возвращает
полную информацию о нелокальном выходе, если он есть. Если возвращаемое
значение — emacs_funcall_exit_signal, функция сохраняет
символ ошибки в *symbol и данные об ошибке в
*data (см. Как сигнализировать об ошибке). Если возвращаемое значение —
emacs_funcall_exit_throw, функция сохраняет символ метки catch
в *symbol и значение throw в
*data. Функция ничего не сохраняет в память,
на которую указывают эти аргументы, когда возвращаемое значение —
emacs_funcall_exit_return.
Вам следует проверять условия нелокального выхода там, где это важно: до того, как вы выделили какой-либо ресурс, или после выделения ресурса, который может потребовать освобождения, или там, где отказ делает дальнейшую обработку невозможной или нецелесообразной.
Как только ваша функция модуля обнаружила, что ожидается нелокальный выход, она может либо вернуть управление в Emacs (после выполнения необходимой локальной очистки), либо попытаться восстановиться после нелокального выхода. Следующие функции API помогут в решении этих задач.
void non_local_exit_clear (emacs_env *env) ¶Эта функция очищает ожидающие условия нелокального выхода и данные из env. После её вызова функции модульного API будут работать нормально. Используйте эту функцию, если ваша функция модуля может восстановиться после нелокальных выходов вызываемых ею функций Lisp и продолжить работу, а также перед вызовом любой из следующих двух функций (или любых других функций API, если вы хотите, чтобы они выполняли предназначенную обработку, когда ожидается нелокальный выход).
void non_local_exit_throw (emacs_env *env, emacs_value tag, emacs_value value) ¶Эта функция выполняет throw в символ Lisp catch, представленный
tag, передавая ему value в качестве возвращаемого значения. Ваша
функция модуля в общем случае должна вскоре вернуть управление после вызова этой функции.
Одно из применений этой функции — когда вы хотите повторно сгенерировать нелокальный выход
из одной из вызванных функций API или Lisp.
void non_local_exit_signal (emacs_env *env, emacs_value symbol, emacs_value data) ¶Эта функция сигнализирует об ошибке, представленной символом ошибки symbol, с указанными данными об ошибке data. Функция модуля должна вскоре вернуть управление после вызова этой функции. Эта функция может быть полезна, например, для передачи ошибок из функций модуля в Emacs.