mna
mna

Reputation: 263

Parsing redundant parenthesis while restoring input on non-committed failure

I have written a parser in Haskell's parsec library for a lisp-like language, and I would like to improve its error messages, but I am stuck in the following situation:

p :: Parser Integer
p = do
    try (string "number")
    space
    integer

parens :: Parser a -> Parser a
parens p = do
    char '('
    v <- p
    char ')'
    return v

finalParser p = p <|> (parens finalParser)

So the parser p behaves quite nicely error-wise, it does not commit and consume input until it sees the keyword "number". Once it successfully parsed the keyword, it will not restore its input on failure. If this parser is combined with other parsers using the <|> operator, and it parses the keyword, it will show the error message of p and not try the next parser.

Already parens p does not have this property anymore.

I would like to write a function parens as above that consumes only input, if the parser p consumes input.

Here are a few examples of the behavior, I am trying to achieve. finalParser should parse:

  1. "(((number 5)))", "number 5", "(number 5)" all should parse to the integer 5, and consume everything,
  2. "(5)" should consume nothing (not even the parenthesis) and fail
  3. "(number abc)", "number cde" should fail and consume input.

Upvotes: 3

Views: 100

Answers (1)

Li-yao Xia
Li-yao Xia

Reputation: 33569

I would like to write a function parens as above that consumes only input, if the parser p consumes input.

Rather than that, consider factoring your syntax so you don't even need to backtrack after consuming a parenthesis.

Instead of trying to make this work:

parens p1 <|> parens p2

why not write this instead:

parens (p1 <|> p2)

?

Upvotes: 1

Related Questions