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

以上是我从https://github.com/jedrz/.emacs.d/blob/master/setup-flycheck.el获取的代码

除了定义一个可以在https://github.com/lunaryorn/flycheck找到的 flycheck 检查器之外,它并没有做任何事情

我的问题是微不足道的,我已经花了一天的时间,我更困惑。

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

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

我收到编译错误

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)

我想我对宏在 elisp 中的扩展方式感到困惑。

请帮忙!

4

2 回答 2

2

作为一般规则,你最好使用 adefun比 a defmacro,除非defun真的不方便/不可能使用。在您的情况下, adefun确实更有意义。唯一的缺点是您需要引用candc-mode参数。

于 2013-03-23T16:24:42.330 回答
1

您需要决定是要评估还是command评估参数。未评估的参数允许您键入列表而不引用它们,即代替,但代价是无法将变量作为参数传递。评估参数使您能够向宏提供变量(或实际上是任意表达式),但必须引用简单列表。("gcc" "-Wall")'("gcc" "-Wall")

通常,要评估反引号中的宏参数,您只需使用,运算符。但是,您已经在使用该,@运算符,并且您提到command了两次,因此最好使用以下方式明确评估它eval

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

借助您的力量defmacro,您甚至可以更进一步,定义如果宏是符号,则对其进行评估,否则按原样使用。这将允许您拥有蛋糕并吃掉它,即能够同时传递变量名和文字列表。这样做的代价是降低了与正常评估规则的一致性——你可以传递一个列表或一个变量,但不能传递一个任意的表达式,比如函数调用,这会让宏的用户感到不快。因此,该实现留给读者作为练习。

于 2013-03-23T10:32:35.783 回答