【发布时间】:2016-04-05 16:59:03
【问题描述】:
在编写使用syntax/parse 的宏时,我创建了一个拼接语法类,该类捕获可能提供给宏的选项。这些选项都是可选的,可以按任何顺序提供。使用~optional 省略号头部模式使这很容易:
(define-splicing-syntax-class opts
(pattern (~seq (~or (~optional (~seq #:a a))
(~optional (~seq #:b b))
(~optional (~seq #:x x))
(~optional (~seq #:y y)))
...))
但是,有一个问题:我希望能够将这些选项分组分成两组:包含a 和b 的组,以及包含x 和@ 的组987654327@。但是,用户仍然可以按任意顺序指定选项,因此对于本示例输入:
(foobar #:b 3 #:y 7 #:a 2)
我希望能够产生以下属性:
first-opts: (#:a 2 #:b 3)
second-opts: (#:y 7)
到目前为止,我已经设法使用 #:with 手动完成此操作,但它并不漂亮:
(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 ...)
#`(#,@(if (attribute a) #'(#:a a) #'())
#,@(if (attribute b) #'(#:b b) #'()))
#:with (second-opts ...)
#`(#,@(if (attribute x) #'(#:x x) #'())
#,@(if (attribute y) #'(#:y y) #'()))))
这可以使用syntax/parse/experimental/template中的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))))))
但是,这实际上只是上面的一些糖,它实际上并没有解决必须枚举每个子句中的每个选项的问题。例如,如果我添加了一个#:c 选项,我需要记住将其添加到first-opts 组中,否则它将被完全忽略。
我真正想要的是某种声明性方式来对这些可选值集进行分组。例如,我想要这样的语法:
(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))))
...)))
或者,如果我可以使用现有的原语,那就更好了,像这样:
(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)))))
...)))
但是,这些都不起作用。有没有办法使用syntax/parse 提供的内置函数来做到这一点?如果没有,是否有任何简单的方法来定义 ~group 我自己?
【问题讨论】: