----------------------------------------------------------------------------- -- | -- Module : Data.Error -- License : MIT (see the LICENSE file) -- Maintainer : Felix Klein (klein@react.uni-saarland.de) -- -- Data structures to wrap all contents, that are needed to print nice -- error messages. -- ----------------------------------------------------------------------------- {-# LANGUAGE LambdaCase , RecordWildCards #-} ----------------------------------------------------------------------------- module Data.Error ( Error , syntaxError , runtimeError , typeError , bindingError , conversionError , depError , cfgError , parseError , prError , prErrPos ) where ----------------------------------------------------------------------------- import Data.Expression ( ExprPos(..) , SrcPos(..) ) import Text.Parsec.Error ( ParseError ) import System.Exit ( exitFailure ) import System.IO ( hPrint , stderr ) ----------------------------------------------------------------------------- -- | Internal representation of an error. data Error = ErrType TypeError | ErrParse ParseError | ErrBnd BindingError | ErrDep DependencyError | ErrSyntax SyntaxError | ErrRunT RunTimeError | ErrConv ConvError | ErrCfg CfgError ----------------------------------------------------------------------------- data TypeError = TypeError { errTPos :: ExprPos , errTMsgs :: [String] } deriving (Eq, Ord) ----------------------------------------------------------------------------- data BindingError = BindingError { errBPos :: ExprPos , errBMsgs :: [String] } deriving (Eq, Ord) ----------------------------------------------------------------------------- data DependencyError = DependencyError { errDPos :: ExprPos , errDMsgs :: [String] } deriving (Eq, Ord) ----------------------------------------------------------------------------- data SyntaxError = SyntaxError { errSPos :: ExprPos , errSMsgs :: [String] } deriving (Eq, Ord) ----------------------------------------------------------------------------- data RunTimeError = RunTimeError { errRPos :: ExprPos , errRMsgs :: [String] } deriving (Eq, Ord) ----------------------------------------------------------------------------- data ConvError = ConvError { title :: String , cmsg :: String } deriving (Eq, Ord) ----------------------------------------------------------------------------- data CfgError = ConfigError { fmsg :: String } deriving (Eq, Ord) ----------------------------------------------------------------------------- instance Show Error where show = \case ErrParse x -> show x ErrType TypeError{..} -> pr "Type Error" errTPos errTMsgs ErrBnd BindingError{..} -> pr "Binding Error" errBPos errBMsgs ErrDep DependencyError{..} -> pr "Dependency Error" errDPos errDMsgs ErrSyntax SyntaxError{..} -> pr "Syntax Error" errSPos errSMsgs ErrRunT RunTimeError{..} -> pr "Runtime Error" errRPos errRMsgs ErrCfg ConfigError{..} -> "\"Error\":\n" ++ fmsg ErrConv ConvError{..} -> "\"Conversion Error\": " ++ title ++ "\n" ++ cmsg where pr errname pos msgs = "\"" ++ errname ++ "\" (" ++ prErrPos pos ++ "):\n" ++ concat msgs ----------------------------------------------------------------------------- -- | Use this error constructor, if some sytax related misbehavior is -- detected. syntaxError :: ExprPos -> String -> Either Error a syntaxError pos msg = Left $ ErrSyntax $ SyntaxError pos [msg] ----------------------------------------------------------------------------- -- | Use this error constructor, if some runtime execution fails. runtimeError :: ExprPos -> String -> Either Error a runtimeError pos msg = Left $ ErrRunT $ RunTimeError pos [msg] ----------------------------------------------------------------------------- -- | Use this error constructor, if some type related misbehavior is -- detected. typeError :: ExprPos -> String -> Either Error a typeError pos msg = Left $ ErrType $ TypeError pos [msg] ----------------------------------------------------------------------------- -- | Use this error constructor, if some identifier binding related -- misbehavior is detected. bindingError :: ExprPos -> String -> Either Error a bindingError pos msg = Left $ ErrBnd $ BindingError pos [msg] ----------------------------------------------------------------------------- -- | Use this error constructor, if some misbehavior concerning dependencies -- between identifiers is detected. depError :: ExprPos -> String -> Either Error a depError pos msg = Left $ ErrDep $ DependencyError pos [msg] ----------------------------------------------------------------------------- -- | Use this error constructor, if some unresolvable inconsistency in the -- configuration exists. cfgError :: String -> Either Error a cfgError msg = Left $ ErrCfg $ ConfigError msg ----------------------------------------------------------------------------- -- | Use this error constructor, if an invalid command line setting is -- detected. conversionError :: String -> String -> Either Error a conversionError t msg = Left $ ErrConv $ ConvError t msg ----------------------------------------------------------------------------- -- | Use this error constructor, whenever a parser fails. parseError :: ParseError -> Either Error a parseError err = Left $ ErrParse err ----------------------------------------------------------------------------- -- | Prints an error to STDERR and then terminates the program. prError :: Error -> IO a prError err = do hPrint stderr $ show err exitFailure ----------------------------------------------------------------------------- -- | Prints the position of an error related token. prErrPos :: ExprPos -> String prErrPos pos = let bl = srcLine $ srcBegin pos bc = srcColumn $ srcBegin pos el = srcLine $ srcEnd pos ec = srcColumn $ srcEnd pos in "line " ++ show bl ++ "," ++ "column " ++ show bc ++ if bl == el then " - " ++ show ec else " - line " ++ show el ++ ", column " ++ show ec -----------------------------------------------------------------------------