Emacs 通过符号而不是列表传递ELISP宏

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)) ,(

上面是我从中获取的代码

除了为可以找到的flycheck定义一个检查器之外,它没有做什么

我的问题很琐碎,我已经花了一天的时间在上面,我更困惑了

代码的第二部分使用定义的宏调用flycheck来注册编译器

(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)))