とあるツールを作っていてS式のパースが必要なことが判明しました。Scalaで使えそうなものを探してみたのですが、あまりよい物はないようです。
そこでS式処理系goldenport-sexprを作ってみました。
S式は元々のセマンティクスに近い形で保持して、必要に応じてScalaで処理しやすい形式に変換するようなアプローチにしています。
プログラム
プログラムはとても簡単で、以下の2つです。
- https://github.com/asami/goldenport-sexpr/blob/master/src/main/scala/org/goldenport/sexpr/SExpr.scala
- https://github.com/asami/goldenport-sexpr/blob/master/src/main/scala/org/goldenport/sexpr/SExprParser.scala
パーサーコンビネータを使って、ちょちょいと作れるのがScalaのよい所ですね。
使い方
使い方はこんな感じ。とあるツールで使っている範囲しかまだ整備していません。
- class SExprSpec extends WordSpec with ShouldMatchers {
- import org.goldenport.sexpr.SExpr._
- "SExpr" should {
- "list" that {
- "dropWhile" in {
- var s = SExprParser("(:k 100)")
- val r = s.get.list.get.dropWhile(_ match {
- case _: SKeyword => false
- case _ => true
- })
- r should equal (List(SKeyword("k"), SNumber("100")))
- }
- }
- "keyword" that {
- "string" in {
- var s = SExprParser("""(:k "value")""")
- var v = SExpr.getKeyword[String](s.get, "k")
- v should equal (Some("value"))
- }
- "string list" in {
- var s = SExprParser("""(:k ("value"))""")
- var v = SExpr.getKeyword[List[String]](s.get, "k")
- v should equal (Some(List("value")))
- }
- "strings list" in {
- var s = SExprParser("""(:k ("value1" "value2"))""")
- var v = SExpr.getKeyword[List[String]](s.get, "k")
- v should equal (Some(List("value1", "value2")))
- }
- }
- }
- }
sbt
build.sbtの設定は以下になります。
- resolvers += "Asami Maven Repository" at "http://www.asamioffice.com/maven"
- libraryDependencies += "org.goldenport" %% "goldenport-sexpr" % "0.1.0"
ノート
DSLをXtextなどでフルスクラッチで作るケースもあると思いますが、多くの場合は何らかのホスト言語の上にアドオンとして構築することになるでしょう。
ホスト言語としてはScalaやRubyといったプログラミング言語もありますが、XMLやJSONといったマークアップ言語も有力です。
汎用性を採るならXML、Webとの親和性ならJSONといった選択になるかと思います。また表形式のテキストだとCSVという選択もあります。
そういった選択肢の一つとしてS式も案外有力では、と思いつきました。WebブラウザならJSONですが、EmacsならS式です。S式をDSLにするとEmacsとの連携がとても楽になります。
Scalaプログラミングも、Emacs /ensime環境が強力です。この環境上でツールを整備する場合Scala側でS式を簡単に扱えるのはかなり重要な要因になりそうです。
0 件のコメント:
コメントを投稿