Emacs内蔵のヘルプコマンドC-h f(The GNU Emacs
ManualのHelpを参照)などのツールは、ソースコード内で関数やその他のLispオブジェクトの定義箇所を特定できます。そのために、変数find-function-regexp-alistを使用します。
alist find-function-regexp-alist
は、オブジェクト型を、そのソースファイル内で当該オブジェクトの定義を検索する正規表現または関数に関連付けます。各要素の car はオブジェクトの型を表すシンボルであり、nil は
defun で定義された関数を意味します。各要素の cdr は、以下のいずれかになります:
car が正規表現(またはそれを返す関数)で、cdr が form-matcher(マクロ展開されたフォーム用のマッチャーを作成する関数)である cons セル。
正規表現文字列は実際にはフォーマット文字列であり、%s は検索対象のシンボル名に置換されます。
関数は、検索対象のオブジェクト(を表す記号)という1つの引数で呼び出されます。
consセルの値に含まれるフォームマッチャー関数は、1つの引数(検索対象のシンボル)を受け取って呼び出され、関数を返す必要があります。その関数はフォームを受け取り、そのフォームが検索対象のシンボルを定義している場合に
non-nil を返す必要があります。これは、マクロの展開によって生成された定義を探す際に有用です。
検索対象の関数がマクロによって定義されている場合、Emacsがソースコード内でその定義箇所を特定するのが困難なことがあります。マクロ呼び出しが予期せぬ形式をしていることがあり、find-function-regexp-alist では定義を特定できません。
例えば、define-derived-mode(派生モードの定義を参照)が、モード固有の関数や変数を暗黙的に定義する場合や、Lispプログラムが関数を定義するためにdefunへの実行時呼び出しを生成する場合などが考えられます。こうしたケースや同様の状況において、シンボルのdefinition-nameプロパティは、テキスト検索で定義箇所を特定でき、かつそのコードが元のシンボルを定義している別のシンボルであるべきです。define-derived-modeの例では、それが定義する関数や変数のこのプロパティの値は、モードシンボルであるべきです。
場合によっては、別のシンボルの定義を探すことでは、その定義が見つからないことがあります。例えば、テストファイルでマクロを使用して ert-deftest への呼び出しを生成する場合(ERT: Emacs
Lisp Regression Testing の How
to Write Tests を参照)、そのコードは定型文であり、可変データのみを渡せばよいということがあります。このような場合、シンボルの
find-function-type-alist
プロパティは、この型のシンボルの定義の探し方を示す、find-function-regexp-alist を拡張するアリストを記述することができます。
find-function-regexp-alist プロパティは、便利関数 find-function-update-type-alist を用いるのが最も簡単です。
symbol のプロパティ find-function-type-alist を、キー type と値 variable を含む新しい要素で更新する。
ert-deftest
への呼び出しを定義するマクロの例では、このマクロは定義された各テストにプロパティ find-function-type-alist を付与し、ert--test(ERTテストの内部型)を、正しいマクロ呼び出しを特定できる正規表現や関数の名前に関連付けることができます。また、マクロを定義するファイル側でも、その定義検索用の関数や正規表現を提供する必要があります。以下に、関数を用いて定義を検索する例を示します。
(defmacro define-foo-test (data)
"Define a test of the foo system using DATA."
(declare (debug (&rest sexp)))
(let ((test-name (intern (concat ...))))
`(progn
(find-function-update-type-alist
',test-name 'ert--test 'foo-find-test-def-function)
(ert-deftest ,test-name ()
,(concat "Test foo with " ...)
...))))
(defun foo-find-test-def-function (test-name)
"Search for the `define-foo-test' call defining TEST-NAME.
Return non-nil if the definition is found."
(let ((regexp ...))
(re-search-forward regexp nil t)))