macroexpand と environment object
ちょっと諦め気味なので、メモだけ残しておく。昨日からメモりすぎだけど。
こんなマクロを書いた。
(defmacro merge-env (&environment env &optional outer) (if outer `(macroexpand '(merge-env) ,outer) env))
merge-env が呼ばれた環境の environment-object を返す。outer に environment-object が渡されたら
-
- 呼ばれた環境
- 渡された environment-object に保存されてる環境
を混ぜる。つまり
;;; A: local macro 'foo' を含む environment (macrolet ((foo ...)) (setq env-foo (merge-env))) => #<environment-object xxxxx> ;;; B: local macro 'foo' と 'bar' を含む environment (macrolet ((bar ...)) (setq env-bar (merge-env env-foo))) => #<environment-object yyyyy> ;;; env-bar には env-foo も含まれるので、A の local-macro 'foo' を ;;; 展開できる (macroexpand '(foo) env-bar) => ... ;;; もちろん B の local-macro 'bar' も展開できる (macroexpand '(bar) env-bar) => ...
狙いとしては、env-bar が
(macrolet ((foo ...)) (macrolet ((bar ...)) ...))
という環境と同等になって欲しかったんだけど
(macrolet ((foo () :outer)) (setq outer (merge-env))) => #<environment-object 56693724> (macroexpand '(foo) outer) => :outer (macrolet ((foo () :middle)) (setq middle* (merge-env))) => #<environment-object 56693700> (macroexpand '(foo) middle*) => :middle (macrolet ((foo () :inner)) (setq inner* (merge-env middle))) => #<environment-object 56693664> ;;; これで inner* の environment-object はこうなってて欲しい (macrolet ((foo () :outer)) (macrolet ((foo () :middle)) (macrolet ((foo () :inner)) (foo)))) => :inner ;;; (?_?) (macroexpand '(foo) inner*) => :middle