首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ELISP宏按符号而不是列表传递

ELISP宏按符号而不是列表传递
EN

Stack Overflow用户
提问于 2013-03-23 17:19:19
回答 2查看 432关注 0票数 1
代码语言:javascript
复制
(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来注册编译器

代码语言:javascript
复制
(flycheck-define-clike-checker c
                                     ("gcc" "-fsyntax-only" "-Wall" "-Wextra")
                                     c-mode)

上面的代码运行得很好。

但是,因为我希望我的编译器具有一些动态的include et all,所以我有一个变量定义为

代码语言:javascript
复制
(defvar efx-flycheck-c-command '("gcc" "-fsyntax-only" "-Wall" "-Wextra"))

当我把它传递给宏时,比如

代码语言:javascript
复制
(flycheck-define-clike-checker c
                                         efx-flycheck-c-command
                                         c-mode)

我收到一个编译错误

代码语言:javascript
复制
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中宏的扩展方式感到困惑。

请帮帮我!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-03-23 18:32:36

您需要决定是对command参数求值还是不求值。未计算的参数允许您在不引用列表的情况下键入列表,即("gcc" "-Wall")而不是'("gcc" "-Wall"),代价是不能将变量作为参数传递。求值参数使您能够向宏提供变量(或者实际上是任意表达式),代价是必须引用简单的列表。

通常,要用反引号计算宏参数,只需使用,操作符。但是,您已经在使用,@运算符,并且两次提到了command,所以最好使用eval显式地计算它

代码语言:javascript
复制
(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的强大功能,您甚至可以更进一步,定义宏是否为符号进行求值,否则按原样使用。这将允许您既有蛋糕又吃蛋糕,即可以同时传递变量名和文字列表。这样做的代价是降低了与正常计算规则的一致性-您将能够传递列表或变量,但不能传递任意表达式,例如函数调用,这将令宏的用户感到不快。正因为如此,实现留给了读者一个练习。

票数 1
EN

Stack Overflow用户

发布于 2013-03-24 00:24:42

一般来说,您最好使用defun而不是defmacro,除非defun确实不方便/不可能使用。在您的例子中,defun确实更有意义。唯一的缺点是您需要引用cc-mode参数。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15585133

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档