-- | The results from running Grempa on a grammar (i.e. a parser) and parsing -- errors. module Data.Parser.Grempa.Parser.Result ( ParseResult , Parser , ParseError(..) , showError , parse ) where import Data.List import Data.Parser.Grempa.Grammar.Token -- | The result of running a parser type ParseResult t a = Either (ParseError t) a -- | The type of a parser generated by Grempa type Parser t a = [t] -> ParseResult t a -- | The different kinds of errors that can occur data ParseError t -- | The parser did not get an accepted string of tokens. = ParseError { expectedTokens :: [Tok t] -- ^ A list of tokens that would have been -- acceptable inputs when the error occured. , position :: Integer -- ^ The position (index into the input -- token list) at which the error occured. } -- | This should not happen. Please file a bug report if it does. | InternalParserError { position :: Integer -- ^ The position at which something went -- horribly wrong. } deriving Show instance Functor ParseError where fmap f (ParseError e p) = ParseError (map (fmap f) e) p fmap _ (InternalParserError p) = InternalParserError p -- | Make a prettier error string from a 'ParseError'. -- This shows the position as an index into the input string of tokens, which -- may not always be preferable, as that position may differ to the position -- in the input if it is first processed by a lexer. -- It also shows the expected tokens. showError :: Show t => ParseError t -> String showError e = case e of ParseError ts pos -> "Parse error at " ++ show pos ++ ", expecting one of {" ++ intercalate "," (map tokToString ts) ++ "}." InternalParserError pos -> "Internal parser error at " ++ show pos ++ "." -- | Throw away the 'Either' from the 'ParseResult' and throw an exception using -- 'showError' if something went wrong. parse :: Show t => Parser t a -> [t] -> a parse p i = case p i of Left err -> error $ showError err Right res -> res