Scala 解析器组合器自定义错误消息

Scala Parser Combinator Custom Error Messages

我在这里阅读了一些关于 Scala 解析器组合器和更好的错误处理的帖子,但是很多 "solutions" 似乎说 "just use '~!'",或 "Anticipate failure cases with grammar rules"。

所以我尝试实施其中的一些建议,但我仍然无法理解失败/错误解析器的工作原理:

val foo: Parser[String] = """foo""".r | err("Custom Message")
val test: Parser[List[String]] = repsep(foo, ",") | err("Custom Message Repsep")
val r = parseAll(foo, ""bar") //[1.1] error: Custom Message -- YAY
val r = parseAll(test, "foo, bar") //[1.2] failure: string matching regex `foo' expected but `b' found -- NOOOOOO

我的问题基本上是:如果由于 repsep 而对输入字符串重复尝试 foo,那么为什么 - 因为它的定义包含 | 失败尝试和强制 err - 是否显示来自 foo 产品中最左侧终端的错误消息?

有没有办法在解析结果中查看一堆错误消息并始终找到我的并显示给用户?或者我需要实现我自己的 repsep 版本还是什么?我相信我遗漏了一些关于正在发生的事情的概念模型:(

不,您不需要重写 repsep 或跟踪您自己的错误消息。解析器组合器的行为似乎与您要求的一样。匹配了一次"foo",然后找到了“,”。但随后它在 "bar" 上失败了,但由于它已经吞噬了 "foo" 和“,”,它无法将它们返回并尝试第二种选择(您的错误消息)。如果这确实是您想要的行为,您可以尝试使用 Packrat 解析器。

根据我上面的评论:我最终使用 FastParse (lihaoyi.com/fastparse) 解决了这个问题。有一个方法 opaque 包装了一个解析器并产生了一个在失败时有用的自定义错误消息。例如:

val test = foo.rep(1,",").opaque("Custom Message Repsep")

总的来说,我发现 FastParse 比 Scala Parser Combinators 更快,也更容易使用。