axel-0.0.13: src/Axel/Eff/Error.hs
module Axel.Eff.Error where
import Axel.Prelude
import Axel.Parse.AST (getAnn, toAxel)
import qualified Axel.Sourcemap as SM
import Axel.Utils.Text (Renderer)
import Control.Monad ((>=>))
import qualified Data.Text as T
import qualified Effectful as Eff
import qualified Effectful.Error.Static as Eff
data Error where
ConvertError :: FilePath -> Text -> Error
MacroError :: FilePath -> SM.Expression -> Text -> Error
NormalizeError :: FilePath -> Text -> [SM.Expression] -> Error
ParseError :: FilePath -> Text -> Error
ProjectError :: Text -> Error
mkFileErrorMsg :: FilePath -> Text -> Text
mkFileErrorMsg (FilePath filePath) err =
"While compiling '" <> filePath <> "':\n\n" <> err
renderErrorContext :: SM.Expression -> Text
renderErrorContext expr =
let sourcePosition =
case getAnn expr of
Just sp -> ", at " <> SM.renderSourcePosition sp
Nothing -> ""
in toAxel expr <> sourcePosition
renderError :: Renderer Error
renderError (ConvertError filePath err) = mkFileErrorMsg filePath err
renderError (MacroError filePath ctxt err) =
mkFileErrorMsg filePath $
"While expanding " <> renderErrorContext ctxt <> ":\n\n" <> err
renderError (NormalizeError filePath err context) =
mkFileErrorMsg filePath $
err <> "\n\n" <> "Context:\n" <> T.unlines (map renderErrorContext context)
renderError (ParseError filePath err) = mkFileErrorMsg filePath err
renderError (ProjectError err) = err
-- | This should ONLY be used for truly impossible situations.
fatal :: Text -> Text -> a
fatal context message = error $ "[FATAL] " <> context <> " - " <> message
unsafeRunError ::
Renderer e -> Eff.Eff (Eff.Error e ': effs) a -> Eff.Eff effs a
unsafeRunError render =
Eff.runErrorNoCallStack >=> either (errorWithoutStackTrace . render) pure -- TODO Don't(?) use `error(WithoutStackTrace)` directly