{- | Module : $Header$ Description : Monads for message handling Copyright : 2009 Holger Siegel 2012 - 2015 Björn Peemöller License : BSD-3-clause Maintainer : bjp@informatik.uni-kiel.de Stability : experimental Portability : portable The type message represents a compiler message with an optional source code position. -} {-# LANGUAGE CPP #-} module Curry.Base.Message ( Message (..), message, posMessage, spanMessage, spanInfoMessage , showWarning, showError , ppMessage, ppWarning, ppError, ppMessages, ppMessagesWithPreviews ) where #if __GLASGOW_HASKELL__ >= 804 import Prelude hiding ((<>)) #endif import Curry.Base.Position import Curry.Base.Pretty import Curry.Base.Span import Curry.Base.SpanInfo -- --------------------------------------------------------------------------- -- Message -- --------------------------------------------------------------------------- -- |Compiler message data Message = Message { msgSpanInfo :: SpanInfo -- ^ span in the source code , msgTxt :: Doc -- ^ the message itself } instance Eq Message where Message s1 t1 == Message s2 t2 = (s1, show t1) == (s2, show t2) instance Ord Message where Message s1 t1 `compare` Message s2 t2 = compare (s1, show t1) (s2, show t2) instance Show Message where showsPrec _ = shows . ppMessage instance HasPosition Message where getPosition = getStartPosition setPosition = setStartPosition instance HasSpanInfo Message where getSpanInfo = msgSpanInfo setSpanInfo spi m = m { msgSpanInfo = spi } instance Pretty Message where pPrint = ppMessage -- |Construct a 'Message' without a 'SpanInfo' message :: Doc -> Message message = Message NoSpanInfo -- |Construct a message from a position. posMessage :: HasPosition p => p -> Doc -> Message posMessage p = spanMessage $ pos2Span $ getPosition p -- |Construct a message from a span and a text spanMessage :: Span -> Doc -> Message spanMessage s = spanInfoMessage $ fromSrcSpan s -- |Construct a message from an entity with a 'SpanInfo' and a text spanInfoMessage :: HasSpanInfo s => s -> Doc -> Message spanInfoMessage s msg = Message (getSpanInfo s) msg -- |Show a 'Message' as a warning showWarning :: Message -> String showWarning = show . ppWarning -- |Show a 'Message' as an error showError :: Message -> String showError = show . ppError -- |Pretty print a 'Message' ppMessage :: Message -> Doc ppMessage = ppAs "" -- |Pretty print a 'Message' as a warning ppWarning :: Message -> Doc ppWarning = ppAs "Warning" -- |Pretty print a 'Message' as an error ppError :: Message -> Doc ppError = ppAs "Error" -- |Pretty print a 'Message' with a given key ppAs :: String -> Message -> Doc ppAs key (Message mbSpanInfo txt) = (hsep $ filter (not . isEmpty) [spanPP, keyPP]) $$ nest 4 txt where spanPP = ppCompactSpan $ getSrcSpan $ mbSpanInfo keyPP = if null key then empty else text key <> colon -- |Pretty print a list of 'Message's by vertical concatenation ppMessages :: (Message -> Doc) -> [Message] -> Doc ppMessages ppFun = foldr (\m ms -> text "" $+$ m $+$ ms) empty . map ppFun -- |Pretty print a list of 'Message's with previews by vertical concatenation ppMessagesWithPreviews :: (Message -> Doc) -> [Message] -> IO Doc ppMessagesWithPreviews ppFun = (fmap $ foldr (\m ms -> text "" $+$ m $+$ ms) empty) . mapM ppFunWithPreview where ppFunWithPreview m = do preview <- case m of Message (SpanInfo sp _) _ -> ppSpanPreview sp _ -> return empty return $ ppFun m $+$ preview