Begin work in Builtins.hs

This commit is contained in:
John Wiegley 2019-03-15 13:27:05 -07:00
parent 568fe7f825
commit 483dded8db
No known key found for this signature in database
GPG key ID: C144D8F4F19FE630

View file

@ -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 qualified "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
@ -96,24 +96,24 @@ import Text.Read
import Text.Regex.TDFA
-- | 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. (MonadNix 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 @(NValue t f m) @t @m $ nvList $
map (wrapValue @(NValue t f m) @t @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 @(NValue t f m) @t @m $ nvPath path
pushScope (M.singleton "__cur_file" ref) action
builtins :: (MonadNix e m, Scoped (NThunk m) m)
=> m (Scopes m (NThunk m))
builtins :: (MonadNix 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 +129,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 :: forall e t f m. MonadNix 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. MonadNix 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. MonadNix e t f m => m [Builtin t]
builtinsList = sequence [
do version <- toValue (principledMakeNixStringWithoutContext "2.0")
pure $ Builtin Normal ("nixVersion", version)
@ -288,12 +288,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 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. MonadNix e t f m
=> (FilePath -> Maybe String -> NixPathEntryType -> r -> m r) -> r -> m r
foldNixPath f z = do
mres <- lookupVar "__includes"
@ -313,7 +313,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 :: MonadNix 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 +323,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 :: MonadNix 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. MonadNix 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 :: MonadNix 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 :: MonadNix 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. MonadNix 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. MonadNix 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 +359,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. MonadNix 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_ :: MonadNix 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 +372,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_ :: MonadNix 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 +382,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_ :: MonadNix 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 +402,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_ :: MonadNix 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 +414,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_ :: MonadNix 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. MonadNix 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_ :: MonadNix 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_ :: MonadNix 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
@ -467,7 +467,7 @@ 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_ :: MonadNix 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
@ -479,7 +479,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_ :: MonadNix 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 +507,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. MonadNix 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. MonadNix 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 +540,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. MonadNix 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 +555,11 @@ split_ pat str =
splitMatches 0 (map elems $ matchAllText re haystack) haystack
splitMatches
:: forall e m. MonadNix e m
:: forall e t f m. MonadNix 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 +572,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 :: MonadNix 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. MonadNix 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. MonadNix 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. MonadNix 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
toNix <=< traverse (thunk @_ @t . withFrame Debug
(ErrorCall "While applying f in map:\n")
. (f `callFunc`) . force')
<=< fromValue @[NThunk m] $ xs
<=< 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. MonadNix 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. MonadNix 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. MonadNix 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 :: MonadNix 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. MonadNix 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. MonadNix 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. MonadNix 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 :: MonadNix 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 :: MonadNix 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_ :: MonadNix 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 :: MonadNix 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 +663,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. MonadNix 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_ :: MonadNix 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. MonadNix 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. MonadNix 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 +703,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 +720,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 :: MonadNix 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 +760,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. MonadNix 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. MonadNix 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. MonadNix 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 +789,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 :: MonadNix 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,58 +801,58 @@ toFile name s = do
sc = StringContext t DirectPath
toNix $ principledMakeNixStringWithSingletonContext t sc
toPath :: MonadNix e m => m (NValue m) -> m (NValue m)
toPath :: MonadNix 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_ :: MonadNix 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. (MonadNix 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. MonadNix 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. MonadNix 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. MonadNix 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. MonadNix 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. MonadNix 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. MonadNix 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. MonadNix 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 :: MonadNix 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_ :: MonadNix 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. MonadNix 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. MonadNix 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
mres <- lookupVar "__cur_file"
@ -858,15 +860,15 @@ scopedImport asetArg pathArg =
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'
getEnv_ :: MonadNix e m => m (NValue m) -> m (NValue m)
getEnv_ :: MonadNix 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 +876,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_ :: MonadNix 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 +890,7 @@ sort_ comparator xs = comparator >>= \comp ->
True -> GT
False -> EQ
lessThan :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
lessThan :: MonadNix 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 +905,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. MonadNix 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. MonadNix 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 +921,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 :: MonadNix 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 +953,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 :: MonadNix 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 +961,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 :: MonadNix e t f m => NValue t f m -> m FilePath
absolutePathFromValue = \case
NVStr ns -> do
let path = Text.unpack $ hackyStringIgnoreContext ns
@ -969,12 +971,12 @@ 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_ :: MonadNix 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. MonadNix 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' ->
@ -993,14 +995,14 @@ data FileType
| FileTypeUnknown
deriving (Show, Read, Eq, Ord)
instance Applicative m => ToNix FileType m (NValue m) where
instance Applicative 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. MonadNix 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 +1016,7 @@ 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. (MonadNix e t f m, Typeable 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 ->
@ -1035,15 +1037,15 @@ fromJSON = fromValue >=> fromStringNoContext >=> \encoded ->
A.Null -> pure $ nvConstant NNull
prim_toJSON
:: MonadNix e m
=> m (NValue m)
-> m (NValue m)
:: MonadNix 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_ :: MonadNix 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 :: MonadNix 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 +1060,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. MonadNix 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 +1068,38 @@ 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. MonadNix 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
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. MonadNix 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. MonadNix 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. MonadNix 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 +1112,41 @@ 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. MonadNix 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 :: MonadNix 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_ :: MonadNix 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_ :: MonadNix 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 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 (MonadNix e t f m, ToNix a m (NValue t f m))
=> ToBuiltin t 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
instance (MonadNix e t f m, FromNix a m (NValue t f m), ToBuiltin t m b)
=> ToBuiltin t m (a -> b) where
toBuiltin name f = return $ nvBuiltin name (fromNix >=> toBuiltin name . f)