私はここしばらく Scala パーサー コンビネーターをいじっており、組み込み関数を使用して、適切に動作し、必要なことを最大限に実行する方法をいくつか学びました。
しかし、組み込み言語 (php や ruby の erb など) を作成するにはどうすればよいでしょうか。実際のコードの埋め込み以外では、空白を無視しないようにする必要があります。
特定の正規表現一致までのすべてのテキストに一致する単純なパーサーを作成することができましたが、これを行うためのより良い、きれいな方法を探しています。おそらく、必要なものを実行する定義済みの関数がいくつかあります。
テスト言語は、次のようなテキストを解析します。
now: [[ millis; ]]
and now: [[; millis; ]]
次のコードによって生成されます。
package test
import scala.util.parsing.combinator.RegexParsers
import scala.util.matching.Regex
sealed abstract class Statement
case class Print(s: String) extends Statement
case class Millis() extends Statement
object SimpleLang extends RegexParsers {
def until(r: Regex): Parser[String] = new Parser[String]{
def apply(in: Input) = {
val source = in.source
val offset = in.offset
val start = offset
(r.findFirstMatchIn( source.subSequence(offset, source.length) )) match {
case Some(matched) =>
Success(source.subSequence(offset, offset + matched.start).toString, in.drop(matched.start))
case None =>
Failure("string matching regex `"+ r +"' expected but `"+ in.first +"' found", in.drop(0))
}
}
}
def until(s: String): Parser[String] = until(java.util.regex.Pattern.quote(s).r)
def interpret(stats: List[Statement]): Unit = stats match {
case Print(s) :: rest => {
print(s)
interpret(rest)
}
case Millis() :: rest => {
print(System.currentTimeMillis)
interpret(rest)
}
case Nil => ()
}
def apply(input: String) : List[Statement] = parseAll(beginning, input) match {
case Success(tree,_) => tree
case e: NoSuccess => throw new RuntimeException("Syntax error: " + e)
}
/** GRAMMAR **/
def beginning = (
"[[" ~> stats |
until("[[") ~ "[[" ~ stats ^^ {
case s ~ _ ~ ss => Print(s) :: ss
}
)
def stats = rep1sep(stat, ";")
def stat = (
"millis" ^^^ { Millis() } |
"]]" ~> ( (until("[[") <~ "[[") | until("\\z".r)) ^^ {
case s => Print(s)
}
)
def main(args: Array[String]){
val tree = SimpleLang("now: [[ millis; ]]\nand now: [[; millis; ]]")
println(tree)
interpret(tree)
}
}