関数またはマクロはバイトコンパイラの警告を指定できますか?


15

原則として、任意の数の引数を取る関数を作成しています。ただし、実際には、偶数の引数のみが渡される必要があり、 そうでない場合は望ましくない結果が生成されます。

コンテキストのダミーの例を次に示します。

(defun my-caller (&rest args)
  (while args
    (call-other-function (pop args) (pop args))))

elispファイルがバイトコンパイルされると、バイトコンパイラーは、間違った数の引数で呼び出されている関数を検出すると、警告をスローします。明らかに、これはで発生my-callerすることはありません。これは、任意の数を取るように定義されているためです。

それでも、設定できるシンボルプロパティや、(declare)その定義に追加できるフォームがあるかもしれません。この関数には偶数個の引数のみを指定する必要があることをユーザーに通知するもの。

  1. この制限をバイトコンパイラに通知する方法はありますか?
  2. そうでない場合、関数の代わりにマクロで可能ですか?

「... 引数の数が間違って呼び出されている関数を見たとき」?
itsjeyd 14年

回答:


13

編集:最近のEmacsでこれを行うより良い方法は、引数の数をチェックするコンパイラマクロを定義することです。通常のマクロを使用した私の最初の答えは以下に保存されていますが、コンパイラマクロは、実行時funcallまたはapply実行時に関数を渡すことを妨げないため、優れています。

Emacsの最近のバージョンでは、関数のコンパイラマクロを定義して引数の数をチェックし、一致しない場合は警告(またはエラー)を生成することでこれを行うことができます。唯一の微妙な点は、コンパイラマクロが、評価またはコンパイルのために元の関数呼び出し形式を変更せずに返すことです。これは、&whole引数を使用し、その値を返すことにより行われます。これは次のように実行できます。

(require 'cl-lib)

(defun my-caller (&rest args)
  (while args
    (message "%S %S" (pop args) (pop args))))

(define-compiler-macro my-caller (&whole form &rest args)
  (when (not (cl-evenp (length args)))
    (byte-compile-warn "`my-caller' requires an even number of arguments"))
  form)

(my-caller 1 2 3 4)
(my-caller 1 2)
(funcall #'my-caller 1 2 3 4)       ; ok
(apply #'my-caller '(1 2))          ; also ok
(my-caller 1)                       ; produces a warning
(funcall #'my-caller 1 2 3)         ; no warning!
(apply #'my-caller '(1 2 3))        ; also no warning

ノートfuncallapplyコンパイラマクロによって引数のチェックのバイパス使用できるようになりましたが、彼ら。その名前にもかかわらず、コンパイラマクロも経由して評価を「解釈」の過程で展開されているように見えるC-xC-eM-xeval-bufferあなたはこの例をコンパイルする上で評価するだけでなく、上のエラーが発生しますので、。


元の答えは次のとおりです。

「展開時に警告を提供するマクロを使用する」というJordonの提案を実装する方法を次に示します。非常に簡単であることがわかりました。

(require 'cl-lib)

(defmacro my-caller (&rest args)
  (if (cl-evenp (length args))
      `(my-caller--function ,@args)
    (error "Function `my-caller' requires an even number of arguments")))

(defun my-caller--function (&rest args)
  ;; function body goes here
  args)

(my-caller 1 2 3 4)
(my-caller 1 2 3)

上記のファイルをコンパイルしようとすると失敗し(.elcファイルは生成されません)、コンパイルログにクリック可能なエラーメッセージが表示されます。

test.el:14:1:Error: `my-caller' requires an even number of arguments

エラーの代わりに警告を生成するように置き換え(error …)(byte-compile-warn …)、コンパイルを続行することもできます。(コメントでこれを指摘してくれたJordonに感謝します)。

マクロはコンパイル時に展開されるため、このチェックに関連する実行時のペナルティはありません。もちろん、他の人がmy-caller--function直接電話をかけるのを止めることはできませんが、ダブルハイフン規則を使用して、少なくとも「プライベート」関数として宣伝することができます。

注目すべき欠点この目的のためにマクロを使用するのは、それはありませんmy-caller、あなたはそれを渡すことはできません。もはや第一級関数であるfuncallapply、実行時に(あるいは少なくともそれはあなたが何を期待しないだろう)。その点で、このソリューションは、実際の関数に対してコンパイラ警告を単に宣言できるほど優れていません。もちろん、を使用applyすると、コンパイル時に関数に渡される引数の数をチェックすることが不可能になるため、おそらくこれは許容できるトレードオフです。


2
コンパイル警告は次のように作成されますbyte-compile-warn
ジョーダンビオンド14年

関数のコンパイラマクロを定義することで、これをより効果的に達成できるのではないかと思います。これはにないという欠点排除するapplyか、funcallマクロラッパーを。私はそれを試して、それがうまくいけば答えを編集します。
ジョンO.

11

はいbyte-defop-compiler、関数をコンパイルする関数を実際に指定するために使用でき、byte-defop-compilerいくつかの引数を持つことに基づいて関数が警告を生成する必要があることを指定するのに役立つ組み込みの機能がいくつかあります。

ドキュメンテーション

FUNCTIONのコンパイラ形式を追加します。関数がシンボルの場合、変数「byte-SYMBOL」は使用するオペコードを指定する必要があります。functionがリストの場合、最初の要素は関数であり、2番目の要素はバイトコード記号です。2番目の要素はnilである可能性があります。これは、オペコードがないことを意味します。COMPILE-HANDLERは、このバイト操作をコンパイルするために使用する関数、または省略形0、1、2、3、0-1、または1-2です。nilの場合、ハンドラーは「byte-compile-SYMBOL」です。


使用法

特定のケースでは、略語の1つを使用して、関数に2つの引数を与えることを定義できます。

(byte-defop-compiler my-caller 2)

これで、2つの引数以外でコンパイルすると、警告が表示されます。

より具体的な警告を出し、独自のコンパイラー関数を作成する場合。見byte-compile-one-argや参照のためbytecomp.el内の他の同様の機能。

検証を処理するための関数を指定するだけでなく、実際にコンパイルすることにも注意してください。繰り返しますが、bytecomp.elのコンパイル関数は、適切なリファレンスを提供します。


より安全なルート

これは、私がオンラインで文書化または議論したものではありませんが、全体としては、これは取るに足らない方法だと思います。正しいルート(IMO)は、説明的な署名を使用してdefunを記述するか、拡張時に警告を提供するマクロを使用して、引数の長さをチェックし、エラーを表示byte-compile-warnまたは使用errorすることです。また、eval-when-compileエラーチェックを行うために利用することも有益です。

また、関数を使用する前に定義byte-defop-compilerする必要があり、呼び出しは、コンパイラが関数の実際の呼び出しに到達する前に行う必要があります。

繰り返しますが、実際に文書化されていないか、私が見たものからアドバイスされていないようです(間違っている可能性があります)を呼び出しますbyte-defop-compiler。これは基本的に、実際のパッケージをコンパイルする前に必要なパッケージです。

意見:私が知っていることは、それほど多くはありませんが、これについてはすべて学んだので、絶対にやらないことをお勧めします。今まで


1
関連:バイトコンパイラに追加の警告を教えるbytecomp-simplifyがあります。
ウィルフレッドヒューズ14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.