Result.hs revision 92dc581bf568c9e225aa9d0570ab0a4b6ebdab69
bbae6e6ca0de7f2ffbb44d2c8da179f2b717237fChristian MaederModule : $Header$
bbae6e6ca0de7f2ffbb44d2c8da179f2b717237fChristian MaederDescription : Result monad for accumulating Diagnosis messages
97018cf5fa25b494adffd7e9b4e87320dae6bf47Christian MaederCopyright : (c) T. Mossakowski, C. Maeder, Uni Bremen 2002-2008
bbae6e6ca0de7f2ffbb44d2c8da179f2b717237fChristian MaederLicense : similar to LGPL, see HetCATS/LICENSE.txt or LIZENZ.txt
bbae6e6ca0de7f2ffbb44d2c8da179f2b717237fChristian MaederMaintainer : Christian.Maeder@dfki.de
bbae6e6ca0de7f2ffbb44d2c8da179f2b717237fChristian MaederStability : provisional
f3a94a197960e548ecd6520bb768cb0d547457bbChristian MaederPortability : portable
bbae6e6ca0de7f2ffbb44d2c8da179f2b717237fChristian Maeder'Result' monad for accumulating 'Diagnosis' messages
bbae6e6ca0de7f2ffbb44d2c8da179f2b717237fChristian Maeder during analysis phases.
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maeder ( DiagKind(..)
ee9eddfa6953868fd6fbaff0d9ff68675a13675aChristian Maeder , Diagnosis(..)
bbae6e6ca0de7f2ffbb44d2c8da179f2b717237fChristian Maeder , isErrorDiag
715ffaf874309df081d1e1cd8e05073fc1227729Christian Maeder , checkUniqueness
ee9eddfa6953868fd6fbaff0d9ff68675a13675aChristian Maeder , appendDiags
bbae6e6ca0de7f2ffbb44d2c8da179f2b717237fChristian Maeder , joinResultWith
715ffaf874309df081d1e1cd8e05073fc1227729Christian Maeder , fatal_error
b645cf3dc1e449038ed291bbd11fcc6e02b2fc7fChristian Maeder , plain_error
715ffaf874309df081d1e1cd8e05073fc1227729Christian Maeder , maybeToResult
b645cf3dc1e449038ed291bbd11fcc6e02b2fc7fChristian Maeder , maybeToMonad
715ffaf874309df081d1e1cd8e05073fc1227729Christian Maeder , resultToMaybe
715ffaf874309df081d1e1cd8e05073fc1227729Christian Maeder , propagateErrors
715ffaf874309df081d1e1cd8e05073fc1227729Christian Maeder , filterDiags
715ffaf874309df081d1e1cd8e05073fc1227729Christian Maeder , showRelDiags
ccf3de3d66b521a260e5c22d335c64a48e3f0195Christian Maederimport Text.ParserCombinators.Parsec.Char (char)
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maederimport Text.ParserCombinators.Parsec (parse)
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maeder-- | severness of diagnostic messages
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maederdata DiagKind = Error | Warning | Hint | Debug
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maeder | MessageW -- ^ used for messages in the web interface
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maeder deriving (Eq, Ord, Show)
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maeder-- | a diagnostic message with 'Pos'
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maederdata Diagnosis = Diag { diagKind :: DiagKind
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maeder , diagString :: String
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maeder , diagPos :: Range
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maeder } deriving Eq
715ffaf874309df081d1e1cd8e05073fc1227729Christian Maeder-- | construct a message for a printable item that carries a position
715ffaf874309df081d1e1cd8e05073fc1227729Christian MaedermkDiag :: (GetRange a, Pretty a) => DiagKind -> String -> a -> Diagnosis
d17834302eaa101395b4b806cd73670fd864445fChristian MaedermkDiag k s a = let q = text "'" in
ccf3de3d66b521a260e5c22d335c64a48e3f0195Christian Maeder Diag k (show $ sep [text s, q <> pretty a <> q]) $ getRange a
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maeder-- | construct a message for a printable item that carries a position
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian MaedermkNiceDiag :: (GetRange a, Pretty a) => GlobalAnnos
715ffaf874309df081d1e1cd8e05073fc1227729Christian Maeder -> DiagKind -> String -> a -> Diagnosis
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian MaedermkNiceDiag ga k s a = let q = text "'" in
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maeder Diag k (show (toText ga $ sep [text s, q <> pretty a <> q])) $ getRange a
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maeder-- | check whether a diagnosis is an error
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian MaederisErrorDiag :: Diagnosis -> Bool
715ffaf874309df081d1e1cd8e05073fc1227729Christian MaederisErrorDiag d = case diagKind d of
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maeder Error -> True
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maeder-- | Check whether a diagnosis list contains errors
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian MaederhasErrors :: [Diagnosis] -> Bool
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian MaederhasErrors = any isErrorDiag
836e72a3c413366ba9801726f3b249c7791cb9caChristian Maeder-- | add range to a diagnosis
836e72a3c413366ba9801726f3b249c7791cb9caChristian MaederadjustDiagPos :: Range -> Diagnosis -> Diagnosis
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian MaederadjustDiagPos r d = if isNullRange $ diagPos d then d { diagPos = r } else d
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maeder-- | A uniqueness check yields errors for duplicates in a given list.
7dec34aee2b609b9535c48d060e0f7baf3536457Christian MaedercheckUniqueness :: (Pretty a, GetRange a, Ord a) => [a] -> [Diagnosis]
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian MaedercheckUniqueness l =
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maeder let vd = filter ( not . null . tail) $ group $ sort l
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maeder in map ( \ vs -> mkDiag Error ("duplicates at '" ++
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maeder showSepList (showString " ") shortPosShow
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maeder (concatMap getPosList (tail vs)) "'"
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maeder ++ " for") (head vs)) vd
bbae6e6ca0de7f2ffbb44d2c8da179f2b717237fChristian Maeder where shortPosShow :: Pos -> ShowS
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maeder shortPosShow p = showParen True
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maeder (shows (sourceLine p) .
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maeder showString "," .
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maeder shows (sourceColumn p))
797f811e57952d59e73b8cd03b667eef276db972Christian Maeder-- | The result monad. A failing result should include an error message.
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maederdata Result a = Result { diags :: [Diagnosis]
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maeder , maybeResult :: Maybe a
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maeder } deriving Show
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maederinstance Functor Result where
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maeder fmap f (Result errs m) = Result errs $ fmap f m
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maederinstance Monad Result where
bbae6e6ca0de7f2ffbb44d2c8da179f2b717237fChristian Maeder return x = Result [] $ Just x
ccf3de3d66b521a260e5c22d335c64a48e3f0195Christian Maeder r@(Result e m) >>= f = case m of
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maeder Nothing -> Result e Nothing
d17834302eaa101395b4b806cd73670fd864445fChristian Maeder Just x -> joinResult r $ f x
e1839fb37a3a2ccd457464cb0dcc5efd466dbe22Christian Maeder fail s = fatal_error s nullRange
e774ab5733a1d673b123b0e63b14dd533e6fd4fcChristian Maederinstance MonadPlus Result where
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maeder mzero = Result [] Nothing
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian Maeder r1@(Result _ m) `mplus` r2 = case m of
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maeder Nothing -> r2
1738d16957389457347bee85075d3d33d002158fChristian MaederappendDiags :: [Diagnosis] -> Result ()
1738d16957389457347bee85075d3d33d002158fChristian MaederappendDiags ds = Result ds (Just ())
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maeder-- | join two results with a combining function
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian MaederjoinResultWith :: (a -> b -> c) -> Result a -> Result b -> Result c
2a598ff0c1b7b51c33aee7029b43bc5cfcbea6b8Christian MaederjoinResultWith f (Result d1 m1) (Result d2 m2) = Result (d1 ++ d2) $
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maeder return $ f r1 r2
5e26bfc8d7b18cf3a3fa7b919b4450fb669f37a5Christian Maeder-- | join two results
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian MaederjoinResult :: Result a -> Result b -> Result b
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian MaederjoinResult = joinResultWith (\ _ b -> b)
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian Maeder-- | join a list of results that are independently computed
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian MaedermapR :: (a -> Result b) -> [a] -> Result [b]
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian MaedermapR ana = foldr (joinResultWith (:)) (Result [] $ Just []) . map ana
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian Maeder-- | a failing result with a proper position
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian Maederfatal_error :: String -> Range -> Result a
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian Maederfatal_error s p = Result [Diag Error s p] Nothing
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian Maeder-- | a failing result constructing a message from a type
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian MaedermkError :: (GetRange a, Pretty a) => String -> a -> Result b
88ece6e49930670e8fd3ee79c89a2e918d2fbd0cChristian MaedermkError s c = Result [mkDiag Error s c] Nothing
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian Maeder-- | add a debug point
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian Maederdebug :: (GetRange a, Pretty a) => Int -> (String, a) -> Result ()
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maederdebug n (s, a) = Result
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maeder [mkDiag Debug (unlines [" point " ++ show n, "Variable "++ s ++":"]) a ]
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian Maeder-- | add an error message but don't fail
88ece6e49930670e8fd3ee79c89a2e918d2fbd0cChristian Maederplain_error :: a -> String -> Range -> Result a
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian Maederplain_error x s p = Result [Diag Error s p] $ Just x
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maeder-- | add a warning
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian Maederwarning :: a -> String -> Range -> Result a
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maederwarning x s p = Result [Diag Warning s p] $ Just x
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian Maeder-- | add a hint
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian Maederhint :: a -> String -> Range -> Result a
1d589334ba6b4a4cbfb35307a7a732261e77b0cdChristian Maederhint x s p = Result [Diag Hint s p] $ Just x
88ece6e49930670e8fd3ee79c89a2e918d2fbd0cChristian Maeder-- | add a (web interface) message
aff01ee50b66032469c232e00c945d1fd4f57d1bChristian Maedermessage :: a -> String -> Result a