serokell/importify

View on GitHub
src/Importify/ParseException.hs

Summary

Maintainability
Test Coverage
-- | This module contains data type for parsing exception and pretty
-- formatting of such exceptions.

module Importify.ParseException
       ( ModuleParseException (..)
       , eitherParseResult
       , reportErrorsIfAny
       , setMpeFile
       ) where

import           Universum

import           Fmt                   (Builder, blockListF, build, indentF, (+|), (|+))
import           Language.Haskell.Exts (ParseResult (..), SrcLoc (srcFilename),
                                        prettyPrint)

import           Extended.Data.Str     (charWrap, wordWrap)
import           Extended.System.Wlog  (printWarning)

data ModuleParseException = MPE !SrcLoc !String
    deriving (Show)

instance Exception ModuleParseException
instance Buildable ModuleParseException where
    build (MPE loc reason) = "Location:\n"
                          +| indentF 4 (build $ charWrap 80 $ prettyPrint loc)
                          |+ "Reason:\n"
                          +| indentF 4 (build $ wordWrap 80 reason)
                          |+ ""

-- | Updates file name of error location. Sometimes error location
-- looks like @- Location: : -1: -1@ which is not very helpful.
setMpeFile :: FilePath -> ModuleParseException -> ModuleParseException
setMpeFile modulePath (MPE loc msg) = MPE (loc {srcFilename = modulePath}) msg

-- | Converts 'ParseResult' into 'Either' making error look pretty.
eitherParseResult :: ParseResult res
                  -> Either ModuleParseException res
eitherParseResult (ParseOk res)            = Right res
eitherParseResult (ParseFailed loc reason) = Left $ MPE loc reason

-- | Pretty printing 'NonEmpty' list of errors in really nice way.
prettyParseErrors :: Text -> NonEmpty ModuleParseException -> Text
prettyParseErrors libName exceptions =
    "Next errors occured during caching of package: "+|libName|+"\n"
 +| indentF 4 (blockListF exceptions) |+ ""

-- | Prints parse errors if list of errors is not empty.
reportErrorsIfAny :: [ModuleParseException] -> Text -> IO ()
reportErrorsIfAny exceptions libName = whenNotNull exceptions $
    printWarning . prettyParseErrors libName