Consider a scenario of two macros: the outer-macro
defines a general structure of some entity, and the inner-macro
expands in the scope of the outer macro. My intent is captured in the following code, where the expected output is a print statement. This example throws the following error for the pattern of the inner macro: (_ value ...)
.
syntax: no pattern variables before ellipsis in template in: ...
I intend to use value ...
in the same way as the body ...
pattern of the outer macro. In fact, a list of the 'values' is exactly what I need (not necessarily a very flexible 'ellipsis pattern'). Sadly it does not work this way. How can I capture a variable amount of arguments in the inner macro?
#lang racket
(require
racket/stxparam
(for-syntax syntax/parse))
(define-syntax-parameter inner-macro
(lambda (stx)
(raise-syntax-error 'inner-macro "generic error message" stx)))
(define-syntax (outter-macro stx)
(syntax-parse stx
[(_ body:expr ...+)
#'(syntax-parameterize
([inner-macro
(lambda (stx)
(syntax-case stx ()
[(_ value ...)
(printf "values are: ~a~n" (list value ...))]))])
body ...)]))
(outter-macro
(inner-macro 'a 'b 'c))
; expected result
; > "values are: (a b c)"
Alexis King's answer is good. However another way to do it, which I find simpler to think about, is to use a
#:with
pattern (or awith-syntax
), to define something likeooo
as a literal ellipsis.You can create a literal ellipsis with
quote-syntax
, so the#:with
clause looks like#:with ooo (quote-syntax ...)
. Then you useooo
whenever you want to generate an ellipsis in the output of the macro.To “escape” ellipses in syntax templates, you can use the syntax
(... <form>)
, where<form>
is a syntax template where...
sequences are treated literally. Therefore, you can wrap a piece of syntax to include literal ellipses:You can use this to surround your inner macro definition to escape the inner ellipses:
However, this is actually not quite right, because your
syntax-case
body is wrong—it does not return a syntax object. You are just missing a#'
before the(printf ...)
(or you could usesyntax-rules
), so the correct implementation should be the following:This should work as intended.