マクロを使用して Scala で SQL などの外部 DSL を実装したいと考えています。Scala を使用して内部 DSLを実装する方法に関する論文を既に見ました。また、私は最近、これを Javaで行う方法についての記事を書きました。
現在、内部 DSL は、ホスト言語 (Scala など) で実装して使用する必要があり、ホスト言語の構文制約に従う必要があるため、常に少しぎこちなく感じられます。そういうわけで、Scala Macros がそのような制約なしに外部 DSL を内部化できるようになることを願っています。しかし、私は Scala マクロを完全には理解していません。SLICKと、あまり知られていないsqltypedというライブラリがマクロを使用し始めているのを見てきましたが、SLICK はクエリに「Scalaesque」構文を使用しますが、これは実際には SQL ではありませんが、sqltyped はマクロを使用して SQL 文字列を解析します (マクロなしでも実行できます)。また、Scala の Web サイトにあるさまざまな例は、私がやろうとしていることにはあまりにも些細なことです。
私の質問は:
次のような BNF 文法として定義された外部 DSL の例を考えます。
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のように文字列を解析するソリューションには興味がありません