我想使用宏在 Scala 中实现外部 DSL,例如 SQL。我已经看过有关如何使用 Scala实现内部 DSL的论文。另外,我最近自己写了一篇关于如何在 Java 中做到这一点的文章。
现在,内部 DSL 总是感觉有点笨拙,因为它们必须在宿主语言(例如 Scala)中实现和使用,并遵守宿主语言的语法约束。这就是为什么我希望 Scala 宏将允许在没有任何此类限制的情况下内部化外部 DSL。但是,我并不完全了解 Scala 宏以及我能用它们走多远。我已经看到SLICK和一个鲜为人知的名为sqltyped的库已经开始使用宏,但是 SLICK 使用“Scalaesque”语法进行查询,这不是真正的 SQL,而 sqltyped 使用宏来解析 SQL 字符串(可以也可以在没有宏的情况下完成)。此外,Scala 网站上给出的各种示例对于我正在尝试做的事情来说太微不足道了
我的问题是:
给定一个外部 DSL 示例,定义为一些 BNF 语法,如下所示:
MyGrammar ::= (
'SOME-KEYWORD' 'OPTION'?
(
( 'CHOICE-1' 'ARG-1'+ )
| ( 'CHOICE-2' 'ARG-2' )
)
)
我可以使用 Scala 宏实现上述语法以允许这样的客户端程序吗?还是 Scala 宏不够强大,无法实现这样的 DSL?
// This function would take a Scala compile-checked argument and produce an AST
// of some sort, that I can further process
def evaluate(args: MyGrammar): MyGrammarEvaluated = ...
// These expressions produce a valid result, as the argument is valid according
// to my grammar
val result1 = evaluate(SOME-KEYWORD CHOICE-1 ARG-1 ARG-1)
val result2 = evaluate(SOME-KEYWORD CHOICE-2 ARG-2)
val result3 = evaluate(SOME-KEYWORD OPTION CHOICE-1 ARG-1 ARG-1)
val result4 = evaluate(SOME-KEYWORD OPTION CHOICE-2 ARG-2)
// These expressions produce a compilation error, as the argument is invalid
// according to my grammar
val result5 = evaluate(SOME-KEYWORD CHOICE-1)
val result6 = evaluate(SOME-KEYWORD CHOICE-2 ARG-2 ARG-2)
注意,我对解析字符串的解决方案不感兴趣,就像sqltyped那样