Emacs 通过符号而不是列表传递ELISP宏
上面是我从中获取的代码 除了为可以找到的flycheck定义一个检查器之外,它没有做什么 我的问题很琐碎,我已经花了一天的时间在上面,我更困惑了 代码的第二部分使用定义的宏调用flycheck来注册编译器Emacs 通过符号而不是列表传递ELISP宏,emacs,elisp,flymake,Emacs,Elisp,Flymake,上面是我从中获取的代码 除了为可以找到的flycheck定义一个检查器之外,它没有做什么 我的问题很琐碎,我已经花了一天的时间在上面,我更困惑了 代码的第二部分使用定义的宏调用flycheck来注册编译器 (defmacro flycheck-define-clike-checker (name command modes) `(flycheck-declare-checker ,(intern (format "flycheck-checker-%s" name)) ,(
(defmacro flycheck-define-clike-checker (name command modes)
`(flycheck-declare-checker ,(intern (format "flycheck-checker-%s" name))
,(format "A %s checker using %s" name (car command))
:command '(,@command source-inplace)
:error-patterns
'(("^\\(?1:.*\\):\\(?2:[0-9]+\\):\\(?3:[0-9]+\\): error: \\(?4:.*\\)$"
error)
("^\\(?1:.*\\):\\(?2:[0-9]+\\):\\(?3:[0-9]+\\): warning: \\(?4:.*\\)$"
warning))
:modes ',modes))
(flycheck-define-clike-checker c
("gcc" "-fsyntax-only" "-Wall" "-Wextra")
c-mode)
上面的代码工作得很好
但是,由于我希望我的编译器有一些动态的include等,我有一个变量定义为
(flycheck-define-clike-checker c
("gcc" "-fsyntax-only" "-Wall" "-Wextra")
c-mode)
当我把它传递给宏
(defvar efx-flycheck-c-command '("gcc" "-fsyntax-only" "-Wall" "-Wextra"))
我收到一个编译错误
(flycheck-define-clike-checker c
efx-flycheck-c-command
c-mode)
我想我弄糊涂了宏在elisp中是如何展开的
请帮忙 您需要决定是要计算还是取消计算
命令
参数。未赋值的参数允许您键入列表而不引用它们,即(“gcc”-Wall”)
而不是(“gcc”-Wall”)
,代价是无法将变量作为参数传递。经过计算的参数使您能够向宏提供变量(实际上是任意表达式),而代价是必须引用简单的列表
通常,要在backticks中计算宏参数,只需使用,
运算符。但是,您已经在使用,@
操作符,并且您已经提到了命令两次,因此最好使用eval
显式地计算它:
Debugger entered--Lisp error: (wrong-type-argument sequencep efx-flycheck-c-command)
append(efx-flycheck-c-command (source-inplace))
(list (quote quote) (append command (quote (source-inplace))))
(list (quote flycheck-declare-checker) (intern (format "flycheck-checker-%s" name)) (format "A %s checker" name) (quote :command) (list (quote quote) (app$
(\` (flycheck-declare-checker (\, (intern (format "flycheck-checker-%s" name))) (\, (format "A %s checker" name)) :command (quote ((\,@ command) source-in$
(lambda (name command modes) (\` (flycheck-declare-checker (\, (intern (format "flycheck-checker-%s" name))) (\, (format "A %s checker" name)) :command (q$
(flycheck-define-clike-checker c efx-flycheck-c-command c-mode)
eval((flycheck-define-clike-checker c efx-flycheck-c-command c-mode) nil)
eval-last-sexp-1(nil)
eval-last-sexp(nil)
call-interactively(eval-last-sexp nil nil)
借助defmacro
的强大功能,您甚至可以更进一步,定义宏是符号时进行求值,否则按原样使用。这将允许您吃蛋糕,也就是说,能够传递变量名和文本列表。这样做的代价是降低了与常规求值规则的一致性—您可以传递列表或变量,但不能传递任意表达式(如函数调用),这会让宏的用户感到意外。因此,实现留给读者作为练习。作为一般规则,最好使用defun
而不是defmacro
,除非defun
确实不方便/无法使用。在您的例子中,一个defun
确实更有意义。唯一的缺点是需要引用c
和c-mode
参数。ok。。这是可行的,但我脑子里的某些东西仍然没有意义。我确实理解您在做什么,但我仍然可以理解为什么扩展没有使用,@
?@RamneekHanda,@
正在宏中评估命令
符号,将其扩展到efx-flycheck-c-command
,并尝试将其拼接到列表中。此操作失败,因为efx-flycheck-c-command
不是列表,而是符号。因此,您希望对命令进行求值,然后在列表中展开,这就是我的版本所做的。要理解这一点,最好从一个更简单的宏开始,先不使用反引号。请始终记住,反引号只是列表构造的语法糖,并不是宏所特有的,也不是宏所必需的。
(defmacro flycheck-define-clike-checker (name command modes)
(let ((command (eval command)))
`(flycheck-declare-checker ,(intern (format "flycheck-checker-%s" name))
,(format "A %s checker using %s" name (car command))
:command '(,@command source-inplace)
:error-patterns
'(("^\\(?1:.*\\):\\(?2:[0-9]+\\):\\(?3:[0-9]+\\): error: \\(?4:.*\\)$"
error)
("^\\(?1:.*\\):\\(?2:[0-9]+\\):\\(?3:[0-9]+\\): warning: \\(?4:.*\\)$"
warning))
:modes ',modes)))