megaparsec icon indicating copy to clipboard operation
megaparsec copied to clipboard

Error context with additional source positions

Open JakeWheat opened this issue 5 months ago • 4 comments

Hello, I'm trying to implement a error helper for unmatched delimiters, which will add the source location and quoted source from the suspected unmatched opening delimiter when the close delimiter parser fails.

This is what I have so far, which almost works, but it would be much better for the closed delimiter error to come first. Is there a way to quote some additional source given the offset in showErrorComponent?

parens :: Parser a -> Parser a
parens p = do
    d <- matchOpenDelimiter (void openParen) "("
    p <* d (void closeParen)

matchOpenDelimiter :: Parser a -> Text -> Parser (Parser b -> Parser ())
matchOpenDelimiter pOpenDelim openDelimLabel = do
    openDelimOffset <- getOffset
    void pOpenDelim
    pure $ \pCloseDelim -> do
        res <- observing $ void pCloseDelim
        case res of
            Left e -> do
                region (setErrorOffset openDelimOffset)
                    $ registerFancyFailure
                    (Set.fromList
                     [ErrorFail $ "context: possible unmatched "
                          <> T.unpack openDelimLabel])
                parseError e
            Right () -> pure ()

What it outputs when it fails:

( ( a ) 
1:1:
  |
1 | ( ( a ) 
  | ^
context: possible unmatched (

1:9:
  |
1 | ( ( a ) 
  |         ^
unexpected end of input
expecting ')'

Goal is to output something like this:

1:9:
  |
1 | ( ( a ) 
  |         ^
unexpected end of input
expecting ')'

( ( a ) 
1:1:
  |
1 | ( ( a ) 
  | ^
context: possible unmatched (

JakeWheat avatar Feb 07 '24 12:02 JakeWheat