I have created a splicing syntax class that captures keyword options that may be
provided in any order. Using the ~optional ellipsis head pattern makes this
easy enough:

    (define-splicing-syntax-class opts
      (pattern (~seq (~or (~optional (~seq #:a a))
                          (~optional (~seq #:b b))
                          (~optional (~seq #:x x))
                          (~optional (~seq #:y y)))
                     ...))

However, there is a catch: I want to be able to *group* these options into two
sets: the group containing `a` and `b`, and the group containing `x` and `y`.
However, the user may still specify the options in any order, so for this
example input:

    (foobar #:b 3 #:y 7 #:a 2)

I want to be able to produce the following attributes:

    first-opts:  (#:a 2 #:b 3)
    second-opts: (#:y 7)

So far, I’ve managed to do this manually using #:with, but it isn’t pretty:

    (define-splicing-syntax-class opts
      #:attributes ([first-opts 1] [second-opts 1])
      (pattern (~seq (~or (~optional (~seq #:a a))
                          (~optional (~seq #:b b))
                          (~optional (~seq #:x x))
                          (~optional (~seq #:y y)))
                     ...)
               #`(#,@(if (attribute a) #'(#:a a) #'())
                  #,@(if (attribute b) #'(#:b b) #'()))
               #:with (second-opts ...)
               #`(#,@(if (attribute x) #'(#:x x) #'())
                  #,@(if (attribute y) #'(#:y y) #'()))))

This can be simplified a little bit using `template` from
syntax/parse/experimental/template:

    (define-splicing-syntax-class opts
      #:attributes ([first-opts 1] [second-opts 1])
      (pattern (~seq (~or (~optional (~seq #:a a))
                          (~optional (~seq #:b b))
                          (~optional (~seq #:x x))
                          (~optional (~seq #:y y)))
                     ...)
               #:with (first-opts ...)
               (template ((?? (?@ #:a a))
                          (?? (?@ #:b b))))
               #:with (second-opts ...)
               (template ((?? (?@ #:a x))
                          (?? (?@ #:b y))))))

However, this is really just some sugar for the above, and it doesn’t actually
address the problem of having to enumerate each option in each clause. If I, for
example, added a #:c option, I would need to remember to add it to the
`first-opts` group, otherwise it would be completely ignored.

What I *really* want is some declarative way to group these sets of optional
values. For example, I’d like a syntax like this:

    (define-splicing-syntax-class opts
      #:attributes ([first-opts 1] [second-opts 1])
      (pattern (~seq (~or (~group first-opts
                                  (~optional (~seq #:a a))
                                  (~optional (~seq #:b b)))
                          (~group second-opts
                                  (~optional (~seq #:x x))
                                  (~optional (~seq #:y y))))
                     ...)))

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 #:a a))
                                      (~optional (~seq #:b b))))
                          (~and second-opts
                                (~seq (~optional (~seq #:x x))
                                      (~optional (~seq #:y y)))))
                     ...)))

However, neither of those work. Is there any way to do this using the builtins
provided by syntax/parse? If not, is there any simple way to define something
like ~group myself?

Thanks,
Alexis

(also asked as http://stackoverflow.com/q/34551203/465378)

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to