Search code examples
haskellparsec

Parsec - improving error message for "between"


I'm learning Parsec. I've got this code:

import Text.Parsec.String (Parser)
import Control.Applicative hiding ((<|>))
import Text.ParserCombinators.Parsec hiding (many)

inBracketsP :: Parser [String]
inBracketsP = (many $ between (char '[') (char ']') (many $ char '.')) <* eof

main :: IO ()
main =  putStr $ show $ parse inBracketsP "" "[...][..."

The result is

Left (line 1, column 10):
unexpected end of input
expecting "." or "]"

This message is not useful (adding . won't fix the problem). I'd expect something like ']' expected (only ] fixes the problem).

Is it possible to achieve that easily with Parsec? I've seen the SO question Parsec: error message at specific location, which is inspiring, but I'd prefer to stick to the between combinator, without manual lookahead or other overengineering (kind of), if possible.


Solution

  • You can hide a terminal from being displayed in the expected input list by attaching an empty label to it (parser <?> ""):

    inBracketsP :: Parser [String]
    inBracketsP = (many $ between (char '[') (char ']') (many $ (char '.' <?> ""))) <* eof
    
    -- >>> main
    -- Left (line 1, column 10):
    -- unexpected end of input
    -- expecting "]"
    

    In megaparsec, there is also a hidden combinator that achieves the same effect.