2016-08-14 77 views
2

我正在尝试使用FastParse API实现以下语法。FastParse。如何强制执行一次规则

  1. expr可以仅含有富,酒吧,巴兹子表达式
  2. expr必须至少含有一个子表达的Foo /酒吧/酒吧。它不能为空
  3. Foo/Bar/Baz可以以任何顺序出现在Expr中。
  4. 富/酒吧/巴兹不能重复,所以你可以使用他们只有一次

因此,一个有效的表达式是Expr(Baz(10),Foo(10),Bar(10))和无效的表达Expr()Expr(Bar(10),Bar(10))

到目前为止,我已经写了这个代码,可以强制执行并解析1,2,3,规则。但4号规则被证明是棘手的。

import fastparse.noApi._ 
import fastparse.WhitespaceApi 

object FastParsePOC { 

    val White = WhitespaceApi.Wrapper{ 
     import fastparse.all._ 
     NoTrace(" ".rep) 
    } 

    def print(input: Parsed[(String, String, Seq[(String, String)])]) : Unit = { 
     input match { 
     case Parsed.Success(value, index) => 
      println(s"${value._1} ${value._2}") 
      value._3.foreach{case (name, index) => println(s"$name $index")} 
     case f @ Parsed.Failure(error, line, col) => println(s"Error: $error $line $col ${f.extra.traced.trace}") 
     } 
    } 

    def main(args: Array[String]) : Unit = { 
     import White._ 
     val base = P("(" ~ (!")" ~ AnyChar).rep(1).! ~ ")") 
     val foo = P("Foo".! ~ base) 
     val bar = P("Bar".! ~ base) 
     val baz = P("Baz".! ~ base) 
     val foobarbaz = (foo | bar | baz) 
     val parser = P("Expr" ~ "(" ~ foobarbaz ~ ",".? ~ (foobarbaz).rep(sep=",") ~ ")") 
     val input3 = "Expr(Baz(20),Bar(10),Foo(30))" 
     val parsed = parser.parse(input3) 
     print(parsed) 
    } 
} 

回答

1

您可以检查 “仅一次” 约束带filter电话:

test("foo bar baz") { 
    val arg: P0 = P("(") ~ (!P(")") ~ AnyChar).rep(1) ~ ")" 

    val subExpr: P[String] = (P("Foo") | P("Bar") | P("Baz")).! ~ arg 

    val subExprList: P[Seq[String]] = subExpr.rep(min = 1, sep = P(",")).filter { list => 
    list.groupBy(identity[String]).values.forall(_.length == 1) 
    } 

    val expr: P[Seq[String]] = P("Expr") ~ "(" ~ subExprList ~ ")" 

    expr.parse("Expr(Foo(10))").get.value 

    expr.parse("Expr(Foo(10),Bar(20),Baz(30))").get.value 

    intercept[Throwable] { 
    expr.parse("Expr()").get.value 
    } 

    intercept[Throwable] { 
    expr.parse("Expr(Foo(10),Foo(20))").get.value 
    } 
}