Search code examples
haskellparsecarithmetic-expressionsmathematical-expressions

Parsec-Haskell, formatting parse errors


I am developing a simple calculator that takes one line of input, parses it using parsec and then processes it.

I want to make the parsec parse-error messages smaller. They include position info which is not necessary for a one line input. I've tried using <?> but it doesn't quite do what I want.

Trying to extract the cause of parse error didn't yield good results.

Some way to specify errors for unmatched parentheses, or just a syntax error message would be nice.


Solution

  • You can get at the error messages and source position of an error using the errorMessages, messageString, errorPos and sourceColumn functions from Text.Parsec.Error.

    Here is an example taken from this blog post. It demonstrates the use of <?> and using the above mentioned functions to customize error processing:

    import Text.ParserCombinators.Parsec
    import Text.ParserCombinators.Parsec.Expr
    import Text.Parsec.Error
    
    expr :: Parser Integer
    expr = buildExpressionParser table factor <?> "expression"
    
    table :: [[ Operator Char st Integer ]]
    table = [
        [ op "*" (*) AssocLeft, op "/" div AssocLeft ],
        [ op "+" (+) AssocLeft, op "-" (-) AssocLeft ]
        ]
      where
        op s f assoc = Infix (do { string s ; return f }) assoc
    
    factor = do { char '(' ; x <- expr ; char ')' ; return x }
       <|> number
       <?> "simple expression"
    
    number :: Parser Integer
    number = do { ds <- many1 digit; return (read ds) } <?> "number"
    
    doit str =
      case parse expr "blah" str of
        Left e -> do let msgs = filter (not.null) $ map messageString (errorMessages e)
                     let col = sourceColumn (errorPos e)
                     putStrLn $ "error at column " ++ show col ++ ": " ++ show msgs
        Right x -> putStrLn $ "ok - got: " ++ show x
    
    main = do
      doit "3+5"
      doit "5-"
      doit "("