0
votes

I have read a few posts on here about Scala parser-combinators and better error handling, but a lot of the "solutions" seem to say "just use '~!'", or "Anticipate failure cases with grammar rules".

So I attempted to implement some of that advice, but I am stuck understanding how the failure / err parsers work:

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

My question is basically: if foo is being repeatedly attempted against the input string because of repsep, then why - since its definition includes a | on failure to try and force an err - is the error message from the leftmost terminal in the foo production being displayed?

Is there a way to view a stack of error messages in the parse result and always find mine and display to the user? Or do I need to implement my own version of repsep or something? I believe I am missing something about the conceptual model of what is going on :(

2
I ended up solving this problem by using FastParse (lihaoyi.com/fastparse). There is a method opaque that wraps a parser and yields a custom error message that is useful on failure. E.g.: val test = foo.rep(1,",").opaque("Custom Message Repsep") - mephicide

2 Answers

1
votes

Per my comment above: I ended up solving this problem by using FastParse (lihaoyi.com/fastparse). There is a method opaque that wraps a parser and yields a custom error message that is useful on failure. E.g.:

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

Overall, I find FastParse much faster, and easier to use, than Scala Parser Combinators.

0
votes

No, you don't need to re-write repsep or keep track of your own error messages. The parser-combinator seems to be behaving just like you asked it to. It matched "foo" once, and then found ",". But then it failed on "bar", but since it had already gobbled up "foo" and ",", it couldn't give them back and then try the second alternative (your error message). You could try using a packrat parser instead if this is really the behavior you want.