通常、バイトコンパイラはコンパイルするファイルのフォームを実際には
実行しない。たとえば、ファイルが(setq foo t)を含む場合、
コンパイルすることは実際にはtをfooに設定しない。
setqがトップレベルフォーム(すなわちdefunまたは他の
フォームに囲まれていない)だったとしてもそれは真である。しかし、ある
トップレベルフォームをコンパイル時に評価させたい場合がある。たとえば、
ファイルの残りの部分が定義されたマクロを参照できるように、コンパイラは
defmacroフォームをコンパイル時に実際に評価する。
このフォームは本体formsがいつ評価されるかを制御する。
situationsリストはシンボルcompile、load、そして
eval(または長いANSIの同等物、:compile-toplevel、
:load-toplevel、そして:execute)のいずれの集合を
含んでもよい。
eval-whenフォームは、トップレベルフォームとして
コンパイルされているかどうかによって異なって扱われる。つまり、
byte-compile-fileのようにファイルやコードのバッファを
コンパイルするコマンドによってコンパイルされているときに特別に扱われ、
文字通りファイルのトップレベルかprognの内部のトップレベルに
現れる。
コンパイルされたトップレベルのeval-whenには、compileが
situationsリストにある場合には、forms本体はコンパイル時に
実行され、loadがsituationsリストにある場合には、
formsは(ロード時に実行されるように)ファイルに書かれる。
コンパイルされていないトップレベルフォームには、状況evalのみが
関係する。(これはインタプリタが実行するフォーム、
byte-compile-fileではなくbyte-compileでコンパイルされた
フォーム、トップレベルではないフォームを含む。 ) evalが
指定された場合、eval-whenはprognのように振る舞い、
そうでない場合はnil(forms本体を無視する)のように
振る舞う。
eval-whenが入れ子の場合、規則はさらに微妙になる;
ぞっとするような詳細(そしてぞっとするような例)はSteele(第2版)を
調べること。
単純な例:
;; top-level forms in foo.el: (eval-when (compile) (setq foo1 'bar)) (eval-when (load) (setq foo2 'bar)) (eval-when (compile load) (setq foo3 'bar)) (eval-when (eval) (setq foo4 'bar)) (eval-when (eval compile) (setq foo5 'bar)) (eval-when (eval load) (setq foo6 'bar)) (eval-when (eval compile load) (setq foo7 'bar))
foo.elがコンパイルされると、これらの変数がコンパイル自身の間に設定される:
foo1 foo3 foo5 foo7 ; `compile'
foo.elcがロードされると、これらの変数が設定される:
foo2 foo3 foo6 foo7 ; `load'
ロードされたfoo.elがコンパイルされていないと、これらの変数が設定される:
foo4 foo5 foo6 foo7 ; `eval'
仮にこれら7個のeval-whenがdefun内部にあれば、最初の3個は
nilと同等であり、最後の4個は対応するsetqと同等である。
(eval-when (load eval) …)はあらゆるコンテキストで
(progn …)と同等であることに注意せよ。コンパイラは
defmacro(多少)やrequireのようないくつかの
トップレベルフォームを(eval-when (compile load eval) …)で
包まれているかのように扱う。
Emacs 19はeval-whenと関係がある2個の特殊形式を含む。そのうちの
1個であるeval-when-compileは、どのeval-when構文要素と
完全に同等ではなく以下に記述される。このパッケージはEmacs 18
ユーザのためにeval-when-compileの1個の版を定義する。
他方のフォーム(eval-and-compile …)は
‘(eval-when (compile load eval) …)’と正確に同等なので、それ
自身はこのパッケージで定義されていない。
formsはコンパイル時に評価される;実行時、このフォームは結果として
生じる値の引用された定数のように振る舞う。トップレベルで使われると、
eval-when-compileはちょうど‘eval-when (compile eval)’
のようである。他のコンテキストでは、eval-when-compileは効率
その他の理由でコードがコンパイル時に1度だけ評価されることを許す。
このフォームは真のCommon Lispの‘#.’文法に類似している。
formはロード時に評価される; 実行時、このフォームは結果として 生じる値の引用された定数のように振る舞う。
初期のCommon Lispはこれに類似した‘#,’文法を持っていたが、ANSI
Common Lispはload-time-valueで置き換えてよりよく定義された
意味論を与えた。
コンパイルされたファイルでは、load-time-valueはformが
.elcファイルがロードされたときに評価され引用された定数だったか
のように使われるように準備する。byte-compile-fileではなく
byte-compileでコンパイルされたコードでは、効果は
eval-when-compileと同一である。コンパイルされていないコードでは、
eval-when-compileとload-time-valueは正確にprognの
ように振る舞う。
(defun report ()
(insert "This function was executed on: "
(current-time-string)
", compiled on: "
(eval-when-compile (current-time-string))
;; or '#.(current-time-string) in real Common Lisp
", and loaded on: "
(load-time-value (current-time-string))))
バイトコンパイルされると、上のdefunの例は下記のコード (またはもちろんそのコンパイルされた同等のもの)を.elcファイルに 生じる:
(setq --temp-- (current-time-string))
(defun report ()
(insert "This function was executed on: "
(current-time-string)
", compiled on: "
'"Wed Jun 23 18:33:43 1993"
", and loaded on: "
--temp--))