我认为甚至不可能准确地突出变量绑定范围,或者至少在不实际涉及字节编译器(或其部分)或重新实现部分 Emacs Lisp 语义的情况下是不可能的。
关键问题是宏。这些在 Emacs Lisp 中并不卫生。因此,任何宏
都可以引入任意本地绑定。事实上,许多宏都是这样做的,例如dolist
,来自标准库的宏,或者来自 dash.el 的照应列表处理函数condition-case
,以命名一个流行的 3rd 方库。pcase
使用这些宏,不可能仅从句法上下文中确定变量范围。举个例子:
(condition-case err
(--each my-fancy-list
(my-fancy-function it nil t))
(error (message "Error %S happened: %s" (car err) (cadr err))))
在不知道condition-case
and的情况下, and--each
是本地绑定的吗?如果是这样,它们绑定在哪些子表达式中,例如绑定在所有子表达式中,还是仅绑定处理程序形式(后者是这种情况)?err
it
err
要在这种情况下确定变量范围,您需要维护一个详尽的宏白名单及其绑定属性,或者您需要扩展宏以动态确定它们的绑定属性(例如,let
在扩展的正文中查找)。
这两种方法在实施时都需要大量的工作,并且存在缺陷。宏定义的白名单几乎自然是不完整、不正确和过时的(只需查看 的复杂绑定语义pcase
),而扩展宏需要存在宏定义,但情况并非总是如此,例如,如果您正在编辑 Emacs Lisp使用前面提到的 dash.el,实际上没有安装这个库。
尽管如此,扩展宏可能是最好的努力,甚至更好的是,您不需要自己实现它。Emacs Lisp 字节编译器已经做到了这一点,它警告对自由变量的引用,并在启用词法绑定的情况下也对未使用的词法变量发出警告。所以,字节编译你的文件!
byte-compile-file
最好避免从正在运行的 Emacs 中调用,而是Makefile
在新的 Emacs 实例中编写一个字节编译,以获得一个干净的环境:
SRCS = foo.el
OBJECTS = $(SRCS:.el=.elc)
.PHONY: compile
compile : $(OBJECTS)
%.elc : %.el
$(EMACS) -Q --batch -f batch-byte-compile $<
在更复杂的库中,使用-L
Emacs 的标志来设置适当
load-path
的编译。