{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ScopedTypeVariables #-} module Nix.Frames ( NixLevel(..) , Frames , Framed , NixFrame(..) , NixException(..) , withFrame , throwError , module Data.Typeable , module Control.Exception ) where import Control.Exception hiding ( catch , evaluate ) import Control.Monad.Catch import Control.Monad.Reader import Data.Typeable hiding ( typeOf ) import Nix.Utils data NixLevel = Fatal | Error | Warning | Info | Debug deriving (Ord, Eq, Bounded, Enum, Show) data NixFrame = NixFrame { frameLevel :: NixLevel , frame :: SomeException } instance Show NixFrame where show (NixFrame level f) = "Nix frame at level " ++ show level ++ ": " ++ show f type Frames = [NixFrame] type Framed e m = (MonadReader e m, Has e Frames, MonadThrow m) newtype NixException = NixException Frames deriving Show instance Exception NixException withFrame :: forall s e m a . (Framed e m, Exception s) => NixLevel -> s -> m a -> m a withFrame level f = local (over hasLens (NixFrame level (toException f) :)) throwError :: forall s e m a . (Framed e m, Exception s, MonadThrow m) => s -> m a throwError err = do context <- asks (view hasLens) traceM "Throwing error..." throwM $ NixException (NixFrame Error (toException err) : context)