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.