(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
获取的代码除了定义可以找到的flycheck检查器之外,它没有做任何事情https://github.com/lunaryorn/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中的扩展感到困惑。
请帮忙!
答案 0 :(得分:2)
作为一般规则,您最好使用defun
而不是defmacro
,除非defun
真的不方便/无法使用。在你的情况下,defun
确实更有意义。唯一的缺点是你需要引用c
和c-mode
参数。
答案 1 :(得分: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
的强大功能,你甚至可以更进一步,定义宏是评估如果它是一个符号,否则它按原样使用。这将允许你吃蛋糕并吃掉它,即能够传递变量名和文字列表。这样做的成本会降低与正常评估规则的一致性 - 您可以传递一个列表或变量,但不能传递一个任意表达式,例如函数调用,这会让宏用户感到不愉快。因此,实施仍然是读者的练习。