hnix-0.13.0: src/Nix.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
module Nix
( module Nix.Cache
, module Nix.Exec
, module Nix.Expr
, module Nix.Frames
, module Nix.Render.Frame
, module Nix.Normal
, module Nix.Options
, module Nix.String
, module Nix.Parser
, module Nix.Pretty
, module Nix.Reduce
, module Nix.Thunk
, module Nix.Value
, module Nix.XML
, withNixContext
, nixEvalExpr
, nixEvalExprLoc
, nixTracingEvalExprLoc
, evaluateExpression
, processResult
)
where
import Relude.Unsafe ( (!!) )
import GHC.Err ( errorWithoutStackTrace )
import Data.Fix ( Fix )
import qualified Data.HashMap.Lazy as M
import qualified Data.Text as Text
import qualified Data.Text.Read as Text
import Nix.Builtins
import Nix.Cache
import qualified Nix.Eval as Eval
import Nix.Exec
import Nix.Expr
import Nix.Frames
import Nix.String
import Nix.Normal
import Nix.Options
import Nix.Parser
import Nix.Pretty
import Nix.Reduce
import Nix.Render.Frame
import Nix.Thunk
import Nix.Utils
import Nix.Value
import Nix.Value.Monad
import Nix.XML
-- | This is the entry point for all evaluations, whatever the expression tree
-- type. It sets up the common Nix environment and applies the
-- transformations, allowing them to be easily composed.
nixEval
:: (MonadNix e t f m, Has e Options, Functor g)
=> Maybe FilePath
-> Transform g (m a)
-> Alg g (m a)
-> Fix g
-> m a
nixEval mpath xform alg = withNixContext mpath . adi alg xform
-- | Evaluate a nix expression in the default context
nixEvalExpr
:: (MonadNix e t f m, Has e Options)
=> Maybe FilePath
-> NExpr
-> m (NValue t f m)
nixEvalExpr mpath = nixEval mpath id Eval.eval
-- | Evaluate a nix expression in the default context
nixEvalExprLoc
:: forall e t f m
. (MonadNix e t f m, Has e Options)
=> Maybe FilePath
-> NExprLoc
-> m (NValue t f m)
nixEvalExprLoc mpath =
nixEval
mpath
(Eval.addStackFrames . Eval.addSourcePositions)
(Eval.eval . annotated . getCompose)
-- | Evaluate a nix expression with tracing in the default context. Note that
-- this function doesn't do any tracing itself, but 'evalExprLoc' will be
-- 'tracing' is set to 'True' in the Options structure (accessible through
-- 'MonadNix'). All this function does is provide the right type class
-- context.
nixTracingEvalExprLoc
:: (MonadNix e t f m, Has e Options, MonadIO m, Alternative m)
=> Maybe FilePath
-> NExprLoc
-> m (NValue t f m)
nixTracingEvalExprLoc mpath = withNixContext mpath . evalExprLoc
evaluateExpression
:: (MonadNix e t f m, Has e Options)
=> Maybe FilePath
-> (Maybe FilePath -> NExprLoc -> m (NValue t f m))
-> (NValue t f m -> m a)
-> NExprLoc
-> m a
evaluateExpression mpath evaluator handler expr =
do
opts :: Options <- asks $ view hasLens
args <-
(traverse . traverse)
eval'
$ (second parseArg <$> arg opts) <>
(second mkStr <$> argstr opts)
f <- evaluator mpath expr
f' <- demand f
val <-
case f' of
NVClosure _ g -> g $ argmap args
_ -> pure f
processResult handler val
where
parseArg s =
either
(errorWithoutStackTrace . show)
id
(parseNixText s)
eval' = normalForm <=< nixEvalExpr mpath
argmap args = nvSet mempty (M.fromList args)
processResult
:: forall e t f m a
. (MonadNix e t f m, Has e Options)
=> (NValue t f m -> m a)
-> NValue t f m
-> m a
processResult h val = do
opts :: Options <- asks (view hasLens)
maybe
(h val)
(\ (Text.splitOn "." -> keys) -> go keys val)
(attr opts)
where
go :: [Text.Text] -> NValue t f m -> m a
go [] v = h v
go ((Text.decimal -> Right (n,"")) : ks) v =
(\case
NVList xs ->
list
h
go
ks
(xs !! n)
_ -> errorWithoutStackTrace $ "Expected a list for selector '" <> show n <> "', but got: " <> show v
) =<< demand v
go (k : ks) v =
(\case
NVSet xs _ ->
maybe
(errorWithoutStackTrace $ toString $ "Set does not contain key '" <> k <> "'")
(list
h
go
ks
)
(M.lookup k xs)
_ -> errorWithoutStackTrace $ toString $ "Expected a set for selector '" <> k <> "', but got: " <> show v
) =<< demand v