快速解析。如何执行exactly once规则
FastParse. How to enforce exactly once rule
我正在尝试使用 FastParse 实现以下语法 API。
- Expr 只能包含 Foo,Bar,Baz 子表达式
- Expr 必须包含至少 1 个子表达式 Foo/Bar/Bar。不能为空
- Foo/Bar/Baz 可以以任何顺序出现在 Expr.
中
- Foo/Bar/Baz不能重复所以只能使用一次
所以有效表达式是 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)
}
}
您可以通过 filter
调用检查 "exactly-once" 约束:
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
}
}
我正在尝试使用 FastParse 实现以下语法 API。
- Expr 只能包含 Foo,Bar,Baz 子表达式
- Expr 必须包含至少 1 个子表达式 Foo/Bar/Bar。不能为空
- Foo/Bar/Baz 可以以任何顺序出现在 Expr. 中
- Foo/Bar/Baz不能重复所以只能使用一次
所以有效表达式是 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)
}
}
您可以通过 filter
调用检查 "exactly-once" 约束:
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
}
}