(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)
Above is the code that i took from https://github.com/jedrz/.emacs.d/blob/master/setup-flycheck.el
It doesn't do anything much apart from defining a checker for flycheck which can be found https://github.com/lunaryorn/flycheck
My problem is trivial and i have already spent a day on it and i am more confused.
The second part of the code uses the defined macro to call flycheck to register a compiler
(flycheck-define-clike-checker c
("gcc" "-fsyntax-only" "-Wall" "-Wextra")
c-mode)
Above code works perfectly.
But since i wanted my compiler to have some dynamic includes et all, I have a variable defined as
(defvar efx-flycheck-c-command '("gcc" "-fsyntax-only" "-Wall" "-Wextra"))
when i pass that to the macro like
(flycheck-define-clike-checker c
efx-flycheck-c-command
c-mode)
i receive a compilation error
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)
I guess i confused in how the macro expands in elisp.
Please help!
You need to decide whether you want the command
argument to be evaluated or unevaluated. An unevaluated argument allows you to type lists without quoting them, i.e. ("gcc" "-Wall")
instead of '("gcc" "-Wall")
, at the cost of not being able to pass a variable as the argument. An evaluated argument enables you to provide variables (or indeed arbitrary expressions) to the macro, at the cost of having to quote simple lists.
Normally, to evaluate the macro argument in backticks, you'd just use the ,
operator. However, you're already using the ,@
operator, and you're mentioning command
twice, so it's better to explicitly evaluate it using 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)))
With the power of defmacro
at your disposal, you can even go one step further and define that the macro is evaluates if it is a symbol, otherwise it's used as-is. This would allow you to have your cake and eat it, i.e. be able to pass both variable names and literal lists. The cost of this would be reduced consistency with normal evaluation rules—you would be able to pass a list or a variable, but not an arbitrary expression such as a function call, which would unpleasantly surprise the users of the macro. Because of that the implementation is left as an exercise for the reader.