Merge pull request #478 from haskell-nix/johnw/data-abstract
Abstract the core value representation further
This commit is contained in:
commit
767ebe4ea1
37
README-design.md
Normal file
37
README-design.md
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Design of the hnix code base
|
||||
|
||||
Welcome to the hnix code! You may notice some strange things as you venture
|
||||
into this realm, so this document is meant to prepare you, dear reader, for
|
||||
the secrets of the labyrinth as we've designed them.
|
||||
|
||||
The first thing to note is that hnix was primarily designed so that Haskell
|
||||
authors could use it to craft custom tooling around the Nix ecosystem. Thus,
|
||||
it was never fully intended for just the end user. As a result, we use a great
|
||||
deal of abstraction so that these enterprising Haskell authors may inject
|
||||
their own behavior at various points within the type hierarchy, the value
|
||||
representation, and the behavior of the evaluator.
|
||||
|
||||
To this end, you'll see a lot of type variables floating around, almost
|
||||
everywhere. These provide many of the "injection points" mentioned above.
|
||||
There is a strict convention followed for the naming of these variables, the
|
||||
lexicon for which is stated here.
|
||||
|
||||
`t` is the type of thunks. It turns out that hnix dosen't actually need to
|
||||
know how thunks are represented, at all. It only needs to know that the
|
||||
interface can be honored: pending action that yield values may be turned into
|
||||
thunks, and thunks can later be forced into values.
|
||||
|
||||
`f` is the type of a comonadic and applicative functor that gets injected at
|
||||
every level of a value's recursive structure. In the standard evaluation
|
||||
scheme, this is used to provide "provenance" information to track which
|
||||
expression context a value originated from (e.g., this 10 came from that
|
||||
expression "5 + 5" over in this file, here).
|
||||
|
||||
`m` is the "monad of evaluation", which must support at least the features
|
||||
required by the evaluator. The fact that the user can evaluate in his own base
|
||||
monad makes it possible to create custom builtins that make use of arbitrary
|
||||
effects.
|
||||
|
||||
`v` is the type of values, which is almost always going to be `NValue t f m`,
|
||||
though it could be `NValueNF t f m`, the type of normal form values. Very few
|
||||
points in the code are generic over both.
|
|
@ -439,6 +439,7 @@ library
|
|||
Nix.Atoms
|
||||
Nix.Builtins
|
||||
Nix.Cache
|
||||
Nix.Cited
|
||||
Nix.Context
|
||||
Nix.Convert
|
||||
Nix.Effects
|
||||
|
@ -465,6 +466,7 @@ library
|
|||
Nix.TH
|
||||
Nix.Thunk
|
||||
Nix.Thunk.Basic
|
||||
Nix.Thunk.Standard
|
||||
Nix.Type.Assumption
|
||||
Nix.Type.Env
|
||||
Nix.Type.Infer
|
||||
|
@ -484,6 +486,7 @@ library
|
|||
, base >=4.9 && <5
|
||||
, binary
|
||||
, bytestring
|
||||
, comonad
|
||||
, containers
|
||||
, data-fix
|
||||
, deepseq >=1.4.2 && <1.5
|
||||
|
@ -502,6 +505,7 @@ library
|
|||
, lens-family-th
|
||||
, logict
|
||||
, megaparsec >=7.0 && <7.1
|
||||
, monad-control
|
||||
, monadlist
|
||||
, mtl
|
||||
, optparse-applicative
|
||||
|
@ -520,6 +524,7 @@ library
|
|||
, these
|
||||
, time
|
||||
, transformers
|
||||
, transformers-base
|
||||
, unix
|
||||
, unordered-containers >=0.2.9 && <0.3
|
||||
, vector
|
||||
|
@ -572,6 +577,7 @@ executable hnix
|
|||
aeson
|
||||
, base >=4.9 && <5
|
||||
, bytestring
|
||||
, comonad
|
||||
, containers
|
||||
, data-fix
|
||||
, deepseq >=1.4.2 && <1.5
|
||||
|
@ -584,6 +590,7 @@ executable hnix
|
|||
, optparse-applicative
|
||||
, pretty-show
|
||||
, prettyprinter
|
||||
, ref-tf
|
||||
, repline
|
||||
, template-haskell
|
||||
, text
|
||||
|
|
29
main/Main.hs
29
main/Main.hs
|
@ -26,12 +26,14 @@ import qualified Data.Text.Lazy.IO as TL
|
|||
import Data.Text.Prettyprint.Doc
|
||||
import Data.Text.Prettyprint.Doc.Render.Text
|
||||
import Nix
|
||||
import Nix.Cited
|
||||
import Nix.Convert
|
||||
import qualified Nix.Eval as Eval
|
||||
import Nix.Json
|
||||
-- import Nix.Lint
|
||||
import Nix.Options.Parser
|
||||
import Nix.Thunk.Basic
|
||||
import Nix.Thunk.Standard
|
||||
import qualified Nix.Type.Env as Env
|
||||
import qualified Nix.Type.Infer as HM
|
||||
import Nix.Utils
|
||||
|
@ -46,7 +48,7 @@ main :: IO ()
|
|||
main = do
|
||||
time <- liftIO getCurrentTime
|
||||
opts <- execParser (nixOptionsInfo time)
|
||||
runLazyM opts $ case readFrom opts of
|
||||
runStdLazyM opts $ case readFrom opts of
|
||||
Just path -> do
|
||||
let file = addExtension (dropExtension path) "nixc"
|
||||
process opts (Just file) =<< liftIO (readCache path)
|
||||
|
@ -93,7 +95,7 @@ main = do
|
|||
catch (process opts mpath expr) $ \case
|
||||
NixException frames ->
|
||||
errorWithoutStackTrace . show
|
||||
=<< renderFrames @(NThunk (Lazy IO)) frames
|
||||
=<< renderFrames @(StdValue IO) @(StdThunk IO) frames
|
||||
|
||||
when (repl opts) $
|
||||
withNixContext Nothing $ Repl.main
|
||||
|
@ -135,13 +137,15 @@ main = do
|
|||
. prettyNix
|
||||
. stripAnnotation $ expr
|
||||
where
|
||||
printer :: forall e m. (MonadNix e m, MonadIO m, Typeable m)
|
||||
=> NValue m -> m ()
|
||||
printer
|
||||
| finder opts =
|
||||
fromValue @(AttrSet (NThunk m)) >=> findAttrs
|
||||
fromValue @(AttrSet (StdThunk IO)) >=> findAttrs
|
||||
| xml opts =
|
||||
liftIO . putStrLn . Text.unpack . principledStringIgnoreContext . toXML <=< normalForm
|
||||
liftIO . putStrLn
|
||||
. Text.unpack
|
||||
. principledStringIgnoreContext
|
||||
. toXML
|
||||
<=< normalForm
|
||||
| json opts =
|
||||
liftIO . Text.putStrLn
|
||||
. principledStringIgnoreContext
|
||||
|
@ -157,12 +161,12 @@ main = do
|
|||
where
|
||||
go prefix s = do
|
||||
xs <- forM (sortOn fst (M.toList s))
|
||||
$ \(k, nv@(NThunk (NCited _ t))) -> case t of
|
||||
$ \(k, nv@(StdThunk (StdCited (NCited _ t)))) -> case t of
|
||||
Value v -> pure (k, Just v)
|
||||
Thunk _ _ ref -> do
|
||||
let path = prefix ++ Text.unpack k
|
||||
(_, descend) = filterEntry path k
|
||||
val <- readVar ref
|
||||
val <- readVar @(StdLazy IO) ref
|
||||
case val of
|
||||
Computed _ -> pure (k, Nothing)
|
||||
_ | descend -> (k,) <$> forceEntry path nv
|
||||
|
@ -176,7 +180,8 @@ main = do
|
|||
when descend $ case mv of
|
||||
Nothing -> return ()
|
||||
Just v -> case v of
|
||||
NVSet s' _ -> go (path ++ ".") s'
|
||||
NVSet s' _ ->
|
||||
go (path ++ ".") s'
|
||||
_ -> return ()
|
||||
where
|
||||
filterEntry path k = case (path, k) of
|
||||
|
@ -202,7 +207,7 @@ main = do
|
|||
. ("Exception forcing " ++)
|
||||
. (k ++)
|
||||
. (": " ++) . show
|
||||
=<< renderFrames @(NThunk (Lazy IO)) frames
|
||||
=<< renderFrames @(StdValue IO) @(StdThunk IO) frames
|
||||
return Nothing
|
||||
|
||||
reduction path mp x = do
|
||||
|
@ -212,8 +217,8 @@ main = do
|
|||
|
||||
handleReduced :: (MonadThrow m, MonadIO m)
|
||||
=> FilePath
|
||||
-> (NExprLoc, Either SomeException (NValue m))
|
||||
-> m (NValue m)
|
||||
-> (NExprLoc, Either SomeException (NValue t f m))
|
||||
-> m (NValue t f m)
|
||||
handleReduced path (expr', eres) = do
|
||||
liftIO $ do
|
||||
putStrLn $ "Wrote winnowed expression tree to " ++ path
|
||||
|
|
49
main/Repl.hs
49
main/Repl.hs
|
@ -23,6 +23,8 @@
|
|||
module Repl where
|
||||
|
||||
import Nix hiding (exec, try)
|
||||
import Nix.Builtins (MonadBuiltins)
|
||||
import Nix.Cited
|
||||
import Nix.Convert
|
||||
import Nix.Eval
|
||||
import Nix.Scope
|
||||
|
@ -30,6 +32,7 @@ import qualified Nix.Type.Env as Env
|
|||
import Nix.Type.Infer
|
||||
import Nix.Utils
|
||||
|
||||
import Control.Comonad
|
||||
import qualified Data.HashMap.Lazy as M
|
||||
import Data.List (isPrefixOf, foldl')
|
||||
import qualified Data.Map as Map
|
||||
|
@ -51,7 +54,7 @@ import System.Environment
|
|||
import System.Exit
|
||||
|
||||
|
||||
main :: (MonadNix e m, MonadIO m, MonadException m) => m ()
|
||||
main :: (MonadBuiltins e t f m, MonadIO m, MonadException m) => m ()
|
||||
main = flip evalStateT initState $
|
||||
#if MIN_VERSION_repline(0, 2, 0)
|
||||
evalRepl (return prefix) cmd options (Just ':') completer welcomeText
|
||||
|
@ -66,15 +69,15 @@ main = flip evalStateT initState $
|
|||
-- Types
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
newtype IState m = IState
|
||||
{ tmctx :: AttrSet (NValue m) -- Value environment
|
||||
newtype IState t f m = IState
|
||||
{ tmctx :: AttrSet (NValue t f m) -- Value environment
|
||||
}
|
||||
|
||||
initState :: MonadIO m => IState m
|
||||
initState :: MonadIO m => IState t f m
|
||||
initState = IState M.empty
|
||||
|
||||
type Repl e m = HaskelineT (StateT (IState m) m)
|
||||
hoistErr :: MonadIO m => Result a -> Repl e m a
|
||||
type Repl e t f m = HaskelineT (StateT (IState t f m) m)
|
||||
hoistErr :: MonadIO m => Result a -> Repl e t f m a
|
||||
hoistErr (Success val) = return val
|
||||
hoistErr (Failure err) = do
|
||||
liftIO $ print err
|
||||
|
@ -84,8 +87,8 @@ hoistErr (Failure err) = do
|
|||
-- Execution
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
exec :: forall e m. (MonadNix e m, MonadIO m, MonadException m)
|
||||
=> Bool -> Text.Text -> Repl e m (NValue m)
|
||||
exec :: forall e t f m. (MonadBuiltins e t f m, MonadIO m, MonadException m)
|
||||
=> Bool -> Text.Text -> Repl e t f m (NValue t f m)
|
||||
exec update source = do
|
||||
-- Get the current interpreter state
|
||||
st <- get
|
||||
|
@ -98,11 +101,12 @@ exec update source = do
|
|||
-- tyctx' <- hoistErr $ inferTop (tyctx st) expr
|
||||
|
||||
-- TODO: track scope with (tmctx st)
|
||||
mVal <- lift $ lift $ try $ pushScope @(NThunk m) M.empty (evalExprLoc expr)
|
||||
mVal <- lift $ lift $ try $ pushScope @t M.empty (evalExprLoc expr)
|
||||
|
||||
case mVal of
|
||||
Left (NixException frames) -> do
|
||||
lift $ lift $ liftIO . print =<< renderFrames @(NThunk m) frames
|
||||
lift $ lift $ liftIO . print
|
||||
=<< renderFrames @(NValue t f m) @t frames
|
||||
abort
|
||||
Right val -> do
|
||||
-- Update the interpreter state
|
||||
|
@ -113,7 +117,7 @@ exec update source = do
|
|||
return val
|
||||
|
||||
|
||||
cmd :: (MonadNix e m, MonadIO m, MonadException m) => String -> Repl e m ()
|
||||
cmd :: (MonadBuiltins e t f m, MonadIO m, MonadException m) => String -> Repl e t f m ()
|
||||
cmd source = do
|
||||
val <- exec True (Text.pack source)
|
||||
lift $ lift $ do
|
||||
|
@ -129,31 +133,31 @@ cmd source = do
|
|||
-------------------------------------------------------------------------------
|
||||
|
||||
-- :browse command
|
||||
browse :: MonadNix e m => [String] -> Repl e m ()
|
||||
browse :: MonadBuiltins e t f m => [String] -> Repl e t f m ()
|
||||
browse _ = do
|
||||
st <- get
|
||||
undefined
|
||||
-- liftIO $ mapM_ putStrLn $ ppenv (tyctx st)
|
||||
|
||||
-- :load command
|
||||
load :: (MonadNix e m, MonadIO m, MonadException m) => [String] -> Repl e m ()
|
||||
load :: (MonadBuiltins e t f m, MonadIO m, MonadException m) => [String] -> Repl e t f m ()
|
||||
load args = do
|
||||
contents <- liftIO $ Text.readFile (unwords args)
|
||||
void $ exec True contents
|
||||
|
||||
-- :type command
|
||||
typeof :: (MonadNix e m, MonadException m, MonadIO m) => [String] -> Repl e m ()
|
||||
typeof :: (MonadBuiltins e t f m, MonadException m, MonadIO m) => [String] -> Repl e t f m ()
|
||||
typeof args = do
|
||||
st <- get
|
||||
val <- case M.lookup line (tmctx st) of
|
||||
Just val -> return val
|
||||
Nothing -> exec False line
|
||||
liftIO $ putStrLn $ describeValue . valueType . _cited . _nValue $ val
|
||||
liftIO $ putStrLn $ describeValue . valueType . extract . _nValue $ val
|
||||
where
|
||||
line = Text.pack (unwords args)
|
||||
|
||||
-- :quit command
|
||||
quit :: (MonadNix e m, MonadIO m) => a -> Repl e m ()
|
||||
quit :: (MonadBuiltins e t f m, MonadIO m) => a -> Repl e t f m ()
|
||||
quit _ = liftIO exitSuccess
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
@ -175,8 +179,8 @@ comp n = do
|
|||
-- let defs = map unpack $ Map.keys ctx
|
||||
return $ filter (isPrefixOf n) (cmds {-++ defs-})
|
||||
|
||||
options :: (MonadNix e m, MonadIO m, MonadException m)
|
||||
=> [(String, [String] -> Repl e m ())]
|
||||
options :: (MonadBuiltins e t f m, MonadIO m, MonadException m)
|
||||
=> [(String, [String] -> Repl e t f m ())]
|
||||
options = [
|
||||
("load" , load)
|
||||
--, ("browse" , browse)
|
||||
|
@ -185,11 +189,12 @@ options = [
|
|||
, ("help" , help)
|
||||
]
|
||||
|
||||
help :: forall e m . (MonadNix e m, MonadIO m, MonadException m)
|
||||
=> [String] -> Repl e m ()
|
||||
help :: forall e t f m . (MonadBuiltins e t f m, MonadIO m, MonadException m)
|
||||
=> [String] -> Repl e t f m ()
|
||||
help _ = liftIO $ do
|
||||
putStrLn "Available commands:\n"
|
||||
mapM_ putStrLn $ map (\o -> ":" ++ (fst o)) (options @e @m)
|
||||
mapM_ putStrLn $ map (\o -> ":" ++ (fst o)) (options @e @t @f @m)
|
||||
|
||||
completer :: (MonadNix e m, MonadIO m) => CompleterStyle (StateT (IState m) m)
|
||||
completer :: (MonadBuiltins e t f m, MonadIO m)
|
||||
=> CompleterStyle (StateT (IState t f m) m)
|
||||
completer = Prefix (wordCompleter comp) defaultMatcher
|
||||
|
|
41
src/Nix.hs
41
src/Nix.hs
|
@ -24,7 +24,6 @@ module Nix (module Nix.Cache,
|
|||
|
||||
import Control.Applicative
|
||||
import Control.Arrow (second)
|
||||
import Control.Monad.Free
|
||||
import Control.Monad.Reader
|
||||
import Data.Fix
|
||||
import qualified Data.HashMap.Lazy as M
|
||||
|
@ -51,20 +50,20 @@ 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 m, Has e Options, Functor f)
|
||||
=> Maybe FilePath -> Transform f (m a) -> Alg f (m a) -> Fix f -> m a
|
||||
nixEval :: (MonadBuiltins 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 :: forall e m. (MonadNix e m, Has e Options)
|
||||
=> Maybe FilePath -> NExpr -> m (NValue m)
|
||||
nixEvalExpr :: (MonadBuiltins 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 m. (MonadNix e m, Has e Options)
|
||||
=> Maybe FilePath -> NExprLoc -> m (NValue m)
|
||||
nixEvalExprLoc :: forall e t f m. (MonadBuiltins e t f m, Has e Options)
|
||||
=> Maybe FilePath -> NExprLoc -> m (NValue t f m)
|
||||
nixEvalExprLoc mpath =
|
||||
nixEval mpath (Eval.addStackFrames @(NThunk m) . Eval.addSourcePositions)
|
||||
nixEval mpath (Eval.addStackFrames @t . Eval.addSourcePositions)
|
||||
(Eval.eval . annotated . getCompose)
|
||||
|
||||
-- | Evaluate a nix expression with tracing in the default context. Note that
|
||||
|
@ -73,15 +72,15 @@ nixEvalExprLoc mpath =
|
|||
-- 'MonadNix'). All this function does is provide the right type class
|
||||
-- context.
|
||||
nixTracingEvalExprLoc
|
||||
:: forall e m. (MonadNix e m, Has e Options, MonadIO m, Alternative m)
|
||||
=> Maybe FilePath -> NExprLoc -> m (NValue m)
|
||||
:: (MonadBuiltins 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 m, Has e Options)
|
||||
:: (MonadBuiltins e t f m, Has e Options)
|
||||
=> Maybe FilePath
|
||||
-> (Maybe FilePath -> NExprLoc -> m (NValue m))
|
||||
-> (NValue m -> m a)
|
||||
-> (Maybe FilePath -> NExprLoc -> m (NValue t f m))
|
||||
-> (NValue t f m -> m a)
|
||||
-> NExprLoc
|
||||
-> m a
|
||||
evaluateExpression mpath evaluator handler expr = do
|
||||
|
@ -97,27 +96,29 @@ evaluateExpression mpath evaluator handler expr = do
|
|||
|
||||
eval' = (normalForm =<<) . nixEvalExpr mpath
|
||||
|
||||
argmap args = embed $ Free $ NVSetF (M.fromList args) mempty
|
||||
argmap args = pure $ nvSet (M.fromList args') mempty
|
||||
where
|
||||
args' = map (fmap (wrapValue . nValueFromNF)) args
|
||||
|
||||
compute ev x args p = do
|
||||
f <- ev mpath x
|
||||
f :: NValue t f m <- ev mpath x
|
||||
processResult p =<< case f of
|
||||
NVClosure _ g -> g args
|
||||
NVClosure _ g -> force ?? pure =<< g args
|
||||
_ -> pure f
|
||||
|
||||
processResult :: forall e m a. (MonadNix e m, Has e Options)
|
||||
=> (NValue m -> m a) -> NValue m -> m a
|
||||
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)
|
||||
case attr opts of
|
||||
Nothing -> h val
|
||||
Just (Text.splitOn "." -> keys) -> go keys val
|
||||
where
|
||||
go :: [Text.Text] -> NValue m -> m a
|
||||
go :: [Text.Text] -> NValue t f m -> m a
|
||||
go [] v = h v
|
||||
go ((Text.decimal -> Right (n,"")):ks) v = case v of
|
||||
NVList xs -> case ks of
|
||||
[] -> force @(NValue m) @(NThunk m) (xs !! n) h
|
||||
[] -> force @t @m @(NValue t f m) (xs !! n) h
|
||||
_ -> force (xs !! n) (go ks)
|
||||
_ -> errorWithoutStackTrace $
|
||||
"Expected a list for selector '" ++ show n
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
{-# OPTIONS_GHC -Wno-missing-signatures #-}
|
||||
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
|
||||
|
||||
module Nix.Builtins (withNixContext, builtins) where
|
||||
module Nix.Builtins (MonadBuiltins, withNixContext, builtins) where
|
||||
|
||||
import Control.Monad
|
||||
import Control.Monad.Catch
|
||||
|
@ -32,7 +32,7 @@ import Control.Monad.Reader (asks)
|
|||
-- us to put the hashing package in the unconditional dependency list.
|
||||
-- See https://github.com/NixOS/cabal2nix/issues/348 for more info
|
||||
#if MIN_VERSION_hashing(0, 1, 0)
|
||||
import Crypto.Hash
|
||||
import "hashing" Crypto.Hash
|
||||
import qualified "hashing" Crypto.Hash.MD5 as MD5
|
||||
import qualified "hashing" Crypto.Hash.SHA1 as SHA1
|
||||
import qualified "hashing" Crypto.Hash.SHA256 as SHA256
|
||||
|
@ -95,25 +95,41 @@ import System.Posix.Files (isRegularFile, isDirectory, isSymbolicLink)
|
|||
import Text.Read
|
||||
import Text.Regex.TDFA
|
||||
|
||||
-- | This constraint synonym establishes all the ways in which we must be able
|
||||
-- to relate different Haskell values to the thunk representation that will
|
||||
-- be chosen by the caller.
|
||||
type MonadBuiltins e t f m =
|
||||
( MonadNix e t f m
|
||||
, FromValue NixString m t
|
||||
, FromValue Path m t
|
||||
, FromValue [t] m t
|
||||
, FromValue (M.HashMap Text t) m t
|
||||
, ToValue NixString m t
|
||||
, ToValue Int m t
|
||||
, ToValue () m t
|
||||
, FromNix [NixString] m t
|
||||
, ToNix t m (NValue t f m)
|
||||
)
|
||||
|
||||
-- | Evaluate a nix expression in the default context
|
||||
withNixContext :: forall e m r. (MonadNix e m, Has e Options)
|
||||
withNixContext :: forall e t f m r. (MonadBuiltins e t f m, Has e Options)
|
||||
=> Maybe FilePath -> m r -> m r
|
||||
withNixContext mpath action = do
|
||||
base <- builtins
|
||||
opts :: Options <- asks (view hasLens)
|
||||
let i = wrapValue @(NValue m) @(NThunk m) @m $ nvList $
|
||||
map (wrapValue @(NValue m) @(NThunk m) @m
|
||||
let i = wrapValue @t @m @(NValue t f m) $ nvList $
|
||||
map (wrapValue @t @m @(NValue t f m)
|
||||
. nvStr . hackyMakeNixStringWithoutContext . Text.pack) (include opts)
|
||||
pushScope (M.singleton "__includes" i) $
|
||||
pushScopes base $ case mpath of
|
||||
Nothing -> action
|
||||
Just path -> do
|
||||
traceM $ "Setting __cur_file = " ++ show path
|
||||
let ref = wrapValue @(NValue m) @(NThunk m) @m $ nvPath path
|
||||
let ref = wrapValue @t @m @(NValue t f m) $ nvPath path
|
||||
pushScope (M.singleton "__cur_file" ref) action
|
||||
|
||||
builtins :: (MonadNix e m, Scoped (NThunk m) m)
|
||||
=> m (Scopes m (NThunk m))
|
||||
builtins :: (MonadBuiltins e t f m, Scoped t m)
|
||||
=> m (Scopes m t)
|
||||
builtins = do
|
||||
ref <- thunk $ flip nvSet M.empty <$> buildMap
|
||||
lst <- ([("builtins", ref)] ++) <$> topLevelBuiltins
|
||||
|
@ -129,18 +145,18 @@ builtins = do
|
|||
Builtin TopLevel ("__" <> name, builtin)
|
||||
|
||||
data BuiltinType = Normal | TopLevel
|
||||
data Builtin m = Builtin
|
||||
data Builtin t = Builtin
|
||||
{ _kind :: BuiltinType
|
||||
, mapping :: (Text, NThunk m)
|
||||
, mapping :: (Text, t)
|
||||
}
|
||||
|
||||
valueThunk :: forall e m. MonadNix e m => NValue m -> NThunk m
|
||||
valueThunk = wrapValue @_ @_ @m
|
||||
valueThunk :: forall e t f m. MonadBuiltins e t f m => NValue t f m -> t
|
||||
valueThunk = wrapValue @_ @m
|
||||
|
||||
force' :: forall e m. MonadNix e m => NThunk m -> m (NValue m)
|
||||
force' :: forall e t f m. MonadBuiltins e t f m => t -> m (NValue t f m)
|
||||
force' = force ?? pure
|
||||
|
||||
builtinsList :: forall e m. MonadNix e m => m [ Builtin m ]
|
||||
builtinsList :: forall e t f m. MonadBuiltins e t f m => m [Builtin t]
|
||||
builtinsList = sequence [
|
||||
do version <- toValue (principledMakeNixStringWithoutContext "2.0")
|
||||
pure $ Builtin Normal ("nixVersion", version)
|
||||
|
@ -288,12 +304,12 @@ builtinsList = sequence [
|
|||
add2 t n v = wrap t n <$> mkThunk n (builtin2 (Text.unpack n) v)
|
||||
add3 t n v = wrap t n <$> mkThunk n (builtin3 (Text.unpack n) v)
|
||||
|
||||
add' :: ToBuiltin m a => BuiltinType -> Text -> a -> m (Builtin m)
|
||||
add' :: ToBuiltin t f m a => BuiltinType -> Text -> a -> m (Builtin t)
|
||||
add' t n v = wrap t n <$> mkThunk n (toBuiltin (Text.unpack n) v)
|
||||
|
||||
-- Primops
|
||||
|
||||
foldNixPath :: forall e m r. MonadNix e m
|
||||
foldNixPath :: forall e t f m r. MonadBuiltins e t f m
|
||||
=> (FilePath -> Maybe String -> NixPathEntryType -> r -> m r) -> r -> m r
|
||||
foldNixPath f z = do
|
||||
mres <- lookupVar "__includes"
|
||||
|
@ -313,7 +329,7 @@ foldNixPath f z = do
|
|||
[n, p] -> f (Text.unpack p) (Just (Text.unpack n)) ty rest
|
||||
_ -> throwError $ ErrorCall $ "Unexpected entry in NIX_PATH: " ++ show x
|
||||
|
||||
nixPath :: MonadNix e m => m (NValue m)
|
||||
nixPath :: MonadBuiltins e t f m => m (NValue t f m)
|
||||
nixPath = fmap nvList $ flip foldNixPath [] $ \p mn ty rest ->
|
||||
pure $ valueThunk
|
||||
(flip nvSet mempty $ M.fromList
|
||||
|
@ -323,33 +339,33 @@ nixPath = fmap nvList $ flip foldNixPath [] $ \p mn ty rest ->
|
|||
, ("prefix", valueThunk $
|
||||
nvStr (hackyMakeNixStringWithoutContext $ Text.pack (fromMaybe "" mn))) ]) : rest
|
||||
|
||||
toString :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
toString :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
toString str = str >>= coerceToString DontCopyToStore CoerceAny >>= toNix
|
||||
|
||||
hasAttr :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
hasAttr :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
hasAttr x y =
|
||||
fromValue x >>= fromStringNoContext >>= \key ->
|
||||
fromValue @(AttrSet (NThunk m), AttrSet SourcePos) y >>= \(aset, _) ->
|
||||
fromValue @(AttrSet t, AttrSet SourcePos) y >>= \(aset, _) ->
|
||||
toNix $ M.member key aset
|
||||
|
||||
attrsetGet :: MonadNix e m => Text -> AttrSet t -> m t
|
||||
attrsetGet :: MonadBuiltins e t f m => Text -> AttrSet t -> m t
|
||||
attrsetGet k s = case M.lookup k s of
|
||||
Just v -> pure v
|
||||
Nothing ->
|
||||
throwError $ ErrorCall $ "Attribute '" ++ Text.unpack k ++ "' required"
|
||||
|
||||
hasContext :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
hasContext :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
hasContext =
|
||||
toNix . stringHasContext <=< fromValue
|
||||
|
||||
getAttr :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
getAttr :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
getAttr x y =
|
||||
fromValue x >>= fromStringNoContext >>= \key ->
|
||||
fromValue @(AttrSet (NThunk m), AttrSet SourcePos) y >>= \(aset, _) ->
|
||||
fromValue @(AttrSet t, AttrSet SourcePos) y >>= \(aset, _) ->
|
||||
attrsetGet key aset >>= force'
|
||||
|
||||
unsafeGetAttrPos :: forall e m. MonadNix e m
|
||||
=> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
unsafeGetAttrPos :: forall e t f m. MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
unsafeGetAttrPos x y = x >>= \x' -> y >>= \y' -> case (x', y') of
|
||||
(NVStr ns, NVSet _ apos) -> case M.lookup (hackyStringIgnoreContext ns) apos of
|
||||
Nothing -> pure $ nvConstant NNull
|
||||
|
@ -359,10 +375,10 @@ unsafeGetAttrPos x y = x >>= \x' -> y >>= \y' -> case (x', y') of
|
|||
|
||||
-- This function is a bit special in that it doesn't care about the contents
|
||||
-- of the list.
|
||||
length_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
length_ = toValue . (length :: [NThunk m] -> Int) <=< fromValue
|
||||
length_ :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
length_ = toValue . (length :: [t] -> Int) <=< fromValue
|
||||
|
||||
add_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
add_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
add_ x y = x >>= \x' -> y >>= \y' -> case (x', y') of
|
||||
(NVConstant (NInt x), NVConstant (NInt y)) ->
|
||||
toNix ( x + y :: Integer)
|
||||
|
@ -372,7 +388,7 @@ add_ x y = x >>= \x' -> y >>= \y' -> case (x', y') of
|
|||
(_, _) ->
|
||||
throwError $ Addition x' y'
|
||||
|
||||
mul_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
mul_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
mul_ x y = x >>= \x' -> y >>= \y' -> case (x', y') of
|
||||
(NVConstant (NInt x), NVConstant (NInt y)) ->
|
||||
toNix ( x * y :: Integer)
|
||||
|
@ -382,7 +398,7 @@ mul_ x y = x >>= \x' -> y >>= \y' -> case (x', y') of
|
|||
(_, _) ->
|
||||
throwError $ Multiplication x' y'
|
||||
|
||||
div_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
div_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
div_ x y = x >>= \x' -> y >>= \y' -> case (x', y') of
|
||||
(NVConstant (NInt x), NVConstant (NInt y)) | y /= 0 ->
|
||||
toNix (floor (fromInteger x / fromInteger y :: Double) :: Integer)
|
||||
|
@ -402,7 +418,7 @@ anyM p (x:xs) = do
|
|||
if q then return True
|
||||
else anyM p xs
|
||||
|
||||
any_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
any_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
any_ fun xs = fun >>= \f ->
|
||||
toNix <=< anyM fromValue <=< mapM ((f `callFunc`) . force')
|
||||
<=< fromValue $ xs
|
||||
|
@ -414,24 +430,24 @@ allM p (x:xs) = do
|
|||
if q then allM p xs
|
||||
else return False
|
||||
|
||||
all_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
all_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
all_ fun xs = fun >>= \f ->
|
||||
toNix <=< allM fromValue <=< mapM ((f `callFunc`) . force')
|
||||
<=< fromValue $ xs
|
||||
|
||||
foldl'_ :: forall e m. MonadNix e m
|
||||
=> m (NValue m) -> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
foldl'_ :: forall e t f m. MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
foldl'_ fun z xs =
|
||||
fun >>= \f -> fromValue @[NThunk m] xs >>= foldl' (go f) z
|
||||
fun >>= \f -> fromValue @[t] xs >>= foldl' (go f) z
|
||||
where
|
||||
go f b a = f `callFunc` b >>= (`callFunc` force' a)
|
||||
|
||||
head_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
head_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
head_ = fromValue >=> \case
|
||||
[] -> throwError $ ErrorCall "builtins.head: empty list"
|
||||
h:_ -> force' h
|
||||
|
||||
tail_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
tail_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
tail_ = fromValue >=> \case
|
||||
[] -> throwError $ ErrorCall "builtins.tail: empty list"
|
||||
_:t -> return $ nvList t
|
||||
|
@ -459,7 +475,11 @@ splitVersion s = case Text.uncons s of
|
|||
| h `elem` versionComponentSeparators -> splitVersion t
|
||||
| isDigit h ->
|
||||
let (digits, rest) = Text.span isDigit s
|
||||
in VersionComponent_Number (fromMaybe (error $ "splitVersion: couldn't parse " <> show digits) $ readMaybe $ Text.unpack digits) : splitVersion rest
|
||||
in VersionComponent_Number
|
||||
(fromMaybe (error $ "splitVersion: couldn't parse " <> show digits)
|
||||
$ readMaybe
|
||||
$ Text.unpack digits)
|
||||
: splitVersion rest
|
||||
| otherwise ->
|
||||
let (chars, rest) = Text.span (\c -> not $ isDigit c || c `elem` versionComponentSeparators) s
|
||||
thisComponent = case chars of
|
||||
|
@ -467,10 +487,12 @@ splitVersion s = case Text.uncons s of
|
|||
x -> VersionComponent_String x
|
||||
in thisComponent : splitVersion rest
|
||||
|
||||
splitVersion_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
splitVersion_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
splitVersion_ = fromValue >=> fromStringNoContext >=> \s ->
|
||||
return $ nvList $ flip map (splitVersion s) $ \c ->
|
||||
valueThunk $ nvStr $ principledMakeNixStringWithoutContext $ versionComponentToString c
|
||||
return $ nvList $ flip map (splitVersion s) $
|
||||
valueThunk . nvStr
|
||||
. principledMakeNixStringWithoutContext
|
||||
. versionComponentToString
|
||||
|
||||
compareVersions :: Text -> Text -> Ordering
|
||||
compareVersions s1 s2 =
|
||||
|
@ -479,7 +501,7 @@ compareVersions s1 s2 =
|
|||
z = VersionComponent_String ""
|
||||
f = uncurry compare . fromThese z z
|
||||
|
||||
compareVersions_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
compareVersions_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
compareVersions_ t1 t2 =
|
||||
fromValue t1 >>= fromStringNoContext >>= \s1 ->
|
||||
fromValue t2 >>= fromStringNoContext >>= \s2 ->
|
||||
|
@ -507,19 +529,19 @@ splitDrvName s =
|
|||
breakAfterFirstItem isFirstVersionPiece pieces
|
||||
in (Text.intercalate sep namePieces, Text.intercalate sep versionPieces)
|
||||
|
||||
parseDrvName :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
parseDrvName :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
parseDrvName = fromValue >=> fromStringNoContext >=> \s -> do
|
||||
let (name :: Text, version :: Text) = splitDrvName s
|
||||
-- jww (2018-04-15): There should be an easier way to write this.
|
||||
(toValue =<<) $ sequence $ M.fromList
|
||||
[ ("name" :: Text,
|
||||
thunk @_ @(NThunk m)
|
||||
thunk @t
|
||||
(toValue $ principledMakeNixStringWithoutContext name))
|
||||
, ("version",
|
||||
thunk @_ @(NThunk m)
|
||||
thunk @t
|
||||
(toValue $ principledMakeNixStringWithoutContext version)) ]
|
||||
|
||||
match_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
match_ :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
match_ pat str =
|
||||
fromValue pat >>= fromStringNoContext >>= \p ->
|
||||
fromValue str >>= \ns -> do
|
||||
|
@ -540,7 +562,7 @@ match_ pat str =
|
|||
(if length s > 1 then tail s else s)
|
||||
_ -> pure $ nvConstant NNull
|
||||
|
||||
split_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
split_ :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
split_ pat str =
|
||||
fromValue pat >>= fromStringNoContext >>= \p ->
|
||||
fromValue str >>= \ns -> do
|
||||
|
@ -555,11 +577,11 @@ split_ pat str =
|
|||
splitMatches 0 (map elems $ matchAllText re haystack) haystack
|
||||
|
||||
splitMatches
|
||||
:: forall e m. MonadNix e m
|
||||
:: forall e t f m. MonadBuiltins e t f m
|
||||
=> Int
|
||||
-> [[(ByteString, (Int, Int))]]
|
||||
-> ByteString
|
||||
-> [NThunk m]
|
||||
-> [t]
|
||||
splitMatches _ [] haystack = [thunkStr haystack]
|
||||
splitMatches _ ([]:_) _ = error "Error in splitMatches: this should never happen!"
|
||||
splitMatches numDropped (((_,(start,len)):captures):mts) haystack =
|
||||
|
@ -572,86 +594,88 @@ splitMatches numDropped (((_,(start,len)):captures):mts) haystack =
|
|||
|
||||
thunkStr s = valueThunk (nvStr (hackyMakeNixStringWithoutContext (decodeUtf8 s)))
|
||||
|
||||
substring :: MonadNix e m => Int -> Int -> NixString -> Prim m NixString
|
||||
substring :: MonadBuiltins e t f m => Int -> Int -> NixString -> Prim m NixString
|
||||
substring start len str = Prim $
|
||||
if start < 0 --NOTE: negative values of 'len' are OK
|
||||
then throwError $ ErrorCall $ "builtins.substring: negative start position: " ++ show start
|
||||
else pure $ principledModifyNixContents (Text.take len . Text.drop start) str
|
||||
|
||||
attrNames :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
attrNames = fromValue @(ValueSet m) >=> toNix . map principledMakeNixStringWithoutContext . sort . M.keys
|
||||
attrNames :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
attrNames = fromValue @(AttrSet t)
|
||||
>=> toNix . map principledMakeNixStringWithoutContext . sort . M.keys
|
||||
|
||||
attrValues :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
attrValues = fromValue @(ValueSet m) >=>
|
||||
toValue . fmap snd . sortOn (fst @Text @(NThunk m)) . M.toList
|
||||
attrValues :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
attrValues = fromValue @(AttrSet t) >=>
|
||||
toValue . fmap snd . sortOn (fst @Text @t) . M.toList
|
||||
|
||||
map_ :: forall e m. MonadNix e m
|
||||
=> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
map_ :: forall e t f m. MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
map_ fun xs = fun >>= \f ->
|
||||
toNix <=< traverse (thunk @_ @(NThunk m) . withFrame Debug
|
||||
(ErrorCall "While applying f in map:\n")
|
||||
. (f `callFunc`) . force')
|
||||
<=< fromValue @[NThunk m] $ xs
|
||||
toNix <=< traverse (thunk @t . withFrame Debug
|
||||
(ErrorCall "While applying f in map:\n")
|
||||
. (f `callFunc`) . force')
|
||||
<=< fromValue @[t] $ xs
|
||||
|
||||
mapAttrs_ :: forall e m. MonadNix e m
|
||||
=> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
mapAttrs_ :: forall e t f m. MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
mapAttrs_ fun xs = fun >>= \f ->
|
||||
fromValue @(AttrSet (NThunk m)) xs >>= \aset -> do
|
||||
fromValue @(AttrSet t) xs >>= \aset -> do
|
||||
let pairs = M.toList aset
|
||||
values <- for pairs $ \(key, value) ->
|
||||
thunk @_ @(NThunk m) $
|
||||
thunk @t $
|
||||
withFrame Debug (ErrorCall "While applying f in mapAttrs:\n") $
|
||||
callFunc ?? force' value =<< callFunc f (pure (nvStr (principledMakeNixStringWithoutContext key)))
|
||||
callFunc ?? force' value
|
||||
=<< callFunc f (pure (nvStr (principledMakeNixStringWithoutContext key)))
|
||||
toNix . M.fromList . zip (map fst pairs) $ values
|
||||
|
||||
filter_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
filter_ :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
filter_ fun xs = fun >>= \f ->
|
||||
toNix <=< filterM (fromValue <=< callFunc f . force')
|
||||
<=< fromValue @[NThunk m] $ xs
|
||||
<=< fromValue @[t] $ xs
|
||||
|
||||
catAttrs :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
catAttrs :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
catAttrs attrName xs =
|
||||
fromValue attrName >>= fromStringNoContext >>= \n ->
|
||||
fromValue @[NThunk m] xs >>= \l ->
|
||||
fromValue @[t] xs >>= \l ->
|
||||
fmap (nvList . catMaybes) $
|
||||
forM l $ fmap (M.lookup n) . fromValue
|
||||
|
||||
baseNameOf :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
baseNameOf :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
baseNameOf x = do
|
||||
ns <- coerceToString DontCopyToStore CoerceStringy =<< x
|
||||
pure $ nvStr (principledModifyNixContents (Text.pack . takeFileName . Text.unpack) ns)
|
||||
|
||||
bitAnd :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
bitAnd :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
bitAnd x y =
|
||||
fromValue @Integer x >>= \a ->
|
||||
fromValue @Integer y >>= \b -> toNix (a .&. b)
|
||||
|
||||
bitOr :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
bitOr :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
bitOr x y =
|
||||
fromValue @Integer x >>= \a ->
|
||||
fromValue @Integer y >>= \b -> toNix (a .|. b)
|
||||
|
||||
bitXor :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
bitXor :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
bitXor x y =
|
||||
fromValue @Integer x >>= \a ->
|
||||
fromValue @Integer y >>= \b -> toNix (a `xor` b)
|
||||
|
||||
dirOf :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
dirOf :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
dirOf x = x >>= \case
|
||||
NVStr ns -> pure $ nvStr (principledModifyNixContents (Text.pack . takeDirectory . Text.unpack) ns)
|
||||
NVPath path -> pure $ nvPath $ takeDirectory path
|
||||
v -> throwError $ ErrorCall $ "dirOf: expected string or path, got " ++ show v
|
||||
|
||||
-- jww (2018-04-28): This should only be a string argument, and not coerced?
|
||||
unsafeDiscardStringContext :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
unsafeDiscardStringContext :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
unsafeDiscardStringContext mnv = do
|
||||
ns <- fromValue mnv
|
||||
toNix $ principledMakeNixStringWithoutContext $ principledStringIgnoreContext ns
|
||||
|
||||
seq_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
seq_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
seq_ a b = a >> b
|
||||
|
||||
deepSeq :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
deepSeq :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
deepSeq a b = do
|
||||
-- We evaluate 'a' only for its effects, so data cycles are ignored.
|
||||
normalForm_ =<< a
|
||||
|
@ -661,34 +685,34 @@ deepSeq a b = do
|
|||
-- recursive data structures in Haskell).
|
||||
b
|
||||
|
||||
elem_ :: forall e m. MonadNix e m
|
||||
=> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
elem_ :: forall e t f m. MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
elem_ x xs = x >>= \x' ->
|
||||
toValue <=< anyM (valueEq x' <=< force') <=< fromValue @[NThunk m] $ xs
|
||||
toValue <=< anyM (valueEq x' <=< force') <=< fromValue @[t] $ xs
|
||||
|
||||
elemAt :: [a] -> Int -> Maybe a
|
||||
elemAt ls i = case drop i ls of
|
||||
[] -> Nothing
|
||||
a:_ -> Just a
|
||||
|
||||
elemAt_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
elemAt_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
elemAt_ xs n = fromValue n >>= \n' -> fromValue xs >>= \xs' ->
|
||||
case elemAt xs' n' of
|
||||
Just a -> force' a
|
||||
Nothing -> throwError $ ErrorCall $ "builtins.elem: Index " ++ show n'
|
||||
++ " too large for list of length " ++ show (length xs')
|
||||
|
||||
genList :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
genList :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
genList generator = fromValue @Integer >=> \n ->
|
||||
if n >= 0
|
||||
then generator >>= \f ->
|
||||
toNix =<< forM [0 .. n - 1]
|
||||
(\i -> thunk @_ @(NThunk m) $ f `callFunc` toNix i)
|
||||
(\i -> thunk @t $ f `callFunc` toNix i)
|
||||
else throwError $ ErrorCall $ "builtins.genList: Expected a non-negative number, got "
|
||||
++ show n
|
||||
|
||||
genericClosure :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
genericClosure = fromValue @(AttrSet (NThunk m)) >=> \s ->
|
||||
genericClosure :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
genericClosure = fromValue @(AttrSet t) >=> \s ->
|
||||
case (M.lookup "startSet" s, M.lookup "operator" s) of
|
||||
(Nothing, Nothing) ->
|
||||
throwError $ ErrorCall $
|
||||
|
@ -701,15 +725,15 @@ genericClosure = fromValue @(AttrSet (NThunk m)) >=> \s ->
|
|||
throwError $ ErrorCall $
|
||||
"builtins.genericClosure: Attribute 'operator' required"
|
||||
(Just startSet, Just operator) ->
|
||||
fromValue @[NThunk m] startSet >>= \ss ->
|
||||
fromValue @[t] startSet >>= \ss ->
|
||||
force operator $ \op ->
|
||||
toValue @[NThunk m] =<< snd <$> go op ss S.empty
|
||||
toValue @[t] =<< snd <$> go op ss S.empty
|
||||
where
|
||||
go :: NValue m -> [NThunk m] -> Set (NValue m)
|
||||
-> m (Set (NValue m), [NThunk m])
|
||||
go :: NValue t f m -> [t] -> Set (NValue t f m)
|
||||
-> m (Set (NValue t f m), [t])
|
||||
go _ [] ks = pure (ks, [])
|
||||
go op (t:ts) ks =
|
||||
force t $ \v -> fromValue @(AttrSet (NThunk m)) t >>= \s ->
|
||||
force t $ \v -> fromValue @(AttrSet t) t >>= \s ->
|
||||
case M.lookup "key" s of
|
||||
Nothing ->
|
||||
throwError $ ErrorCall $
|
||||
|
@ -718,13 +742,13 @@ genericClosure = fromValue @(AttrSet (NThunk m)) >=> \s ->
|
|||
if S.member k' ks
|
||||
then go op ts ks
|
||||
else do
|
||||
ys <- fromValue @[NThunk m] =<< (op `callFunc` pure v)
|
||||
ys <- fromValue @[t] =<< (op `callFunc` pure v)
|
||||
case S.toList ks of
|
||||
[] -> checkComparable k' k'
|
||||
j:_ -> checkComparable k' j
|
||||
fmap (t:) <$> go op (ts ++ ys) (S.insert k' ks)
|
||||
|
||||
replaceStrings :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
replaceStrings :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
replaceStrings tfrom tto ts =
|
||||
fromNix tfrom >>= \(nsFrom :: [NixString]) ->
|
||||
fromNix tto >>= \(nsTo :: [NixString]) ->
|
||||
|
@ -758,28 +782,28 @@ replaceStrings tfrom tto ts =
|
|||
_ -> go rest (result <> Builder.fromText replacement) (ctx <> newCtx)
|
||||
toNix $ go (principledStringIgnoreContext ns) mempty $ principledGetContext ns
|
||||
|
||||
removeAttrs :: forall e m. MonadNix e m
|
||||
=> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
removeAttrs :: forall e t f m. MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
removeAttrs set = fromNix >=> \(nsToRemove :: [NixString]) ->
|
||||
fromValue @(AttrSet (NThunk m),
|
||||
fromValue @(AttrSet t,
|
||||
AttrSet SourcePos) set >>= \(m, p) -> do
|
||||
toRemove <- mapM fromStringNoContext nsToRemove
|
||||
toNix (go m toRemove, go p toRemove)
|
||||
where
|
||||
go = foldl' (flip M.delete)
|
||||
|
||||
intersectAttrs :: forall e m. MonadNix e m
|
||||
=> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
intersectAttrs :: forall e t f m. MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
intersectAttrs set1 set2 =
|
||||
fromValue @(AttrSet (NThunk m),
|
||||
fromValue @(AttrSet t,
|
||||
AttrSet SourcePos) set1 >>= \(s1, p1) ->
|
||||
fromValue @(AttrSet (NThunk m),
|
||||
fromValue @(AttrSet t,
|
||||
AttrSet SourcePos) set2 >>= \(s2, p2) ->
|
||||
return $ nvSet (s2 `M.intersection` s1) (p2 `M.intersection` p1)
|
||||
|
||||
functionArgs :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
functionArgs :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
functionArgs fun = fun >>= \case
|
||||
NVClosure p _ -> toValue @(AttrSet (NThunk m)) $
|
||||
NVClosure p _ -> toValue @(AttrSet t) $
|
||||
valueThunk . nvConstant . NBool <$>
|
||||
case p of
|
||||
Param name -> M.singleton name False
|
||||
|
@ -787,7 +811,7 @@ functionArgs fun = fun >>= \case
|
|||
v -> throwError $ ErrorCall $
|
||||
"builtins.functionArgs: expected function, got " ++ show v
|
||||
|
||||
toFile :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
toFile :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
toFile name s = do
|
||||
name' <- fromStringNoContext =<< fromValue name
|
||||
s' <- fromValue s
|
||||
|
@ -799,74 +823,74 @@ toFile name s = do
|
|||
sc = StringContext t DirectPath
|
||||
toNix $ principledMakeNixStringWithSingletonContext t sc
|
||||
|
||||
toPath :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
toPath :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
toPath = fromValue @Path >=> toNix @Path
|
||||
|
||||
pathExists_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
pathExists_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
pathExists_ path = path >>= \case
|
||||
NVPath p -> toNix =<< pathExists p
|
||||
NVStr ns -> toNix =<< pathExists (Text.unpack (hackyStringIgnoreContext ns))
|
||||
v -> throwError $ ErrorCall $
|
||||
"builtins.pathExists: expected path, got " ++ show v
|
||||
|
||||
hasKind :: forall a e m. (MonadNix e m, FromValue a m (NValue m))
|
||||
=> m (NValue m) -> m (NValue m)
|
||||
hasKind :: forall a e t f m. (MonadBuiltins e t f m, FromValue a m (NValue t f m))
|
||||
=> m (NValue t f m) -> m (NValue t f m)
|
||||
hasKind = fromValueMay >=> toNix . \case Just (_ :: a) -> True; _ -> False
|
||||
|
||||
isAttrs :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
isAttrs = hasKind @(ValueSet m)
|
||||
isAttrs :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
isAttrs = hasKind @(AttrSet t)
|
||||
|
||||
isList :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
isList = hasKind @[NThunk m]
|
||||
isList :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
isList = hasKind @[t]
|
||||
|
||||
isString :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
isString :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
isString = hasKind @NixString
|
||||
|
||||
isInt :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
isInt :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
isInt = hasKind @Int
|
||||
|
||||
isFloat :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
isFloat :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
isFloat = hasKind @Float
|
||||
|
||||
isBool :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
isBool :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
isBool = hasKind @Bool
|
||||
|
||||
isNull :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
isNull :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
isNull = hasKind @()
|
||||
|
||||
isFunction :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
isFunction :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
isFunction func = func >>= \case
|
||||
NVClosure {} -> toValue True
|
||||
_ -> toValue False
|
||||
|
||||
throw_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
throw_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
throw_ mnv = do
|
||||
ns <- coerceToString CopyToStore CoerceStringy =<< mnv
|
||||
throwError . ErrorCall . Text.unpack $ principledStringIgnoreContext ns
|
||||
|
||||
import_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
import_ :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
import_ = scopedImport (pure (nvSet M.empty M.empty))
|
||||
|
||||
scopedImport :: forall e m. MonadNix e m
|
||||
=> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
scopedImport :: forall e t f m. MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
scopedImport asetArg pathArg =
|
||||
fromValue @(AttrSet (NThunk m)) asetArg >>= \s ->
|
||||
fromValue @(AttrSet t) asetArg >>= \s ->
|
||||
fromValue pathArg >>= \(Path p) -> do
|
||||
path <- pathToDefaultNix p
|
||||
path <- pathToDefaultNix @t @f @m p
|
||||
mres <- lookupVar "__cur_file"
|
||||
path' <- case mres of
|
||||
Nothing -> do
|
||||
traceM "No known current directory"
|
||||
return path
|
||||
Just p -> fromValue @_ @_ @(NThunk m) p >>= \(Path p') -> do
|
||||
Just p -> fromValue @_ @_ @t p >>= \(Path p') -> do
|
||||
traceM $ "Current file being evaluated is: " ++ show p'
|
||||
return $ takeDirectory p' </> path
|
||||
clearScopes @(NThunk m) $
|
||||
clearScopes @t $
|
||||
withNixContext (Just path') $
|
||||
pushScope s $
|
||||
importPath @m path'
|
||||
importPath @t @f @m path'
|
||||
|
||||
getEnv_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
getEnv_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
getEnv_ = fromValue >=> fromStringNoContext >=> \s -> do
|
||||
mres <- getEnvVar (Text.unpack s)
|
||||
toNix $ principledMakeNixStringWithoutContext $
|
||||
|
@ -874,7 +898,7 @@ getEnv_ = fromValue >=> fromStringNoContext >=> \s -> do
|
|||
Nothing -> ""
|
||||
Just v -> Text.pack v
|
||||
|
||||
sort_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
sort_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
sort_ comparator xs = comparator >>= \comp ->
|
||||
fromValue xs >>= sortByM (cmp comp) >>= toValue
|
||||
where
|
||||
|
@ -888,7 +912,7 @@ sort_ comparator xs = comparator >>= \comp ->
|
|||
True -> GT
|
||||
False -> EQ
|
||||
|
||||
lessThan :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
lessThan :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
lessThan ta tb = ta >>= \va -> tb >>= \vb -> do
|
||||
let badType = throwError $ ErrorCall $
|
||||
"builtins.lessThan: expected two numbers or two strings, "
|
||||
|
@ -903,15 +927,15 @@ lessThan ta tb = ta >>= \va -> tb >>= \vb -> do
|
|||
(NVStr a, NVStr b) -> pure $ principledStringIgnoreContext a < principledStringIgnoreContext b
|
||||
_ -> badType
|
||||
|
||||
concatLists :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
concatLists = fromValue @[NThunk m]
|
||||
>=> mapM (fromValue @[NThunk m] >=> pure)
|
||||
concatLists :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
concatLists = fromValue @[t]
|
||||
>=> mapM (fromValue @[t] >=> pure)
|
||||
>=> toValue . concat
|
||||
|
||||
listToAttrs :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
listToAttrs = fromValue @[NThunk m] >=> \l ->
|
||||
listToAttrs :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
listToAttrs = fromValue @[t] >=> \l ->
|
||||
fmap (flip nvSet M.empty . M.fromList . reverse) $
|
||||
forM l $ fromValue @(AttrSet (NThunk m)) >=> \s -> do
|
||||
forM l $ fromValue @(AttrSet t) >=> \s -> do
|
||||
name <- fromStringNoContext =<< fromValue =<< attrsetGet "name" s
|
||||
val <- attrsetGet "value" s
|
||||
pure (name, val)
|
||||
|
@ -919,7 +943,7 @@ listToAttrs = fromValue @[NThunk m] >=> \l ->
|
|||
-- prim_hashString from nix/src/libexpr/primops.cc
|
||||
-- fail if context in the algo arg
|
||||
-- propagate context from the s arg
|
||||
hashString :: MonadNix e m => NixString -> NixString -> Prim m NixString
|
||||
hashString :: MonadBuiltins e t f m => NixString -> NixString -> Prim m NixString
|
||||
hashString nsAlgo ns = Prim $ do
|
||||
algo <- fromStringNoContext nsAlgo
|
||||
let f g = pure $ principledModifyNixContents g ns
|
||||
|
@ -951,7 +975,7 @@ hashString nsAlgo ns = Prim $ do
|
|||
_ -> throwError $ ErrorCall $ "builtins.hashString: "
|
||||
++ "expected \"md5\", \"sha1\", \"sha256\", or \"sha512\", got " ++ show algo
|
||||
|
||||
placeHolder :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
placeHolder :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
placeHolder = fromValue >=> fromStringNoContext >=> \t -> do
|
||||
h <- runPrim (hashString (principledMakeNixStringWithoutContext "sha256")
|
||||
(principledMakeNixStringWithoutContext ("nix-output:" <> t)))
|
||||
|
@ -959,7 +983,7 @@ placeHolder = fromValue >=> fromStringNoContext >=> \t -> do
|
|||
-- The result coming out of hashString is base16 encoded
|
||||
fst $ Base16.decode $ encodeUtf8 $ principledStringIgnoreContext h
|
||||
|
||||
absolutePathFromValue :: MonadNix e m => NValue m -> m FilePath
|
||||
absolutePathFromValue :: MonadBuiltins e t f m => NValue t f m -> m FilePath
|
||||
absolutePathFromValue = \case
|
||||
NVStr ns -> do
|
||||
let path = Text.unpack $ hackyStringIgnoreContext ns
|
||||
|
@ -969,18 +993,18 @@ absolutePathFromValue = \case
|
|||
NVPath path -> pure path
|
||||
v -> throwError $ ErrorCall $ "expected a path, got " ++ show v
|
||||
|
||||
readFile_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
readFile_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
readFile_ path =
|
||||
path >>= absolutePathFromValue >>= Nix.Render.readFile >>= toNix
|
||||
|
||||
findFile_ :: forall e m. MonadNix e m
|
||||
=> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
findFile_ :: forall e t f m. MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
findFile_ aset filePath =
|
||||
aset >>= \aset' ->
|
||||
filePath >>= \filePath' ->
|
||||
case (aset', filePath') of
|
||||
(NVList x, NVStr ns) -> do
|
||||
mres <- findPath x (Text.unpack (hackyStringIgnoreContext ns))
|
||||
mres <- findPath @t @f @m x (Text.unpack (hackyStringIgnoreContext ns))
|
||||
pure $ nvPath mres
|
||||
(NVList _, y) -> throwError $ ErrorCall $ "expected a string, got " ++ show y
|
||||
(x, NVStr _) -> throwError $ ErrorCall $ "expected a list, got " ++ show x
|
||||
|
@ -993,14 +1017,14 @@ data FileType
|
|||
| FileTypeUnknown
|
||||
deriving (Show, Read, Eq, Ord)
|
||||
|
||||
instance Applicative m => ToNix FileType m (NValue m) where
|
||||
instance Convertible e t f m => ToNix FileType m (NValue t f m) where
|
||||
toNix = toNix . principledMakeNixStringWithoutContext . \case
|
||||
FileTypeRegular -> "regular" :: Text
|
||||
FileTypeDirectory -> "directory"
|
||||
FileTypeSymlink -> "symlink"
|
||||
FileTypeUnknown -> "unknown"
|
||||
|
||||
readDir_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
readDir_ :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
readDir_ pathThunk = do
|
||||
path <- absolutePathFromValue =<< pathThunk
|
||||
items <- listDirectory path
|
||||
|
@ -1014,7 +1038,8 @@ readDir_ pathThunk = do
|
|||
pure (Text.pack item, t)
|
||||
toNix (M.fromList itemsWithTypes)
|
||||
|
||||
fromJSON :: forall e m. (MonadNix e m, Typeable m) => m (NValue m) -> m (NValue m)
|
||||
fromJSON :: forall e t f m. MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m)
|
||||
fromJSON = fromValue >=> fromStringNoContext >=> \encoded ->
|
||||
case A.eitherDecodeStrict' @A.Value $ encodeUtf8 encoded of
|
||||
Left jsonError ->
|
||||
|
@ -1025,8 +1050,10 @@ fromJSON = fromValue >=> fromStringNoContext >=> \encoded ->
|
|||
A.Object m -> flip nvSet M.empty
|
||||
<$> traverse (thunk . jsonToNValue) m
|
||||
A.Array l -> nvList <$>
|
||||
traverse (\x -> thunk . whileForcingThunk (CoercionFromJson @m x)
|
||||
. jsonToNValue $ x) (V.toList l)
|
||||
traverse (\x -> thunk @t @m @(NValue t f m)
|
||||
. whileForcingThunk @t @f (CoercionFromJson @t @f @m x)
|
||||
. jsonToNValue $ x)
|
||||
(V.toList l)
|
||||
A.String s -> pure $ nvStr $ hackyMakeNixStringWithoutContext s
|
||||
A.Number n -> pure $ nvConstant $ case floatingOrInteger n of
|
||||
Left r -> NFloat r
|
||||
|
@ -1035,15 +1062,15 @@ fromJSON = fromValue >=> fromStringNoContext >=> \encoded ->
|
|||
A.Null -> pure $ nvConstant NNull
|
||||
|
||||
prim_toJSON
|
||||
:: MonadNix e m
|
||||
=> m (NValue m)
|
||||
-> m (NValue m)
|
||||
:: MonadBuiltins e t f m
|
||||
=> m (NValue t f m)
|
||||
-> m (NValue t f m)
|
||||
prim_toJSON x = x >>= nvalueToJSONNixString >>= pure . nvStr
|
||||
|
||||
toXML_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
toXML_ :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
toXML_ v = v >>= normalForm >>= pure . nvStr . toXML
|
||||
|
||||
typeOf :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
typeOf :: MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
typeOf v = v >>= toNix . principledMakeNixStringWithoutContext . \case
|
||||
NVConstant a -> case a of
|
||||
NInt _ -> "int"
|
||||
|
@ -1058,7 +1085,7 @@ typeOf v = v >>= toNix . principledMakeNixStringWithoutContext . \case
|
|||
NVBuiltin _ _ -> "lambda"
|
||||
_ -> error "Pattern synonyms obscure complete patterns"
|
||||
|
||||
tryEval :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
tryEval :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
tryEval e = catch (onSuccess <$> e) (pure . onError)
|
||||
where
|
||||
onSuccess v = flip nvSet M.empty $ M.fromList
|
||||
|
@ -1066,38 +1093,43 @@ tryEval e = catch (onSuccess <$> e) (pure . onError)
|
|||
, ("value", valueThunk v)
|
||||
]
|
||||
|
||||
onError :: SomeException -> NValue m
|
||||
onError :: SomeException -> NValue t f m
|
||||
onError _ = flip nvSet M.empty $ M.fromList
|
||||
[ ("success", valueThunk (nvConstant (NBool False)))
|
||||
, ("value", valueThunk (nvConstant (NBool False)))
|
||||
]
|
||||
|
||||
trace_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
trace_ :: forall e t f m. MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
trace_ msg action = do
|
||||
traceEffect . Text.unpack . principledStringIgnoreContext =<< fromValue msg
|
||||
traceEffect @t @f @m
|
||||
. Text.unpack
|
||||
. principledStringIgnoreContext
|
||||
=<< fromValue msg
|
||||
action
|
||||
|
||||
-- TODO: remember error context
|
||||
addErrorContext :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
addErrorContext :: forall e t f m. MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
addErrorContext _ action = action
|
||||
|
||||
exec_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
exec_ :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
exec_ xs = do
|
||||
ls <- fromValue @[NThunk m] xs
|
||||
ls <- fromValue @[t] xs
|
||||
xs <- traverse (coerceToString DontCopyToStore CoerceStringy <=< force') ls
|
||||
-- TODO Still need to do something with the context here
|
||||
-- See prim_exec in nix/src/libexpr/primops.cc
|
||||
-- Requires the implementation of EvalState::realiseContext
|
||||
exec (map (Text.unpack . hackyStringIgnoreContext) xs)
|
||||
|
||||
fetchurl :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
fetchurl :: forall e t f m. MonadBuiltins e t f m => m (NValue t f m) -> m (NValue t f m)
|
||||
fetchurl v = v >>= \case
|
||||
NVSet s _ -> attrsetGet "url" s >>= force ?? (go (M.lookup "sha256" s))
|
||||
v@NVStr {} -> go Nothing v
|
||||
v -> throwError $ ErrorCall $ "builtins.fetchurl: Expected URI or set, got "
|
||||
++ show v
|
||||
where
|
||||
go :: Maybe (NThunk m) -> NValue m -> m (NValue m)
|
||||
go :: Maybe t -> NValue t f m -> m (NValue t f m)
|
||||
go _msha = \case
|
||||
NVStr ns -> noContextAttrs ns >>= getURL >>= \case -- msha
|
||||
Left e -> throwError e
|
||||
|
@ -1110,41 +1142,45 @@ fetchurl v = v >>= \case
|
|||
"builtins.fetchurl: unsupported arguments to url"
|
||||
Just t -> pure t
|
||||
|
||||
partition_ :: forall e m. MonadNix e m
|
||||
=> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||
partition_ :: forall e t f m. MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)
|
||||
partition_ fun xs = fun >>= \f ->
|
||||
fromValue @[NThunk m] xs >>= \l -> do
|
||||
fromValue @[t] xs >>= \l -> do
|
||||
let match t = f `callFunc` force' t >>= fmap (, t) . fromValue
|
||||
selection <- traverse match l
|
||||
let (right, wrong) = partition fst selection
|
||||
let makeSide = valueThunk . nvList . map snd
|
||||
toValue @(AttrSet (NThunk m)) $
|
||||
toValue @(AttrSet t) $
|
||||
M.fromList [("right", makeSide right), ("wrong", makeSide wrong)]
|
||||
|
||||
currentSystem :: MonadNix e m => m (NValue m)
|
||||
currentSystem :: MonadBuiltins e t f m => m (NValue t f m)
|
||||
currentSystem = do
|
||||
os <- getCurrentSystemOS
|
||||
arch <- getCurrentSystemArch
|
||||
return $ nvStr $ principledMakeNixStringWithoutContext (arch <> "-" <> os)
|
||||
|
||||
currentTime_ :: MonadNix e m => m (NValue m)
|
||||
currentTime_ :: MonadBuiltins e t f m => m (NValue t f m)
|
||||
currentTime_ = do
|
||||
opts :: Options <- asks (view hasLens)
|
||||
toNix @Integer $ round $ Time.utcTimeToPOSIXSeconds (currentTime opts)
|
||||
|
||||
derivationStrict_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
derivationStrict_ :: MonadBuiltins e t f m
|
||||
=> m (NValue t f m) -> m (NValue t f m)
|
||||
derivationStrict_ = (>>= derivationStrict)
|
||||
|
||||
newtype Prim m a = Prim { runPrim :: m a }
|
||||
|
||||
-- | Types that support conversion to nix in a particular monad
|
||||
class ToBuiltin m a | a -> m where
|
||||
toBuiltin :: String -> a -> m (NValue m)
|
||||
class ToBuiltin t f m a | a -> m where
|
||||
toBuiltin :: String -> a -> m (NValue t f m)
|
||||
|
||||
instance (MonadNix e m, ToNix a m (NValue m))
|
||||
=> ToBuiltin m (Prim m a) where
|
||||
instance (MonadBuiltins e t f m, ToNix a m (NValue t f m))
|
||||
=> ToBuiltin t f m (Prim m a) where
|
||||
toBuiltin _ p = toNix =<< runPrim p
|
||||
|
||||
instance (MonadNix e m, FromNix a m (NValue m), ToBuiltin m b)
|
||||
=> ToBuiltin m (a -> b) where
|
||||
toBuiltin name f = return $ nvBuiltin name (fromNix >=> toBuiltin name . f)
|
||||
instance ( MonadBuiltins e t f m
|
||||
, FromNix a m (NValue t f m)
|
||||
, ToBuiltin t f m b)
|
||||
=> ToBuiltin t f m (a -> b) where
|
||||
toBuiltin name f = return $ nvBuiltin name
|
||||
(fromNix >=> fmap wrapValue . toBuiltin name . f)
|
||||
|
|
66
src/Nix/Cited.hs
Normal file
66
src/Nix/Cited.hs
Normal file
|
@ -0,0 +1,66 @@
|
|||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE DeriveFoldable #-}
|
||||
{-# LANGUAGE DeriveFunctor #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE DeriveTraversable #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
|
||||
{-# OPTIONS_GHC -Wno-missing-signatures #-}
|
||||
|
||||
module Nix.Cited where
|
||||
|
||||
import Control.Comonad
|
||||
import Control.Comonad.Env
|
||||
import Data.Typeable (Typeable)
|
||||
import GHC.Generics
|
||||
import Lens.Family2.TH
|
||||
|
||||
import Nix.Expr.Types.Annotated
|
||||
import Nix.Scope
|
||||
import Nix.Value
|
||||
|
||||
data Provenance t f m = Provenance
|
||||
{ _lexicalScope :: Scopes m t
|
||||
, _originExpr :: NExprLocF (Maybe (NValue t f m))
|
||||
-- ^ When calling the function x: x + 2 with argument x = 3, the
|
||||
-- 'originExpr' for the resulting value will be 3 + 2, while the
|
||||
-- 'contextExpr' will be @(x: x + 2) 3@, preserving not only the
|
||||
-- result of the call, but what was called and with what arguments.
|
||||
}
|
||||
deriving (Generic, Typeable, Show)
|
||||
|
||||
data NCited t f m a = NCited
|
||||
{ _provenance :: [Provenance t f m]
|
||||
, _cited :: a
|
||||
}
|
||||
deriving (Generic, Typeable, Functor, Foldable, Traversable, Show)
|
||||
|
||||
instance Applicative (NCited t f m) where
|
||||
pure = NCited []
|
||||
-- jww (2019-03-11): ??
|
||||
NCited xs f <*> NCited ys x = NCited (xs <> ys) (f x)
|
||||
|
||||
instance Comonad (NCited t f m) where
|
||||
duplicate p = NCited (_provenance p) p
|
||||
extract = _cited
|
||||
|
||||
instance ComonadEnv [Provenance t f m] (NCited t f m) where
|
||||
ask = _provenance
|
||||
|
||||
$(makeLenses ''Provenance)
|
||||
$(makeLenses ''NCited)
|
||||
|
||||
class HasCitations t f m a where
|
||||
citations :: a -> [Provenance t f m]
|
||||
addProvenance :: Provenance t f m -> a -> a
|
||||
|
||||
instance HasCitations t f m (NCited t f m a) where
|
||||
citations = _provenance
|
||||
addProvenance x (NCited p v) = (NCited (x : p) v)
|
||||
|
||||
class HasCitations1 t f m where
|
||||
citations1 :: f a -> [Provenance t f m]
|
||||
addProvenance1 :: Provenance t f m -> f a -> f a
|
|
@ -10,24 +10,24 @@ import Nix.Frames
|
|||
import Nix.Utils
|
||||
import Nix.Expr.Types.Annotated (SrcSpan, nullSpan)
|
||||
|
||||
data Context m v = Context
|
||||
{ scopes :: Scopes m v
|
||||
data Context m t = Context
|
||||
{ scopes :: Scopes m t
|
||||
, source :: SrcSpan
|
||||
, frames :: Frames
|
||||
, options :: Options
|
||||
}
|
||||
|
||||
instance Has (Context m v) (Scopes m v) where
|
||||
instance Has (Context m t) (Scopes m t) where
|
||||
hasLens f (Context x y z w) = (\x' -> Context x' y z w) <$> f x
|
||||
|
||||
instance Has (Context m v) SrcSpan where
|
||||
instance Has (Context m t) SrcSpan where
|
||||
hasLens f (Context x y z w) = (\y' -> Context x y' z w) <$> f y
|
||||
|
||||
instance Has (Context m v) Frames where
|
||||
instance Has (Context m t) Frames where
|
||||
hasLens f (Context x y z w) = (\z' -> Context x y z' w) <$> f z
|
||||
|
||||
instance Has (Context m v) Options where
|
||||
instance Has (Context m t) Options where
|
||||
hasLens f (Context x y z w) = (\w' -> Context x y z w') <$> f w
|
||||
|
||||
newContext :: Options -> Context m v
|
||||
newContext :: Options -> Context m t
|
||||
newContext = Context emptyScopes nullSpan []
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE TypeSynonymInstances #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
|
||||
{-# OPTIONS_GHC -Wno-missing-signatures #-}
|
||||
|
@ -26,7 +28,6 @@
|
|||
module Nix.Convert where
|
||||
|
||||
import Control.Monad
|
||||
import Control.Monad.Free
|
||||
import Data.ByteString
|
||||
import Data.HashMap.Lazy (HashMap)
|
||||
import qualified Data.HashMap.Lazy as M
|
||||
|
@ -40,9 +41,7 @@ import Nix.Expr.Types.Annotated
|
|||
import Nix.Frames
|
||||
import Nix.String
|
||||
import Nix.Thunk
|
||||
import Nix.Utils
|
||||
import Nix.Value
|
||||
import Nix.Var
|
||||
|
||||
{-
|
||||
|
||||
|
@ -61,18 +60,18 @@ class FromValue a m v where
|
|||
fromValue :: v -> m a
|
||||
fromValueMay :: v -> m (Maybe a)
|
||||
|
||||
type Convertible e m = (Framed e m, MonadVar m, Typeable m)
|
||||
type Convertible e t f m =
|
||||
(Framed e m, MonadThunk t m (NValue t f m), MonadDataErrorContext t f m)
|
||||
|
||||
instance Convertible e m => FromValue () m (NValueNF m) where
|
||||
instance Convertible e t f m => FromValue () m (NValueNF t f m) where
|
||||
fromValueMay = \case
|
||||
Free (NVConstantF NNull) -> pure $ Just ()
|
||||
NVConstantNF NNull -> pure $ Just ()
|
||||
_ -> pure Nothing
|
||||
fromValue v = fromValueMay v >>= \case
|
||||
Just b -> pure b
|
||||
_ -> throwError $ ExpectationNF TNull v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue () m (NValue m) where
|
||||
instance Convertible e t f m => FromValue () m (NValue t f m) where
|
||||
fromValueMay = \case
|
||||
NVConstant NNull -> pure $ Just ()
|
||||
_ -> pure Nothing
|
||||
|
@ -80,17 +79,15 @@ instance Convertible e m
|
|||
Just b -> pure b
|
||||
_ -> throwError $ Expectation TNull v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue Bool m (NValueNF m) where
|
||||
instance Convertible e t f m => FromValue Bool m (NValueNF t f m) where
|
||||
fromValueMay = \case
|
||||
Free (NVConstantF (NBool b)) -> pure $ Just b
|
||||
NVConstantNF (NBool b) -> pure $ Just b
|
||||
_ -> pure Nothing
|
||||
fromValue v = fromValueMay v >>= \case
|
||||
Just b -> pure b
|
||||
_ -> throwError $ ExpectationNF TBool v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue Bool m (NValue m) where
|
||||
instance Convertible e t f m => FromValue Bool m (NValue t f m) where
|
||||
fromValueMay = \case
|
||||
NVConstant (NBool b) -> pure $ Just b
|
||||
_ -> pure Nothing
|
||||
|
@ -98,17 +95,15 @@ instance Convertible e m
|
|||
Just b -> pure b
|
||||
_ -> throwError $ Expectation TBool v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue Int m (NValueNF m) where
|
||||
instance Convertible e t f m => FromValue Int m (NValueNF t f m) where
|
||||
fromValueMay = \case
|
||||
Free (NVConstantF (NInt b)) -> pure $ Just (fromInteger b)
|
||||
NVConstantNF (NInt b) -> pure $ Just (fromInteger b)
|
||||
_ -> pure Nothing
|
||||
fromValue v = fromValueMay v >>= \case
|
||||
Just b -> pure b
|
||||
_ -> throwError $ ExpectationNF TInt v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue Int m (NValue m) where
|
||||
instance Convertible e t f m => FromValue Int m (NValue t f m) where
|
||||
fromValueMay = \case
|
||||
NVConstant (NInt b) -> pure $ Just (fromInteger b)
|
||||
_ -> pure Nothing
|
||||
|
@ -116,17 +111,15 @@ instance Convertible e m
|
|||
Just b -> pure b
|
||||
_ -> throwError $ Expectation TInt v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue Integer m (NValueNF m) where
|
||||
instance Convertible e t f m => FromValue Integer m (NValueNF t f m) where
|
||||
fromValueMay = \case
|
||||
Free (NVConstantF (NInt b)) -> pure $ Just b
|
||||
NVConstantNF (NInt b) -> pure $ Just b
|
||||
_ -> pure Nothing
|
||||
fromValue v = fromValueMay v >>= \case
|
||||
Just b -> pure b
|
||||
_ -> throwError $ ExpectationNF TInt v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue Integer m (NValue m) where
|
||||
instance Convertible e t f m => FromValue Integer m (NValue t f m) where
|
||||
fromValueMay = \case
|
||||
NVConstant (NInt b) -> pure $ Just b
|
||||
_ -> pure Nothing
|
||||
|
@ -134,18 +127,16 @@ instance Convertible e m
|
|||
Just b -> pure b
|
||||
_ -> throwError $ Expectation TInt v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue Float m (NValueNF m) where
|
||||
instance Convertible e t f m => FromValue Float m (NValueNF t f m) where
|
||||
fromValueMay = \case
|
||||
Free (NVConstantF (NFloat b)) -> pure $ Just b
|
||||
Free (NVConstantF (NInt i)) -> pure $ Just (fromInteger i)
|
||||
NVConstantNF (NFloat b) -> pure $ Just b
|
||||
NVConstantNF (NInt i) -> pure $ Just (fromInteger i)
|
||||
_ -> pure Nothing
|
||||
fromValue v = fromValueMay v >>= \case
|
||||
Just b -> pure b
|
||||
_ -> throwError $ ExpectationNF TFloat v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue Float m (NValue m) where
|
||||
instance Convertible e t f m => FromValue Float m (NValue t f m) where
|
||||
fromValueMay = \case
|
||||
NVConstant (NFloat b) -> pure $ Just b
|
||||
NVConstant (NInt i) -> pure $ Just (fromInteger i)
|
||||
|
@ -154,12 +145,14 @@ instance Convertible e m
|
|||
Just b -> pure b
|
||||
_ -> throwError $ Expectation TFloat v
|
||||
|
||||
instance (Convertible e m, MonadEffects m)
|
||||
=> FromValue NixString m (NValueNF m) where
|
||||
instance (Convertible e t f m, MonadEffects t f m)
|
||||
=> FromValue NixString m (NValueNF t f m) where
|
||||
fromValueMay = \case
|
||||
Free (NVStrF ns) -> pure $ Just ns
|
||||
Free (NVPathF p) -> Just . hackyMakeNixStringWithoutContext . Text.pack . unStorePath <$> addPath p
|
||||
Free (NVSetF s _) -> case M.lookup "outPath" s of
|
||||
NVStrNF ns -> pure $ Just ns
|
||||
NVPathNF p ->
|
||||
Just . hackyMakeNixStringWithoutContext
|
||||
. Text.pack . unStorePath <$> addPath p
|
||||
NVSetNF s _ -> case M.lookup "outPath" s of
|
||||
Nothing -> pure Nothing
|
||||
Just p -> fromValueMay p
|
||||
_ -> pure Nothing
|
||||
|
@ -167,11 +160,13 @@ instance (Convertible e m, MonadEffects m)
|
|||
Just b -> pure b
|
||||
_ -> throwError $ ExpectationNF (TString NoContext) v
|
||||
|
||||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m, MonadEffects m)
|
||||
=> FromValue NixString m (NValue m) where
|
||||
instance (Convertible e t f m, MonadEffects t f m, FromValue NixString m t)
|
||||
=> FromValue NixString m (NValue t f m) where
|
||||
fromValueMay = \case
|
||||
NVStr ns -> pure $ Just ns
|
||||
NVPath p -> Just . hackyMakeNixStringWithoutContext . Text.pack . unStorePath <$> addPath p
|
||||
NVPath p ->
|
||||
Just . hackyMakeNixStringWithoutContext
|
||||
. Text.pack . unStorePath <$> addPath p
|
||||
NVSet s _ -> case M.lookup "outPath" s of
|
||||
Nothing -> pure Nothing
|
||||
Just p -> fromValueMay p
|
||||
|
@ -180,17 +175,17 @@ instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m, MonadEffects m)
|
|||
Just b -> pure b
|
||||
_ -> throwError $ Expectation (TString NoContext) v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue ByteString m (NValueNF m) where
|
||||
instance Convertible e t f m
|
||||
=> FromValue ByteString m (NValueNF t f m) where
|
||||
fromValueMay = \case
|
||||
Free (NVStrF ns) -> pure $ encodeUtf8 <$> hackyGetStringNoContext ns
|
||||
NVStrNF ns -> pure $ encodeUtf8 <$> hackyGetStringNoContext ns
|
||||
_ -> pure Nothing
|
||||
fromValue v = fromValueMay v >>= \case
|
||||
Just b -> pure b
|
||||
_ -> throwError $ ExpectationNF (TString NoContext) v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue ByteString m (NValue m) where
|
||||
instance Convertible e t f m
|
||||
=> FromValue ByteString m (NValue t f m) where
|
||||
fromValueMay = \case
|
||||
NVStr ns -> pure $ encodeUtf8 <$> hackyGetStringNoContext ns
|
||||
_ -> pure Nothing
|
||||
|
@ -201,11 +196,11 @@ instance Convertible e m
|
|||
newtype Path = Path { getPath :: FilePath }
|
||||
deriving Show
|
||||
|
||||
instance Convertible e m => FromValue Path m (NValueNF m) where
|
||||
instance Convertible e t f m => FromValue Path m (NValueNF t f m) where
|
||||
fromValueMay = \case
|
||||
Free (NVPathF p) -> pure $ Just (Path p)
|
||||
Free (NVStrF ns) -> pure $ Path . Text.unpack <$> hackyGetStringNoContext ns
|
||||
Free (NVSetF s _) -> case M.lookup "outPath" s of
|
||||
NVPathNF p -> pure $ Just (Path p)
|
||||
NVStrNF ns -> pure $ Path . Text.unpack <$> hackyGetStringNoContext ns
|
||||
NVSetNF s _ -> case M.lookup "outPath" s of
|
||||
Nothing -> pure Nothing
|
||||
Just p -> fromValueMay @Path p
|
||||
_ -> pure Nothing
|
||||
|
@ -213,8 +208,8 @@ instance Convertible e m => FromValue Path m (NValueNF m) where
|
|||
Just b -> pure b
|
||||
_ -> throwError $ ExpectationNF TPath v
|
||||
|
||||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m)
|
||||
=> FromValue Path m (NValue m) where
|
||||
instance (Convertible e t f m, FromValue Path m t)
|
||||
=> FromValue Path m (NValue t f m) where
|
||||
fromValueMay = \case
|
||||
NVPath p -> pure $ Just (Path p)
|
||||
NVStr ns -> pure $ Path . Text.unpack <$> hackyGetStringNoContext ns
|
||||
|
@ -226,16 +221,16 @@ instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m)
|
|||
Just b -> pure b
|
||||
_ -> throwError $ Expectation TPath v
|
||||
|
||||
instance (Convertible e m, FromValue a m (NValueNF m), Show a)
|
||||
=> FromValue [a] m (NValueNF m) where
|
||||
instance (Convertible e t f m, FromValue a m (NValueNF t f m), Show a)
|
||||
=> FromValue [a] m (NValueNF t f m) where
|
||||
fromValueMay = \case
|
||||
Free (NVListF l) -> sequence <$> traverse fromValueMay l
|
||||
NVListNF l -> sequence <$> traverse fromValueMay l
|
||||
_ -> pure Nothing
|
||||
fromValue v = fromValueMay v >>= \case
|
||||
Just b -> pure b
|
||||
_ -> throwError $ ExpectationNF TList v
|
||||
|
||||
instance Convertible e m => FromValue [NThunk m] m (NValue m) where
|
||||
instance Convertible e t f m => FromValue [t] m (NValue t f m) where
|
||||
fromValueMay = \case
|
||||
NVList l -> pure $ Just l
|
||||
_ -> pure Nothing
|
||||
|
@ -243,17 +238,17 @@ instance Convertible e m => FromValue [NThunk m] m (NValue m) where
|
|||
Just b -> pure b
|
||||
_ -> throwError $ Expectation TList v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue (HashMap Text (NValueNF m)) m (NValueNF m) where
|
||||
instance Convertible e t f m
|
||||
=> FromValue (HashMap Text (NValueNF t f m)) m (NValueNF t f m) where
|
||||
fromValueMay = \case
|
||||
Free (NVSetF s _) -> pure $ Just s
|
||||
NVSetNF s _ -> pure $ Just s
|
||||
_ -> pure Nothing
|
||||
fromValue v = fromValueMay v >>= \case
|
||||
Just b -> pure b
|
||||
_ -> throwError $ ExpectationNF TSet v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue (HashMap Text (NThunk m)) m (NValue m) where
|
||||
instance Convertible e t f m
|
||||
=> FromValue (HashMap Text t) m (NValue t f m) where
|
||||
fromValueMay = \case
|
||||
NVSet s _ -> pure $ Just s
|
||||
_ -> pure Nothing
|
||||
|
@ -261,19 +256,19 @@ instance Convertible e m
|
|||
Just b -> pure b
|
||||
_ -> throwError $ Expectation TSet v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue (HashMap Text (NValueNF m),
|
||||
HashMap Text SourcePos) m (NValueNF m) where
|
||||
instance Convertible e t f m
|
||||
=> FromValue (HashMap Text (NValueNF t f m),
|
||||
HashMap Text SourcePos) m (NValueNF t f m) where
|
||||
fromValueMay = \case
|
||||
Free (NVSetF s p) -> pure $ Just (s, p)
|
||||
NVSetNF s p -> pure $ Just (s, p)
|
||||
_ -> pure Nothing
|
||||
fromValue v = fromValueMay v >>= \case
|
||||
Just b -> pure b
|
||||
_ -> throwError $ ExpectationNF TSet v
|
||||
|
||||
instance Convertible e m
|
||||
=> FromValue (HashMap Text (NThunk m),
|
||||
HashMap Text SourcePos) m (NValue m) where
|
||||
instance Convertible e t f m
|
||||
=> FromValue (HashMap Text t,
|
||||
HashMap Text SourcePos) m (NValue t f m) where
|
||||
fromValueMay = \case
|
||||
NVSet s p -> pure $ Just (s, p)
|
||||
_ -> pure Nothing
|
||||
|
@ -281,127 +276,110 @@ instance Convertible e m
|
|||
Just b -> pure b
|
||||
_ -> throwError $ Expectation TSet v
|
||||
|
||||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m)
|
||||
=> FromValue (NThunk m) m (NValue m) where
|
||||
fromValueMay = pure . Just . wrapValue @_ @_ @m
|
||||
fromValue v = fromValueMay v >>= \case
|
||||
Just b -> pure b
|
||||
_ -> error "Impossible, see fromValueMay"
|
||||
|
||||
instance (Monad m, FromValue a m v) => FromValue a m (m v) where
|
||||
fromValueMay = (>>= fromValueMay)
|
||||
fromValue = (>>= fromValue)
|
||||
|
||||
instance (MonadThunk (NValue m) (NThunk m) m, FromValue a m (NValue m))
|
||||
=> FromValue a m (NThunk m) where
|
||||
fromValueMay = force ?? fromValueMay
|
||||
fromValue = force ?? fromValue
|
||||
|
||||
class ToValue a m v where
|
||||
toValue :: a -> m v
|
||||
|
||||
instance Applicative m => ToValue () m (NValueNF m) where
|
||||
toValue _ = pure . Free . NVConstantF $ NNull
|
||||
instance Convertible e t f m => ToValue () m (NValueNF t f m) where
|
||||
toValue _ = pure . nvConstantNF $ NNull
|
||||
|
||||
instance Applicative m => ToValue () m (NValue m) where
|
||||
instance Convertible e t f m => ToValue () m (NValue t f m) where
|
||||
toValue _ = pure . nvConstant $ NNull
|
||||
|
||||
instance Applicative m => ToValue Bool m (NValueNF m) where
|
||||
toValue = pure . Free . NVConstantF . NBool
|
||||
instance Convertible e t f m => ToValue Bool m (NValueNF t f m) where
|
||||
toValue = pure . nvConstantNF . NBool
|
||||
|
||||
instance Applicative m => ToValue Bool m (NValue m) where
|
||||
instance Convertible e t f m => ToValue Bool m (NValue t f m) where
|
||||
toValue = pure . nvConstant . NBool
|
||||
|
||||
instance Applicative m => ToValue Int m (NValueNF m) where
|
||||
toValue = pure . Free . NVConstantF . NInt . toInteger
|
||||
instance Convertible e t f m => ToValue Int m (NValueNF t f m) where
|
||||
toValue = pure . nvConstantNF . NInt . toInteger
|
||||
|
||||
instance Applicative m => ToValue Int m (NValue m) where
|
||||
instance Convertible e t f m => ToValue Int m (NValue t f m) where
|
||||
toValue = pure . nvConstant . NInt . toInteger
|
||||
|
||||
instance Applicative m => ToValue Integer m (NValueNF m) where
|
||||
toValue = pure . Free . NVConstantF . NInt
|
||||
instance Convertible e t f m => ToValue Integer m (NValueNF t f m) where
|
||||
toValue = pure . nvConstantNF . NInt
|
||||
|
||||
instance Applicative m => ToValue Integer m (NValue m) where
|
||||
instance Convertible e t f m => ToValue Integer m (NValue t f m) where
|
||||
toValue = pure . nvConstant . NInt
|
||||
|
||||
instance Applicative m => ToValue Float m (NValueNF m) where
|
||||
toValue = pure . Free . NVConstantF . NFloat
|
||||
instance Convertible e t f m => ToValue Float m (NValueNF t f m) where
|
||||
toValue = pure . nvConstantNF . NFloat
|
||||
|
||||
instance Applicative m => ToValue Float m (NValue m) where
|
||||
instance Convertible e t f m => ToValue Float m (NValue t f m) where
|
||||
toValue = pure . nvConstant . NFloat
|
||||
|
||||
instance Applicative m => ToValue NixString m (NValueNF m) where
|
||||
toValue = pure . Free . NVStrF
|
||||
instance Convertible e t f m => ToValue NixString m (NValueNF t f m) where
|
||||
toValue = pure . nvStrNF
|
||||
|
||||
instance Applicative m => ToValue NixString m (NValue m) where
|
||||
instance Convertible e t f m => ToValue NixString m (NValue t f m) where
|
||||
toValue = pure . nvStr
|
||||
|
||||
instance Applicative m => ToValue ByteString m (NValueNF m) where
|
||||
toValue = pure . Free . NVStrF . hackyMakeNixStringWithoutContext . decodeUtf8
|
||||
instance Convertible e t f m => ToValue ByteString m (NValueNF t f m) where
|
||||
toValue = pure . nvStrNF . hackyMakeNixStringWithoutContext . decodeUtf8
|
||||
|
||||
instance Applicative m => ToValue ByteString m (NValue m) where
|
||||
instance Convertible e t f m => ToValue ByteString m (NValue t f m) where
|
||||
toValue = pure . nvStr . hackyMakeNixStringWithoutContext . decodeUtf8
|
||||
|
||||
instance Applicative m => ToValue Path m (NValueNF m) where
|
||||
toValue = pure . Free . NVPathF . getPath
|
||||
instance Convertible e t f m => ToValue Path m (NValueNF t f m) where
|
||||
toValue = pure . nvPathNF . getPath
|
||||
|
||||
instance Applicative m => ToValue Path m (NValue m) where
|
||||
instance Convertible e t f m => ToValue Path m (NValue t f m) where
|
||||
toValue = pure . nvPath . getPath
|
||||
|
||||
instance Applicative m => ToValue StorePath m (NValueNF m) where
|
||||
instance Convertible e t f m => ToValue StorePath m (NValueNF t f m) where
|
||||
toValue = toValue . Path . unStorePath
|
||||
|
||||
instance Applicative m => ToValue StorePath m (NValue m) where
|
||||
instance Convertible e t f m => ToValue StorePath m (NValue t f m) where
|
||||
toValue = toValue . Path . unStorePath
|
||||
|
||||
instance MonadThunk (NValue m) (NThunk m) m
|
||||
=> ToValue SourcePos m (NValue m) where
|
||||
instance Convertible e t f m => ToValue SourcePos m (NValue t f m) where
|
||||
toValue (SourcePos f l c) = do
|
||||
f' <- pure $ nvStr $ principledMakeNixStringWithoutContext (Text.pack f)
|
||||
l' <- toValue (unPos l)
|
||||
c' <- toValue (unPos c)
|
||||
let pos = M.fromList
|
||||
[ ("file" :: Text, wrapValue @_ @_ @m f')
|
||||
, ("line", wrapValue @_ @_ @m l')
|
||||
, ("column", wrapValue @_ @_ @m c') ]
|
||||
[ ("file" :: Text, wrapValue f')
|
||||
, ("line", wrapValue l')
|
||||
, ("column", wrapValue c') ]
|
||||
pure $ nvSet pos mempty
|
||||
|
||||
instance (ToValue a m (NValueNF m), Applicative m)
|
||||
=> ToValue [a] m (NValueNF m) where
|
||||
toValue = fmap (Free . NVListF) . traverse toValue
|
||||
instance (Convertible e t f m, ToValue a m (NValueNF t f m))
|
||||
=> ToValue [a] m (NValueNF t f m) where
|
||||
toValue = fmap nvListNF . traverse toValue
|
||||
|
||||
instance Applicative m => ToValue [NThunk m] m (NValue m) where
|
||||
instance Convertible e t f m => ToValue [t] m (NValue t f m) where
|
||||
toValue = pure . nvList
|
||||
|
||||
instance Applicative m
|
||||
=> ToValue (HashMap Text (NValueNF m)) m (NValueNF m) where
|
||||
toValue = pure . Free . flip NVSetF M.empty
|
||||
instance Convertible e t f m
|
||||
=> ToValue (HashMap Text (NValueNF t f m)) m (NValueNF t f m) where
|
||||
toValue = pure . flip nvSetNF M.empty
|
||||
|
||||
instance Applicative m => ToValue (HashMap Text (NThunk m)) m (NValue m) where
|
||||
instance Convertible e t f m => ToValue (HashMap Text t) m (NValue t f m) where
|
||||
toValue = pure . flip nvSet M.empty
|
||||
|
||||
instance Applicative m => ToValue (HashMap Text (NValueNF m),
|
||||
HashMap Text SourcePos) m (NValueNF m) where
|
||||
toValue (s, p) = pure $ Free $ NVSetF s p
|
||||
instance Convertible e t f m => ToValue (HashMap Text (NValueNF t f m),
|
||||
HashMap Text SourcePos) m (NValueNF t f m) where
|
||||
toValue (s, p) = pure $ nvSetNF s p
|
||||
|
||||
instance Applicative m => ToValue (HashMap Text (NThunk m),
|
||||
HashMap Text SourcePos) m (NValue m) where
|
||||
instance Convertible e t f m => ToValue (HashMap Text t,
|
||||
HashMap Text SourcePos) m (NValue t f m) where
|
||||
toValue (s, p) = pure $ nvSet s p
|
||||
|
||||
instance (MonadThunk (NValue m) (NThunk m) m, ToValue a m (NValue m))
|
||||
=> ToValue a m (NThunk m) where
|
||||
toValue = fmap (wrapValue @(NValue m) @_ @m) . toValue
|
||||
|
||||
instance Applicative m => ToValue Bool m (NExprF r) where
|
||||
instance Convertible e t f m => ToValue Bool m (NExprF r) where
|
||||
toValue = pure . NConstant . NBool
|
||||
|
||||
instance Applicative m => ToValue () m (NExprF r) where
|
||||
instance Convertible e t f m => ToValue () m (NExprF r) where
|
||||
toValue _ = pure . NConstant $ NNull
|
||||
|
||||
whileForcingThunk :: forall s e m r. (Framed e m, Exception s, Typeable m)
|
||||
whileForcingThunk :: forall t f m s e r. (Exception s, Convertible e t f m)
|
||||
=> s -> m r -> m r
|
||||
whileForcingThunk frame =
|
||||
withFrame Debug (ForcingThunk @m) . withFrame Debug frame
|
||||
withFrame Debug (ForcingThunk @t @f @m) . withFrame Debug frame
|
||||
|
||||
class FromNix a m v where
|
||||
fromNix :: v -> m a
|
||||
|
@ -412,9 +390,8 @@ class FromNix a m v where
|
|||
default fromNixMay :: FromValue a m v => v -> m (Maybe a)
|
||||
fromNixMay = fromValueMay
|
||||
|
||||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m,
|
||||
FromNix a m (NValue m))
|
||||
=> FromNix [a] m (NValue m) where
|
||||
instance (Convertible e t f m, FromNix a m (NValue t f m))
|
||||
=> FromNix [a] m (NValue t f m) where
|
||||
fromNixMay = \case
|
||||
NVList l -> sequence <$> traverse (`force` fromNixMay) l
|
||||
_ -> pure Nothing
|
||||
|
@ -422,9 +399,8 @@ instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m,
|
|||
Just b -> pure b
|
||||
_ -> throwError $ Expectation TList v
|
||||
|
||||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m,
|
||||
FromNix a m (NValue m))
|
||||
=> FromNix (HashMap Text a) m (NValue m) where
|
||||
instance (Convertible e t f m, FromNix a m (NValue t f m))
|
||||
=> FromNix (HashMap Text a) m (NValue t f m) where
|
||||
fromNixMay = \case
|
||||
NVSet s _ -> sequence <$> traverse (`force` fromNixMay) s
|
||||
_ -> pure Nothing
|
||||
|
@ -432,91 +408,91 @@ instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m,
|
|||
Just b -> pure b
|
||||
_ -> throwError $ Expectation TSet v
|
||||
|
||||
instance Convertible e m => FromNix () m (NValueNF m) where
|
||||
instance Convertible e m => FromNix () m (NValue m) where
|
||||
instance Convertible e m => FromNix Bool m (NValueNF m) where
|
||||
instance Convertible e m => FromNix Bool m (NValue m) where
|
||||
instance Convertible e m => FromNix Int m (NValueNF m) where
|
||||
instance Convertible e m => FromNix Int m (NValue m) where
|
||||
instance Convertible e m => FromNix Integer m (NValueNF m) where
|
||||
instance Convertible e m => FromNix Integer m (NValue m) where
|
||||
instance Convertible e m => FromNix Float m (NValueNF m) where
|
||||
instance Convertible e m => FromNix Float m (NValue m) where
|
||||
instance (Convertible e m, MonadEffects m) => FromNix NixString m (NValueNF m) where
|
||||
instance (Convertible e m, MonadEffects m, MonadThunk (NValue m) (NThunk m) m) => FromNix NixString m (NValue m) where
|
||||
instance Convertible e m => FromNix ByteString m (NValueNF m) where
|
||||
instance Convertible e m => FromNix ByteString m (NValue m) where
|
||||
instance Convertible e m => FromNix Path m (NValueNF m) where
|
||||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m) => FromNix Path m (NValue m) where
|
||||
instance (Convertible e m, FromValue a m (NValueNF m), Show a) => FromNix [a] m (NValueNF m) where
|
||||
instance Convertible e m => FromNix (HashMap Text (NValueNF m)) m (NValueNF m) where
|
||||
instance Convertible e m => FromNix (HashMap Text (NValueNF m), HashMap Text SourcePos) m (NValueNF m) where
|
||||
instance Convertible e m => FromNix (HashMap Text (NThunk m), HashMap Text SourcePos) m (NValue m) where
|
||||
instance Convertible e t f m => FromNix () m (NValueNF t f m) where
|
||||
instance Convertible e t f m => FromNix () m (NValue t f m) where
|
||||
instance Convertible e t f m => FromNix Bool m (NValueNF t f m) where
|
||||
instance Convertible e t f m => FromNix Bool m (NValue t f m) where
|
||||
instance Convertible e t f m => FromNix Int m (NValueNF t f m) where
|
||||
instance Convertible e t f m => FromNix Int m (NValue t f m) where
|
||||
instance Convertible e t f m => FromNix Integer m (NValueNF t f m) where
|
||||
instance Convertible e t f m => FromNix Integer m (NValue t f m) where
|
||||
instance Convertible e t f m => FromNix Float m (NValueNF t f m) where
|
||||
instance Convertible e t f m => FromNix Float m (NValue t f m) where
|
||||
instance (Convertible e t f m, MonadEffects t f m)
|
||||
=> FromNix NixString m (NValueNF t f m) where
|
||||
instance (Convertible e t f m, MonadEffects t f m, FromValue NixString m t)
|
||||
=> FromNix NixString m (NValue t f m) where
|
||||
instance Convertible e t f m => FromNix ByteString m (NValueNF t f m) where
|
||||
instance Convertible e t f m => FromNix ByteString m (NValue t f m) where
|
||||
instance Convertible e t f m => FromNix Path m (NValueNF t f m) where
|
||||
instance (Convertible e t f m, FromValue Path m t)
|
||||
=> FromNix Path m (NValue t f m) where
|
||||
instance (Convertible e t f m, FromValue a m (NValueNF t f m), Show a)
|
||||
=> FromNix [a] m (NValueNF t f m) where
|
||||
instance Convertible e t f m
|
||||
=> FromNix (HashMap Text (NValueNF t f m)) m (NValueNF t f m) where
|
||||
instance Convertible e t f m
|
||||
=> FromNix (HashMap Text (NValueNF t f m),
|
||||
HashMap Text SourcePos) m (NValueNF t f m) where
|
||||
instance Convertible e t f m
|
||||
=> FromNix (HashMap Text t, HashMap Text SourcePos) m (NValue t f m) where
|
||||
|
||||
instance (Monad m, FromNix a m v) => FromNix a m (m v) where
|
||||
fromNixMay = (>>= fromNixMay)
|
||||
fromNix = (>>= fromNix)
|
||||
|
||||
instance (MonadThunk (NValue m) (NThunk m) m, FromNix a m (NValue m))
|
||||
=> FromNix a m (NThunk m) where
|
||||
fromNixMay = force ?? fromNixMay
|
||||
fromNix = force ?? fromNix
|
||||
|
||||
instance MonadThunk (NValue m) (NThunk m) m
|
||||
=> FromNix (NThunk m) m (NValue m) where
|
||||
fromNixMay = pure . Just . wrapValue
|
||||
fromNix = pure . wrapValue
|
||||
|
||||
class ToNix a m v where
|
||||
toNix :: a -> m v
|
||||
default toNix :: ToValue a m v => a -> m v
|
||||
toNix = toValue
|
||||
|
||||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m,
|
||||
ToNix a m (NValue m))
|
||||
=> ToNix [a] m (NValue m) where
|
||||
toNix = fmap nvList
|
||||
. traverse (thunk . ((\v -> whileForcingThunk (ConcerningValue v) (pure v))
|
||||
<=< toNix))
|
||||
instance (Convertible e t f m, ToNix a m (NValue t f m))
|
||||
=> ToNix [a] m (NValue t f m) where
|
||||
toNix = fmap nvList . traverse (thunk . go)
|
||||
where
|
||||
go = (\v -> whileForcingThunk @t @f @m (ConcerningValue v) (pure v))
|
||||
<=< toNix
|
||||
|
||||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m,
|
||||
ToNix a m (NValue m))
|
||||
=> ToNix (HashMap Text a) m (NValue m) where
|
||||
toNix = fmap (flip nvSet M.empty)
|
||||
. traverse (thunk . ((\v -> whileForcingThunk (ConcerningValue v) (pure v))
|
||||
<=< toNix))
|
||||
instance (Convertible e t f m, ToNix a m (NValue t f m))
|
||||
=> ToNix (HashMap Text a) m (NValue t f m) where
|
||||
toNix = fmap (flip nvSet M.empty) . traverse (thunk . go)
|
||||
where
|
||||
go = (\v -> whileForcingThunk @t @f @m (ConcerningValue v) (pure v))
|
||||
<=< toNix
|
||||
|
||||
instance Applicative m => ToNix () m (NValueNF m) where
|
||||
instance Applicative m => ToNix () m (NValue m) where
|
||||
instance Applicative m => ToNix Bool m (NValueNF m) where
|
||||
instance Applicative m => ToNix Bool m (NValue m) where
|
||||
instance Applicative m => ToNix Int m (NValueNF m) where
|
||||
instance Applicative m => ToNix Int m (NValue m) where
|
||||
instance Applicative m => ToNix Integer m (NValueNF m) where
|
||||
instance Applicative m => ToNix Integer m (NValue m) where
|
||||
instance Applicative m => ToNix Float m (NValueNF m) where
|
||||
instance Applicative m => ToNix Float m (NValue m) where
|
||||
instance Applicative m => ToNix NixString m (NValueNF m) where
|
||||
instance Applicative m => ToNix NixString m (NValue m) where
|
||||
instance Applicative m => ToNix ByteString m (NValueNF m) where
|
||||
instance Applicative m => ToNix ByteString m (NValue m) where
|
||||
instance Applicative m => ToNix Path m (NValueNF m) where
|
||||
instance Applicative m => ToNix Path m (NValue m) where
|
||||
instance Applicative m => ToNix (HashMap Text (NValueNF m)) m (NValueNF m) where
|
||||
instance Applicative m => ToNix (HashMap Text (NValueNF m), HashMap Text SourcePos) m (NValueNF m) where
|
||||
instance Applicative m => ToNix (HashMap Text (NThunk m), HashMap Text SourcePos) m (NValue m) where
|
||||
instance Applicative m => ToNix Bool m (NExprF r) where
|
||||
instance Applicative m => ToNix () m (NExprF r) where
|
||||
instance Convertible e t f m => ToNix () m (NValueNF t f m) where
|
||||
instance Convertible e t f m => ToNix () m (NValue t f m) where
|
||||
instance Convertible e t f m => ToNix Bool m (NValueNF t f m) where
|
||||
instance Convertible e t f m => ToNix Bool m (NValue t f m) where
|
||||
instance Convertible e t f m => ToNix Int m (NValueNF t f m) where
|
||||
instance Convertible e t f m => ToNix Int m (NValue t f m) where
|
||||
instance Convertible e t f m => ToNix Integer m (NValueNF t f m) where
|
||||
instance Convertible e t f m => ToNix Integer m (NValue t f m) where
|
||||
instance Convertible e t f m => ToNix Float m (NValueNF t f m) where
|
||||
instance Convertible e t f m => ToNix Float m (NValue t f m) where
|
||||
instance Convertible e t f m => ToNix NixString m (NValueNF t f m) where
|
||||
instance Convertible e t f m => ToNix NixString m (NValue t f m) where
|
||||
instance Convertible e t f m => ToNix ByteString m (NValueNF t f m) where
|
||||
instance Convertible e t f m => ToNix ByteString m (NValue t f m) where
|
||||
instance Convertible e t f m => ToNix Path m (NValueNF t f m) where
|
||||
instance Convertible e t f m => ToNix Path m (NValue t f m) where
|
||||
instance Convertible e t f m
|
||||
=> ToNix (HashMap Text (NValueNF t f m)) m (NValueNF t f m) where
|
||||
instance Convertible e t f m
|
||||
=> ToNix (HashMap Text (NValueNF t f m),
|
||||
HashMap Text SourcePos) m (NValueNF t f m) where
|
||||
instance Convertible e t f m
|
||||
=> ToNix (HashMap Text t, HashMap Text SourcePos) m (NValue t f m) where
|
||||
|
||||
instance (MonadThunk (NValue m) (NThunk m) m, ToNix a m (NValue m))
|
||||
=> ToNix a m (NThunk m) where
|
||||
toNix = thunk . toNix
|
||||
instance Convertible e t f m => ToNix Bool m (NExprF r) where
|
||||
toNix = pure . NConstant . NBool
|
||||
|
||||
instance (Applicative m, ToNix a m (NValueNF m)) => ToNix [a] m (NValueNF m) where
|
||||
toNix = fmap (Free . NVListF) . traverse toNix
|
||||
instance Convertible e t f m => ToNix () m (NExprF r) where
|
||||
toNix _ = pure $ NConstant NNull
|
||||
|
||||
instance MonadThunk (NValue m) (NThunk m) m => ToNix (NThunk m) m (NValue m) where
|
||||
toNix = force ?? pure
|
||||
instance (Convertible e t f m, ToNix a m (NValueNF t f m))
|
||||
=> ToNix [a] m (NValueNF t f m) where
|
||||
toNix = fmap nvListNF . traverse toNix
|
||||
|
||||
convertNix :: forall a t m v. (FromNix a m t, ToNix a m v, Monad m) => t -> m v
|
||||
convertNix = fromNix @a >=> toNix
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
{-# LANGUAGE AllowAmbiguousTypes #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DefaultSignatures #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
|
||||
module Nix.Effects where
|
||||
|
||||
import Prelude hiding (putStr, putStrLn, print)
|
||||
|
@ -31,19 +34,26 @@ import System.Process
|
|||
-- | A path into the nix store
|
||||
newtype StorePath = StorePath { unStorePath :: FilePath }
|
||||
|
||||
class (MonadFile m, MonadStore m, MonadPutStr m, MonadHttp m, MonadEnv m, MonadInstantiate m, MonadExec m, MonadIntrospect m) => MonadEffects m where
|
||||
class (MonadFile m,
|
||||
MonadStore m,
|
||||
MonadPutStr m,
|
||||
MonadHttp m,
|
||||
MonadEnv m,
|
||||
MonadInstantiate m,
|
||||
MonadExec m,
|
||||
MonadIntrospect m) => MonadEffects t f m where
|
||||
-- | Determine the absolute path of relative path in the current context
|
||||
makeAbsolutePath :: FilePath -> m FilePath
|
||||
findEnvPath :: String -> m FilePath
|
||||
|
||||
-- | Having an explicit list of sets corresponding to the NIX_PATH
|
||||
-- and a file path try to find an existing path
|
||||
findPath :: [NThunk m] -> FilePath -> m FilePath
|
||||
findPath :: [t] -> FilePath -> m FilePath
|
||||
|
||||
importPath :: FilePath -> m (NValue m)
|
||||
importPath :: FilePath -> m (NValue t f m)
|
||||
pathToDefaultNix :: FilePath -> m FilePath
|
||||
|
||||
derivationStrict :: NValue m -> m (NValue m)
|
||||
derivationStrict :: NValue t f m -> m (NValue t f m)
|
||||
|
||||
traceEffect :: String -> m ()
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ class (Show v, Monad m) => MonadEval v m where
|
|||
type MonadNixEval v t m =
|
||||
(MonadEval v m,
|
||||
Scoped t m,
|
||||
MonadThunk v t m,
|
||||
MonadThunk t m v,
|
||||
MonadFix m,
|
||||
ToValue Bool m v,
|
||||
ToValue [t] m v,
|
||||
|
@ -88,14 +88,14 @@ type MonadNixEval v t m =
|
|||
ToValue (AttrSet t, AttrSet SourcePos) m v,
|
||||
FromValue (AttrSet t, AttrSet SourcePos) m v)
|
||||
|
||||
data EvalFrame m v
|
||||
= EvaluatingExpr (Scopes m v) NExprLoc
|
||||
| ForcingExpr (Scopes m v) NExprLoc
|
||||
data EvalFrame m t
|
||||
= EvaluatingExpr (Scopes m t) NExprLoc
|
||||
| ForcingExpr (Scopes m t) NExprLoc
|
||||
| Calling String SrcSpan
|
||||
| SynHole (SynHoleInfo m v)
|
||||
| SynHole (SynHoleInfo m t)
|
||||
deriving (Show, Typeable)
|
||||
|
||||
instance (Typeable m, Typeable v) => Exception (EvalFrame m v)
|
||||
instance (Typeable m, Typeable t) => Exception (EvalFrame m t)
|
||||
|
||||
data SynHoleInfo m t = SynHoleInfo
|
||||
{ _synHoleInfo_expr :: NExprLoc
|
||||
|
@ -131,7 +131,7 @@ eval (NHasAttr aset attr) = evalSelect aset attr >>= toValue . isRight
|
|||
|
||||
eval (NList l) = do
|
||||
scope <- currentScopes
|
||||
for l (thunk @v @t . withScopes @t scope) >>= toValue
|
||||
for l (thunk @t @m @v . withScopes @t scope) >>= toValue
|
||||
|
||||
eval (NSet binds) =
|
||||
evalBinds False (desugarBinds (eval . NSet) binds) >>= toValue
|
||||
|
@ -168,7 +168,7 @@ evalWithAttrSet aset body = do
|
|||
-- we want to be sure the action it evaluates is to force a thunk, so
|
||||
-- its value is only computed once.
|
||||
scope <- currentScopes :: m (Scopes m t)
|
||||
s <- thunk @v @t $ withScopes scope aset
|
||||
s <- thunk @t @m @v $ withScopes scope aset
|
||||
pushWeakScope ?? body $ force s $
|
||||
fmap fst . fromValue @(AttrSet t, AttrSet SourcePos)
|
||||
|
||||
|
@ -241,7 +241,7 @@ evalBinds recursive binds = do
|
|||
finalValue >>= fromValue >>= \(o', p') ->
|
||||
-- jww (2018-05-09): What to do with the key position here?
|
||||
return $ map (\(k, v) -> ([k], fromMaybe pos (M.lookup k p'),
|
||||
force @v @t v pure))
|
||||
force @t @m @v v pure))
|
||||
(M.toList o')
|
||||
|
||||
go _ (NamedVar pathExpr finalValue pos) = do
|
||||
|
|
424
src/Nix/Exec.hs
424
src/Nix/Exec.hs
|
@ -37,9 +37,7 @@ import Control.Monad.Ref
|
|||
import Control.Monad.State.Strict
|
||||
import Control.Monad.Trans.Reader (ReaderT(..))
|
||||
import Control.Monad.Trans.State.Strict (StateT(..))
|
||||
import Data.Coerce
|
||||
import Data.Fix
|
||||
import Data.GADT.Compare
|
||||
import Data.HashMap.Lazy (HashMap)
|
||||
import qualified Data.HashMap.Lazy as M
|
||||
import Data.List
|
||||
|
@ -51,25 +49,23 @@ import qualified Data.Text as Text
|
|||
import Data.Text.Prettyprint.Doc
|
||||
import Data.Typeable
|
||||
import Nix.Atoms
|
||||
import Nix.Cited
|
||||
import Nix.Context
|
||||
import Nix.Convert
|
||||
import Nix.Effects
|
||||
import Nix.Eval as Eval
|
||||
import Nix.Expr
|
||||
import Nix.Frames
|
||||
import Nix.Fresh
|
||||
import Nix.String
|
||||
import Nix.Normal
|
||||
import Nix.Options
|
||||
import Nix.Parser
|
||||
import Nix.Pretty
|
||||
import Nix.Render
|
||||
import Nix.Scope
|
||||
import Nix.String
|
||||
import Nix.Thunk
|
||||
import Nix.Thunk.Basic
|
||||
import Nix.Utils
|
||||
import Nix.Value
|
||||
import Nix.Var
|
||||
#ifdef MIN_VERSION_haskeline
|
||||
import System.Console.Haskeline.MonadException hiding (catch)
|
||||
#endif
|
||||
|
@ -84,18 +80,75 @@ import GHC.DataSize
|
|||
#endif
|
||||
#endif
|
||||
|
||||
type MonadNix e m =
|
||||
(Scoped (NThunk m) m, Framed e m, Has e SrcSpan, Has e Options,
|
||||
Typeable m, MonadVar m, MonadEffects m, MonadFix m, MonadCatch m,
|
||||
Alternative m, MonadFreshId Int m)
|
||||
type Cited t f m =
|
||||
( HasCitations1 t f m
|
||||
, MonadDataContext f m
|
||||
)
|
||||
|
||||
data ExecFrame m = Assertion SrcSpan (NValue m)
|
||||
nvConstantP :: Cited t f m
|
||||
=> Provenance t f m -> NAtom -> NValue t f m
|
||||
nvConstantP p x = addProvenance p (nvConstant x)
|
||||
|
||||
nvStrP :: Cited t f m
|
||||
=> Provenance t f m -> NixString -> NValue t f m
|
||||
nvStrP p ns = addProvenance p (nvStr ns)
|
||||
|
||||
nvPathP :: Cited t f m
|
||||
=> Provenance t f m -> FilePath -> NValue t f m
|
||||
nvPathP p x = addProvenance p (nvPath x)
|
||||
|
||||
nvListP :: Cited t f m
|
||||
=> Provenance t f m -> [t] -> NValue t f m
|
||||
nvListP p l = addProvenance p (nvList l)
|
||||
|
||||
nvSetP :: Cited t f m
|
||||
=> Provenance t f m -> AttrSet t -> AttrSet SourcePos
|
||||
-> NValue t f m
|
||||
nvSetP p s x = addProvenance p (nvSet s x)
|
||||
|
||||
nvClosureP :: Cited t f m
|
||||
=> Provenance t f m
|
||||
-> Params ()
|
||||
-> (m (NValue t f m) -> m t)
|
||||
-> NValue t f m
|
||||
nvClosureP p x f = addProvenance p (nvClosure x f)
|
||||
|
||||
nvBuiltinP :: Cited t f m
|
||||
=> Provenance t f m
|
||||
-> String
|
||||
-> (m (NValue t f m) -> m t)
|
||||
-> NValue t f m
|
||||
nvBuiltinP p name f = addProvenance p (nvBuiltin name f)
|
||||
|
||||
type MonadCitedThunks t f m =
|
||||
( MonadThunk t m (NValue t f m)
|
||||
, MonadDataErrorContext t f m
|
||||
, HasCitations1 t f m
|
||||
)
|
||||
|
||||
type MonadNix e t f m =
|
||||
( Has e SrcSpan
|
||||
, Has e Options
|
||||
, Scoped t m
|
||||
, Framed e m
|
||||
, MonadFix m
|
||||
, MonadCatch m
|
||||
, MonadThrow m
|
||||
, Alternative m
|
||||
, MonadEffects t f m
|
||||
, MonadCitedThunks t f m
|
||||
)
|
||||
|
||||
data ExecFrame t f m = Assertion SrcSpan (NValue t f m)
|
||||
deriving (Show, Typeable)
|
||||
|
||||
instance Typeable m => Exception (ExecFrame m)
|
||||
instance MonadDataErrorContext t f m => Exception (ExecFrame t f m)
|
||||
|
||||
nverr :: forall s e m a. (MonadNix e m, Exception s) => s -> m a
|
||||
nverr = evalError @(NValue m)
|
||||
nverr
|
||||
:: forall e t f s m a.
|
||||
(MonadNix e t f m, FromValue NixString m t, Exception s)
|
||||
=> s -> m a
|
||||
nverr = evalError @(NValue t f m)
|
||||
|
||||
currentPos :: forall e m. (MonadReader e m, Has e SrcSpan) => m SrcSpan
|
||||
currentPos = asks (view hasLens)
|
||||
|
@ -103,94 +156,41 @@ currentPos = asks (view hasLens)
|
|||
wrapExprLoc :: SrcSpan -> NExprLocF r -> NExprLoc
|
||||
wrapExprLoc span x = Fix (Fix (NSym_ span "<?>") <$ x)
|
||||
|
||||
instance MonadNix e m => MonadThunk (NValue m) (NThunk m) m where
|
||||
thunk mv = do
|
||||
opts :: Options <- asks (view hasLens)
|
||||
|
||||
if thunks opts
|
||||
then do
|
||||
frames :: Frames <- asks (view hasLens)
|
||||
|
||||
-- Gather the current evaluation context at the time of thunk
|
||||
-- creation, and record it along with the thunk.
|
||||
let go (fromException ->
|
||||
Just (EvaluatingExpr scope
|
||||
(Fix (Compose (Ann span e))))) =
|
||||
let e' = Compose (Ann span (Nothing <$ e))
|
||||
in [Provenance scope e']
|
||||
go _ = []
|
||||
ps = concatMap (go . frame) frames
|
||||
|
||||
fmap (NThunk . NCited ps . coerce) . buildThunk $ mv
|
||||
else
|
||||
fmap (NThunk . NCited [] . coerce) . buildThunk $ mv
|
||||
|
||||
-- The ThunkLoop exception is thrown as an exception with MonadThrow,
|
||||
-- which does not capture the current stack frame information to provide
|
||||
-- it in a NixException, so we catch and re-throw it here using
|
||||
-- 'throwError' from Frames.hs.
|
||||
force (NThunk (NCited ps t)) f = catch go (throwError @ThunkLoop)
|
||||
where
|
||||
go = case ps of
|
||||
[] -> forceThunk t f
|
||||
Provenance scope e@(Compose (Ann span _)):_ ->
|
||||
withFrame Info (ForcingExpr scope (wrapExprLoc span e))
|
||||
(forceThunk t f)
|
||||
|
||||
forceEff (NThunk (NCited ps t)) f = catch go (throwError @ThunkLoop)
|
||||
where
|
||||
go = case ps of
|
||||
[] -> forceEffects t f
|
||||
Provenance scope e@(Compose (Ann span _)):_ ->
|
||||
withFrame Info (ForcingExpr scope (wrapExprLoc span e))
|
||||
(forceEffects t f)
|
||||
|
||||
wrapValue = NThunk . NCited [] . coerce . valueRef
|
||||
getValue (NThunk (NCited _ v)) = thunkValue (coerce v)
|
||||
|
||||
{-
|
||||
prov :: MonadNix e m
|
||||
=> (NValue m -> Provenance m) -> NValue m -> m (NValue m)
|
||||
prov p v = do
|
||||
opts :: Options <- asks (view hasLens)
|
||||
pure $ if values opts
|
||||
then addProvenance p v
|
||||
else v
|
||||
-}
|
||||
|
||||
instance MonadNix e m => MonadEval (NValue m) m where
|
||||
freeVariable var =
|
||||
nverr $ ErrorCall $ "Undefined variable '" ++ Text.unpack var ++ "'"
|
||||
instance ( MonadNix e t f m
|
||||
, FromValue NixString m t
|
||||
) => MonadEval (NValue t f m) m where
|
||||
freeVariable var = nverr @e @t @f $
|
||||
ErrorCall $ "Undefined variable '" ++ Text.unpack var ++ "'"
|
||||
|
||||
synHole name = do
|
||||
span <- currentPos
|
||||
scope <- currentScopes
|
||||
evalError @(NValue m) $ SynHole $ SynHoleInfo
|
||||
evalError @(NValue t f m) $ SynHole $ SynHoleInfo
|
||||
{ _synHoleInfo_expr = Fix $ NSynHole_ span name
|
||||
, _synHoleInfo_scope = scope
|
||||
}
|
||||
|
||||
attrMissing ks Nothing =
|
||||
evalError @(NValue m) $ ErrorCall $
|
||||
evalError @(NValue t f m) $ ErrorCall $
|
||||
"Inheriting unknown attribute: "
|
||||
++ intercalate "." (map Text.unpack (NE.toList ks))
|
||||
|
||||
attrMissing ks (Just s) = do
|
||||
s' <- prettyNValue s
|
||||
evalError @(NValue m) $ ErrorCall $ "Could not look up attribute "
|
||||
evalError @(NValue t f m) $ ErrorCall $ "Could not look up attribute "
|
||||
++ intercalate "." (map Text.unpack (NE.toList ks))
|
||||
++ " in " ++ show s'
|
||||
|
||||
evalCurPos = do
|
||||
scope <- currentScopes
|
||||
span@(SrcSpan delta _) <- currentPos
|
||||
addProvenance (\_ -> Provenance scope (NSym_ span "__curPos"))
|
||||
addProvenance @_ @f (Provenance scope (NSym_ span "__curPos"))
|
||||
<$> toValue delta
|
||||
|
||||
evaledSym name val = do
|
||||
scope <- currentScopes
|
||||
span <- currentPos
|
||||
pure $ addProvenance (const $ Provenance scope (NSym_ span name)) val
|
||||
pure $ addProvenance @_ @f (Provenance scope (NSym_ span name)) val
|
||||
|
||||
evalConstant c = do
|
||||
scope <- currentScopes
|
||||
|
@ -208,12 +208,12 @@ instance MonadNix e m => MonadEval (NValue m) m where
|
|||
evalLiteralPath p = do
|
||||
scope <- currentScopes
|
||||
span <- currentPos
|
||||
nvPathP (Provenance scope (NLiteralPath_ span p)) <$> makeAbsolutePath p
|
||||
nvPathP (Provenance scope (NLiteralPath_ span p)) <$> makeAbsolutePath @t @f @m p
|
||||
|
||||
evalEnvPath p = do
|
||||
scope <- currentScopes
|
||||
span <- currentPos
|
||||
nvPathP (Provenance scope (NEnvPath_ span p)) <$> findEnvPath p
|
||||
nvPathP (Provenance scope (NEnvPath_ span p)) <$> findEnvPath @t @f @m p
|
||||
|
||||
evalUnary op arg = do
|
||||
scope <- currentScopes
|
||||
|
@ -228,7 +228,7 @@ instance MonadNix e m => MonadEval (NValue m) m where
|
|||
evalWith c b = do
|
||||
scope <- currentScopes
|
||||
span <- currentPos
|
||||
addProvenance (\b -> Provenance scope (NWith_ span Nothing (Just b)))
|
||||
(\b -> addProvenance (Provenance scope (NWith_ span Nothing (Just b))) b)
|
||||
<$> evalWithAttrSet c b
|
||||
|
||||
evalIf c t f = do
|
||||
|
@ -236,34 +236,34 @@ instance MonadNix e m => MonadEval (NValue m) m where
|
|||
span <- currentPos
|
||||
fromValue c >>= \b ->
|
||||
if b
|
||||
then addProvenance (\t -> Provenance scope (NIf_ span (Just c) (Just t) Nothing)) <$> t
|
||||
else addProvenance (\f -> Provenance scope (NIf_ span (Just c) Nothing (Just f))) <$> f
|
||||
then (\t -> addProvenance (Provenance scope (NIf_ span (Just c) (Just t) Nothing)) t) <$> t
|
||||
else (\f -> addProvenance (Provenance scope (NIf_ span (Just c) Nothing (Just f))) f) <$> f
|
||||
|
||||
evalAssert c body = fromValue c >>= \b -> do
|
||||
span <- currentPos
|
||||
if b
|
||||
then do
|
||||
scope <- currentScopes
|
||||
addProvenance (\b -> Provenance scope (NAssert_ span (Just c) (Just b))) <$> body
|
||||
(\b -> addProvenance (Provenance scope (NAssert_ span (Just c) (Just b))) b) <$> body
|
||||
else nverr $ Assertion span c
|
||||
|
||||
evalApp f x = do
|
||||
scope <- currentScopes
|
||||
span <- currentPos
|
||||
addProvenance (const $ Provenance scope (NBinary_ span NApp (Just f) Nothing))
|
||||
addProvenance (Provenance scope (NBinary_ span NApp (Just f) Nothing))
|
||||
<$> callFunc f x
|
||||
|
||||
evalAbs p k = do
|
||||
scope <- currentScopes
|
||||
span <- currentPos
|
||||
pure $ nvClosureP (Provenance scope (NAbs_ span (Nothing <$ p) Nothing))
|
||||
(void p) (\arg -> snd <$> k arg (\_ b -> ((),) <$> b))
|
||||
(void p) (\arg -> wrapValue . snd <$> k arg (\_ b -> ((),) <$> b))
|
||||
|
||||
evalError = throwError
|
||||
|
||||
infixl 1 `callFunc`
|
||||
callFunc :: forall e m. (MonadNix e m, Typeable m)
|
||||
=> NValue m -> m (NValue m) -> m (NValue m)
|
||||
callFunc :: forall e t f m. MonadNix e t f m
|
||||
=> NValue t f m -> m (NValue t f m) -> m (NValue t f m)
|
||||
callFunc fun arg = do
|
||||
frames :: Frames <- asks (view hasLens)
|
||||
when (length frames > 2000) $
|
||||
|
@ -271,18 +271,18 @@ callFunc fun arg = do
|
|||
case fun of
|
||||
NVClosure params f -> do
|
||||
traceM $ "callFunc:NVFunction taking " ++ show params
|
||||
f arg
|
||||
force ?? pure =<< f arg
|
||||
NVBuiltin name f -> do
|
||||
span <- currentPos
|
||||
withFrame Info (Calling @m @(NThunk m) name span) $ f arg
|
||||
force ?? pure =<< withFrame Info (Calling @m @t name span) (f arg)
|
||||
s@(NVSet m _) | Just f <- M.lookup "__functor" m -> do
|
||||
traceM "callFunc:__functor"
|
||||
force f $ (`callFunc` pure s) >=> (`callFunc` arg)
|
||||
x -> throwError $ ErrorCall $ "Attempt to call non-function: " ++ show x
|
||||
|
||||
execUnaryOp :: (Framed e m, MonadVar m)
|
||||
=> Scopes m (NThunk m) -> SrcSpan -> NUnaryOp -> NValue m
|
||||
-> m (NValue m)
|
||||
execUnaryOp :: (Framed e m, Cited t f m, Show t)
|
||||
=> Scopes m t -> SrcSpan -> NUnaryOp -> NValue t f m
|
||||
-> m (NValue t f m)
|
||||
execUnaryOp scope span op arg = do
|
||||
traceM "NUnary"
|
||||
case arg of
|
||||
|
@ -298,13 +298,16 @@ execUnaryOp scope span op arg = do
|
|||
unaryOp = pure . nvConstantP (Provenance scope (NUnary_ span op (Just arg)))
|
||||
|
||||
execBinaryOp
|
||||
:: forall e m. (MonadNix e m, MonadEval (NValue m) m)
|
||||
=> Scopes m (NThunk m)
|
||||
:: forall e t f m.
|
||||
(MonadNix e t f m,
|
||||
FromValue NixString m t,
|
||||
MonadEval (NValue t f m) m)
|
||||
=> Scopes m t
|
||||
-> SrcSpan
|
||||
-> NBinaryOp
|
||||
-> NValue m
|
||||
-> m (NValue m)
|
||||
-> m (NValue m)
|
||||
-> NValue t f m
|
||||
-> m (NValue t f m)
|
||||
-> m (NValue t f m)
|
||||
|
||||
execBinaryOp scope span NOr larg rarg = fromNix larg >>= \l ->
|
||||
if l
|
||||
|
@ -324,7 +327,7 @@ execBinaryOp scope span NAnd larg rarg = fromNix larg >>= \l ->
|
|||
|
||||
execBinaryOp scope span op lval rarg = do
|
||||
rval <- rarg
|
||||
let bin :: (Provenance m -> a) -> a
|
||||
let bin :: (Provenance t f m -> a) -> a
|
||||
bin f = f (Provenance scope (NBinary_ span op (Just lval) (Just rval)))
|
||||
toBool = pure . bin nvConstantP . NBool
|
||||
case (lval, rval) of
|
||||
|
@ -420,11 +423,12 @@ execBinaryOp scope span op lval rarg = do
|
|||
(NVPath p, NVStr ns) -> case op of
|
||||
NEq -> toBool False -- From eqValues in nix/src/libexpr/eval.cc
|
||||
NNEq -> toBool True
|
||||
NPlus -> bin nvPathP <$> makeAbsolutePath (p `mappend` Text.unpack (hackyStringIgnoreContext ns))
|
||||
NPlus -> bin nvPathP <$> makeAbsolutePath @t @f
|
||||
(p `mappend` Text.unpack (hackyStringIgnoreContext ns))
|
||||
_ -> nverr $ ErrorCall $ unsupportedTypes lval rval
|
||||
|
||||
(NVPath ls, NVPath rs) -> case op of
|
||||
NPlus -> bin nvPathP <$> makeAbsolutePath (ls ++ rs)
|
||||
NPlus -> bin nvPathP <$> makeAbsolutePath @t @f (ls ++ rs)
|
||||
_ -> nverr $ ErrorCall $ unsupportedTypes lval rval
|
||||
|
||||
_ -> case op of
|
||||
|
@ -437,14 +441,14 @@ execBinaryOp scope span op lval rarg = do
|
|||
"Unsupported argument types for binary operator "
|
||||
++ show op ++ ": " ++ show lval ++ ", " ++ show rval
|
||||
|
||||
numBinOp :: (forall r. (Provenance m -> r) -> r)
|
||||
-> (forall a. Num a => a -> a -> a) -> NAtom -> NAtom -> m (NValue m)
|
||||
numBinOp :: (forall r. (Provenance t f m -> r) -> r)
|
||||
-> (forall a. Num a => a -> a -> a) -> NAtom -> NAtom -> m (NValue t f m)
|
||||
numBinOp bin f = numBinOp' bin f f
|
||||
|
||||
numBinOp' :: (forall r. (Provenance m -> r) -> r)
|
||||
numBinOp' :: (forall r. (Provenance t f m -> r) -> r)
|
||||
-> (Integer -> Integer -> Integer)
|
||||
-> (Float -> Float -> Float)
|
||||
-> NAtom -> NAtom -> m (NValue m)
|
||||
-> NAtom -> NAtom -> m (NValue t f m)
|
||||
numBinOp' bin intF floatF l r = case (l, r) of
|
||||
(NInt li, NInt ri) -> toInt $ li `intF` ri
|
||||
(NInt li, NFloat rf) -> toFloat $ fromInteger li `floatF` rf
|
||||
|
@ -471,7 +475,7 @@ data CopyToStoreMode
|
|||
-- ^ Add paths to the store as they are encountered
|
||||
deriving (Eq,Ord,Enum,Bounded)
|
||||
|
||||
coerceToString :: MonadNix e m => CopyToStoreMode -> CoercionLevel -> NValue m -> m NixString
|
||||
coerceToString :: MonadNix e t f m => CopyToStoreMode -> CoercionLevel -> NValue t f m -> m NixString
|
||||
coerceToString ctsm clevel = go
|
||||
where
|
||||
go = \case
|
||||
|
@ -502,71 +506,94 @@ coerceToString ctsm clevel = go
|
|||
where
|
||||
t = Text.pack $ unStorePath sp
|
||||
|
||||
fromStringNoContext :: MonadNix e m => NixString -> m Text
|
||||
fromStringNoContext :: MonadNix e t f m => NixString -> m Text
|
||||
fromStringNoContext ns =
|
||||
case principledGetStringNoContext ns of
|
||||
Just str -> return str
|
||||
Nothing -> throwError $ ErrorCall
|
||||
"expected string with no context"
|
||||
|
||||
newtype Lazy m a = Lazy
|
||||
{ runLazy :: ReaderT (Context (Lazy m) (NThunk (Lazy m)))
|
||||
(StateT (HashMap FilePath NExprLoc) (FreshIdT Int m)) a }
|
||||
deriving (Functor, Applicative, Alternative, Monad, MonadPlus,
|
||||
MonadFix, MonadIO,
|
||||
MonadReader (Context (Lazy m) (NThunk (Lazy m))))
|
||||
newtype Lazy t (f :: * -> *) m a = Lazy
|
||||
{ runLazy :: ReaderT (Context (Lazy t f m) t)
|
||||
(StateT (HashMap FilePath NExprLoc) m) a }
|
||||
deriving
|
||||
( Functor
|
||||
, Applicative
|
||||
, Alternative
|
||||
, Monad
|
||||
, MonadPlus
|
||||
, MonadFix
|
||||
, MonadIO
|
||||
, MonadReader (Context (Lazy t f m) t)
|
||||
)
|
||||
|
||||
instance MonadTrans Lazy where
|
||||
lift = Lazy . lift . lift . lift
|
||||
instance MonadTrans (Lazy t f) where
|
||||
lift = Lazy . lift . lift
|
||||
|
||||
instance MonadRef m => MonadRef (Lazy m) where
|
||||
type Ref (Lazy m) = Ref m
|
||||
instance MonadRef m => MonadRef (Lazy t f m) where
|
||||
type Ref (Lazy t f m) = Ref m
|
||||
newRef = lift . newRef
|
||||
readRef = lift . readRef
|
||||
writeRef r = lift . writeRef r
|
||||
|
||||
instance MonadAtomicRef m => MonadAtomicRef (Lazy m) where
|
||||
instance MonadAtomicRef m => MonadAtomicRef (Lazy t f m) where
|
||||
atomicModifyRef r = lift . atomicModifyRef r
|
||||
|
||||
instance (MonadFile m, Monad m) => MonadFile (Lazy m)
|
||||
instance (MonadFile m, Monad m) => MonadFile (Lazy t f m)
|
||||
|
||||
instance MonadCatch m => MonadCatch (Lazy m) where
|
||||
instance MonadCatch m => MonadCatch (Lazy t f m) where
|
||||
catch (Lazy (ReaderT m)) f = Lazy $ ReaderT $ \e ->
|
||||
catch (m e) ((`runReaderT` e) . runLazy . f)
|
||||
|
||||
instance MonadThrow m => MonadThrow (Lazy m) where
|
||||
instance MonadThrow m => MonadThrow (Lazy t f m) where
|
||||
throwM = Lazy . throwM
|
||||
|
||||
#ifdef MIN_VERSION_haskeline
|
||||
instance MonadException m => MonadException (Lazy m) where
|
||||
instance MonadException m => MonadException (Lazy t f m) where
|
||||
controlIO f = Lazy $ controlIO $ \(RunIO run) ->
|
||||
let run' = RunIO (fmap Lazy . run . runLazy)
|
||||
in runLazy <$> f run'
|
||||
#endif
|
||||
|
||||
instance Monad m => MonadFreshId Int (Lazy m) where
|
||||
freshId = Lazy $ lift $ lift freshId
|
||||
|
||||
instance MonadStore m => MonadStore (Lazy m) where
|
||||
instance MonadStore m => MonadStore (Lazy t f m) where
|
||||
addPath' = lift . addPath'
|
||||
toFile_' n = lift . toFile_' n
|
||||
|
||||
instance MonadPutStr m => MonadPutStr (Lazy m)
|
||||
instance MonadPutStr m => MonadPutStr (Lazy t f m)
|
||||
|
||||
instance MonadHttp m => MonadHttp (Lazy m)
|
||||
instance MonadHttp m => MonadHttp (Lazy t f m)
|
||||
|
||||
instance MonadEnv m => MonadEnv (Lazy m)
|
||||
instance MonadEnv m => MonadEnv (Lazy t f m)
|
||||
|
||||
instance MonadInstantiate m => MonadInstantiate (Lazy m)
|
||||
instance MonadInstantiate m => MonadInstantiate (Lazy t f m)
|
||||
|
||||
instance MonadExec m => MonadExec (Lazy m)
|
||||
instance MonadExec m => MonadExec (Lazy t f m)
|
||||
|
||||
instance MonadIntrospect m => MonadIntrospect (Lazy m)
|
||||
instance MonadIntrospect m => MonadIntrospect (Lazy t f m)
|
||||
|
||||
instance (MonadFix m, MonadCatch m, MonadFile m, MonadStore m, MonadVar m,
|
||||
MonadPutStr m, MonadHttp m, MonadEnv m, MonadInstantiate m, MonadExec m,
|
||||
MonadIntrospect m, Alternative m, MonadPlus m, Typeable m)
|
||||
=> MonadEffects (Lazy m) where
|
||||
instance MonadThunkId m => MonadThunkId (Lazy t f m) where
|
||||
type ThunkId (Lazy t f m) = ThunkId m
|
||||
|
||||
instance ( MonadFix m
|
||||
, MonadCatch m
|
||||
, MonadFile m
|
||||
, MonadStore m
|
||||
, MonadPutStr m
|
||||
, MonadHttp m
|
||||
, MonadEnv m
|
||||
, MonadInstantiate m
|
||||
, MonadExec m
|
||||
, MonadIntrospect m
|
||||
, Alternative m
|
||||
, MonadPlus m
|
||||
, MonadCitedThunks t f (Lazy t f m)
|
||||
, FromNix Bool (Lazy t f m) t
|
||||
, FromValue NixString (Lazy t f m) t
|
||||
, FromValue Path (Lazy t f m) t
|
||||
, ToNix NixString (Lazy t f m) t
|
||||
, ToNix [t] (Lazy t f m) t
|
||||
)
|
||||
=> MonadEffects t f (Lazy t f m) where
|
||||
makeAbsolutePath origPath = do
|
||||
origPathExpanded <- expandHomePath origPath
|
||||
absPath <- if isAbsolute origPathExpanded then pure origPathExpanded else do
|
||||
|
@ -608,17 +635,18 @@ instance (MonadFix m, MonadCatch m, MonadFile m, MonadStore m, MonadVar m,
|
|||
modify (M.insert path expr)
|
||||
pure expr
|
||||
|
||||
derivationStrict = fromValue @(ValueSet (Lazy m)) >=> \s -> do
|
||||
derivationStrict = fromValue @(AttrSet t) >=> \s -> do
|
||||
nn <- maybe (pure False) fromNix (M.lookup "__ignoreNulls" s)
|
||||
s' <- M.fromList <$> mapMaybeM (handleEntry nn) (M.toList s)
|
||||
v' <- normalForm =<< toValue @(ValueSet (Lazy m)) s'
|
||||
v' <- normalForm
|
||||
=<< toValue @(AttrSet t) @_ @(NValue t f (Lazy t f m)) s'
|
||||
nixInstantiateExpr $ "derivationStrict " ++ show (prettyNValueNF v')
|
||||
where
|
||||
mapMaybeM :: (a -> Lazy m (Maybe b)) -> [a] -> Lazy m [b]
|
||||
mapMaybeM :: (a -> Lazy t f m (Maybe b)) -> [a] -> Lazy t f m [b]
|
||||
mapMaybeM op = foldr f (return [])
|
||||
where f x xs = op x >>= (<$> xs) . (++) . maybeToList
|
||||
|
||||
handleEntry :: Bool -> (Text, NThunk (Lazy m)) -> Lazy m (Maybe (Text, NThunk (Lazy m)))
|
||||
handleEntry :: Bool -> (Text, t) -> Lazy t f m (Maybe (Text, t))
|
||||
handleEntry ignoreNulls (k, v) = fmap (k,) <$> case k of
|
||||
-- The `args' attribute is special: it supplies the command-line
|
||||
-- arguments to the builder.
|
||||
|
@ -631,16 +659,17 @@ instance (MonadFix m, MonadCatch m, MonadFile m, MonadStore m, MonadVar m,
|
|||
v' -> Just <$> coerceNix v'
|
||||
where
|
||||
coerceNix = toNix <=< coerceToString CopyToStore CoerceAny
|
||||
coerceNixList = toNix <=< traverse (\x -> force x coerceNix) <=< fromValue @[NThunk (Lazy m)]
|
||||
coerceNixList =
|
||||
toNix <=< traverse (\x -> force x coerceNix)
|
||||
<=< fromValue @[t]
|
||||
|
||||
traceEffect = putStrLn
|
||||
|
||||
getRecursiveSize :: MonadIntrospect m => a -> m (NValue m)
|
||||
getRecursiveSize = toNix @Integer . fromIntegral <=< recursiveSize
|
||||
getRecursiveSize :: (MonadIntrospect m, Applicative f) => a -> m (NValue t f m)
|
||||
getRecursiveSize = fmap (nvConstant . NInt . fromIntegral) . recursiveSize
|
||||
|
||||
runLazyM :: Options -> MonadIO m => Lazy m a -> m a
|
||||
runLazyM opts = runFreshIdT 0
|
||||
. (`evalStateT` M.empty)
|
||||
runLazyM :: Options -> MonadIO m => Lazy t f m a -> m a
|
||||
runLazyM opts = (`evalStateT` M.empty)
|
||||
. (`runReaderT` newContext opts)
|
||||
. runLazy
|
||||
|
||||
|
@ -673,9 +702,11 @@ x <///> y | isAbsolute y || "." `isPrefixOf` y = x </> y
|
|||
joinPath $ head [ xs ++ drop (length tx) ys
|
||||
| tx <- tails xs, tx `elem` inits ys ]
|
||||
|
||||
findPathBy :: forall e m. MonadNix e m =>
|
||||
(FilePath -> m (Maybe FilePath)) ->
|
||||
[NThunk m] -> FilePath -> m FilePath
|
||||
findPathBy
|
||||
:: forall e t f m.
|
||||
(MonadNix e t f m, FromValue NixString m t, FromValue Path m t)
|
||||
=> (FilePath -> m (Maybe FilePath))
|
||||
-> [t] -> FilePath -> m FilePath
|
||||
findPathBy finder l name = do
|
||||
mpath <- foldM go Nothing l
|
||||
case mpath of
|
||||
|
@ -685,10 +716,10 @@ findPathBy finder l name = do
|
|||
++ " (add it using $NIX_PATH or -I)"
|
||||
Just path -> return path
|
||||
where
|
||||
go :: Maybe FilePath -> NThunk m -> m (Maybe FilePath)
|
||||
go :: Maybe FilePath -> t -> m (Maybe FilePath)
|
||||
go p@(Just _) _ = pure p
|
||||
go Nothing l = force l $ fromValue >=>
|
||||
\(s :: HashMap Text (NThunk m)) -> do
|
||||
\(s :: HashMap Text t) -> do
|
||||
p <- resolvePath s
|
||||
force p $ fromValue >=> \(Path path) ->
|
||||
case M.lookup "prefix" s of
|
||||
|
@ -713,36 +744,40 @@ findPathBy finder l name = do
|
|||
throwError $ ErrorCall $ "__nixPath must be a list of attr sets"
|
||||
++ " with 'path' elements, but saw: " ++ show s
|
||||
|
||||
findPathM :: forall e m. MonadNix e m =>
|
||||
[NThunk m] -> FilePath -> m FilePath
|
||||
findPathM
|
||||
:: forall e t f m.
|
||||
(MonadNix e t f m, FromValue NixString m t, FromValue Path m t)
|
||||
=> [t] -> FilePath -> m FilePath
|
||||
findPathM l name = findPathBy path l name
|
||||
where
|
||||
path :: MonadEffects m => FilePath -> m (Maybe FilePath)
|
||||
path :: MonadEffects t f m => FilePath -> m (Maybe FilePath)
|
||||
path path = do
|
||||
path <- makeAbsolutePath path
|
||||
path <- makeAbsolutePath @t @f path
|
||||
exists <- doesPathExist path
|
||||
return $ if exists then Just path else Nothing
|
||||
|
||||
findEnvPathM :: forall e m. MonadNix e m
|
||||
=> FilePath -> m FilePath
|
||||
findEnvPathM
|
||||
:: forall e t f m.
|
||||
(MonadNix e t f m, FromValue NixString m t, FromValue Path m t)
|
||||
=> FilePath -> m FilePath
|
||||
findEnvPathM name = do
|
||||
mres <- lookupVar "__nixPath"
|
||||
case mres of
|
||||
Nothing -> error "impossible"
|
||||
Just x -> force x $ fromValue >=> \(l :: [NThunk m]) ->
|
||||
Just x -> force x $ fromValue >=> \(l :: [t]) ->
|
||||
findPathBy nixFilePath l name
|
||||
where
|
||||
nixFilePath :: MonadEffects m => FilePath -> m (Maybe FilePath)
|
||||
nixFilePath :: MonadEffects t f m => FilePath -> m (Maybe FilePath)
|
||||
nixFilePath path = do
|
||||
path <- makeAbsolutePath path
|
||||
path <- makeAbsolutePath @t @f path
|
||||
exists <- doesDirectoryExist path
|
||||
path' <- if exists
|
||||
then makeAbsolutePath $ path </> "default.nix"
|
||||
then makeAbsolutePath @t @f $ path </> "default.nix"
|
||||
else return path
|
||||
exists <- doesFileExist path'
|
||||
return $ if exists then Just path' else Nothing
|
||||
|
||||
addTracing :: (MonadNix e m, Has e Options,
|
||||
addTracing :: (MonadNix e t f m, Has e Options,
|
||||
MonadReader Int n, Alternative n)
|
||||
=> Alg NExprLocF (m a) -> Alg NExprLocF (n (m a))
|
||||
addTracing k v = do
|
||||
|
@ -767,21 +802,26 @@ addTracing k v = do
|
|||
print $ msg rendered <> " ...done"
|
||||
return res
|
||||
|
||||
evalExprLoc :: forall e m. (MonadNix e m, Has e Options)
|
||||
=> NExprLoc -> m (NValue m)
|
||||
evalExprLoc
|
||||
:: forall e t f m.
|
||||
(MonadNix e t f m, FromValue NixString m t, Has e Options)
|
||||
=> NExprLoc -> m (NValue t f m)
|
||||
evalExprLoc expr = do
|
||||
opts :: Options <- asks (view hasLens)
|
||||
if tracing opts
|
||||
then join . (`runReaderT` (0 :: Int)) $
|
||||
adi (addTracing phi)
|
||||
(raise (addStackFrames @(NThunk m) . addSourcePositions))
|
||||
(raise (addStackFrames @t . addSourcePositions))
|
||||
expr
|
||||
else adi phi (addStackFrames @(NThunk m) . addSourcePositions) expr
|
||||
else adi phi (addStackFrames @t . addSourcePositions) expr
|
||||
where
|
||||
phi = Eval.eval . annotated . getCompose
|
||||
raise k f x = ReaderT $ \e -> k (\t -> runReaderT (f t) e) x
|
||||
|
||||
fetchTarball :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||
fetchTarball
|
||||
:: forall e t f m.
|
||||
(MonadNix e t f m, FromValue NixString m t)
|
||||
=> m (NValue t f m) -> m (NValue t f m)
|
||||
fetchTarball v = v >>= \case
|
||||
NVSet s _ -> case M.lookup "url" s of
|
||||
Nothing -> throwError $ ErrorCall
|
||||
|
@ -791,14 +831,14 @@ fetchTarball v = v >>= \case
|
|||
v -> throwError $ ErrorCall $
|
||||
"builtins.fetchTarball: Expected URI or set, got " ++ show v
|
||||
where
|
||||
go :: Maybe (NThunk m) -> NValue m -> m (NValue m)
|
||||
go :: Maybe t -> NValue t f m -> m (NValue t f m)
|
||||
go msha = \case
|
||||
NVStr ns -> fetch (hackyStringIgnoreContext ns) msha
|
||||
v -> throwError $ ErrorCall $
|
||||
"builtins.fetchTarball: Expected URI or string, got " ++ show v
|
||||
|
||||
{- jww (2018-04-11): This should be written using pipes in another module
|
||||
fetch :: Text -> Maybe (NThunk m) -> m (NValue m)
|
||||
fetch :: Text -> Maybe (NThunk m) -> m (NValue t f m)
|
||||
fetch uri msha = case takeExtension (Text.unpack uri) of
|
||||
".tgz" -> undefined
|
||||
".gz" -> undefined
|
||||
|
@ -809,7 +849,7 @@ fetchTarball v = v >>= \case
|
|||
++ ext ++ "'"
|
||||
-}
|
||||
|
||||
fetch :: Text -> Maybe (NThunk m) -> m (NValue m)
|
||||
fetch :: Text -> Maybe t -> m (NValue t f m)
|
||||
fetch uri Nothing =
|
||||
nixInstantiateExpr $ "builtins.fetchTarball \"" ++
|
||||
Text.unpack uri ++ "\""
|
||||
|
@ -820,47 +860,25 @@ fetchTarball v = v >>= \case
|
|||
++ "sha256 = \"" ++ Text.unpack sha ++ "\"; }"
|
||||
|
||||
exec
|
||||
:: ( MonadExec m
|
||||
, Framed e m
|
||||
, MonadThrow m
|
||||
, Alternative m
|
||||
, MonadCatch m
|
||||
, MonadFix m
|
||||
, MonadEffects m
|
||||
, MonadFreshId Int m
|
||||
, GEq (Ref m)
|
||||
, MonadAtomicRef m
|
||||
, Typeable m
|
||||
, Has e Options
|
||||
, Has e SrcSpan
|
||||
, Scoped (NThunk m) m
|
||||
)
|
||||
:: ( MonadNix e t f m
|
||||
, MonadInstantiate m
|
||||
, FromValue NixString m t
|
||||
)
|
||||
=> [String]
|
||||
-> m (NValue m)
|
||||
-> m (NValue t f m)
|
||||
exec args = either throwError evalExprLoc =<< exec' args
|
||||
|
||||
nixInstantiateExpr
|
||||
:: ( MonadInstantiate m
|
||||
, Framed e m
|
||||
, MonadThrow m
|
||||
, Alternative m
|
||||
, MonadCatch m
|
||||
, MonadFix m
|
||||
, MonadEffects m
|
||||
, MonadFreshId Int m
|
||||
, GEq (Ref m)
|
||||
, MonadAtomicRef m
|
||||
, Typeable m
|
||||
, Has e Options
|
||||
, Has e SrcSpan
|
||||
, Scoped (NThunk m) m
|
||||
)
|
||||
:: ( MonadNix e t f m
|
||||
, MonadInstantiate m
|
||||
, FromValue NixString m t
|
||||
)
|
||||
=> String
|
||||
-> m (NValue m)
|
||||
-> m (NValue t f m)
|
||||
nixInstantiateExpr s = either throwError evalExprLoc =<< instantiateExpr s
|
||||
|
||||
instance Monad m => Scoped (NThunk (Lazy m)) (Lazy m) where
|
||||
instance Monad m => Scoped t (Lazy t f m) where
|
||||
currentScopes = currentScopesReader
|
||||
clearScopes = clearScopesReader @(Lazy m) @(NThunk (Lazy m))
|
||||
clearScopes = clearScopesReader @(Lazy t f m) @t
|
||||
pushScopes = pushScopesReader
|
||||
lookupVar = lookupVarReader
|
||||
|
|
|
@ -70,6 +70,9 @@ import qualified Type.Reflection as Reflection
|
|||
|
||||
type VarName = Text
|
||||
|
||||
hashAt :: VarName -> Lens' (AttrSet v) (Maybe v)
|
||||
hashAt = flip alterF
|
||||
|
||||
-- unfortunate orphans
|
||||
#if MIN_VERSION_hashable(1, 2, 5)
|
||||
instance Hashable1 NonEmpty
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
{-# LANGUAGE FunctionalDependencies #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
|
||||
|
@ -14,6 +15,7 @@
|
|||
module Nix.Fresh where
|
||||
|
||||
import Control.Applicative
|
||||
import Control.Monad.Base
|
||||
import Control.Monad.Catch
|
||||
import Control.Monad.Except
|
||||
import Control.Monad.Reader
|
||||
|
@ -21,24 +23,21 @@ import Control.Monad.Ref
|
|||
import Control.Monad.ST
|
||||
import Control.Monad.State.Strict
|
||||
import Control.Monad.Writer
|
||||
import Data.Typeable
|
||||
#ifdef MIN_VERSION_haskeline
|
||||
import System.Console.Haskeline.MonadException hiding (catch)
|
||||
#endif
|
||||
|
||||
-- TODO better fresh name supply
|
||||
class Monad m => MonadFreshId i m | m -> i where
|
||||
freshId :: m i
|
||||
default freshId :: (MonadFreshId i m', MonadTrans t, m ~ (t m')) => m i
|
||||
freshId = lift freshId
|
||||
import Nix.Var
|
||||
import Nix.Thunk
|
||||
|
||||
newtype FreshIdT i m a = FreshIdT { unFreshIdT :: StateT i m a }
|
||||
newtype FreshIdT i m a = FreshIdT { unFreshIdT :: ReaderT (Var m i) m a }
|
||||
deriving
|
||||
( Functor
|
||||
, Applicative
|
||||
, Alternative
|
||||
, Monad
|
||||
, MonadPlus
|
||||
, MonadTrans
|
||||
, MonadFix
|
||||
, MonadRef
|
||||
, MonadAtomicRef
|
||||
|
@ -50,16 +49,46 @@ newtype FreshIdT i m a = FreshIdT { unFreshIdT :: StateT i m a }
|
|||
#endif
|
||||
)
|
||||
|
||||
instance (Monad m, Num i) => MonadFreshId i (FreshIdT i m) where
|
||||
freshId = FreshIdT $ get <* modify (+ 1)
|
||||
instance MonadTrans (FreshIdT i) where
|
||||
lift = FreshIdT . lift
|
||||
|
||||
runFreshIdT :: Functor m => i -> FreshIdT i m a -> m a
|
||||
runFreshIdT i m = fst <$> runStateT (unFreshIdT m) i
|
||||
instance MonadBase b m => MonadBase b (FreshIdT i m) where
|
||||
liftBase = FreshIdT . liftBase
|
||||
|
||||
instance MonadFreshId i m => MonadFreshId i (ReaderT r m)
|
||||
instance (Monoid w, MonadFreshId i m) => MonadFreshId i (WriterT w m)
|
||||
instance MonadFreshId i m => MonadFreshId i (ExceptT e m)
|
||||
instance MonadFreshId i m => MonadFreshId i (StateT s m)
|
||||
-- instance MonadTransControl (FreshIdT i) where
|
||||
-- type StT (FreshIdT i) a = StT (ReaderT (Var m i)) a
|
||||
-- liftWith = defaultLiftWith FreshIdT unFreshIdT
|
||||
-- restoreT = defaultRestoreT FreshIdT
|
||||
|
||||
-- instance MonadBaseControl b m => MonadBaseControl b (FreshIdT i m) where
|
||||
-- type StM (FreshIdT i m) a = ComposeSt (FreshIdT i) m a
|
||||
-- liftBaseWith = defaultLiftBaseWith
|
||||
-- restoreM = defaultRestoreM
|
||||
|
||||
instance ( MonadVar m
|
||||
, Eq i
|
||||
, Ord i
|
||||
, Show i
|
||||
, Enum i
|
||||
, Typeable i
|
||||
)
|
||||
=> MonadThunkId (FreshIdT i m) where
|
||||
type ThunkId (FreshIdT i m) = i
|
||||
freshId = FreshIdT $ do
|
||||
v <- ask
|
||||
atomicModifyVar v (\i -> (succ i, i))
|
||||
|
||||
runFreshIdT :: Functor m => Var m i -> FreshIdT i m a -> m a
|
||||
runFreshIdT i m = runReaderT (unFreshIdT m) i
|
||||
|
||||
instance MonadThunkId m => MonadThunkId (ReaderT r m) where
|
||||
type ThunkId (ReaderT r m) = ThunkId m
|
||||
instance (Monoid w, MonadThunkId m) => MonadThunkId (WriterT w m) where
|
||||
type ThunkId (WriterT w m) = ThunkId m
|
||||
instance MonadThunkId m => MonadThunkId (ExceptT e m) where
|
||||
type ThunkId (ExceptT e m) = ThunkId m
|
||||
instance MonadThunkId m => MonadThunkId (StateT s m) where
|
||||
type ThunkId (StateT s m) = ThunkId m
|
||||
|
||||
-- Orphan instance needed by Infer.hs and Lint.hs
|
||||
|
||||
|
|
|
@ -22,12 +22,14 @@ import Nix.Thunk
|
|||
import Nix.Utils
|
||||
import Nix.Value
|
||||
|
||||
nvalueToJSONNixString :: MonadNix e m => NValue m -> m NixString
|
||||
nvalueToJSONNixString :: MonadNix e t f m => NValue t f m -> m NixString
|
||||
nvalueToJSONNixString = runWithStringContextT
|
||||
. fmap (TL.toStrict . TL.decodeUtf8 . A.encodingToLazyByteString . toEncodingSorted)
|
||||
. fmap (TL.toStrict . TL.decodeUtf8
|
||||
. A.encodingToLazyByteString
|
||||
. toEncodingSorted)
|
||||
. nvalueToJSON
|
||||
|
||||
nvalueToJSON :: MonadNix e m => NValue m -> WithStringContextT m A.Value
|
||||
nvalueToJSON :: MonadNix e t f m => NValue t f m -> WithStringContextT m A.Value
|
||||
nvalueToJSON = \case
|
||||
NVConstant (NInt n) -> pure $ A.toJSON n
|
||||
NVConstant (NFloat n) -> pure $ A.toJSON n
|
||||
|
@ -35,9 +37,11 @@ nvalueToJSON = \case
|
|||
NVConstant NNull -> pure $ A.Null
|
||||
NVStr ns -> A.toJSON <$> extractNixString ns
|
||||
NVList l ->
|
||||
A.Array . V.fromList <$> traverse (join . lift . flip force (return . nvalueToJSON)) l
|
||||
A.Array . V.fromList
|
||||
<$> traverse (join . lift . flip force (return . nvalueToJSON)) l
|
||||
NVSet m _ -> case HM.lookup "outPath" m of
|
||||
Nothing -> A.Object <$> traverse (join . lift . flip force (return . nvalueToJSON)) m
|
||||
Nothing -> A.Object
|
||||
<$> traverse (join . lift . flip force (return . nvalueToJSON)) m
|
||||
Just outPath -> join $ lift $ force outPath (return . nvalueToJSON)
|
||||
NVPath p -> do
|
||||
fp <- lift $ unStorePath <$> addPath p
|
||||
|
|
|
@ -120,7 +120,7 @@ unpackSymbolic :: MonadVar m
|
|||
unpackSymbolic = readVar . coerce
|
||||
|
||||
type MonadLint e m = (Scoped (SThunk m) m, Framed e m, MonadVar m,
|
||||
MonadCatch m, MonadFreshId Int m)
|
||||
MonadCatch m, MonadThunkId m)
|
||||
|
||||
symerr :: forall e m a. MonadLint e m => String -> m a
|
||||
symerr = evalError @(Symbolic m) . ErrorCall
|
||||
|
@ -248,12 +248,15 @@ instance FromValue (AttrSet (SThunk m), AttrSet SourcePos) m (Symbolic m) where
|
|||
|
||||
instance ToValue (AttrSet (SThunk m), AttrSet SourcePos) m (Symbolic m) where
|
||||
|
||||
instance MonadLint e m => MonadThunk (Symbolic m) (SThunk m) m where
|
||||
thunk = fmap coerce . buildThunk
|
||||
force = forceThunk . coerce
|
||||
forceEff = forceEffects . coerce
|
||||
wrapValue = coerce . valueRef
|
||||
getValue = thunkValue . coerce
|
||||
instance MonadLint e m => MonadThunk (SThunk m) m (Symbolic m) where
|
||||
thunk = fmap SThunk . thunk
|
||||
thunkId = thunkId . getSThunk
|
||||
query x b f = query (getSThunk x) b f
|
||||
queryM x b f = queryM (getSThunk x) b f
|
||||
force = force . getSThunk
|
||||
forceEff = forceEff . getSThunk
|
||||
wrapValue = SThunk . wrapValue
|
||||
getValue = getValue . getSThunk
|
||||
|
||||
instance MonadLint e m => MonadEval (Symbolic m) m where
|
||||
freeVariable var = symerr $
|
||||
|
@ -303,7 +306,7 @@ instance MonadLint e m => MonadEval (Symbolic m) m where
|
|||
-- evaluated each time a name is looked up within the weak scope, and
|
||||
-- we want to be sure the action it evaluates is to force a thunk, so
|
||||
-- its value is only computed once.
|
||||
s <- thunk @(Symbolic m) @(SThunk m) scope
|
||||
s <- thunk @(SThunk m) @m @(Symbolic m) scope
|
||||
pushWeakScope ?? body $ force s $ unpackSymbolic >=> \case
|
||||
NMany [TSet (Just s')] -> return s'
|
||||
NMany [TSet Nothing] -> error "NYI: with unknown"
|
||||
|
@ -400,7 +403,7 @@ newtype Lint s a = Lint
|
|||
, Monad
|
||||
, MonadFix
|
||||
, MonadReader (Context (Lint s) (SThunk (Lint s)))
|
||||
, MonadFreshId Int
|
||||
, MonadThunkId
|
||||
, MonadRef
|
||||
, MonadAtomicRef
|
||||
)
|
||||
|
@ -412,7 +415,9 @@ instance MonadCatch (Lint s) where
|
|||
catch _m _h = Lint $ ReaderT $ \_ -> error "Cannot catch in 'Lint s'"
|
||||
|
||||
runLintM :: Options -> Lint s a -> ST s a
|
||||
runLintM opts = runFreshIdT 0 . flip runReaderT (newContext opts) . runLint
|
||||
runLintM opts action = do
|
||||
i <- newVar (1 :: Int)
|
||||
runFreshIdT i $ flip runReaderT (newContext opts) $ runLint action
|
||||
|
||||
symbolicBaseEnv :: Monad m => m (Scopes m (SThunk m))
|
||||
symbolicBaseEnv = return emptyScopes
|
||||
|
|
|
@ -12,98 +12,94 @@
|
|||
|
||||
module Nix.Normal where
|
||||
|
||||
import Control.Monad
|
||||
import Control.Monad.Free
|
||||
import Control.Monad.Trans.Class
|
||||
import Control.Monad.Trans.State
|
||||
import qualified Data.HashMap.Lazy as M
|
||||
import Data.List (find)
|
||||
import Data.Maybe (isJust)
|
||||
import Nix.Frames
|
||||
-- import Nix.Pretty
|
||||
import Nix.Thunk
|
||||
import Nix.Thunk.Basic
|
||||
import Nix.Utils
|
||||
import Nix.Value
|
||||
import Nix.Var
|
||||
import Control.Monad
|
||||
import Control.Monad.Trans.Class
|
||||
import Control.Monad.Trans.Reader
|
||||
import Control.Monad.Trans.State
|
||||
import Data.Set
|
||||
import Nix.Frames
|
||||
import Nix.String
|
||||
import Nix.Thunk
|
||||
import Nix.Value
|
||||
|
||||
newtype NormalLoop m = NormalLoop (NValue m)
|
||||
newtype NormalLoop t f m = NormalLoop (NValue t f m)
|
||||
deriving Show
|
||||
|
||||
instance Typeable m => Exception (NormalLoop m)
|
||||
instance MonadDataErrorContext t f m => Exception (NormalLoop t f m)
|
||||
|
||||
normalFormBy
|
||||
:: forall e m. (Framed e m, MonadVar m, Typeable m)
|
||||
=> (forall r. NThunk m -> (NValue m -> StateT [Var m Bool] m r)
|
||||
-> StateT [Var m Bool] m r)
|
||||
-> Int
|
||||
-> NValue m
|
||||
-> StateT [Var m Bool] m (NValueNF m)
|
||||
normalFormBy k n v = case v of
|
||||
NVConstant a -> return $ Free $ NVConstantF a
|
||||
NVStr ns -> return $ Free $ NVStrF ns
|
||||
NVList l ->
|
||||
fmap (Free . NVListF) $ forM (zip [0..] l) $ \(i :: Int, t) -> do
|
||||
traceM $ show n ++ ": normalFormBy: List[" ++ show i ++ "]"
|
||||
k t (next t)
|
||||
NVSet s p ->
|
||||
fmap (Free . flip NVSetF p) $ sequence $ flip M.mapWithKey s $ \ky t -> do
|
||||
traceM $ show n ++ ": normalFormBy: Set{" ++ show ky ++ "}"
|
||||
k t (next t)
|
||||
NVClosure p f -> return $ Free $ NVClosureF p f
|
||||
NVPath fp -> return $ Free $ NVPathF fp
|
||||
NVBuiltin name f -> return $ Free $ NVBuiltinF name f
|
||||
_ -> error "Pattern synonyms mask complete matches"
|
||||
normalForm'
|
||||
:: forall e t m f.
|
||||
( Framed e m
|
||||
, MonadThunk t m (NValue t f m)
|
||||
, MonadDataErrorContext t f m
|
||||
, Ord (ThunkId m)
|
||||
)
|
||||
=> (forall r. t -> (NValue t f m -> m r) -> m r)
|
||||
-> NValue t f m
|
||||
-> m (NValueNF t f m)
|
||||
normalForm' f = run . nValueToNFM run go
|
||||
where
|
||||
next t val = do
|
||||
b <- seen t
|
||||
if b
|
||||
then return $ Pure val
|
||||
else normalFormBy k (succ n) val
|
||||
start = 0 :: Int
|
||||
table = mempty
|
||||
|
||||
seen (NThunk (NCited _ (Thunk _ b _))) = do
|
||||
res <- gets (isJust . find (eqVar @m b))
|
||||
unless res $
|
||||
modify (b:)
|
||||
return res
|
||||
seen _ = pure False
|
||||
run :: ReaderT Int (StateT (Set (ThunkId m)) m) r -> m r
|
||||
run = (`evalStateT` table) . (`runReaderT` start)
|
||||
|
||||
normalForm' :: forall e m. (Framed e m, MonadVar m, Typeable m,
|
||||
MonadThunk (NValue m) (NThunk m) m)
|
||||
=> (forall r. NThunk m -> (NValue m -> m r) -> m r)
|
||||
-> NValue m -> m (NValueNF m)
|
||||
normalForm' f = flip evalStateT mempty . normalFormBy go 0
|
||||
where
|
||||
go :: NThunk m
|
||||
-> (NValue m -> StateT [Var m Bool] m r)
|
||||
-> StateT [Var m Bool] m r
|
||||
go :: t
|
||||
-> (NValue t f m -> ReaderT Int (StateT (Set (ThunkId m)) m) (NValueNF t f m))
|
||||
-> ReaderT Int (StateT (Set (ThunkId m)) m) (NValueNF t f m)
|
||||
go t k = do
|
||||
s <- get
|
||||
(res, s') <- lift $ f t $ \v -> runStateT (k v) s
|
||||
put s'
|
||||
i <- ask
|
||||
when (i > 2000) $
|
||||
error "Exceeded maximum normalization depth of 2000 levels"
|
||||
s <- lift get
|
||||
(res, s') <- lift $ lift $ f t $ \v ->
|
||||
(`runStateT` s) . (`runReaderT` i) $ local succ $ do
|
||||
b <- seen t
|
||||
if b
|
||||
then return $ pure (error "Loop detected" <$ v)
|
||||
else k v
|
||||
lift $ put s'
|
||||
return res
|
||||
|
||||
normalForm :: forall e m. (Framed e m, MonadVar m, Typeable m,
|
||||
MonadThunk (NValue m) (NThunk m) m)
|
||||
=> NValue m -> m (NValueNF m)
|
||||
seen t = case thunkId t of
|
||||
Just tid -> lift $ do
|
||||
res <- gets (member tid)
|
||||
unless res $ modify (insert tid)
|
||||
return res
|
||||
Nothing ->
|
||||
return False
|
||||
|
||||
normalForm
|
||||
:: ( Framed e m
|
||||
, MonadThunk t m (NValue t f m)
|
||||
, MonadDataErrorContext t f m
|
||||
, Ord (ThunkId m)
|
||||
)
|
||||
=> NValue t f m -> m (NValueNF t f m)
|
||||
normalForm = normalForm' force
|
||||
|
||||
normalForm_
|
||||
:: forall e m. (Framed e m, MonadVar m, Typeable m,
|
||||
MonadThunk (NValue m) (NThunk m) m)
|
||||
=> NValue m -> m ()
|
||||
normalForm_ = void . normalForm' (forceEffects . _cited . _nThunk)
|
||||
:: ( Framed e m
|
||||
, MonadThunk t m (NValue t f m)
|
||||
, MonadDataErrorContext t f m
|
||||
, Ord (ThunkId m)
|
||||
)
|
||||
=> NValue t f m -> m ()
|
||||
normalForm_ = void <$> normalForm' forceEff
|
||||
|
||||
embed :: forall m. (MonadThunk (NValue m) (NThunk m) m)
|
||||
=> NValueNF m -> m (NValue m)
|
||||
embed (Pure v) = return v
|
||||
embed (Free x) = case x of
|
||||
NVConstantF a -> return $ nvConstant a
|
||||
NVStrF ns -> return $ nvStr ns
|
||||
NVListF l ->
|
||||
nvList . fmap (wrapValue @_ @_ @m) <$> traverse embed l
|
||||
NVSetF s p ->
|
||||
flip nvSet p . fmap (wrapValue @_ @_ @m) <$> traverse embed s
|
||||
NVClosureF p f -> return $ nvClosure p f
|
||||
NVPathF fp -> return $ nvPath fp
|
||||
NVBuiltinF n f -> return $ nvBuiltin n f
|
||||
removeEffects :: (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
||||
=> NValue t f m -> NValueNF t f m
|
||||
removeEffects = nValueToNF (flip query opaque)
|
||||
|
||||
removeEffectsM :: (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
||||
=> NValue t f m -> m (NValueNF t f m)
|
||||
removeEffectsM = nValueToNFM id (flip queryM (pure opaque))
|
||||
|
||||
opaque :: (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
||||
=> NValueNF t f m
|
||||
opaque = nvStrNF $ principledMakeNixStringWithoutContext "<thunk>"
|
||||
|
||||
dethunk :: (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
||||
=> t -> m (NValueNF t f m)
|
||||
dethunk t = queryM t (pure opaque) removeEffectsM
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE TypeSynonymInstances #-}
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
|
||||
|
@ -14,8 +17,7 @@
|
|||
module Nix.Pretty where
|
||||
|
||||
import Control.Applicative ((<|>))
|
||||
import Control.Monad
|
||||
import Control.Monad.Free
|
||||
import Control.Comonad
|
||||
import Data.Fix
|
||||
import Data.HashMap.Lazy (toList)
|
||||
import qualified Data.HashMap.Lazy as M
|
||||
|
@ -28,19 +30,19 @@ import Data.Text (pack, unpack, replace, strip)
|
|||
import qualified Data.Text as Text
|
||||
import Data.Text.Prettyprint.Doc
|
||||
import Nix.Atoms
|
||||
import Nix.Cited
|
||||
import Nix.Expr
|
||||
import Nix.Normal
|
||||
import Nix.Parser
|
||||
import Nix.String
|
||||
import Nix.Strings
|
||||
import Nix.Thunk
|
||||
import Nix.Thunk.Basic
|
||||
#if ENABLE_TRACING
|
||||
import Nix.Utils
|
||||
#else
|
||||
import Nix.Utils hiding ((<$>))
|
||||
#endif
|
||||
import Nix.Value
|
||||
import Nix.Var
|
||||
import Prelude hiding ((<$>))
|
||||
import Text.Read (readMaybe)
|
||||
|
||||
|
@ -170,14 +172,22 @@ prettyAtom atom = simpleExpr $ pretty $ unpack $ atomText atom
|
|||
prettyNix :: NExpr -> Doc ann
|
||||
prettyNix = withoutParens . cata exprFNixDoc
|
||||
|
||||
prettyOriginExpr :: NExprLocF (Maybe (NValue m)) -> Doc ann
|
||||
instance HasCitations1 t f m
|
||||
=> HasCitations t f m (NValue' t f m a) where
|
||||
citations (NValue f) = citations1 f
|
||||
addProvenance x (NValue f) = NValue (addProvenance1 x f)
|
||||
|
||||
prettyOriginExpr :: forall t f m ann. HasCitations1 t f m
|
||||
=> NExprLocF (Maybe (NValue t f m)) -> Doc ann
|
||||
prettyOriginExpr = withoutParens . go
|
||||
where
|
||||
go = exprFNixDoc . annotated . getCompose . fmap render
|
||||
|
||||
render :: Maybe (NValue t f m) -> NixDoc ann
|
||||
render Nothing = simpleExpr $ "_"
|
||||
render (Just (NValue (NCited (reverse -> p:_) _))) = go (_originExpr p)
|
||||
render (Just (NValue (NCited _ _))) = simpleExpr "?"
|
||||
render (Just (reverse . citations @t @f @m -> p:_)) = go (_originExpr p)
|
||||
render _ = simpleExpr "?"
|
||||
-- render (Just (NValue (citations -> ps))) =
|
||||
-- simpleExpr $ foldr ((\x y -> vsep [x, y]) . parens . indent 2 . withoutParens
|
||||
-- . go . originExpr)
|
||||
-- mempty (reverse ps)
|
||||
|
@ -264,42 +274,36 @@ exprFNixDoc = \case
|
|||
where
|
||||
recPrefix = "rec" <> space
|
||||
|
||||
fixate :: Functor f => (a -> f (Fix f)) -> Free f a -> Fix f
|
||||
fixate g = Fix . go
|
||||
valueToExpr :: forall t f m. MonadDataContext f m => NValueNF t f m -> NExpr
|
||||
valueToExpr = iterNValueNF
|
||||
(const (mkStr (principledMakeNixStringWithoutContext "<CYCLE>")))
|
||||
phi
|
||||
where
|
||||
go (Pure a) = g a
|
||||
go (Free f) = fmap (Fix . go) f
|
||||
|
||||
valueToExpr :: Functor m => NValueNF m -> NExpr
|
||||
valueToExpr = transport go . check
|
||||
where
|
||||
check :: NValueNF m -> Fix (NValueF m)
|
||||
check = fixate $ const $ NVStrF $ principledMakeNixStringWithoutContext "<CYCLE>"
|
||||
|
||||
go (NVConstantF a) = NConstant a
|
||||
go (NVStrF ns) = NStr (DoubleQuoted [Plain (hackyStringIgnoreContext ns)])
|
||||
go (NVListF l) = NList l
|
||||
go (NVSetF s p) = NSet
|
||||
phi :: NValue' t f m NExpr -> NExpr
|
||||
phi (NVConstant a) = Fix $ NConstant a
|
||||
phi (NVStr ns) = mkStr ns
|
||||
phi (NVList l) = Fix $ NList l
|
||||
phi (NVSet s p) = Fix $ NSet
|
||||
[ NamedVar (StaticKey k :| []) v (fromMaybe nullPos (M.lookup k p))
|
||||
| (k, v) <- toList s ]
|
||||
go (NVClosureF _ _) = NSym . pack $ "<closure>"
|
||||
go (NVPathF p) = NLiteralPath p
|
||||
go (NVBuiltinF name _) = NSym $ Text.pack $ "builtins." ++ name
|
||||
phi (NVClosure _ _) = Fix . NSym . pack $ "<closure>"
|
||||
phi (NVPath p) = Fix $ NLiteralPath p
|
||||
phi (NVBuiltin name _) = Fix . NSym . pack $ "builtins." ++ name
|
||||
phi _ = error "Pattern synonyms foil completeness check"
|
||||
|
||||
prettyNValueNF :: Functor m => NValueNF m -> Doc ann
|
||||
mkStr ns = Fix $ NStr $ DoubleQuoted [Plain (hackyStringIgnoreContext ns)]
|
||||
|
||||
prettyNValueNF :: MonadDataContext f m => NValueNF t f m -> Doc ann
|
||||
prettyNValueNF = prettyNix . valueToExpr
|
||||
|
||||
printNix :: Functor m => NValueNF m -> String
|
||||
printNix = iter phi . check
|
||||
printNix :: forall t f m. MonadDataContext f m => NValueNF t f m -> String
|
||||
printNix = iterNValueNF (const "<CYCLE>") phi
|
||||
where
|
||||
check :: NValueNF m -> Free (NValueF m) String
|
||||
check = fmap (const "<CYCLE>")
|
||||
|
||||
phi :: NValueF m String -> String
|
||||
phi (NVConstantF a) = unpack $ atomText a
|
||||
phi (NVStrF ns) = show $ hackyStringIgnoreContext ns
|
||||
phi (NVListF l) = "[ " ++ unwords l ++ " ]"
|
||||
phi (NVSetF s _) =
|
||||
phi :: NValue' t f m String -> String
|
||||
phi (NVConstant a) = unpack $ atomText a
|
||||
phi (NVStr ns) = show $ hackyStringIgnoreContext ns
|
||||
phi (NVList l) = "[ " ++ unwords l ++ " ]"
|
||||
phi (NVSet s _) =
|
||||
"{ " ++ concat [ check (unpack k) ++ " = " ++ v ++ "; "
|
||||
| (k, v) <- sort $ toList s ] ++ "}"
|
||||
where
|
||||
|
@ -309,60 +313,50 @@ printNix = iter phi . check
|
|||
<|> (fmap (surround . show) (readMaybe v :: Maybe Float)))
|
||||
where
|
||||
surround s = "\"" ++ s ++ "\""
|
||||
phi NVClosureF {} = "<<lambda>>"
|
||||
phi (NVPathF fp) = fp
|
||||
phi (NVBuiltinF name _) = "<<builtin " ++ name ++ ">>"
|
||||
phi NVClosure {} = "<<lambda>>"
|
||||
phi (NVPath fp) = fp
|
||||
phi (NVBuiltin name _) = "<<builtin " ++ name ++ ">>"
|
||||
phi _ = error "Pattern synonyms foil completeness check"
|
||||
|
||||
removeEffects :: MonadThunk (NThunk m) (NValue m) m
|
||||
=> NValueF m (NThunk m) -> NValueNF m
|
||||
removeEffects = Free . fmap dethunk
|
||||
where
|
||||
dethunk (NThunk (NCited _ (Value (NValue v)))) = removeEffects (_cited v)
|
||||
dethunk (NThunk (NCited _ _)) =
|
||||
Free $ NVStrF $ principledMakeNixStringWithoutContext "<thunk>"
|
||||
prettyNValue
|
||||
:: (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
||||
=> NValue t f m -> m (Doc ann)
|
||||
prettyNValue = fmap prettyNValueNF . removeEffectsM
|
||||
|
||||
removeEffectsM :: MonadVar m => NValueF m (NThunk m) -> m (NValueNF m)
|
||||
removeEffectsM = fmap Free . traverse dethunk
|
||||
prettyNValueProv
|
||||
:: forall t f m ann.
|
||||
( HasCitations1 t f m
|
||||
, MonadThunk t m (NValue t f m)
|
||||
, MonadDataContext f m
|
||||
)
|
||||
=> NValue t f m -> m (Doc ann)
|
||||
prettyNValueProv v@(NValue nv) = do
|
||||
let ps = citations1 @t @f @m nv
|
||||
case ps of
|
||||
[] -> prettyNValue v
|
||||
ps -> do
|
||||
v' <- prettyNValue v
|
||||
pure $ fillSep $
|
||||
[ v'
|
||||
, indent 2 $ parens $ mconcat
|
||||
$ "from: "
|
||||
: map (prettyOriginExpr . _originExpr) ps
|
||||
]
|
||||
|
||||
prettyNValueF :: MonadVar m => NValueF m (NThunk m) -> m (Doc ann)
|
||||
prettyNValueF = fmap prettyNValueNF . removeEffectsM
|
||||
|
||||
prettyNValue :: MonadVar m => NValue m -> m (Doc ann)
|
||||
prettyNValue (NValue (NCited _ v)) = prettyNValueF v
|
||||
|
||||
prettyNValueProv :: MonadVar m => NValue m -> m (Doc ann)
|
||||
prettyNValueProv = \case
|
||||
NValue (NCited [] v) -> prettyNValueF v
|
||||
NValue (NCited ps v) -> do
|
||||
v' <- prettyNValueF v
|
||||
pure $ fillSep $
|
||||
[ v'
|
||||
, indent 2 $ parens $ mconcat
|
||||
$ "from: "
|
||||
: map (prettyOriginExpr . _originExpr) ps
|
||||
]
|
||||
prettyNThunk :: MonadVar m => NThunk m -> m (Doc ann)
|
||||
prettyNThunk = \case
|
||||
t@(NThunk (NCited ps _)) -> do
|
||||
v' <- fmap prettyNValueNF (dethunk t)
|
||||
pure $ fillSep $
|
||||
[ v'
|
||||
, indent 2 $ parens $ mconcat
|
||||
$ "thunk from: "
|
||||
: map (prettyOriginExpr . _originExpr) ps
|
||||
]
|
||||
|
||||
dethunk :: MonadVar m => NThunk m -> m (NValueNF m)
|
||||
dethunk = \case
|
||||
NThunk (NCited _ (Value (NValue v))) -> removeEffectsM (_cited v)
|
||||
NThunk (NCited _ (Thunk _ active ref)) -> do
|
||||
nowActive <- atomicModifyVar active (True,)
|
||||
if nowActive
|
||||
then pure $ Free $ NVStrF $ principledMakeNixStringWithoutContext "<thunk>"
|
||||
else do
|
||||
eres <- readVar ref
|
||||
res <- case eres of
|
||||
Computed (NValue v) -> removeEffectsM (_cited v)
|
||||
_ -> pure $ Free $ NVStrF $ principledMakeNixStringWithoutContext "<thunk>"
|
||||
_ <- atomicModifyVar active (False,)
|
||||
return res
|
||||
prettyNThunk
|
||||
:: forall t f m ann.
|
||||
( HasCitations t f m t
|
||||
, HasCitations1 t f m
|
||||
, MonadThunk t m (NValue t f m)
|
||||
, MonadDataContext f m
|
||||
)
|
||||
=> t -> m (Doc ann)
|
||||
prettyNThunk t = do
|
||||
let ps = citations @t @f @m @t t
|
||||
v' <- prettyNValueNF <$> dethunk t
|
||||
pure $ fillSep $
|
||||
[ v'
|
||||
, indent 2 $ parens $ mconcat
|
||||
$ "thunk from: "
|
||||
: map (prettyOriginExpr . _originExpr) ps
|
||||
]
|
||||
|
|
|
@ -28,28 +28,31 @@ import Nix.Render
|
|||
import Nix.Thunk
|
||||
import Nix.Utils
|
||||
import Nix.Value
|
||||
import Nix.Var
|
||||
import Text.Megaparsec.Pos
|
||||
#ifdef MIN_VERSION_pretty_show
|
||||
import qualified Text.Show.Pretty as PS
|
||||
#endif
|
||||
|
||||
renderFrames
|
||||
:: forall v e m ann
|
||||
. ( MonadReader e m, Has e Options
|
||||
, MonadVar m, MonadFile m, Typeable m, Typeable v)
|
||||
:: 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 x
|
||||
renderFrame @v @t @f x
|
||||
| verbose opts <= Informational -> do
|
||||
f <- renderFrame @v x
|
||||
f <- renderFrame @v @t @f x
|
||||
pure $ concatMap go (reverse xs) ++ f
|
||||
| otherwise ->
|
||||
concat <$> mapM (renderFrame @v) (reverse (x:xs))
|
||||
concat <$> mapM (renderFrame @v @t @f) (reverse (x:xs))
|
||||
pure $ case frames of
|
||||
[] -> mempty
|
||||
_ -> vsep frames
|
||||
|
@ -62,8 +65,8 @@ renderFrames (x:xs) = do
|
|||
<> colon]
|
||||
Nothing -> []
|
||||
|
||||
framePos :: forall v (m :: * -> *). (Typeable m, Typeable v) => NixFrame
|
||||
-> Maybe SourcePos
|
||||
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 _) _))) ->
|
||||
|
@ -71,18 +74,23 @@ framePos (NixFrame _ f)
|
|||
_ -> Nothing
|
||||
| otherwise = Nothing
|
||||
|
||||
renderFrame :: forall v e m ann.
|
||||
(MonadReader e m, Has e Options, MonadVar m,
|
||||
MonadFile m, Typeable m, Typeable v)
|
||||
=> NixFrame -> m [Doc ann]
|
||||
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 m) <- fromException f = renderValueFrame level e
|
||||
| Just (e :: NormalLoop m) <- fromException f = renderNormalLoop level e
|
||||
| Just (e :: ExecFrame 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)]
|
||||
| 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
|
||||
|
@ -142,9 +150,13 @@ renderExpr _level longLabel shortLabel e@(Fix (Compose (Ann _ x))) = do
|
|||
]
|
||||
else pretty shortLabel <> fillSep [": ", rendered]
|
||||
|
||||
renderValueFrame :: (MonadReader e m, Has e Options,
|
||||
MonadFile m, MonadVar m)
|
||||
=> NixLevel -> ValueFrame m -> m [Doc ann]
|
||||
renderValueFrame
|
||||
:: ( 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 -> pure "ForcingThunk"
|
||||
ConcerningValue _v -> pure "ConcerningValue"
|
||||
|
@ -173,31 +185,45 @@ renderValueFrame level = fmap (:[]) . \case
|
|||
pure $ "Saw " <> v'
|
||||
<> " but expected " <> pretty (describeValue t)
|
||||
|
||||
renderValue :: (MonadReader e m, Has e Options, MonadFile m, MonadVar m)
|
||||
=> NixLevel -> String -> String -> NValue m -> m (Doc ann)
|
||||
renderValue
|
||||
:: ( 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 v
|
||||
else prettyNValue v
|
||||
|
||||
renderExecFrame :: (MonadReader e m, Has e Options, MonadVar m, MonadFile m)
|
||||
=> NixLevel -> ExecFrame m -> m [Doc ann]
|
||||
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)
|
||||
=> NixLevel -> ThunkLoop -> m [Doc ann]
|
||||
renderThunkLoop
|
||||
:: (MonadReader e m, Has e Options, MonadFile m, Show (ThunkId m))
|
||||
=> NixLevel -> ThunkLoop -> m [Doc ann]
|
||||
renderThunkLoop _level = pure . (:[]) . \case
|
||||
ThunkLoop Nothing -> "Infinite recursion"
|
||||
ThunkLoop (Just n) ->
|
||||
pretty $ "Infinite recursion in thunk #" ++ show n
|
||||
ThunkLoop n -> pretty $ "Infinite recursion in thunk " ++ n
|
||||
|
||||
renderNormalLoop :: (MonadReader e m, Has e Options, MonadFile m, MonadVar m)
|
||||
=> NixLevel -> NormalLoop m -> m [Doc ann]
|
||||
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
|
||||
|
|
|
@ -20,38 +20,38 @@ import Data.Text (Text)
|
|||
import Lens.Family2
|
||||
import Nix.Utils
|
||||
|
||||
newtype Scope a = Scope { getScope :: AttrSet a }
|
||||
deriving (Functor, Foldable, Traversable)
|
||||
newtype Scope t = Scope { getScope :: AttrSet t }
|
||||
deriving (Functor, Foldable, Traversable, Eq)
|
||||
|
||||
instance Show (Scope a) where
|
||||
instance Show (Scope t) where
|
||||
show (Scope m) = show (M.keys m)
|
||||
|
||||
newScope :: AttrSet a -> Scope a
|
||||
newScope :: AttrSet t -> Scope t
|
||||
newScope = Scope
|
||||
|
||||
scopeLookup :: Text -> [Scope v] -> Maybe v
|
||||
scopeLookup :: Text -> [Scope t] -> Maybe t
|
||||
scopeLookup key = foldr go Nothing
|
||||
where
|
||||
go (Scope m) rest = M.lookup key m <|> rest
|
||||
|
||||
data Scopes m v = Scopes
|
||||
{ lexicalScopes :: [Scope v]
|
||||
, dynamicScopes :: [m (Scope v)]
|
||||
data Scopes m t = Scopes
|
||||
{ lexicalScopes :: [Scope t]
|
||||
, dynamicScopes :: [m (Scope t)]
|
||||
}
|
||||
|
||||
instance Show (Scopes m v) where
|
||||
show (Scopes m v) =
|
||||
instance Show (Scopes m t) where
|
||||
show (Scopes m t) =
|
||||
"Scopes: " ++ show m ++ ", and "
|
||||
++ show (length v) ++ " with-scopes"
|
||||
++ show (length t) ++ " with-scopes"
|
||||
|
||||
instance Semigroup (Scopes m v) where
|
||||
instance Semigroup (Scopes m t) where
|
||||
Scopes ls lw <> Scopes rs rw = Scopes (ls <> rs) (lw <> rw)
|
||||
|
||||
instance Monoid (Scopes m v) where
|
||||
instance Monoid (Scopes m t) where
|
||||
mempty = emptyScopes
|
||||
mappend = (<>)
|
||||
|
||||
emptyScopes :: forall m v. Scopes m v
|
||||
emptyScopes :: forall m t. Scopes m t
|
||||
emptyScopes = Scopes [] []
|
||||
|
||||
class Scoped t m | m -> t where
|
||||
|
|
|
@ -23,7 +23,7 @@ module Nix.String (
|
|||
, principledStringMempty
|
||||
, principledStringMConcat
|
||||
, WithStringContext
|
||||
, WithStringContextT
|
||||
, WithStringContextT(..)
|
||||
, extractNixString
|
||||
, addStringContext
|
||||
, addSingletonStringContext
|
||||
|
|
|
@ -1,21 +1,51 @@
|
|||
{-# LANGUAGE DefaultSignatures #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FunctionalDependencies #-}
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
|
||||
module Nix.Thunk where
|
||||
|
||||
import Control.Exception hiding (catch)
|
||||
import Data.Typeable
|
||||
import Control.Exception (Exception)
|
||||
import Control.Monad.Trans.Class (MonadTrans(..))
|
||||
import Data.Typeable (Typeable)
|
||||
|
||||
class Monad m => MonadThunk v t m | t -> m, t -> v where
|
||||
class ( Monad m
|
||||
, Eq (ThunkId m)
|
||||
, Ord (ThunkId m)
|
||||
, Show (ThunkId m)
|
||||
, Typeable (ThunkId m)
|
||||
)
|
||||
=> MonadThunkId m where
|
||||
type ThunkId m :: *
|
||||
freshId :: m (ThunkId m)
|
||||
default freshId
|
||||
:: ( MonadThunkId m'
|
||||
, MonadTrans t
|
||||
, m ~ t m'
|
||||
, ThunkId m ~ ThunkId m'
|
||||
)
|
||||
=> m (ThunkId m)
|
||||
freshId = lift freshId
|
||||
|
||||
class MonadThunkId m => MonadThunk t m v | t -> m, t -> v where
|
||||
thunk :: m v -> m t
|
||||
-- | Return an identifier for the thunk unless it is a pure value (i.e.,
|
||||
-- strictly an encapsulation of some 'v' without any additional
|
||||
-- structure). For pure values represented as thunks, returns Nothing.
|
||||
thunkId :: t -> Maybe (ThunkId m)
|
||||
query :: t -> r -> (v -> r) -> r
|
||||
queryM :: t -> m r -> (v -> m r) -> m r
|
||||
force :: t -> (v -> m r) -> m r
|
||||
forceEff :: t -> (v -> m r) -> m r
|
||||
wrapValue :: v -> t
|
||||
getValue :: t -> Maybe v
|
||||
|
||||
newtype ThunkLoop = ThunkLoop (Maybe Int)
|
||||
deriving (Show, Typeable)
|
||||
newtype ThunkLoop = ThunkLoop String -- contains rendering of ThunkId
|
||||
deriving Typeable
|
||||
|
||||
instance Show ThunkLoop where
|
||||
show (ThunkLoop i) = "ThunkLoop " ++ i
|
||||
|
||||
instance Exception ThunkLoop
|
||||
|
|
|
@ -4,21 +4,20 @@
|
|||
{-# LANGUAGE DeriveTraversable #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
|
||||
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||
|
||||
module Nix.Thunk.Basic where
|
||||
module Nix.Thunk.Basic (NThunkF(..), Deferred(..), MonadBasicThunk) where
|
||||
|
||||
import Control.Exception hiding (catch)
|
||||
import Control.Monad.Catch
|
||||
import Control.Monad.Ref
|
||||
import Data.GADT.Compare
|
||||
|
||||
import Nix.Fresh
|
||||
import Nix.Thunk
|
||||
import Nix.Utils
|
||||
import Nix.Var
|
||||
|
@ -29,22 +28,31 @@ data Deferred m v = Deferred (m v) | Computed v
|
|||
-- | The type of very basic thunks
|
||||
data NThunkF m v
|
||||
= Value v
|
||||
| Thunk Int (Var m Bool) (Var m (Deferred m v))
|
||||
| Thunk (ThunkId m) (Var m Bool) (Var m (Deferred m v))
|
||||
|
||||
instance (Eq v, Eq (ThunkId m)) => Eq (NThunkF m v) where
|
||||
Value x == Value y = x == y
|
||||
Thunk x _ _ == Thunk y _ _ = x == y
|
||||
_ == _ = False -- jww (2019-03-16): not accurate...
|
||||
|
||||
instance Show v => Show (NThunkF m v) where
|
||||
show (Value v) = show v
|
||||
show (Thunk _ _ _) = "<thunk>"
|
||||
|
||||
type MonadBasicThunk m
|
||||
= (MonadAtomicRef m, GEq (Ref m), MonadFreshId Int m, MonadCatch m)
|
||||
type MonadBasicThunk m = (MonadThunkId m, MonadVar m)
|
||||
|
||||
instance (MonadAtomicRef m, GEq (Ref m), MonadFreshId Int m, MonadCatch m)
|
||||
=> MonadThunk v (NThunkF m v) m where
|
||||
thunk = buildThunk
|
||||
force = forceThunk
|
||||
forceEff = forceEffects
|
||||
instance (MonadBasicThunk m, MonadCatch m)
|
||||
=> MonadThunk (NThunkF m v) m v where
|
||||
thunk = buildThunk
|
||||
thunkId = \case
|
||||
Value _ -> Nothing
|
||||
Thunk n _ _ -> Just n
|
||||
query = queryValue
|
||||
queryM = queryThunk
|
||||
force = forceThunk
|
||||
forceEff = forceEffects
|
||||
wrapValue = valueRef
|
||||
getValue = thunkValue
|
||||
getValue = thunkValue
|
||||
|
||||
valueRef :: v -> NThunkF m v
|
||||
valueRef = Value
|
||||
|
@ -53,14 +61,38 @@ thunkValue :: NThunkF m v -> Maybe v
|
|||
thunkValue (Value v) = Just v
|
||||
thunkValue _ = Nothing
|
||||
|
||||
buildThunk :: (MonadVar m, MonadFreshId Int m) => m v -> m (NThunkF m v)
|
||||
buildThunk :: MonadBasicThunk m => m v -> m (NThunkF m v)
|
||||
buildThunk action =do
|
||||
freshThunkId <- freshId
|
||||
Thunk freshThunkId <$> newVar False <*> newVar (Deferred action)
|
||||
|
||||
forceThunk :: (MonadVar m, MonadThrow m, MonadCatch m)
|
||||
=> NThunkF m v -> (v -> m a) -> m a
|
||||
forceThunk (Value ref) k = k ref
|
||||
queryValue :: MonadVar m => NThunkF m v -> a -> (v -> a) -> a
|
||||
queryValue (Value v) _ k = k v
|
||||
queryValue _ n _ = n
|
||||
|
||||
queryThunk :: MonadVar m => NThunkF m v -> m a -> (v -> m a) -> m a
|
||||
queryThunk (Value v) _ k = k v
|
||||
queryThunk (Thunk _ active ref) n k = do
|
||||
nowActive <- atomicModifyVar active (True,)
|
||||
if nowActive
|
||||
then n
|
||||
else do
|
||||
eres <- readVar ref
|
||||
res <- case eres of
|
||||
Computed v -> k v
|
||||
_ -> n
|
||||
_ <- atomicModifyVar active (False,)
|
||||
return res
|
||||
|
||||
forceThunk
|
||||
:: forall m v a.
|
||||
( MonadVar m
|
||||
, MonadThrow m
|
||||
, MonadCatch m
|
||||
, Show (ThunkId m)
|
||||
)
|
||||
=> NThunkF m v -> (v -> m a) -> m a
|
||||
forceThunk (Value v) k = k v
|
||||
forceThunk (Thunk n active ref) k = do
|
||||
eres <- readVar ref
|
||||
case eres of
|
||||
|
@ -69,7 +101,7 @@ forceThunk (Thunk n active ref) k = do
|
|||
nowActive <- atomicModifyVar active (True,)
|
||||
if nowActive
|
||||
then
|
||||
throwM $ ThunkLoop (Just n)
|
||||
throwM $ ThunkLoop $ show n
|
||||
else do
|
||||
traceM $ "Forcing " ++ show n
|
||||
v <- catch action $ \(e :: SomeException) -> do
|
||||
|
@ -79,12 +111,12 @@ forceThunk (Thunk n active ref) k = do
|
|||
writeVar ref (Computed v)
|
||||
k v
|
||||
|
||||
forceEffects :: MonadVar m => NThunkF m v -> (v -> m a) -> m a
|
||||
forceEffects (Value ref) k = k ref
|
||||
forceEffects :: MonadVar m => NThunkF m v -> (v -> m r) -> m r
|
||||
forceEffects (Value v) k = k v
|
||||
forceEffects (Thunk _ active ref) k = do
|
||||
nowActive <- atomicModifyVar active (True,)
|
||||
if nowActive
|
||||
then return $ error "forceEffects: a value was expected"
|
||||
then return $ error "Loop detected"
|
||||
else do
|
||||
eres <- readVar ref
|
||||
case eres of
|
||||
|
|
216
src/Nix/Thunk/Standard.hs
Normal file
216
src/Nix/Thunk/Standard.hs
Normal file
|
@ -0,0 +1,216 @@
|
|||
{-# LANGUAGE ConstraintKinds #-}
|
||||
{-# LANGUAGE DeriveFoldable #-}
|
||||
{-# LANGUAGE DeriveFunctor #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE DeriveTraversable #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE StandaloneDeriving #-}
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
|
||||
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||
|
||||
module Nix.Thunk.Standard where
|
||||
|
||||
import Control.Comonad (Comonad)
|
||||
import Control.Comonad.Env (ComonadEnv)
|
||||
import Control.Monad.Catch hiding (catchJust)
|
||||
import Control.Monad.Reader
|
||||
import Data.Fix
|
||||
import GHC.Generics
|
||||
import Nix.Cited
|
||||
import Nix.Convert
|
||||
import Nix.Effects
|
||||
import Nix.Eval as Eval
|
||||
import Nix.Exec
|
||||
import Nix.Expr
|
||||
import Nix.Frames
|
||||
import Nix.Fresh
|
||||
import Nix.Options
|
||||
import Nix.Render
|
||||
import Nix.Thunk
|
||||
import Nix.Thunk.Basic
|
||||
import Nix.Utils
|
||||
import Nix.Value
|
||||
import Nix.Var (MonadVar, newVar)
|
||||
|
||||
newtype StdCited m a = StdCited
|
||||
{ _stdCited :: NCited (StdThunk m) (StdCited m) (StdLazy m) a }
|
||||
deriving
|
||||
( Generic
|
||||
, Typeable
|
||||
, Functor
|
||||
, Applicative
|
||||
, Foldable
|
||||
, Traversable
|
||||
, Comonad
|
||||
, ComonadEnv [Provenance (StdThunk m) (StdCited m) (StdLazy m)]
|
||||
)
|
||||
|
||||
newtype StdThunk m = StdThunk
|
||||
{ _stdThunk :: StdCited m (NThunkF (StdLazy m) (StdValue m)) }
|
||||
|
||||
type StdValue m = NValue (StdThunk m) (StdCited m) (StdLazy m)
|
||||
type StdValueNF m = NValueNF (StdThunk m) (StdCited m) (StdLazy m)
|
||||
|
||||
type StdIdT m = FreshIdT Int m
|
||||
|
||||
type StdLazy m = Lazy (StdThunk m) (StdCited m) (StdIdT m)
|
||||
|
||||
type MonadStdThunk m =
|
||||
( MonadVar m
|
||||
, MonadCatch m
|
||||
, MonadThrow m
|
||||
, Typeable m
|
||||
)
|
||||
|
||||
instance MonadStdThunk m
|
||||
=> MonadThunk (StdThunk m) (StdLazy m) (StdValue m) where
|
||||
thunk mv = do
|
||||
opts :: Options <- asks (view hasLens)
|
||||
|
||||
if thunks opts
|
||||
then do
|
||||
frames :: Frames <- asks (view hasLens)
|
||||
|
||||
-- Gather the current evaluation context at the time of thunk
|
||||
-- creation, and record it along with the thunk.
|
||||
let go (fromException ->
|
||||
Just (EvaluatingExpr scope
|
||||
(Fix (Compose (Ann s e))))) =
|
||||
let e' = Compose (Ann s (Nothing <$ e))
|
||||
in [Provenance scope e']
|
||||
go _ = []
|
||||
ps = concatMap (go . frame) frames
|
||||
|
||||
fmap (StdThunk . StdCited . NCited ps) . thunk $ mv
|
||||
else
|
||||
fmap (StdThunk . StdCited . NCited []) . thunk $ mv
|
||||
|
||||
thunkId (StdThunk (StdCited (NCited _ t))) = thunkId t
|
||||
|
||||
query (StdThunk (StdCited (NCited _ t))) = query t
|
||||
queryM (StdThunk (StdCited (NCited _ t))) = queryM t
|
||||
|
||||
-- The ThunkLoop exception is thrown as an exception with MonadThrow,
|
||||
-- which does not capture the current stack frame information to provide
|
||||
-- it in a NixException, so we catch and re-throw it here using
|
||||
-- 'throwError' from Frames.hs.
|
||||
force (StdThunk (StdCited (NCited ps t))) f =
|
||||
catch go (throwError @ThunkLoop)
|
||||
where
|
||||
go = case ps of
|
||||
[] -> force t f
|
||||
Provenance scope e@(Compose (Ann s _)):_ ->
|
||||
-- r <- liftWith $ \run -> do
|
||||
-- withFrame Info (ForcingExpr scope (wrapExprLoc s e))
|
||||
-- (run (force t f))
|
||||
-- restoreT $ return r
|
||||
withFrame Info (ForcingExpr scope (wrapExprLoc s e))
|
||||
(force t f)
|
||||
|
||||
forceEff (StdThunk (StdCited (NCited ps t))) f =
|
||||
catch go (throwError @ThunkLoop)
|
||||
where
|
||||
go = case ps of
|
||||
[] -> forceEff t f
|
||||
Provenance scope e@(Compose (Ann s _)):_ -> do
|
||||
-- r <- liftWith $ \run -> do
|
||||
-- withFrame Info (ForcingExpr scope (wrapExprLoc s e))
|
||||
-- (run (forceEff t f))
|
||||
-- restoreT $ return r
|
||||
withFrame Info (ForcingExpr scope (wrapExprLoc s e))
|
||||
(forceEff t f)
|
||||
|
||||
wrapValue = StdThunk . StdCited . NCited [] . wrapValue
|
||||
getValue (StdThunk (StdCited (NCited _ v))) = getValue v
|
||||
|
||||
instance ( MonadStdThunk m
|
||||
, ToValue a (StdLazy m) (StdValue m)
|
||||
)
|
||||
=> ToValue a (StdLazy m) (StdThunk m) where
|
||||
toValue = fmap wrapValue . toValue
|
||||
|
||||
instance MonadStdThunk m
|
||||
=> ToValue (StdThunk m) (StdLazy m) (StdValue m) where
|
||||
toValue = force ?? pure
|
||||
|
||||
instance ( MonadStdThunk m
|
||||
, FromValue a (StdLazy m) (StdValue m)
|
||||
)
|
||||
=> FromValue a (StdLazy m) (StdThunk m) where
|
||||
fromValueMay = force ?? fromValueMay
|
||||
fromValue = force ?? fromValue
|
||||
|
||||
instance MonadStdThunk m
|
||||
=> FromValue (StdThunk m) (StdLazy m) (StdValue m) where
|
||||
fromValueMay = pure . Just . wrapValue
|
||||
fromValue = pure . wrapValue
|
||||
|
||||
instance ( MonadStdThunk m
|
||||
, ToNix a (StdLazy m) (StdValue m)
|
||||
)
|
||||
=> ToNix a (StdLazy m) (StdThunk m) where
|
||||
toNix = fmap wrapValue . toNix
|
||||
|
||||
instance MonadStdThunk m
|
||||
=> ToNix (StdThunk m) (StdLazy m) (StdValue m) where
|
||||
toNix = force ?? pure
|
||||
|
||||
instance ( MonadStdThunk m
|
||||
, FromNix a (StdLazy m) (StdValue m)
|
||||
)
|
||||
=> FromNix a (StdLazy m) (StdThunk m) where
|
||||
fromNixMay = force ?? fromNixMay
|
||||
fromNix = force ?? fromNix
|
||||
|
||||
instance MonadStdThunk m
|
||||
=> FromNix (StdThunk m) (StdLazy m) (StdValue m) where
|
||||
fromNixMay = pure . Just . wrapValue
|
||||
fromNix = pure . wrapValue
|
||||
|
||||
instance Show (StdThunk m) where
|
||||
show _ = "<thunk>" -- jww (2019-03-15): NYI
|
||||
|
||||
instance MonadFile m => MonadFile (StdIdT m)
|
||||
instance MonadIntrospect m => MonadIntrospect (StdIdT m)
|
||||
instance MonadStore m => MonadStore (StdIdT m) where
|
||||
addPath' = lift . addPath'
|
||||
toFile_' = (lift .) . toFile_'
|
||||
instance MonadPutStr m => MonadPutStr (StdIdT m)
|
||||
instance MonadHttp m => MonadHttp (StdIdT m)
|
||||
instance MonadEnv m => MonadEnv (StdIdT m)
|
||||
instance MonadInstantiate m => MonadInstantiate (StdIdT m)
|
||||
instance MonadExec m => MonadExec (StdIdT m)
|
||||
|
||||
instance (MonadEffects t f m, MonadDataContext f m)
|
||||
=> MonadEffects t f (StdIdT m) where
|
||||
makeAbsolutePath = lift . makeAbsolutePath @t @f @m
|
||||
findEnvPath = lift . findEnvPath @t @f @m
|
||||
findPath = (lift .) . findPath @t @f @m
|
||||
importPath path = do
|
||||
i <- FreshIdT ask
|
||||
p <- lift $ importPath @t @f @m path
|
||||
return $ liftNValue (runFreshIdT i) p
|
||||
pathToDefaultNix = lift . pathToDefaultNix @t @f @m
|
||||
derivationStrict v = do
|
||||
i <- FreshIdT ask
|
||||
p <- lift $ derivationStrict @t @f @m (unliftNValue (runFreshIdT i) v)
|
||||
return $ liftNValue (runFreshIdT i) p
|
||||
traceEffect = lift . traceEffect @t @f @m
|
||||
|
||||
instance HasCitations1 (StdThunk m) (StdCited m) (StdLazy m) where
|
||||
citations1 (StdCited c) = citations c
|
||||
addProvenance1 x (StdCited c) = StdCited (addProvenance x c)
|
||||
|
||||
runStdLazyM :: (MonadVar m, MonadIO m) => Options -> StdLazy m a -> m a
|
||||
runStdLazyM opts action = do
|
||||
i <- newVar (1 :: Int)
|
||||
runFreshIdT i $ runLazyM opts action
|
|
@ -1,3 +1,5 @@
|
|||
{-# LANGUAGE AllowAmbiguousTypes #-}
|
||||
{-# LANGUAGE ConstraintKinds #-}
|
||||
{-# LANGUAGE ExistentialQuantification #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
|
@ -40,7 +42,6 @@ import Data.List (delete, find, nub, intersect, (\\))
|
|||
import Data.Map (Map)
|
||||
import qualified Data.Map as Map
|
||||
import Data.Maybe (fromJust)
|
||||
import Data.STRef
|
||||
import qualified Data.Set as Set
|
||||
import Data.Text (Text)
|
||||
import Nix.Atoms
|
||||
|
@ -59,6 +60,7 @@ import Nix.Type.Env
|
|||
import qualified Nix.Type.Env as Env
|
||||
import Nix.Type.Type
|
||||
import Nix.Utils
|
||||
import Nix.Var
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Classes
|
||||
|
@ -70,10 +72,24 @@ newtype InferT s m a = InferT
|
|||
ReaderT (Set.Set TVar, Scopes (InferT s m) (JThunkT s m))
|
||||
(StateT InferState (ExceptT InferError m)) a
|
||||
}
|
||||
deriving (Functor, Applicative, Alternative, Monad, MonadPlus, MonadFix,
|
||||
MonadReader (Set.Set TVar, Scopes (InferT s m) (JThunkT s m)), MonadFail,
|
||||
MonadState InferState, MonadError InferError,
|
||||
MonadFreshId i)
|
||||
deriving
|
||||
( Functor
|
||||
, Applicative
|
||||
, Alternative
|
||||
, Monad
|
||||
, MonadPlus
|
||||
, MonadFix
|
||||
, MonadReader (Set.Set TVar, Scopes (InferT s m) (JThunkT s m))
|
||||
, MonadFail
|
||||
, MonadState InferState
|
||||
, MonadError InferError
|
||||
)
|
||||
|
||||
instance MonadTrans (InferT s) where
|
||||
lift = InferT . lift . lift . lift
|
||||
|
||||
instance MonadThunkId m => MonadThunkId (InferT s m) where
|
||||
type ThunkId (InferT s m) = ThunkId m
|
||||
|
||||
-- | Inference state
|
||||
newtype InferState = InferState { count :: Int }
|
||||
|
@ -189,26 +205,19 @@ instance Monoid InferError where
|
|||
-------------------------------------------------------------------------------
|
||||
|
||||
-- | Run the inference monad
|
||||
runInfer' ::
|
||||
( MonadFreshId Int m
|
||||
, MonadAtomicRef m
|
||||
, Ref m ~ STRef s
|
||||
, MonadFix m
|
||||
) => InferT s m a -> m (Either InferError a)
|
||||
runInfer' :: MonadInfer m => InferT s m a -> m (Either InferError a)
|
||||
runInfer' = runExceptT
|
||||
. (`evalStateT` initInfer)
|
||||
. (`runReaderT` (Set.empty, emptyScopes))
|
||||
. getInfer
|
||||
|
||||
runInfer :: (forall s. InferT s (FreshIdT Int (ST s)) a) -> Either InferError a
|
||||
runInfer m = runST (runFreshIdT 0 (runInfer' m))
|
||||
runInfer m = runST $ do
|
||||
i <- newVar (1 :: Int)
|
||||
runFreshIdT i (runInfer' m)
|
||||
|
||||
inferType ::
|
||||
( MonadFreshId Int m
|
||||
, MonadAtomicRef m
|
||||
, Ref m ~ STRef s
|
||||
, MonadFix m
|
||||
) => Env -> NExpr -> InferT s m [(Subst, Type)]
|
||||
inferType :: forall s m. MonadInfer m
|
||||
=> Env -> NExpr -> InferT s m [(Subst, Type)]
|
||||
inferType env ex = do
|
||||
Judgment as cs t <- infer ex
|
||||
let unbounds = Set.fromList (As.keys as) `Set.difference`
|
||||
|
@ -325,13 +334,13 @@ binops u1 = \case
|
|||
liftInfer :: Monad m => m a -> InferT s m a
|
||||
liftInfer = InferT . lift . lift . lift
|
||||
|
||||
instance (MonadRef m, Ref m ~ STRef s) => MonadRef (InferT s m) where
|
||||
instance MonadRef m => MonadRef (InferT s m) where
|
||||
type Ref (InferT s m) = Ref m
|
||||
newRef x = liftInfer $ newRef x
|
||||
readRef x = liftInfer $ readRef x
|
||||
writeRef x y = liftInfer $ writeRef x y
|
||||
|
||||
instance (MonadAtomicRef m, Ref m ~ STRef s) => MonadAtomicRef (InferT s m) where
|
||||
instance MonadAtomicRef m => MonadAtomicRef (InferT s m) where
|
||||
atomicModifyRef x f = liftInfer $ do
|
||||
res <- snd . f <$> readRef x
|
||||
_ <- modifyRef x (fst . f)
|
||||
|
@ -349,27 +358,31 @@ instance Monad m => MonadCatch (InferT s m) where
|
|||
(fromException (toException e))
|
||||
err -> error $ "Unexpected error: " ++ show err
|
||||
|
||||
instance ( MonadFreshId Int m
|
||||
, MonadAtomicRef m
|
||||
, Ref m ~ STRef s
|
||||
) => MonadThunk (Judgment s) (JThunkT s m) (InferT s m) where
|
||||
thunk = fmap JThunk . buildThunk
|
||||
type MonadInfer m
|
||||
= ( MonadThunkId m
|
||||
, MonadVar m
|
||||
, MonadFix m
|
||||
)
|
||||
|
||||
force (JThunk t) f = catch (forceThunk t f) $ \(_ :: ThunkLoop) ->
|
||||
instance MonadInfer m
|
||||
=> MonadThunk (JThunkT s m) (InferT s m) (Judgment s) where
|
||||
thunk = fmap JThunk . thunk
|
||||
thunkId (JThunk x) = thunkId x
|
||||
|
||||
query (JThunk x) b f = query x b f
|
||||
queryM (JThunk x) b f = queryM x b f
|
||||
|
||||
force (JThunk t) f = catch (force t f) $ \(_ :: ThunkLoop) ->
|
||||
-- If we have a thunk loop, we just don't know the type.
|
||||
f =<< Judgment As.empty [] <$> fresh
|
||||
forceEff (JThunk t) f = catch (forceEffects t f) $ \(_ :: ThunkLoop) ->
|
||||
forceEff (JThunk t) f = catch (forceEff t f) $ \(_ :: ThunkLoop) ->
|
||||
-- If we have a thunk loop, we just don't know the type.
|
||||
f =<< Judgment As.empty [] <$> fresh
|
||||
|
||||
wrapValue = JThunk . valueRef
|
||||
getValue (JThunk x) = thunkValue x
|
||||
wrapValue = JThunk . wrapValue
|
||||
getValue (JThunk x) = getValue x
|
||||
|
||||
instance ( MonadFreshId Int m
|
||||
, MonadAtomicRef m
|
||||
, Ref m ~ STRef s
|
||||
, MonadFix m
|
||||
) => MonadEval (Judgment s) (InferT s m) where
|
||||
instance MonadInfer m => MonadEval (Judgment s) (InferT s m) where
|
||||
freeVariable var = do
|
||||
tv <- fresh
|
||||
return $ Judgment (As.singleton var tv) [] tv
|
||||
|
@ -486,11 +499,9 @@ instance Monad m => FromValue NixString (InferT s m) (Judgment s) where
|
|||
fromValueMay _ = return Nothing
|
||||
fromValue _ = error "Unused"
|
||||
|
||||
instance ( MonadFreshId Int m
|
||||
, MonadAtomicRef m
|
||||
, Ref m ~ STRef s
|
||||
, MonadFix m
|
||||
) => FromValue (AttrSet (JThunkT s m), AttrSet SourcePos) (InferT s m) (Judgment s) where
|
||||
instance MonadInfer m
|
||||
=> FromValue (AttrSet (JThunkT s m), AttrSet SourcePos)
|
||||
(InferT s m) (Judgment s) where
|
||||
fromValueMay (Judgment _ _ (TSet _ xs)) = do
|
||||
let sing _ = Judgment As.empty []
|
||||
pure $ Just (M.mapWithKey (\k v -> wrapValue (sing k v)) xs, M.empty)
|
||||
|
@ -499,11 +510,9 @@ instance ( MonadFreshId Int m
|
|||
Just v -> pure v
|
||||
Nothing -> pure (M.empty, M.empty)
|
||||
|
||||
instance ( MonadFreshId Int m
|
||||
, MonadAtomicRef m
|
||||
, Ref m ~ STRef s
|
||||
, MonadFix m
|
||||
) => ToValue (AttrSet (JThunkT s m), AttrSet SourcePos) (InferT s m) (Judgment s) where
|
||||
instance MonadInfer m
|
||||
=> ToValue (AttrSet (JThunkT s m), AttrSet SourcePos)
|
||||
(InferT s m) (Judgment s) where
|
||||
toValue (xs, _) = Judgment
|
||||
<$> foldrM go As.empty xs
|
||||
<*> (concat <$> traverse (`force` (pure . typeConstraints)) xs)
|
||||
|
@ -511,11 +520,7 @@ instance ( MonadFreshId Int m
|
|||
where
|
||||
go x rest = force x $ \x' -> pure $ As.merge (assumptions x') rest
|
||||
|
||||
instance ( MonadFreshId Int m
|
||||
, MonadAtomicRef m
|
||||
, Ref m ~ STRef s
|
||||
, MonadFix m
|
||||
) => ToValue [JThunkT s m] (InferT s m) (Judgment s) where
|
||||
instance MonadInfer m => ToValue [JThunkT s m] (InferT s m) (Judgment s) where
|
||||
toValue xs = Judgment
|
||||
<$> foldrM go As.empty xs
|
||||
<*> (concat <$> traverse (`force` (pure . typeConstraints)) xs)
|
||||
|
@ -523,18 +528,10 @@ instance ( MonadFreshId Int m
|
|||
where
|
||||
go x rest = force x $ \x' -> pure $ As.merge (assumptions x') rest
|
||||
|
||||
instance ( MonadFreshId Int m
|
||||
, MonadAtomicRef m
|
||||
, Ref m ~ STRef s
|
||||
, MonadFix m
|
||||
) => ToValue Bool (InferT s m) (Judgment s) where
|
||||
instance MonadInfer m => ToValue Bool (InferT s m) (Judgment s) where
|
||||
toValue _ = pure $ Judgment As.empty [] typeBool
|
||||
|
||||
infer :: ( MonadFreshId Int m
|
||||
, MonadAtomicRef m
|
||||
, Ref m ~ STRef s
|
||||
, MonadFix m
|
||||
) => NExpr -> InferT s m (Judgment s)
|
||||
infer :: MonadInfer m => NExpr -> InferT s m (Judgment s)
|
||||
infer = cata Eval.eval
|
||||
|
||||
inferTop :: Env -> [(Text, NExpr)] -> Either InferError Env
|
||||
|
|
|
@ -5,16 +5,22 @@
|
|||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
|
||||
{-# OPTIONS_GHC -Wno-missing-signatures #-}
|
||||
|
||||
module Nix.Utils (module Nix.Utils, module X) where
|
||||
|
||||
import Control.Arrow ((&&&))
|
||||
import Control.Monad
|
||||
import Control.Monad.Fix
|
||||
import Control.Monad.Free
|
||||
import qualified Data.Aeson as A
|
||||
import qualified Data.Aeson.Encoding as A
|
||||
import Data.Fix
|
||||
import Data.Functor.Compose
|
||||
import Data.Hashable
|
||||
import Data.HashMap.Lazy (HashMap)
|
||||
import qualified Data.HashMap.Lazy as M
|
||||
import Data.List (sortOn)
|
||||
|
@ -24,6 +30,7 @@ import qualified Data.Text as Text
|
|||
import qualified Data.Vector as V
|
||||
import Lens.Family2 as X
|
||||
import Lens.Family2.Stock (_1, _2)
|
||||
import Lens.Family2.TH
|
||||
|
||||
#if ENABLE_TRACING
|
||||
import Debug.Trace as X
|
||||
|
@ -35,6 +42,9 @@ traceM :: Monad m => String -> m ()
|
|||
traceM = const (return ())
|
||||
#endif
|
||||
|
||||
$(makeLensesBy (\n -> Just ("_" ++ n)) ''Fix)
|
||||
$(makeLensesBy (\n -> Just ("_" ++ n)) ''Compose)
|
||||
|
||||
type DList a = Endo [a]
|
||||
|
||||
type AttrSet = HashMap Text
|
||||
|
@ -75,6 +85,12 @@ cataPM f x = f x <=< traverse (cataPM f) . unFix $ x
|
|||
transport :: Functor g => (forall x. f x -> g x) -> Fix f -> Fix g
|
||||
transport f (Fix x) = Fix $ fmap (transport f) (f x)
|
||||
|
||||
fixate :: Functor f => Free f (f (Fix f)) -> Fix f
|
||||
fixate = Fix . go
|
||||
where
|
||||
go (Pure a) = a
|
||||
go (Free f) = fmap (Fix . go) f
|
||||
|
||||
-- | adi is Abstracting Definitional Interpreters:
|
||||
--
|
||||
-- https://arxiv.org/abs/1707.04755
|
||||
|
@ -124,3 +140,9 @@ uriAwareSplit = go where
|
|||
let ((suffix, _):path) = go (Text.drop 3 e2)
|
||||
in (e1 <> Text.pack "://" <> suffix, PathEntryURI) : path
|
||||
| otherwise -> (e1, PathEntryPath) : go (Text.drop 1 e2)
|
||||
|
||||
alterF :: (Eq k, Hashable k, Functor f)
|
||||
=> (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)
|
||||
alterF f k m = f (M.lookup k m) <&> \case
|
||||
Nothing -> M.delete k m
|
||||
Just v -> M.insert k v m
|
||||
|
|
543
src/Nix/Value.hs
543
src/Nix/Value.hs
|
@ -9,6 +9,7 @@
|
|||
{-# LANGUAGE DeriveTraversable #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE FunctionalDependencies #-}
|
||||
{-# LANGUAGE GADTs #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
|
@ -18,6 +19,7 @@
|
|||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE StandaloneDeriving #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
|
@ -28,20 +30,22 @@
|
|||
|
||||
module Nix.Value where
|
||||
|
||||
import Control.Comonad
|
||||
import Control.Exception
|
||||
import Control.Monad
|
||||
import Control.Monad.Catch
|
||||
import Control.Monad.Free
|
||||
import Control.Monad.Trans.Class
|
||||
import Control.Monad.Trans.Except
|
||||
import qualified Data.Aeson as A
|
||||
import Data.Align
|
||||
import Data.Fix
|
||||
import Data.Eq.Deriving
|
||||
import Data.Functor.Classes
|
||||
import Data.HashMap.Lazy (HashMap)
|
||||
import qualified Data.HashMap.Lazy as M
|
||||
import Data.Hashable
|
||||
import Data.Text (Text)
|
||||
import Data.These
|
||||
import Data.Typeable (Typeable)
|
||||
import Data.Void
|
||||
import GHC.Generics
|
||||
import Lens.Family2
|
||||
import Lens.Family2.Stock
|
||||
|
@ -50,30 +54,14 @@ import Nix.Atoms
|
|||
import Nix.Expr.Types
|
||||
import Nix.Expr.Types.Annotated
|
||||
import Nix.Frames
|
||||
import Nix.Scope
|
||||
import Nix.String
|
||||
import Nix.Thunk
|
||||
import Nix.Thunk.Basic
|
||||
import Nix.Utils
|
||||
|
||||
data Provenance m = Provenance
|
||||
{ _lexicalScope :: Scopes m (NThunk m)
|
||||
, _originExpr :: NExprLocF (Maybe (NValue m))
|
||||
-- ^ When calling the function x: x + 2 with argument x = 3, the
|
||||
-- 'originExpr' for the resulting value will be 3 + 2, while the
|
||||
-- 'contextExpr' will be @(x: x + 2) 3@, preserving not only the
|
||||
-- result of the call, but what was called and with what arguments.
|
||||
}
|
||||
|
||||
data NCited f m a = NCited
|
||||
{ _provenance :: [Provenance m]
|
||||
, _cited :: f m a
|
||||
}
|
||||
|
||||
-- | An 'NValue' is the most reduced form of an 'NExpr' after evaluation is
|
||||
-- completed. 's' is related to the type of errors that might occur during
|
||||
-- construction or use of a value.
|
||||
data NValueF m r
|
||||
data NValueF p m r
|
||||
= NVConstantF NAtom
|
||||
-- | A string has a value and a context, which can be used to record what a
|
||||
-- string has been build from
|
||||
|
@ -81,7 +69,7 @@ data NValueF m r
|
|||
| NVPathF FilePath
|
||||
| NVListF [r]
|
||||
| NVSetF (AttrSet r) (AttrSet SourcePos)
|
||||
| NVClosureF (Params ()) (m (NValue m) -> m (NValue m))
|
||||
| NVClosureF (Params ()) (m p -> m r)
|
||||
-- ^ A function is a closed set of parameters representing the "call
|
||||
-- signature", used at application time to check the type of arguments
|
||||
-- passed to the function. Since it supports default values which may
|
||||
|
@ -93,87 +81,81 @@ data NValueF m r
|
|||
-- Note that 'm r' is being used here because effectively a function
|
||||
-- and its set of default arguments is "never fully evaluated". This
|
||||
-- enforces in the type that it must be re-evaluated for each call.
|
||||
| NVBuiltinF String (m (NValue m) -> m (NValue m))
|
||||
| NVBuiltinF String (m p -> m r)
|
||||
-- ^ A builtin function is itself already in normal form. Also, it may
|
||||
-- or may not choose to evaluate its argument in the production of a
|
||||
-- result.
|
||||
deriving (Generic, Typeable, Functor, Foldable, Traversable)
|
||||
deriving (Generic, Typeable, Functor)
|
||||
|
||||
-- | An 'NValueNF' is a fully evaluated value in normal form. An 'NValue m' is
|
||||
-- a value in head normal form, where only the "top layer" has been
|
||||
-- evaluated. An action of type 'm (NValue m)' is a pending evualation that
|
||||
-- has yet to be performed. An 'NThunk m' is either a pending evaluation, or
|
||||
-- a value in head normal form. A 'NThunkSet' is a set of mappings from keys
|
||||
-- to thunks.
|
||||
--
|
||||
-- The 'Free' structure is used here to represent the possibility that
|
||||
-- cycles may appear during normalization.
|
||||
-- | This 'Foldable' instance only folds what the value actually is known to
|
||||
-- contain at time of fold.
|
||||
instance Foldable (NValueF p m) where
|
||||
foldMap f = \case
|
||||
NVConstantF _ -> mempty
|
||||
NVStrF _ -> mempty
|
||||
NVPathF _ -> mempty
|
||||
NVListF l -> foldMap f l
|
||||
NVSetF s _ -> foldMap f s
|
||||
NVClosureF _ _ -> mempty
|
||||
NVBuiltinF _ _ -> mempty
|
||||
|
||||
type NValueNF m = Free (NValueF m) (NValue m)
|
||||
type ValueSet m = AttrSet (NThunk m)
|
||||
bindNValueF :: (Monad m, Monad n)
|
||||
=> (forall x. n x -> m x) -> (a -> n b) -> NValueF p m a
|
||||
-> n (NValueF p m b)
|
||||
bindNValueF transform f = \case
|
||||
NVConstantF a -> pure $ NVConstantF a
|
||||
NVStrF s -> pure $ NVStrF s
|
||||
NVPathF p -> pure $ NVPathF p
|
||||
NVListF l -> NVListF <$> traverse f l
|
||||
NVSetF s p -> NVSetF <$> traverse f s <*> pure p
|
||||
NVClosureF p g -> pure $ NVClosureF p (transform . f <=< g)
|
||||
NVBuiltinF s g -> pure $ NVBuiltinF s (transform . f <=< g)
|
||||
|
||||
-- These mutually recursive types interleave thunk representations with value
|
||||
-- representations, each provided by functors 't' and 'v'.
|
||||
newtype NThunkR t v = NThunk { _nThunk :: t (NValueR t v) }
|
||||
newtype NValueR t v = NValue { _nValue :: v (NThunkR t v) }
|
||||
lmapNValueF :: Functor m => (b -> a) -> NValueF a m r -> NValueF b m r
|
||||
lmapNValueF f = \case
|
||||
NVConstantF a -> NVConstantF a
|
||||
NVStrF s -> NVStrF s
|
||||
NVPathF p -> NVPathF p
|
||||
NVListF l -> NVListF l
|
||||
NVSetF s p -> NVSetF s p
|
||||
NVClosureF p g -> NVClosureF p (g . fmap f)
|
||||
NVBuiltinF s g -> NVBuiltinF s (g . fmap f)
|
||||
|
||||
-- jww (2019-03-11): The code below should be generic in 'f', rather than
|
||||
-- specialized to 'NCited'.
|
||||
type NThunk m = NThunkR (NCited NThunkF m) (NCited NValueF m)
|
||||
type NValue m = NValueR (NCited NThunkF m) (NCited NValueF m)
|
||||
liftNValueF :: (MonadTrans u, Monad m)
|
||||
=> (forall x. u m x -> m x)
|
||||
-> NValueF p m a
|
||||
-> NValueF p (u m) a
|
||||
liftNValueF run = \case
|
||||
NVConstantF a -> NVConstantF a
|
||||
NVStrF s -> NVStrF s
|
||||
NVPathF p -> NVPathF p
|
||||
NVListF l -> NVListF l
|
||||
NVSetF s p -> NVSetF s p
|
||||
NVClosureF p g -> NVClosureF p $ lift . g . run
|
||||
NVBuiltinF s g -> NVBuiltinF s $ lift . g . run
|
||||
|
||||
thunkEq :: (MonadThunk (NValue m) (NThunk m) m, MonadBasicThunk m)
|
||||
=> NThunk m -> NThunk m -> m Bool
|
||||
thunkEq lt rt = force lt $ \lv -> force rt $ \rv ->
|
||||
let unsafePtrEq = case (lt, rt) of
|
||||
(NThunk (NCited _ (Thunk lid _ _)),
|
||||
NThunk (NCited _ (Thunk rid _ _))) | lid == rid -> return True
|
||||
_ -> valueEq lv rv
|
||||
in case (lv, rv) of
|
||||
(NVClosure _ _, NVClosure _ _) -> unsafePtrEq
|
||||
(NVList _, NVList _) -> unsafePtrEq
|
||||
(NVSet _ _, NVSet _ _) -> unsafePtrEq
|
||||
_ -> valueEq lv rv
|
||||
unliftNValueF :: (MonadTrans u, Monad m)
|
||||
=> (forall x. u m x -> m x)
|
||||
-> NValueF p (u m) a
|
||||
-> NValueF p m a
|
||||
unliftNValueF run = \case
|
||||
NVConstantF a -> NVConstantF a
|
||||
NVStrF s -> NVStrF s
|
||||
NVPathF p -> NVPathF p
|
||||
NVListF l -> NVListF l
|
||||
NVSetF s p -> NVSetF s p
|
||||
NVClosureF p g -> NVClosureF p $ run . g . lift
|
||||
NVBuiltinF s g -> NVBuiltinF s $ run . g . lift
|
||||
|
||||
addProvenance :: (NValue m -> Provenance m) -> NValue m -> NValue m
|
||||
addProvenance f l@(NValue (NCited p v)) = NValue (NCited (f l : p) v)
|
||||
type MonadDataContext f (m :: * -> *) =
|
||||
(Comonad f, Applicative f, Traversable f, Monad m)
|
||||
|
||||
pattern NVConstant x <- NValue (NCited _ (NVConstantF x))
|
||||
-- | At the time of constructor, the expected arguments to closures are values
|
||||
-- that may contain thunks. The type of such thunks are fixed at that time.
|
||||
newtype NValue' t f m a = NValue { _nValue :: f (NValueF (NValue t f m) m a) }
|
||||
deriving (Generic, Typeable, Functor, Foldable)
|
||||
|
||||
nvConstant x = NValue (NCited [] (NVConstantF x))
|
||||
nvConstantP p x = NValue (NCited [p] (NVConstantF x))
|
||||
|
||||
pattern NVStr ns <- NValue (NCited _ (NVStrF ns))
|
||||
|
||||
nvStr ns = NValue (NCited [] (NVStrF ns))
|
||||
nvStrP p ns = NValue (NCited [p] (NVStrF ns))
|
||||
|
||||
pattern NVPath x <- NValue (NCited _ (NVPathF x))
|
||||
|
||||
nvPath x = NValue (NCited [] (NVPathF x))
|
||||
nvPathP p x = NValue (NCited [p] (NVPathF x))
|
||||
|
||||
pattern NVList l <- NValue (NCited _ (NVListF l))
|
||||
|
||||
nvList l = NValue (NCited [] (NVListF l))
|
||||
nvListP p l = NValue (NCited [p] (NVListF l))
|
||||
|
||||
pattern NVSet s x <- NValue (NCited _ (NVSetF s x))
|
||||
|
||||
nvSet s x = NValue (NCited [] (NVSetF s x))
|
||||
nvSetP p s x = NValue (NCited [p] (NVSetF s x))
|
||||
|
||||
pattern NVClosure x f <- NValue (NCited _ (NVClosureF x f))
|
||||
|
||||
nvClosure x f = NValue (NCited [] (NVClosureF x f))
|
||||
nvClosureP p x f = NValue (NCited [p] (NVClosureF x f))
|
||||
|
||||
pattern NVBuiltin name f <- NValue (NCited _ (NVBuiltinF name f))
|
||||
|
||||
nvBuiltin name f = NValue (NCited [] (NVBuiltinF name f))
|
||||
nvBuiltinP p name f = NValue (NCited [p] (NVBuiltinF name f))
|
||||
|
||||
instance Show (NValueF m (Fix (NValueF m))) where
|
||||
instance Show r => Show (NValueF p m r) where
|
||||
showsPrec = flip go where
|
||||
go (NVConstantF atom) = showsCon1 "NVConstant" atom
|
||||
go (NVStrF ns) = showsCon1 "NVStr" (hackyStringIgnoreContext ns)
|
||||
|
@ -186,17 +168,165 @@ instance Show (NValueF m (Fix (NValueF m))) where
|
|||
showsCon1 :: Show a => String -> a -> Int -> String -> String
|
||||
showsCon1 con a d =
|
||||
showParen (d > 10) $ showString (con ++ " ") . showsPrec 11 a
|
||||
{-
|
||||
showsCon2 :: (Show a, Show b)
|
||||
=> String -> a -> b -> Int -> String -> String
|
||||
showsCon2 con a b d =
|
||||
showParen (d > 10)
|
||||
$ showString (con ++ " ")
|
||||
. showsPrec 11 a
|
||||
. showString " "
|
||||
. showsPrec 11 b
|
||||
-}
|
||||
instance Eq (NValue m) where
|
||||
|
||||
instance (Comonad f, Show a) => Show (NValue' t f m a) where
|
||||
show (NValue (extract -> v)) = show v
|
||||
|
||||
type NValue t f m = NValue' t f m t
|
||||
|
||||
bindNValue :: (Traversable f, Monad m, Monad n)
|
||||
=> (forall x. n x -> m x) -> (a -> n b) -> NValue' t f m a
|
||||
-> n (NValue' t f m b)
|
||||
bindNValue transform f (NValue v) =
|
||||
NValue <$> traverse (bindNValueF transform f) v
|
||||
|
||||
liftNValue :: (MonadTrans u, Monad m, Functor (u m), Functor f)
|
||||
=> (forall x. u m x -> m x)
|
||||
-> NValue' t f m a
|
||||
-> NValue' t f (u m) a
|
||||
liftNValue run (NValue v) =
|
||||
NValue (fmap (lmapNValueF (unliftNValue run) . liftNValueF run) v)
|
||||
|
||||
unliftNValue :: (MonadTrans u, Monad m, Functor (u m), Functor f)
|
||||
=> (forall x. u m x -> m x)
|
||||
-> NValue' t f (u m) a
|
||||
-> NValue' t f m a
|
||||
unliftNValue run (NValue v) =
|
||||
NValue (fmap (lmapNValueF (liftNValue run) . unliftNValueF run) v)
|
||||
|
||||
-- | An 'NValueNF' is a fully evaluated value in normal form. An 'NValue f t m' is
|
||||
-- a value in head normal form, where only the "top layer" has been
|
||||
-- evaluated. An action of type 'm (NValue f t m)' is a pending evualation that
|
||||
-- has yet to be performed. An 't' is either a pending evaluation, or
|
||||
-- a value in head normal form. A 'NThunkSet' is a set of mappings from keys
|
||||
-- to thunks.
|
||||
--
|
||||
-- The 'Free' structure is used here to represent the possibility that
|
||||
-- cycles may appear during normalization.
|
||||
|
||||
type NValueNF t f m = Free (NValue' t f m) (NValue' t f m Void)
|
||||
|
||||
iterNValue
|
||||
:: forall t f m a r. MonadDataContext f m
|
||||
=> (a -> (NValue' t f m a -> r) -> r)
|
||||
-> (NValue' t f m r -> r)
|
||||
-> NValue' t f m a -> r
|
||||
iterNValue k f = f . fmap (\a -> k a (iterNValue k f))
|
||||
|
||||
iterNValueM
|
||||
:: (MonadDataContext f m, Monad n)
|
||||
=> (forall x. n x -> m x)
|
||||
-> (a -> (NValue' t f m a -> n r) -> n r)
|
||||
-> (NValue' t f m r -> n r)
|
||||
-> NValue' t f m a -> n r
|
||||
iterNValueM transform k f =
|
||||
f <=< bindNValue transform (\a -> k a (iterNValueM transform k f))
|
||||
|
||||
iterNValueNF
|
||||
:: MonadDataContext f m
|
||||
=> (NValue' t f m Void -> r)
|
||||
-> (NValue' t f m r -> r)
|
||||
-> NValueNF t f m -> r
|
||||
iterNValueNF k f = iter f . fmap k
|
||||
|
||||
sequenceNValueNF :: (Functor n, Traversable f, Monad m, Monad n)
|
||||
=> (forall x. n x -> m x) -> Free (NValue' t f m) (n a)
|
||||
-> n (Free (NValue' t f m) a)
|
||||
sequenceNValueNF transform = go
|
||||
where
|
||||
go (Pure a) = Pure <$> a
|
||||
go (Free fa) = Free <$> bindNValue transform go fa
|
||||
|
||||
iterNValueNFM
|
||||
:: forall f m n t r. (MonadDataContext f m, Monad n)
|
||||
=> (forall x. n x -> m x)
|
||||
-> (NValue' t f m Void -> n r)
|
||||
-> (NValue' t f m (n r) -> n r)
|
||||
-> NValueNF t f m -> n r
|
||||
iterNValueNFM transform k f v =
|
||||
iterM f =<< sequenceNValueNF transform (fmap k v)
|
||||
|
||||
nValueFromNF :: (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
||||
=> NValueNF t f m -> NValue t f m
|
||||
nValueFromNF = iterNValueNF (fmap absurd) (fmap wrapValue)
|
||||
|
||||
nValueToNF :: (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
||||
=> (t -> (NValue t f m -> NValueNF t f m) -> NValueNF t f m)
|
||||
-> NValue t f m
|
||||
-> NValueNF t f m
|
||||
nValueToNF k = iterNValue k Free
|
||||
|
||||
nValueToNFM
|
||||
:: (MonadDataContext f m, Monad n)
|
||||
=> (forall x. n x -> m x)
|
||||
-> (t -> (NValue t f m -> n (NValueNF t f m)) -> n (NValueNF t f m))
|
||||
-> NValue t f m
|
||||
-> n (NValueNF t f m)
|
||||
nValueToNFM transform k = iterNValueM transform k $ pure . Free
|
||||
|
||||
pattern NVConstant x <- NValue (extract -> NVConstantF x)
|
||||
pattern NVConstantNF x <- Free (NValue (extract -> NVConstantF x))
|
||||
|
||||
nvConstant :: Applicative f => NAtom -> NValue t f m
|
||||
nvConstant x = NValue (pure (NVConstantF x))
|
||||
nvConstantNF :: Applicative f => NAtom -> NValueNF t f m
|
||||
nvConstantNF x = Free (NValue (pure (NVConstantF x)))
|
||||
|
||||
pattern NVStr ns <- NValue (extract -> NVStrF ns)
|
||||
pattern NVStrNF ns <- Free (NValue (extract -> NVStrF ns))
|
||||
|
||||
nvStr :: Applicative f => NixString -> NValue t f m
|
||||
nvStr ns = NValue (pure (NVStrF ns))
|
||||
nvStrNF :: Applicative f => NixString -> NValueNF t f m
|
||||
nvStrNF ns = Free (NValue (pure (NVStrF ns)))
|
||||
|
||||
pattern NVPath x <- NValue (extract -> NVPathF x)
|
||||
pattern NVPathNF x <- Free (NValue (extract -> NVPathF x))
|
||||
|
||||
nvPath :: Applicative f => FilePath -> NValue t f m
|
||||
nvPath x = NValue (pure (NVPathF x))
|
||||
nvPathNF :: Applicative f => FilePath -> NValueNF t f m
|
||||
nvPathNF x = Free (NValue (pure (NVPathF x)))
|
||||
|
||||
pattern NVList l <- NValue (extract -> NVListF l)
|
||||
pattern NVListNF l <- Free (NValue (extract -> NVListF l))
|
||||
|
||||
nvList :: Applicative f => [t] -> NValue t f m
|
||||
nvList l = NValue (pure (NVListF l))
|
||||
nvListNF :: Applicative f => [NValueNF t f m] -> NValueNF t f m
|
||||
nvListNF l = Free (NValue (pure (NVListF l)))
|
||||
|
||||
pattern NVSet s x <- NValue (extract -> NVSetF s x)
|
||||
pattern NVSetNF s x <- Free (NValue (extract -> NVSetF s x))
|
||||
|
||||
nvSet :: Applicative f
|
||||
=> HashMap Text t -> HashMap Text SourcePos -> NValue t f m
|
||||
nvSet s x = NValue (pure (NVSetF s x))
|
||||
nvSetNF :: Applicative f
|
||||
=> HashMap Text (NValueNF t f m) -> HashMap Text SourcePos -> NValueNF t f m
|
||||
nvSetNF s x = Free (NValue (pure (NVSetF s x)))
|
||||
|
||||
pattern NVClosure x f <- NValue (extract -> NVClosureF x f)
|
||||
pattern NVClosureNF x f <- Free (NValue (extract -> NVClosureF x f))
|
||||
|
||||
nvClosure :: Applicative f
|
||||
=> Params () -> (m (NValue t f m) -> m t) -> NValue t f m
|
||||
nvClosure x f = NValue (pure (NVClosureF x f))
|
||||
nvClosureNF :: Applicative f
|
||||
=> Params () -> (m (NValue t f m) -> m (NValueNF t f m)) -> NValueNF t f m
|
||||
nvClosureNF x f = Free (NValue (pure (NVClosureF x f)))
|
||||
|
||||
pattern NVBuiltin name f <- NValue (extract -> NVBuiltinF name f)
|
||||
pattern NVBuiltinNF name f <- Free (NValue (extract -> NVBuiltinF name f))
|
||||
|
||||
nvBuiltin :: Applicative f
|
||||
=> String -> (m (NValue t f m) -> m t) -> NValue t f m
|
||||
nvBuiltin name f = NValue (pure (NVBuiltinF name f))
|
||||
nvBuiltinNF :: Applicative f
|
||||
=> String -> (m (NValue t f m) -> m (NValueNF t f m)) -> NValueNF t f m
|
||||
nvBuiltinNF name f = Free (NValue (pure (NVBuiltinF name f)))
|
||||
|
||||
instance Comonad f => Eq (NValue' t f m a) where
|
||||
NVConstant (NFloat x) == NVConstant (NInt y) = x == fromInteger y
|
||||
NVConstant (NInt x) == NVConstant (NFloat y) = fromInteger x == y
|
||||
NVConstant (NInt x) == NVConstant (NInt y) = x == y
|
||||
|
@ -205,7 +335,7 @@ instance Eq (NValue m) where
|
|||
NVPath x == NVPath y = x == y
|
||||
_ == _ = False
|
||||
|
||||
instance Ord (NValue m) where
|
||||
instance Comonad f => Ord (NValue' t f m a) where
|
||||
NVConstant (NFloat x) <= NVConstant (NInt y) = x <= fromInteger y
|
||||
NVConstant (NInt x) <= NVConstant (NFloat y) = fromInteger x <= y
|
||||
NVConstant (NInt x) <= NVConstant (NInt y) = x <= y
|
||||
|
@ -214,7 +344,8 @@ instance Ord (NValue m) where
|
|||
NVPath x <= NVPath y = x <= y
|
||||
_ <= _ = False
|
||||
|
||||
checkComparable :: (Framed e m, Typeable m) => NValue m -> NValue m -> m ()
|
||||
checkComparable :: (Framed e m, MonadDataErrorContext t f m)
|
||||
=> NValue t f m -> NValue t f m -> m ()
|
||||
checkComparable x y = case (x, y) of
|
||||
(NVConstant (NFloat _), NVConstant (NInt _)) -> pure ()
|
||||
(NVConstant (NInt _), NVConstant (NFloat _)) -> pure ()
|
||||
|
@ -224,24 +355,37 @@ checkComparable x y = case (x, y) of
|
|||
(NVPath _, NVPath _) -> pure ()
|
||||
_ -> throwError $ Comparison x y
|
||||
|
||||
builtin :: Monad m
|
||||
=> String -> (m (NValue m) -> m (NValue m)) -> m (NValue m)
|
||||
builtin name f = return $ nvBuiltin name f
|
||||
thunkEq :: (MonadThunk t m (NValue t f m), Comonad f)
|
||||
=> t -> t -> m Bool
|
||||
thunkEq lt rt = force lt $ \lv -> force rt $ \rv ->
|
||||
let unsafePtrEq = case (lt, rt) of
|
||||
(thunkId -> lid, thunkId -> rid)
|
||||
| lid == rid -> return True
|
||||
_ -> valueEq lv rv
|
||||
in case (lv, rv) of
|
||||
(NVClosure _ _, NVClosure _ _) -> unsafePtrEq
|
||||
(NVList _, NVList _) -> unsafePtrEq
|
||||
(NVSet _ _, NVSet _ _) -> unsafePtrEq
|
||||
_ -> valueEq lv rv
|
||||
|
||||
builtin2 :: Monad m
|
||||
=> String -> (m (NValue m) -> m (NValue m) -> m (NValue m))
|
||||
-> m (NValue m)
|
||||
builtin :: forall m f t. (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
||||
=> String -> (m (NValue t f m) -> m (NValue t f m)) -> m (NValue t f m)
|
||||
builtin name f = return $ nvBuiltin name $ thunk . f
|
||||
|
||||
builtin2 :: (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
||||
=> String -> (m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m))
|
||||
-> m (NValue t f m)
|
||||
builtin2 name f = builtin name (builtin name . f)
|
||||
|
||||
builtin3 :: Monad m
|
||||
builtin3 :: (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
||||
=> String
|
||||
-> (m (NValue m) -> m (NValue m) -> m (NValue m) -> m (NValue m))
|
||||
-> m (NValue m)
|
||||
-> (m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m))
|
||||
-> m (NValue t f m)
|
||||
builtin3 name f =
|
||||
builtin name $ \a -> builtin name $ \b -> builtin name $ \c -> f a b c
|
||||
|
||||
isClosureNF :: Monad m => NValueNF m -> Bool
|
||||
isClosureNF (Free NVClosureF {}) = True
|
||||
isClosureNF :: Comonad f => NValueNF t f m -> Bool
|
||||
isClosureNF NVClosureNF {} = True
|
||||
isClosureNF _ = False
|
||||
|
||||
-- | Checks whether two containers are equal, using the given item equality
|
||||
|
@ -259,36 +403,73 @@ alignEqM eq fa fb = fmap (either (const False) (const True)) $ runExceptT $ do
|
|||
_ -> throwE ()
|
||||
forM_ pairs $ \(a, b) -> guard =<< lift (eq a b)
|
||||
|
||||
isDerivation :: (MonadThunk (NValue m) (NThunk m) m, MonadBasicThunk m)
|
||||
=> AttrSet (NThunk m) -> m Bool
|
||||
isDerivation m = case M.lookup "type" m of
|
||||
isDerivation :: Monad m
|
||||
=> (t -> m (Maybe NixString)) -> AttrSet t
|
||||
-> m Bool
|
||||
isDerivation f m = case M.lookup "type" m of
|
||||
Nothing -> pure False
|
||||
Just t -> force t $ \case
|
||||
-- We should probably really make sure the context is empty here but the
|
||||
-- C++ implementation ignores it.
|
||||
NVStr s -> pure $ principledStringIgnoreContext s == "derivation"
|
||||
_ -> pure False
|
||||
Just t -> do
|
||||
mres <- f t
|
||||
case mres of
|
||||
-- We should probably really make sure the context is empty here
|
||||
-- but the C++ implementation ignores it.
|
||||
Just s -> pure $ principledStringIgnoreContext s == "derivation"
|
||||
Nothing -> pure False
|
||||
|
||||
valueEq :: (MonadThunk (NValue m) (NThunk m) m, MonadBasicThunk m)
|
||||
=> NValue m -> NValue m -> m Bool
|
||||
valueEq = curry $ \case
|
||||
(NVConstant lc, NVConstant rc) -> pure $ lc == rc
|
||||
(NVStr ls, NVStr rs) ->
|
||||
valueFEq :: Monad m
|
||||
=> (AttrSet a -> AttrSet a -> m Bool)
|
||||
-> (a -> a -> m Bool)
|
||||
-> NValueF p m a
|
||||
-> NValueF p m a
|
||||
-> m Bool
|
||||
valueFEq attrsEq eq = curry $ \case
|
||||
(NVConstantF lc, NVConstantF rc) -> pure $ lc == rc
|
||||
(NVStrF ls, NVStrF rs) ->
|
||||
pure $ principledStringIgnoreContext ls
|
||||
== principledStringIgnoreContext rs
|
||||
(NVList ls, NVList rs) -> alignEqM thunkEq ls rs
|
||||
(NVSet lm _, NVSet rm _) -> do
|
||||
let compareAttrs = alignEqM thunkEq lm rm
|
||||
isDerivation lm >>= \case
|
||||
True -> isDerivation rm >>= \case
|
||||
True | Just lp <- M.lookup "outPath" lm
|
||||
, Just rp <- M.lookup "outPath" rm
|
||||
-> thunkEq lp rp
|
||||
_ -> compareAttrs
|
||||
_ -> compareAttrs
|
||||
(NVPath lp, NVPath rp) -> pure $ lp == rp
|
||||
(NVListF ls, NVListF rs) -> alignEqM eq ls rs
|
||||
(NVSetF lm _, NVSetF rm _) -> attrsEq lm rm
|
||||
(NVPathF lp, NVPathF rp) -> pure $ lp == rp
|
||||
_ -> pure False
|
||||
|
||||
compareAttrSets :: Monad m
|
||||
=> (t -> m (Maybe NixString))
|
||||
-> (t -> t -> m Bool)
|
||||
-> AttrSet t
|
||||
-> AttrSet t
|
||||
-> m Bool
|
||||
compareAttrSets f eq lm rm = do
|
||||
isDerivation f lm >>= \case
|
||||
True -> isDerivation f rm >>= \case
|
||||
True | Just lp <- M.lookup "outPath" lm
|
||||
, Just rp <- M.lookup "outPath" rm
|
||||
-> eq lp rp
|
||||
_ -> compareAttrs
|
||||
_ -> compareAttrs
|
||||
where
|
||||
compareAttrs = alignEqM eq lm rm
|
||||
|
||||
valueEq :: (MonadThunk t m (NValue t f m), Comonad f)
|
||||
=> NValue t f m -> NValue t f m -> m Bool
|
||||
valueEq (NValue (extract -> x)) (NValue (extract -> y)) =
|
||||
valueFEq (compareAttrSets f thunkEq) thunkEq x y
|
||||
where
|
||||
f t = force t $ \case
|
||||
NVStr s -> pure $ Just s
|
||||
_ -> pure Nothing
|
||||
|
||||
valueNFEq :: (Comonad f, Monad m)
|
||||
=> NValueNF t f m -> NValueNF t f m -> m Bool
|
||||
valueNFEq (Pure _) (Pure _) = pure False
|
||||
valueNFEq (Pure _) (Free _) = pure False
|
||||
valueNFEq (Free _) (Pure _) = pure False
|
||||
valueNFEq (Free (NValue (extract -> x))) (Free (NValue (extract -> y))) =
|
||||
valueFEq (compareAttrSets f valueNFEq) valueNFEq x y
|
||||
where
|
||||
f (Pure (NVStr s)) = pure $ Just s
|
||||
f (Free (NVStr s)) = pure $ Just s
|
||||
f _ = pure Nothing
|
||||
|
||||
data TStringContext = NoContext | HasContext
|
||||
deriving Show
|
||||
|
||||
|
@ -305,7 +486,7 @@ data ValueType
|
|||
| TBuiltin
|
||||
deriving Show
|
||||
|
||||
valueType :: NValueF m r -> ValueType
|
||||
valueType :: NValueF a m r -> ValueType
|
||||
valueType = \case
|
||||
NVConstantF a -> case a of
|
||||
NInt _ -> TInt
|
||||
|
@ -334,64 +515,50 @@ describeValue = \case
|
|||
TPath -> "a path"
|
||||
TBuiltin -> "a builtin function"
|
||||
|
||||
instance Show (NValueF m (NThunk m)) where
|
||||
show = show . describeValue . valueType
|
||||
|
||||
instance Show (NValue m) where
|
||||
show (NValue (NCited _ v)) = show v
|
||||
|
||||
instance MonadThunk (NValue m) (NThunk m) m => Show (NThunk m) where
|
||||
show (NThunk (NCited _ (thunkValue -> Just v))) = show v
|
||||
show (NThunk (NCited _ _)) = "<thunk>"
|
||||
|
||||
instance Eq1 (NValueF m) where
|
||||
liftEq _ (NVConstantF x) (NVConstantF y) = x == y
|
||||
liftEq _ (NVStrF x) (NVStrF y) = x == y
|
||||
liftEq eq (NVListF x) (NVListF y) = liftEq eq x y
|
||||
liftEq eq (NVSetF x _) (NVSetF y _) = liftEq eq x y
|
||||
liftEq _ (NVPathF x) (NVPathF y) = x == y
|
||||
instance Eq1 (NValueF p m) where
|
||||
liftEq _ (NVConstantF x) (NVConstantF y) = x == y
|
||||
liftEq _ (NVStrF x) (NVStrF y) = x == y
|
||||
liftEq eq (NVListF x) (NVListF y) = liftEq eq x y
|
||||
liftEq eq (NVSetF x _) (NVSetF y _) = liftEq eq x y
|
||||
liftEq _ (NVPathF x) (NVPathF y) = x == y
|
||||
liftEq _ _ _ = False
|
||||
|
||||
instance Show1 (NValueF m) where
|
||||
instance Comonad f => Show1 (NValue' t f m) where
|
||||
liftShowsPrec sp sl p = \case
|
||||
NVConstantF atom -> showsUnaryWith showsPrec "NVConstantF" p atom
|
||||
NVStrF ns -> showsUnaryWith showsPrec "NVStrF" p (hackyStringIgnoreContext ns)
|
||||
NVListF lst -> showsUnaryWith (liftShowsPrec sp sl) "NVListF" p lst
|
||||
NVSetF attrs _ -> showsUnaryWith (liftShowsPrec sp sl) "NVSetF" p attrs
|
||||
NVClosureF c _ -> showsUnaryWith showsPrec "NVClosureF" p c
|
||||
NVPathF path -> showsUnaryWith showsPrec "NVPathF" p path
|
||||
NVBuiltinF name _ -> showsUnaryWith showsPrec "NVBuiltinF" p name
|
||||
NVConstant atom -> showsUnaryWith showsPrec "NVConstantF" p atom
|
||||
NVStr ns -> showsUnaryWith showsPrec "NVStrF" p
|
||||
(hackyStringIgnoreContext ns)
|
||||
NVList lst -> showsUnaryWith (liftShowsPrec sp sl) "NVListF" p lst
|
||||
NVSet attrs _ -> showsUnaryWith (liftShowsPrec sp sl) "NVSetF" p attrs
|
||||
NVPath path -> showsUnaryWith showsPrec "NVPathF" p path
|
||||
NVClosure c _ -> showsUnaryWith showsPrec "NVClosureF" p c
|
||||
NVBuiltin name _ -> showsUnaryWith showsPrec "NVBuiltinF" p name
|
||||
_ -> error "Pattern synonyms mask coverage"
|
||||
|
||||
data ValueFrame m
|
||||
data ValueFrame t f m
|
||||
= ForcingThunk
|
||||
| ConcerningValue (NValue m)
|
||||
| Comparison (NValue m) (NValue m)
|
||||
| Addition (NValue m) (NValue m)
|
||||
| Multiplication (NValue m) (NValue m)
|
||||
| Division (NValue m) (NValue m)
|
||||
| ConcerningValue (NValue t f m)
|
||||
| Comparison (NValue t f m) (NValue t f m)
|
||||
| Addition (NValue t f m) (NValue t f m)
|
||||
| Multiplication (NValue t f m) (NValue t f m)
|
||||
| Division (NValue t f m) (NValue t f m)
|
||||
| Coercion ValueType ValueType
|
||||
| CoercionToJson (NValue m)
|
||||
| CoercionToJson (NValue t f m)
|
||||
| CoercionFromJson A.Value
|
||||
| ExpectationNF ValueType (NValueNF m)
|
||||
| Expectation ValueType (NValue m)
|
||||
| ExpectationNF ValueType (NValueNF t f m)
|
||||
| Expectation ValueType (NValue t f m)
|
||||
deriving (Show, Typeable)
|
||||
|
||||
instance Typeable m => Exception (ValueFrame m)
|
||||
type MonadDataErrorContext t f m =
|
||||
(Show t, Typeable t, Typeable m, Typeable f, MonadDataContext f m)
|
||||
|
||||
instance MonadDataErrorContext t f m => Exception (ValueFrame t f m)
|
||||
|
||||
$(makeTraversals ''NValueF)
|
||||
$(makeLenses ''Provenance)
|
||||
$(makeLenses ''NCited)
|
||||
$(makeLenses ''NThunkR)
|
||||
$(makeLenses ''NValueR)
|
||||
$(makeLenses ''NValue')
|
||||
|
||||
alterF :: (Eq k, Hashable k, Functor f)
|
||||
=> (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)
|
||||
alterF f k m = f (M.lookup k m) <&> \case
|
||||
Nothing -> M.delete k m
|
||||
Just v -> M.insert k v m
|
||||
key :: (Traversable f, Applicative g)
|
||||
=> VarName -> LensLike' g (NValue' t f m a) (Maybe a)
|
||||
key k = nValue.traverse._NVSetF._1.hashAt k
|
||||
|
||||
hashAt :: VarName -> Lens' (AttrSet v) (Maybe v)
|
||||
hashAt = flip alterF
|
||||
|
||||
key :: Applicative f => VarName -> LensLike' f (NValue m) (Maybe (NThunk m))
|
||||
key k = nValue.cited._NVSetF._1.hashAt k
|
||||
$(deriveEq1 ''NValue')
|
||||
|
|
|
@ -20,11 +20,7 @@ import Unsafe.Coerce
|
|||
|
||||
type Var m = Ref m
|
||||
|
||||
--TODO: Eliminate the old MonadVar shims
|
||||
type MonadVar m =
|
||||
( MonadAtomicRef m
|
||||
, GEq (Ref m)
|
||||
)
|
||||
type MonadVar m = MonadAtomicRef m
|
||||
|
||||
eqVar :: forall m a. GEq (Ref m) => Ref m a -> Ref m a -> Bool
|
||||
eqVar a b = isJust $ geq a b
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
module Nix.XML (toXML) where
|
||||
|
||||
import Control.Monad.Free
|
||||
import qualified Data.HashMap.Lazy as M
|
||||
import Data.List
|
||||
import Data.Ord
|
||||
|
@ -16,8 +15,10 @@ import Nix.String
|
|||
import Nix.Value
|
||||
import Text.XML.Light
|
||||
|
||||
toXML :: Functor m => NValueNF m -> NixString
|
||||
toXML = runWithStringContext . fmap pp . iterM phi . check
|
||||
toXML :: forall t f m. MonadDataContext f m => NValueNF t f m -> NixString
|
||||
toXML = runWithStringContext
|
||||
. fmap pp
|
||||
. iterNValueNF (const (pure (mkElem "cycle" "value" ""))) phi
|
||||
where
|
||||
pp = ("<?xml version='1.0' encoding='utf-8'?>\n" <>)
|
||||
. (<> "\n")
|
||||
|
@ -25,22 +26,19 @@ toXML = runWithStringContext . fmap pp . iterM phi . check
|
|||
. ppElement
|
||||
. (\e -> Element (unqual "expr") [] [Elem e] Nothing)
|
||||
|
||||
check :: NValueNF f -> Free (NValueF f) Element
|
||||
check = fmap $ const $ mkElem "cycle" "value" ""
|
||||
|
||||
phi :: NValueF f (WithStringContext Element) -> WithStringContext Element
|
||||
phi :: NValue' t f m (WithStringContext Element) -> WithStringContext Element
|
||||
phi = \case
|
||||
NVConstantF a -> case a of
|
||||
NVConstant a -> case a of
|
||||
NInt n -> return $ mkElem "int" "value" (show n)
|
||||
NFloat f -> return $ mkElem "float" "value" (show f)
|
||||
NBool b -> return $ mkElem "bool" "value" (if b then "true" else "false")
|
||||
NNull -> return $ Element (unqual "null") [] [] Nothing
|
||||
|
||||
NVStrF str -> mkElem "string" "value" . Text.unpack <$> extractNixString str
|
||||
NVListF l -> sequence l >>= \els ->
|
||||
NVStr str -> mkElem "string" "value" . Text.unpack <$> extractNixString str
|
||||
NVList l -> sequence l >>= \els ->
|
||||
return $ Element (unqual "list") [] (Elem <$> els) Nothing
|
||||
|
||||
NVSetF s _ -> sequence s >>= \kvs ->
|
||||
NVSet s _ -> sequence s >>= \kvs ->
|
||||
return $ Element (unqual "attrs") []
|
||||
(map (\(k, v) ->
|
||||
Elem (Element (unqual "attr")
|
||||
|
@ -48,9 +46,10 @@ toXML = runWithStringContext . fmap pp . iterM phi . check
|
|||
[Elem v] Nothing))
|
||||
(sortBy (comparing fst) $ M.toList kvs)) Nothing
|
||||
|
||||
NVClosureF p _ -> return $ Element (unqual "function") [] (paramsXML p) Nothing
|
||||
NVPathF fp -> return $ mkElem "path" "value" fp
|
||||
NVBuiltinF name _ -> return $ mkElem "function" "name" name
|
||||
NVClosure p _ -> return $ Element (unqual "function") [] (paramsXML p) Nothing
|
||||
NVPath fp -> return $ mkElem "path" "value" fp
|
||||
NVBuiltin name _ -> return $ mkElem "function" "name" name
|
||||
_ -> error "Pattern synonyms mask coverage"
|
||||
|
||||
mkElem :: String -> String -> String -> Element
|
||||
mkElem n a v = Element (unqual n) [Attr (unqual a) v] [] Nothing
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
|
||||
|
@ -9,18 +10,19 @@
|
|||
module EvalTests (tests, genEvalCompareTests) where
|
||||
|
||||
import Control.Applicative ((<|>))
|
||||
import Control.Monad.Catch
|
||||
import Control.Monad (when)
|
||||
import Control.Monad.Catch
|
||||
import Control.Monad.IO.Class
|
||||
import qualified Data.HashMap.Lazy as M
|
||||
-- import qualified Data.HashMap.Lazy as M
|
||||
import Data.List ((\\))
|
||||
import Data.Maybe (isJust)
|
||||
import Data.String.Interpolate.IsString
|
||||
import qualified Data.Set as S
|
||||
import Data.String.Interpolate.IsString
|
||||
import Data.Text (Text)
|
||||
import Data.Time
|
||||
import Nix
|
||||
import Nix.TH
|
||||
import Nix.Thunk.Standard
|
||||
import qualified System.Directory as D
|
||||
import System.Environment
|
||||
import System.FilePath
|
||||
|
@ -417,26 +419,27 @@ genEvalCompareTests = do
|
|||
mkTestCase td f = testCase f $ assertEvalFileMatchesNix (td </> f)
|
||||
|
||||
|
||||
instance (Show r, Show (NValueF m r), Eq r) => Eq (NValueF m r) where
|
||||
NVConstantF x == NVConstantF y = x == y
|
||||
NVStrF ls == NVStrF rs = hackyStringIgnoreContext ls == hackyStringIgnoreContext rs
|
||||
NVListF x == NVListF y = and (zipWith (==) x y)
|
||||
NVSetF x _ == NVSetF y _ =
|
||||
M.keys x == M.keys y &&
|
||||
and (zipWith (==) (M.elems x) (M.elems y))
|
||||
NVPathF x == NVPathF y = x == y
|
||||
x == y = error $ "Need to add comparison for values: "
|
||||
++ show x ++ " == " ++ show y
|
||||
-- instance (Show r, Show (NValueF p m r), Eq r) => Eq (NValueF p m r) where
|
||||
-- NVConstantF x == NVConstantF y = x == y
|
||||
-- NVStrF ls == NVStrF rs = hackyStringIgnoreContext ls == hackyStringIgnoreContext rs
|
||||
-- NVListF x == NVListF y = and (zipWith (==) x y)
|
||||
-- NVSetF x _ == NVSetF y _ =
|
||||
-- M.keys x == M.keys y &&
|
||||
-- and (zipWith (==) (M.elems x) (M.elems y))
|
||||
-- NVPathF x == NVPathF y = x == y
|
||||
-- x == y = error $ "Need to add comparison for values: "
|
||||
-- ++ show x ++ " == " ++ show y
|
||||
|
||||
constantEqual :: NExprLoc -> NExprLoc -> Assertion
|
||||
constantEqual a b = do
|
||||
time <- liftIO getCurrentTime
|
||||
let opts = defaultOptions time
|
||||
-- putStrLn =<< lint (stripAnnotation a)
|
||||
a' <- runLazyM opts $ normalForm =<< nixEvalExprLoc Nothing a
|
||||
-- putStrLn =<< lint (stripAnnotation b)
|
||||
b' <- runLazyM opts $ normalForm =<< nixEvalExprLoc Nothing b
|
||||
assertEqual "" a' b'
|
||||
res <- runStdLazyM opts $ do
|
||||
a' <- normalForm =<< nixEvalExprLoc Nothing a
|
||||
b' <- normalForm =<< nixEvalExprLoc Nothing b
|
||||
valueNFEq a' b'
|
||||
assertBool "" res
|
||||
|
||||
constantEqualText' :: Text -> Text -> Assertion
|
||||
constantEqualText' a b = do
|
||||
|
@ -456,14 +459,13 @@ assertNixEvalThrows a = do
|
|||
let Success a' = parseNixTextLoc a
|
||||
time <- liftIO getCurrentTime
|
||||
let opts = defaultOptions time
|
||||
errored <- catch ((runLazyM opts $ normalForm =<< nixEvalExprLoc Nothing a') >> pure False) handler
|
||||
errored <- catch
|
||||
(False <$ runStdLazyM opts (normalForm =<< nixEvalExprLoc Nothing a'))
|
||||
(\(_ :: NixException) -> pure True)
|
||||
if errored then
|
||||
pure ()
|
||||
else
|
||||
assertFailure "Did not catch nix exception"
|
||||
where
|
||||
handler :: NixException -> IO Bool
|
||||
handler _ = pure True
|
||||
|
||||
freeVarsEqual :: Text -> [VarName] -> Assertion
|
||||
freeVarsEqual a xs = do
|
||||
|
|
|
@ -18,12 +18,12 @@ import Data.Text (unpack)
|
|||
import Data.Time
|
||||
import qualified EvalTests
|
||||
import qualified Nix
|
||||
import Nix.Exec
|
||||
import Nix.Expr.Types
|
||||
import Nix.String
|
||||
import Nix.Options
|
||||
import Nix.Parser
|
||||
import Nix.Value
|
||||
import Nix.Thunk.Standard
|
||||
import qualified NixLanguageTests
|
||||
import qualified ParserTests
|
||||
import qualified PrettyTests
|
||||
|
@ -58,7 +58,7 @@ ensureNixpkgsCanParse =
|
|||
}|]) $ \expr -> do
|
||||
NVStr ns <- do
|
||||
time <- liftIO getCurrentTime
|
||||
runLazyM (defaultOptions time) $ Nix.nixEvalExprLoc Nothing expr
|
||||
runStdLazyM (defaultOptions time) $ Nix.nixEvalExprLoc Nothing expr
|
||||
let dir = hackyStringIgnoreContext ns
|
||||
exists <- fileExist (unpack dir)
|
||||
unless exists $
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
|
||||
module TestCommon where
|
||||
|
@ -8,6 +9,7 @@ import Control.Monad.IO.Class
|
|||
import Data.Text (Text, unpack)
|
||||
import Data.Time
|
||||
import Nix
|
||||
import Nix.Thunk.Standard
|
||||
import System.Environment
|
||||
import System.IO
|
||||
import System.Posix.Files
|
||||
|
@ -15,7 +17,7 @@ import System.Posix.Temp
|
|||
import System.Process
|
||||
import Test.Tasty.HUnit
|
||||
|
||||
hnixEvalFile :: Options -> FilePath -> IO (NValueNF (Lazy IO))
|
||||
hnixEvalFile :: Options -> FilePath -> IO (StdValueNF IO)
|
||||
hnixEvalFile opts file = do
|
||||
parseResult <- parseNixFileLoc file
|
||||
case parseResult of
|
||||
|
@ -23,20 +25,21 @@ hnixEvalFile opts file = do
|
|||
error $ "Parsing failed for file `" ++ file ++ "`.\n" ++ show err
|
||||
Success expr -> do
|
||||
setEnv "TEST_VAR" "foo"
|
||||
runLazyM opts $
|
||||
runStdLazyM opts $
|
||||
catch (evaluateExpression (Just file) nixEvalExprLoc
|
||||
normalForm expr) $ \case
|
||||
NixException frames ->
|
||||
errorWithoutStackTrace . show
|
||||
=<< renderFrames @(NThunk (Lazy IO)) frames
|
||||
=<< renderFrames @(StdValue IO) @(StdThunk IO) frames
|
||||
|
||||
hnixEvalText :: Options -> Text -> IO (NValueNF (Lazy IO))
|
||||
hnixEvalText :: Options -> Text -> IO (StdValueNF IO)
|
||||
hnixEvalText opts src = case parseNixText src of
|
||||
Failure err ->
|
||||
error $ "Parsing failed for expressien `"
|
||||
++ unpack src ++ "`.\n" ++ show err
|
||||
Success expr ->
|
||||
runLazyM opts $ normalForm =<< nixEvalExpr Nothing expr
|
||||
-- runStdLazyM opts $ normalForm =<< nixEvalExpr Nothing expr
|
||||
runStdLazyM opts $ normalForm =<< nixEvalExpr Nothing expr
|
||||
|
||||
nixEvalString :: String -> IO String
|
||||
nixEvalString expr = do
|
||||
|
|
Loading…
Reference in a new issue