When writing a macro that uses syntax/parse , I created a splicing syntax class that captures parameters that can be provided to the macro. These parameters are optional and can be provided in any order. Using the ~optional head template with an ellipsis makes this simple enough:
(define-splicing-syntax-class opts (pattern (~seq (~or (~optional (~seq #:aa)) (~optional (~seq #:bb)) (~optional (~seq #:xx)) (~optional (~seq #:yy))) ...))
However, there is a catch: I want to be able to group these parameters into two groups: a group containing a and b , and a group containing x and y . However, the user can still specify the parameters in any order, so for this example, enter:
(foobar #:b 3 #:y 7 #:a 2)
I want to be able to create the following attributes:
first-opts: (#:a 2 #:b 3) second-opts: (#:y 7)
So far, Ive managed to do this manually using #:with , but this is not the case:
(define-splicing-syntax-class opts #:attributes ([first-opts 1] [second-opts 1]) (pattern (~seq (~or (~optional (~seq #:aa)) (~optional (~seq #:bb)) (~optional (~seq #:xx)) (~optional (~seq #:yy))) ...) #:with (first-opts ...) #`(#,@(if (attribute a) #'(#:aa) #'()) #,@(if (attribute b) #'(#:bb) #'())) #:with (second-opts ...) #`(#,@(if (attribute x) #'(#:xx) #'()) #,@(if (attribute y) #'(#:yy) #'()))))
This can be simplified a bit using the template from syntax/parse/experimental/template :
(define-splicing-syntax-class opts #:attributes ([first-opts 1] [second-opts 1]) (pattern (~seq (~or (~optional (~seq #:aa)) (~optional (~seq #:bb)) (~optional (~seq #:xx)) (~optional (~seq #:yy))) ...) #:with (first-opts ...) (template ((?? ( ?@ #:aa)) (?? ( ?@ #:bb)))) #:with (second-opts ...) (template ((?? ( ?@ #:ax)) (?? ( ?@ #:by))))))
However, this is actually just a little sugar for the above, and it does not actually address the problem of having to list each parameter in each section. If, for example, I added the #:c parameter, I wonβt need to add it to the first-opts , otherwise it will be completely ignored.
What I really want is some declarative way of grouping these sets of optional values. For example, Id like syntax like this:
(define-splicing-syntax-class opts #:attributes ([first-opts 1] [second-opts 1]) (pattern (~seq (~or (~group first-opts (~optional (~seq #:aa)) (~optional (~seq #:bb))) (~group second-opts (~optional (~seq #:xx)) (~optional (~seq #:yy)))) ...)))
Or, even better, it would be nice if I could use existing primitives, something like this:
(define-splicing-syntax-class opts #:attributes ([first-opts 1] [second-opts 1]) (pattern (~seq (~or (~and first-opts (~seq (~optional (~seq #:aa)) (~optional (~seq #:bb)))) (~and second-opts (~seq (~optional (~seq #:xx)) (~optional (~seq #:yy))))) ...)))
However, none of them work. Is there a way to do this is by using built-in functions provided by the syntax/parse ? If not, is there an easy way to define something like ~group yourself?