{-# LANGUAGE CPP #-} {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} module Nix.Render.Frame where import Control.Monad.Reader import Data.Fix import Data.Typeable import Data.Text.Prettyprint.Doc import Nix.Eval import Nix.Exec import Nix.Expr import Nix.Frames import Nix.Normal import Nix.Options import Nix.Pretty import Nix.Render import Nix.Thunk import Nix.Utils import Nix.Value import Text.Megaparsec.Pos #ifdef MIN_VERSION_pretty_show import qualified Text.Show.Pretty as PS #endif renderFrames :: forall v t f e m ann . ( MonadReader e m , Has e Options , MonadFile m , MonadCitedThunks t f m , Typeable v ) => Frames -> m (Doc ann) renderFrames [] = pure mempty renderFrames (x : xs) = do opts :: Options <- asks (view hasLens) frames <- if | verbose opts <= ErrorsOnly -> renderFrame @v @t @f x | verbose opts <= Informational -> do f <- renderFrame @v @t @f x pure $ concatMap go (reverse xs) ++ f | otherwise -> concat <$> mapM (renderFrame @v @t @f) (reverse (x : xs)) pure $ case frames of [] -> mempty _ -> vsep frames where go :: NixFrame -> [Doc ann] go f = case framePos @v @m f of Just pos -> ["While evaluating at " <> pretty (sourcePosPretty pos) <> colon] Nothing -> [] framePos :: forall v (m :: * -> *) . (Typeable m, Typeable v) => NixFrame -> Maybe SourcePos framePos (NixFrame _ f) | Just (e :: EvalFrame m v) <- fromException f = case e of EvaluatingExpr _ (Fix (Compose (Ann (SrcSpan beg _) _))) -> Just beg _ -> Nothing | otherwise = Nothing renderFrame :: forall v t f e m ann . ( MonadReader e m , Has e Options , MonadFile m , MonadCitedThunks t f m , Typeable v ) => NixFrame -> m [Doc ann] renderFrame (NixFrame level f) | Just (e :: EvalFrame m v) <- fromException f = renderEvalFrame level e | Just (e :: ThunkLoop) <- fromException f = renderThunkLoop level e | Just (e :: ValueFrame t f m) <- fromException f = renderValueFrame level e | Just (e :: NormalLoop t f m) <- fromException f = renderNormalLoop level e | Just (e :: ExecFrame t f m) <- fromException f = renderExecFrame level e | Just (e :: ErrorCall) <- fromException f = pure [pretty (show e)] | Just (e :: SynHoleInfo m v) <- fromException f = pure [pretty (show e)] | otherwise = error $ "Unrecognized frame: " ++ show f wrapExpr :: NExprF r -> NExpr wrapExpr x = Fix (Fix (NSym "") <$ x) renderEvalFrame :: (MonadReader e m, Has e Options, MonadFile m) => NixLevel -> EvalFrame m v -> m [Doc ann] renderEvalFrame level f = do opts :: Options <- asks (view hasLens) case f of EvaluatingExpr scope e@(Fix (Compose (Ann ann _))) -> do let scopeInfo | scopes opts = [pretty $ show scope] | otherwise = [] fmap (\x -> scopeInfo ++ [x]) $ renderLocation ann =<< renderExpr level "While evaluating" "Expression" e ForcingExpr _scope e@(Fix (Compose (Ann ann _))) | thunks opts -> fmap (: []) $ renderLocation ann =<< renderExpr level "While forcing thunk from" "Forcing thunk" e Calling name ann -> fmap (: []) $ renderLocation ann $ "While calling builtins." <> pretty name SynHole synfo -> sequence $ let e@(Fix (Compose (Ann ann _))) = _synHoleInfo_expr synfo in [ renderLocation ann =<< renderExpr level "While evaluating" "Syntactic Hole" e , pure $ pretty $ show (_synHoleInfo_scope synfo) ] ForcingExpr _ _ -> pure [] renderExpr :: (MonadReader e m, Has e Options, MonadFile m) => NixLevel -> String -> String -> NExprLoc -> m (Doc ann) renderExpr _level longLabel shortLabel e@(Fix (Compose (Ann _ x))) = do opts :: Options <- asks (view hasLens) let rendered | verbose opts >= DebugInfo = #ifdef MIN_VERSION_pretty_show pretty (PS.ppShow (stripAnnotation e)) #else pretty (show (stripAnnotation e)) #endif | verbose opts >= Chatty = prettyNix (stripAnnotation e) | otherwise = prettyNix (Fix (Fix (NSym "") <$ x)) pure $ if verbose opts >= Chatty then vsep $ [pretty (longLabel ++ ":\n>>>>>>>>"), indent 2 rendered, "<<<<<<<<"] else pretty shortLabel <> fillSep [": ", rendered] renderValueFrame :: forall e t f m ann . (MonadReader e m, Has e Options, MonadFile m, MonadCitedThunks t f m) => NixLevel -> ValueFrame t f m -> m [Doc ann] renderValueFrame level = fmap (: []) . \case ForcingThunk _t -> pure "ForcingThunk" -- jww (2019-03-18): NYI ConcerningValue _v -> pure "ConcerningValue" Comparison _ _ -> pure "Comparing" Addition _ _ -> pure "Adding" Division _ _ -> pure "Dividing" Multiplication _ _ -> pure "Multiplying" Coercion x y -> pure $ mconcat [desc, pretty (describeValue x), " to ", pretty (describeValue y)] where desc | level <= Error = "Cannot coerce " | otherwise = "While coercing " CoercionToJson v -> do v' <- renderValue level "" "" v pure $ "CoercionToJson " <> v' CoercionFromJson _j -> pure "CoercionFromJson" Expectation t v -> do v' <- renderValue @_ @t @f @m level "" "" v pure $ "Saw " <> v' <> " but expected " <> pretty (describeValue t) renderValue :: forall e t f m ann . (MonadReader e m, Has e Options, MonadFile m, MonadCitedThunks t f m) => NixLevel -> String -> String -> NValue t f m -> m (Doc ann) renderValue _level _longLabel _shortLabel v = do opts :: Options <- asks (view hasLens) (if values opts then prettyNValueProv else prettyNValue) <$> removeEffects v renderExecFrame :: (MonadReader e m, Has e Options, MonadFile m, MonadCitedThunks t f m) => NixLevel -> ExecFrame t f m -> m [Doc ann] renderExecFrame level = \case Assertion ann v -> fmap (: []) $ renderLocation ann =<< ( (\d -> fillSep ["Assertion failed:", d]) <$> renderValue level "" "" v ) renderThunkLoop :: (MonadReader e m, Has e Options, MonadFile m, Show (ThunkId m)) => NixLevel -> ThunkLoop -> m [Doc ann] renderThunkLoop _level = pure . (: []) . \case ThunkLoop n -> pretty $ "Infinite recursion in thunk " ++ n renderNormalLoop :: (MonadReader e m, Has e Options, MonadFile m, MonadCitedThunks t f m) => NixLevel -> NormalLoop t f m -> m [Doc ann] renderNormalLoop level = fmap (: []) . \case NormalLoop v -> do v' <- renderValue level "" "" v pure $ "Infinite recursion during normalization forcing " <> v'