From 74cf22f2f5a27caa8ad48de4f955b2171ead1fed Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Thu, 11 Mar 2021 12:22:59 +0200 Subject: [PATCH 01/30] Repl: refactor --- main/Repl.hs | 169 +++++++++++++++++++++++++++++---------------------- 1 file changed, 96 insertions(+), 73 deletions(-) diff --git a/main/Repl.hs b/main/Repl.hs index 334207fec..2bebe80c0 100644 --- a/main/Repl.hs +++ b/main/Repl.hs @@ -9,9 +9,7 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiWayIf #-} -{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} @@ -29,12 +27,14 @@ import Nix.Scope import Nix.Utils import Nix.Value.Monad ( demand ) -import qualified Data.List -import qualified Data.Maybe +import qualified Data.List as List +import qualified Data.Maybe as Maybe import qualified Data.HashMap.Lazy -import Data.Text (Text) -import qualified Data.Text -import qualified Data.Text.IO +import Data.Char ( isSpace ) +import Data.List ( dropWhileEnd ) +import Data.Text ( Text ) +import qualified Data.Text as Text +import qualified Data.Text.IO as Text.IO import Data.Version ( showVersion ) import Paths_hnix ( version ) @@ -47,7 +47,7 @@ import Prettyprinter ( Doc , space ) import qualified Prettyprinter -import qualified Prettyprinter.Render.Text +import qualified Prettyprinter.Render.Text as Prettyprinter import System.Console.Haskeline.Completion ( Completion(isFinished) @@ -57,13 +57,15 @@ import System.Console.Haskeline.Completion ) import System.Console.Repline ( Cmd , CompletionFunc - , CompleterStyle (Prefix) + , CompleterStyle(Prefix) + , MultiLine(SingleLine, MultiLine) , ExitDecision(Exit) , HaskelineT + , evalRepl ) -import qualified System.Console.Repline -import qualified System.Exit -import qualified System.IO.Error +import qualified System.Console.Repline as Console +import qualified System.Exit as Exit +import qualified System.IO.Error as Error -- | Repl entry point main :: (MonadNix e t f m, MonadIO m, MonadMask m) => m () @@ -73,8 +75,12 @@ main = main' Nothing -- -- Passed value is stored in context with "input" key. main' :: (MonadNix e t f m, MonadIO m, MonadMask m) => Maybe (NValue t f m) -> m () -main' iniVal = initState iniVal >>= \s -> flip evalStateT s - $ System.Console.Repline.evalRepl +main' iniVal = + do + s <- initState iniVal + + evalStateT + (evalRepl banner cmd options @@ -83,33 +89,41 @@ main' iniVal = initState iniVal >>= \s -> flip evalStateT s completion (rcFile *> greeter) finalizer + ) + s where commandPrefix = ':' banner = pure . \case - System.Console.Repline.SingleLine -> "hnix> " - System.Console.Repline.MultiLine -> "| " + SingleLine -> "hnix> " + MultiLine -> "| " greeter = - liftIO - $ putStrLn - $ "Welcome to hnix " - <> showVersion version - <> ". For help type :help\n" + liftIO $ + putStrLn $ + "Welcome to hnix " + <> showVersion version + <> ". For help type :help\n" finalizer = do liftIO $ putStrLn "Goodbye." pure Exit - rcFile = do - f <- liftIO $ Data.Text.IO.readFile ".hnixrc" `catch` handleMissing - for_ (words . Data.Text.unpack <$> Data.Text.lines f) $ \case - ((prefix:command) : xs) | prefix == commandPrefix -> do - let arguments = unwords xs - optMatcher command options arguments - x -> cmd $ unwords x + rcFile = + do + f <- liftIO $ Text.IO.readFile ".hnixrc" `catch` handleMissing + + traverse_ + (\case + ((prefix:command) : xs) | prefix == commandPrefix -> + do + let arguments = unwords xs + optMatcher command options arguments + x -> cmd $ unwords x + ) + (words . Text.unpack <$> Text.lines f) handleMissing e - | System.IO.Error.isDoesNotExistError e = pure "" + | Error.isDoesNotExistError e = pure "" | otherwise = throwIO e -- Replicated and slightly adjusted `optMatcher` from `System.Console.Repline` @@ -118,12 +132,12 @@ main' iniVal = initState iniVal >>= \s -> flip evalStateT s -- * @putStrLn@ instead of @outputStrLn@ optMatcher :: MonadIO m => String - -> System.Console.Repline.Options m + -> Console.Options m -> String -> m () optMatcher s [] _ = liftIO $ putStrLn $ "No such command :" <> s optMatcher s ((x, m) : xs) args - | s `Data.List.isPrefixOf` x = m args + | s `List.isPrefixOf` x = m args | otherwise = optMatcher s xs args @@ -156,18 +170,20 @@ initState mIni = do opts :: Nix.Options <- asks (view hasLens) - pure $ IState - Nothing - (Data.HashMap.Lazy.fromList - $ ("builtins", builtins) : fmap ("input",) (Data.Maybe.maybeToList mIni)) - defReplConfig - { cfgStrict = strict opts - , cfgValues = values opts - } + pure $ + IState + Nothing + (Data.HashMap.Lazy.fromList $ + ("builtins", builtins) : fmap ("input",) (Maybe.maybeToList mIni) + ) + defReplConfig + { cfgStrict = strict opts + , cfgValues = values opts + } where evalText :: (MonadNix e t f m) => Text -> m (NValue t f m) evalText expr = case parseNixTextLoc expr of - Failure e -> error $ "Impossible happened: Unable to parse expression - '" <> Data.Text.unpack expr <> "' error was " <> show e + Failure e -> error $ "Impossible happened: Unable to parse expression - '" <> Text.unpack expr <> "' error was " <> show e Success e -> do evalExprLoc e type Repl e t f m = HaskelineT (StateT (IState t f m) m) @@ -204,11 +220,11 @@ exec update source = do mVal <- lift $ lift $ try $ pushScope (replCtx st) (evalExprLoc expr) - case mVal of - Left (NixException frames) -> do + either + (\ (NixException frames) -> do lift $ lift $ liftIO . print =<< renderFrames @(NValue t f m) @t frames - pure Nothing - Right val -> do + pure Nothing) + (\ val -> do -- Update the interpreter state when (update && isBinding) $ do -- Set `replIt` to last entered expression @@ -220,6 +236,8 @@ exec update source = do _ -> pure () pure $ pure val + ) + mVal where -- If parsing fails, turn the input into singleton attribute set -- and try again. @@ -234,17 +252,20 @@ exec update source = do Failure _ -> (Failure e, False) -- return the first parsing failure Success e' -> (Success e', True) - toAttrSet i = "{" <> i <> (if Data.Text.isSuffixOf ";" i then mempty else ";") <> "}" + toAttrSet i = + "{" <> i <> bool ";" mempty (Text.isSuffixOf ";" i) <> "}" cmd :: (MonadNix e t f m, MonadIO m) => String -> Repl e t f m () -cmd source = do - mVal <- exec True (Data.Text.pack source) - case mVal of - Nothing -> pure () - Just val -> printValue val +cmd source = + do + mVal <- exec True (Text.pack source) + maybe + (pure ()) + printValue + mVal printValue :: (MonadNix e t f m, MonadIO m) => NValue t f m @@ -267,7 +288,7 @@ browse :: (MonadNix e t f m, MonadIO m) browse _ = do st <- get for_ (Data.HashMap.Lazy.toList $ replCtx st) $ \(k, v) -> do - liftIO $ putStr $ Data.Text.unpack $ k <> " = " + liftIO $ putStr $ Text.unpack $ k <> " = " printValue v -- | @:load@ command @@ -275,13 +296,14 @@ load :: (MonadNix e t f m, MonadIO m) => String -> Repl e t f m () -load args = do - contents <- liftIO - $ Data.Text.IO.readFile - $ Data.Text.unpack - $ Data.Text.strip - $ Data.Text.pack args - void $ exec True contents +load args = + do + contents <- liftIO + $ Text.IO.readFile + $ trim args + void $ exec True contents + where + trim = dropWhileEnd isSpace . dropWhile isSpace -- | @:type@ command typeof @@ -291,14 +313,15 @@ typeof typeof args = do st <- get mVal <- - case Data.HashMap.Lazy.lookup line (replCtx st) of - Nothing -> exec False line - Just val -> pure $ pure val + maybe + (exec False line) + (pure . pure) + (Data.HashMap.Lazy.lookup line (replCtx st)) traverse_ printValueType mVal where - line = Data.Text.pack args + line = Text.pack args printValueType val = do s <- lift . lift . showValueType $ val @@ -307,7 +330,7 @@ typeof args = do -- | @:quit@ command quit :: (MonadNix e t f m, MonadIO m) => a -> Repl e t f m () -quit _ = liftIO System.Exit.exitSuccess +quit _ = liftIO Exit.exitSuccess -- | @:set@ command setConfig :: (MonadNix e t f m, MonadIO m) => String -> Repl e t f m () @@ -324,7 +347,7 @@ setConfig args = case words args of -- | Prefix tab completer defaultMatcher :: MonadIO m => [(String, CompletionFunc m)] defaultMatcher = - [ (":load", System.Console.Repline.fileCompleter) + [ (":load", Console.fileCompleter) ] completion @@ -353,11 +376,11 @@ completeFunc reversedPrev word $ fmap helpOptionName (helpOptions :: HelpOptions e t f m) -- Files - | any (`Data.List.isPrefixOf` word) [ "/", "./", "../", "~/" ] = + | any (`List.isPrefixOf` word) [ "/", "./", "../", "~/" ] = listFiles word -- Attributes of sets in REPL context - | var : subFields <- Data.Text.split (== '.') (Data.Text.pack word) , not $ null subFields = + | var : subFields <- Text.split (== '.') (Text.pack word) , not $ null subFields = do s <- get maybe @@ -365,7 +388,7 @@ completeFunc reversedPrev word (\ binding -> do candidates <- lift $ algebraicComplete subFields binding - pure $ notFinished <$> listCompletion (Data.Text.unpack . (var <>) <$> candidates) + pure $ notFinished <$> listCompletion (Text.unpack . (var <>) <$> candidates) ) (Data.HashMap.Lazy.lookup var (replCtx s)) @@ -379,11 +402,11 @@ completeFunc reversedPrev word pure $ listCompletion $ ["__includes"] - <> (Data.Text.unpack <$> contextKeys) - <> (Data.Text.unpack <$> shortBuiltins) + <> (Text.unpack <$> contextKeys) + <> (Text.unpack <$> shortBuiltins) where - listCompletion = fmap simpleCompletion . filter (word `Data.List.isPrefixOf`) + listCompletion = fmap simpleCompletion . filter (word `List.isPrefixOf`) notFinished x = x { isFinished = False } @@ -527,8 +550,8 @@ help hs _ = do liftIO $ putStrLn "Available commands:\n" for_ hs $ \h -> liftIO . - Data.Text.IO.putStrLn . - Prettyprinter.Render.Text.renderStrict . + Text.IO.putStrLn . + Prettyprinter.renderStrict . Prettyprinter.layoutPretty Prettyprinter.defaultLayoutOptions $ ":" <> Prettyprinter.pretty (helpOptionName h) <> space @@ -538,5 +561,5 @@ help hs _ = do options :: (MonadNix e t f m, MonadIO m) - => System.Console.Repline.Options (Repl e t f m) + => Console.Options (Repl e t f m) options = (\h -> (helpOptionName h, helpOptionFunction h)) <$> helpOptions From ee9bf55ade13ebab710763b3285b53a2de1dd212 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Thu, 11 Mar 2021 12:34:49 +0200 Subject: [PATCH 02/30] Exec: refactor; add ApplicativeDo --- src/Nix/Exec.hs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/Nix/Exec.hs b/src/Nix/Exec.hs index fad478dfe..8ce214618 100644 --- a/src/Nix/Exec.hs +++ b/src/Nix/Exec.hs @@ -14,6 +14,7 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE ApplicativeDo #-} {-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -fno-warn-name-shadowing #-} @@ -289,17 +290,18 @@ callFunc -> m (NValue t f m) callFunc fun arg = do - fun' <- demand fun frames :: Frames <- asks (view hasLens) when (length frames > 2000) $ throwError $ ErrorCall "Function call stack exhausted" + + fun' <- demand fun case fun' of - NVClosure _params f -> do - f arg - NVBuiltin name f -> do - span <- currentPos - withFrame Info (Calling @m @(NValue t f m) name span) (f arg) - s@(NVSet m _) | Just f <- M.lookup "__functor" m -> do - ((`callFunc` arg) <=< (`callFunc` s)) =<< demand f + NVClosure _params f -> f arg + NVBuiltin name f -> + do + span <- currentPos + withFrame Info ((Calling @m @(NValue t f m)) name span) (f arg) + (NVSet m _) | Just f <- M.lookup "__functor" m -> + ((`callFunc` arg) <=< (`callFunc` fun')) =<< demand f x -> throwError $ ErrorCall $ "Attempt to call non-function: " <> show x execUnaryOp @@ -311,12 +313,13 @@ execUnaryOp -> m (NValue t f m) execUnaryOp scope span op arg = do case arg of - NVConstant c -> case (op, c) of - (NNeg, NInt i ) -> unaryOp $ NInt (-i) - (NNeg, NFloat f) -> unaryOp $ NFloat (-f) - (NNot, NBool b ) -> unaryOp $ NBool (not b) - _ -> - throwError $ ErrorCall $ "unsupported argument type for unary operator " <> show op + NVConstant c -> + case (op, c) of + (NNeg, NInt i ) -> unaryOp $ NInt (-i) + (NNeg, NFloat f) -> unaryOp $ NFloat (-f) + (NNot, NBool b ) -> unaryOp $ NBool (not b) + _ -> + throwError $ ErrorCall $ "unsupported argument type for unary operator " <> show op x -> throwError $ ErrorCall $ "argument to unary operator must evaluate to an atomic type: " <> show x where From bc1785c4b9b2dc2db1f6daaf3f7e2c5d4070d468 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Thu, 11 Mar 2021 12:46:18 +0200 Subject: [PATCH 03/30] Utils: rename fun (`if*` -> `when*`) (improves readability) For the `if` FP programmers always internally psychologically ask `& else?`. And since this functions implicitly return as an else a stub instead of processing, for what `when*` is used in the language - fits better. --- src/Nix/Builtins.hs | 2 +- src/Nix/Effects/Basic.hs | 4 ++-- src/Nix/Eval.hs | 2 +- src/Nix/Pretty.hs | 6 ++--- src/Nix/Render/Frame.hs | 2 +- src/Nix/Utils.hs | 48 ++++++++++++++++++++-------------------- src/Nix/XML.hs | 2 +- 7 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/Nix/Builtins.hs b/src/Nix/Builtins.hs index 4b838e5b5..7969b0843 100644 --- a/src/Nix/Builtins.hs +++ b/src/Nix/Builtins.hs @@ -379,7 +379,7 @@ foldNixPath f z = foldrM go z $ (fromInclude . stringIgnoreContext <$> dirs) - <> ((uriAwareSplit . Text.pack) `ifJust` mPath) + <> ((uriAwareSplit . Text.pack) `whenJust` mPath) <> [ fromInclude $ Text.pack $ "nix=" <> dataDir <> "/nix/corepkgs" ] where fromInclude x = (x, ) $ diff --git a/src/Nix/Effects/Basic.hs b/src/Nix/Effects/Basic.hs index 919b53aa6..af7be153e 100644 --- a/src/Nix/Effects/Basic.hs +++ b/src/Nix/Effects/Basic.hs @@ -243,7 +243,7 @@ findPathM = findPathBy existingPath do apath <- makeAbsolutePath @t @f path doesExist <- doesPathExist apath - pure $ ifTrue (pure apath) doesExist + pure $ pure apath `whenTrue` doesExist defaultImportPath :: (MonadNix e t f m, MonadState (HashMap FilePath NExprLoc, b) m) @@ -274,7 +274,7 @@ defaultPathToDefaultNix = pathToDefaultNixFile pathToDefaultNixFile :: MonadFile m => FilePath -> m FilePath pathToDefaultNixFile p = do isDir <- doesDirectoryExist p - pure $ p ifTrue "default.nix" isDir + pure $ p "default.nix" `whenTrue` isDir defaultTraceEffect :: MonadPutStr m => String -> m () defaultTraceEffect = Nix.Effects.putStrLn diff --git a/src/Nix/Eval.hs b/src/Nix/Eval.hs index 8c00450ad..35696fbde 100644 --- a/src/Nix/Eval.hs +++ b/src/Nix/Eval.hs @@ -440,7 +440,7 @@ evalSetterKeyName = \case StaticKey k -> pure (pure k) DynamicKey k -> - ((pure . stringIgnoreContext) `ifJust`) <$> runAntiquoted "\n" assembleString (fromValueMay =<<) k + ((pure . stringIgnoreContext) `whenJust`) <$> runAntiquoted "\n" assembleString (fromValueMay =<<) k assembleString :: forall v m diff --git a/src/Nix/Pretty.hs b/src/Nix/Pretty.hs index 1ed7c5d5a..c4b8b2914 100644 --- a/src/Nix/Pretty.hs +++ b/src/Nix/Pretty.hs @@ -144,7 +144,7 @@ prettyString (Indented _ parts) = group $ nest 2 $ vcat prettyParams :: Params (NixDoc ann) -> Doc ann prettyParams (Param n ) = pretty n prettyParams (ParamSet s v mname) = prettyParamSet s v <> - (\ name -> ("@" <> pretty name) `ifTrue` not (Text.null name)) `ifJust` mname + (\ name -> ("@" <> pretty name) `whenTrue` not (Text.null name)) `whenJust` mname prettyParamSet :: ParamSet (NixDoc ann) -> Bool -> Doc ann prettyParamSet args var = @@ -168,7 +168,7 @@ prettyBind (NamedVar n v _p) = prettyBind (Inherit s ns _p) = "inherit " <> scope <> align (fillSep (fmap prettyKeyName ns)) <> ";" where - scope = ((<> " ") . parens . withoutParens) `ifJust` s + scope = ((<> " ") . parens . withoutParens) `whenJust` s prettyKeyName :: NKeyName (NixDoc ann) -> Doc ann prettyKeyName (StaticKey "") = "\"\"" @@ -252,7 +252,7 @@ exprFNixDoc = \case $ wrapPath selectOp r <> "." <> prettySelector attr <> ordoc where r = mkNixDoc selectOp (wrapParens appOpNonAssoc r') - ordoc = ((" or " <>) . wrapParens appOpNonAssoc) `ifJust` o + ordoc = ((" or " <>) . wrapParens appOpNonAssoc) `whenJust` o NHasAttr r attr -> mkNixDoc hasAttrOp (wrapParens hasAttrOp r <> " ? " <> prettySelector attr) NEnvPath p -> simpleExpr $ pretty ("<" <> p <> ">") diff --git a/src/Nix/Render/Frame.hs b/src/Nix/Render/Frame.hs index 7178ed4b8..da2da5f5b 100644 --- a/src/Nix/Render/Frame.hs +++ b/src/Nix/Render/Frame.hs @@ -60,7 +60,7 @@ renderFrames (x : xs) = do frames where go :: NixFrame -> [Doc ann] - go f = (\ pos -> ["While evaluating at " <> pretty (sourcePosPretty pos) <> colon]) `ifJust` framePos @v @m f + go f = (\ pos -> ["While evaluating at " <> pretty (sourcePosPretty pos) <> colon]) `whenJust` framePos @v @m f framePos :: forall v (m :: * -> *) diff --git a/src/Nix/Utils.hs b/src/Nix/Utils.hs index 3f6cdb983..e7f5f8522 100644 --- a/src/Nix/Utils.hs +++ b/src/Nix/Utils.hs @@ -202,62 +202,62 @@ free fP fF fr = Pure a -> fP a Free fa -> fF fa -{-# inline ifTrue #-} -ifTrue :: (Monoid a) +{-# inline whenTrue #-} +whenTrue :: (Monoid a) => a -> Bool -> a -ifTrue = +whenTrue = bool mempty -{-# inline ifFalse #-} -ifFalse :: (Monoid a) +{-# inline whenFalse #-} +whenFalse :: (Monoid a) => a -> Bool -> a -ifFalse f = +whenFalse f = bool f mempty -{-# inline ifJust #-} -ifJust :: (Monoid b) +{-# inline whenJust #-} +whenJust :: (Monoid b) => (a -> b) -> Maybe a -> b -ifJust = +whenJust = maybe mempty -{-# inline ifNothing #-} -ifNothing :: (Monoid b) +{-# inline whenNothing #-} +whenNothing :: (Monoid b) => b -> Maybe a -> b -ifNothing f = +whenNothing f = maybe f mempty -{-# inline ifRight #-} -ifRight :: (Monoid c) +{-# inline whenRight #-} +whenRight :: (Monoid c) => (b -> c) -> Either a b -> c -ifRight = +whenRight = either mempty -{-# inline ifLeft #-} -ifLeft :: (Monoid c) +{-# inline whenLeft #-} +whenLeft :: (Monoid c) => (a -> c) -> Either a b -> c -ifLeft f = +whenLeft f = either f mempty -{-# inline ifFree #-} -ifFree :: (Monoid b) +{-# inline whenFree #-} +whenFree :: (Monoid b) => (f (Free f a) -> b) -> Free f a -> b -ifFree = +whenFree = free mempty -{-# inline ifPure #-} -ifPure :: (Monoid b) +{-# inline whenPure #-} +whenPure :: (Monoid b) => (a -> b) -> Free f a -> b -ifPure f = +whenPure f = free f mempty diff --git a/src/Nix/XML.hs b/src/Nix/XML.hs index 133db784f..96adb13fe 100644 --- a/src/Nix/XML.hs +++ b/src/Nix/XML.hs @@ -72,7 +72,7 @@ paramsXML (ParamSet s b mname) = where battr = [ Attr (unqual "ellipsis") "1" | b ] nattr = - ((: mempty) . Attr (unqual "name") . Text.unpack) `ifJust` mname + ((: mempty) . Attr (unqual "name") . Text.unpack) `whenJust` mname paramSetXML :: ParamSet r -> [Content] paramSetXML = fmap (\(k, _) -> Elem $ mkElem "attr" "name" (Text.unpack k)) From 8a9fbdea5dfd8756320495a2d9f527c62db17157 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Thu, 11 Mar 2021 22:17:26 +0200 Subject: [PATCH 04/30] Main: layout --- main/Main.hs | 64 ++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/main/Main.hs b/main/Main.hs index ab04d5436..33b9dbb47 100644 --- a/main/Main.hs +++ b/main/Main.hs @@ -85,9 +85,10 @@ main = do ) (readFrom opts) - processFile opts path = do - eres <- parseNixFileLoc path - handleResult opts (pure path) eres + processFile opts path = + do + eres <- parseNixFileLoc path + handleResult opts (pure path) eres handleResult opts mpath = \case Failure err -> @@ -97,36 +98,39 @@ main = do (ignoreErrors opts) $ "Parse failed: " <> show err - Success expr -> do - when (check opts) $ do - expr' <- liftIO (reduceExpr mpath expr) - either - (\ err -> errorWithoutStackTrace $ "Type error: " <> PS.ppShow err) - (\ ty -> liftIO $ putStrLn $ "Type of expression: " <> PS.ppShow - (fromJust $ Map.lookup "it" $ Env.types ty) - ) - (HM.inferTop Env.empty [("it", stripAnnotation expr')]) + (\ expr -> + do + when (check opts) $ + do + expr' <- liftIO (reduceExpr mpath expr) + either + (\ err -> errorWithoutStackTrace $ "Type error: " <> PS.ppShow err) + (\ ty -> liftIO $ putStrLn $ "Type of expression: " <> PS.ppShow + (fromJust $ Map.lookup "it" $ Env.types ty) + ) + (HM.inferTop Env.empty [("it", stripAnnotation expr')]) - -- liftIO $ putStrLn $ runST $ - -- runLintM opts . renderSymbolic =<< lint opts expr + -- liftIO $ putStrLn $ runST $ + -- runLintM opts . renderSymbolic =<< lint opts expr - catch (process opts mpath expr) $ \case - NixException frames -> - errorWithoutStackTrace - . show - =<< renderFrames @(StdValue (StandardT (StdIdT IO))) - @(StdThunk (StandardT (StdIdT IO))) - frames + catch (process opts mpath expr) $ + \case + NixException frames -> + errorWithoutStackTrace . show + =<< renderFrames @(StdValue (StandardT (StdIdT IO))) + @(StdThunk (StandardT (StdIdT IO))) + frames - when (repl opts) $ - withNixContext mempty $ - bool - Repl.main - (do - val <- Nix.nixEvalExprLoc mpath expr - Repl.main' $ pure val - ) - (evaluate opts) + when (repl opts) $ + withNixContext mempty $ + bool + Repl.main + (do + val <- Nix.nixEvalExprLoc mpath expr + Repl.main' $ pure val + ) + (evaluate opts) + ) process opts mpath expr | evaluate opts = From 5c5814188d11917f8e150fe926c3b80d3c3751d8 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Fri, 12 Mar 2021 16:28:28 +0200 Subject: [PATCH 05/30] Utils: add `both` --- src/Nix/Utils.hs | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/Nix/Utils.hs b/src/Nix/Utils.hs index e7f5f8522..37af25fe1 100644 --- a/src/Nix/Utils.hs +++ b/src/Nix/Utils.hs @@ -62,13 +62,13 @@ type AlgM f m a = f a -> m a -- | "Transform" here means a modification of a catamorphism. type Transform f a = (Fix f -> a) -> Fix f -> a -{-# inline (<&>)#-} (<&>) :: Functor f => f a -> (a -> c) -> f c (<&>) = flip (<$>) +{-# inline (<&>)#-} -{-# inline (??)#-} (??) :: Functor f => f (a -> b) -> a -> f b fab ?? a = fmap ($ a) fab +{-# inline (??)#-} loeb :: Functor f => f (f a -> a) -> f a loeb x = go where go = fmap ($ go) x @@ -175,15 +175,14 @@ alterF f k m = ) $ f $ M.lookup k m -{-# inline bool #-} -- | From @Data.Bool ( bool )@. bool :: a -> a -> Bool -> a bool f t b = if b then t else f +{-# inline bool #-} -{-# inline list #-} -- | Analog for @bool@ or @maybe@, for list-like cons structures. list :: Foldable t @@ -193,76 +192,78 @@ list e f l = (f l) e (null l) +{-# inline list #-} -{-# inline free #-} -- | Lambda analog of @maybe@ or @either@ for Free monad. free :: (a -> b) -> (f (Free f a) -> b) -> Free f a -> b free fP fF fr = case fr of Pure a -> fP a Free fa -> fF fa +{-# inline free #-} + -{-# inline whenTrue #-} whenTrue :: (Monoid a) => a -> Bool -> a whenTrue = bool mempty +{-# inline whenTrue #-} -{-# inline whenFalse #-} whenFalse :: (Monoid a) => a -> Bool -> a whenFalse f = bool f mempty +{-# inline whenFalse #-} -{-# inline whenJust #-} whenJust :: (Monoid b) => (a -> b) -> Maybe a -> b whenJust = maybe mempty +{-# inline whenJust #-} -{-# inline whenNothing #-} whenNothing :: (Monoid b) => b -> Maybe a -> b whenNothing f = maybe f mempty +{-# inline whenNothing #-} -{-# inline whenRight #-} whenRight :: (Monoid c) => (b -> c) -> Either a b -> c whenRight = either mempty +{-# inline whenRight #-} -{-# inline whenLeft #-} whenLeft :: (Monoid c) => (a -> c) -> Either a b -> c whenLeft f = either f mempty +{-# inline whenLeft #-} -{-# inline whenFree #-} whenFree :: (Monoid b) => (f (Free f a) -> b) -> Free f a -> b whenFree = free mempty +{-# inline whenFree #-} -{-# inline whenPure #-} whenPure :: (Monoid b) => (a -> b) -> Free f a -> b whenPure f = free f mempty +{-# inline whenPure #-} --- From @base@ @Data.Foldable@ +-- | From @base@ @Data.Foldable@ traverse_ :: (Foldable t, Applicative f) => (a -> f b) -> t a -> f () traverse_ f = foldr c (pure ()) -- See Note [List fusion and continuations in 'c'] @@ -273,3 +274,12 @@ traverse_ f = foldr c (pure ()) for_ :: (Foldable t, Applicative f) => t a -> (a -> f b) -> f () for_ = flip traverse_ {-# inline for_ #-} + +-- | Apply a single function to both components of a pair. +-- +-- > both succ (1,2) == (2,3) +-- +-- Taken From package @extra@ +both :: (a -> b) -> (a, a) -> (b, b) +both f (x,y) = (f x, f y) +{-# inline both #-} From 2fea0dc330bd3b3da10c893847b21ffb0855dca1 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Fri, 12 Mar 2021 16:15:21 +0200 Subject: [PATCH 06/30] Parser: `Result` is just an euphemism to `Either` Implementation show that we so far not needed the custom type for it. Right and Left already embodies the whole semantic meaning, since Either is mostly used as Right for computations being successful, and Left for failure. So why bother everyone with remembering the custom constructors and what they are for if they are not needed, Either is already know to everybody. Current implementation by itself shows that `Result` custom type is being YAGNI, since replacing it with Either changes nothing. So it relates to the topic of https://github.com/haskell-nix/hnix/issues/879. If we would need ad-hock abilities to "our custom class" - the `TypeSynonymInstances` are there for us. I did the main work abstracting implementation from the type and constructors here, so if we would want in the future to change the type - we would just need to replace the `either` function with `result` function and that is all. But just using `either` is more consise. Type synonym left the signature information there. I'd even considered to remove `Result` all togather, since the more I talk about it the more it becomes clear that its use is just what Haskellers use `Either` for. --- main/Main.hs | 16 +++++---- main/Repl.hs | 26 ++++++++------- src/Nix.hs | 7 ++-- src/Nix/Builtins.hs | 2 +- src/Nix/Effects.hs | 14 ++++---- src/Nix/Effects/Basic.hs | 8 +++-- src/Nix/Parser.hs | 14 ++++---- src/Nix/Reduce.hs | 32 ++++++++++-------- src/Nix/TH.hs | 20 ++++++++---- tests/EvalTests.hs | 44 +++++++++++++++---------- tests/Main.hs | 11 ++++--- tests/NixLanguageTests.hs | 34 +++++++++++-------- tests/ParserTests.hs | 69 ++++++++++++++++++++++++--------------- tests/PrettyParseTests.hs | 51 +++++++++++++++-------------- tests/ReduceExprTests.hs | 6 ++-- tests/TestCommon.hs | 45 ++++++++++++++----------- 16 files changed, 233 insertions(+), 166 deletions(-) diff --git a/main/Main.hs b/main/Main.hs index 33b9dbb47..eeb4f4361 100644 --- a/main/Main.hs +++ b/main/Main.hs @@ -90,13 +90,15 @@ main = do eres <- parseNixFileLoc path handleResult opts (pure path) eres - handleResult opts mpath = \case - Failure err -> - bool - errorWithoutStackTrace - (liftIO . hPutStrLn stderr) - (ignoreErrors opts) - $ "Parse failed: " <> show err + handleResult opts mpath = + either + (\ err -> + bool + errorWithoutStackTrace + (liftIO . hPutStrLn stderr) + (ignoreErrors opts) + $ "Parse failed: " <> show err + ) (\ expr -> do diff --git a/main/Repl.hs b/main/Repl.hs index 2bebe80c0..6c4d5d7b8 100644 --- a/main/Repl.hs +++ b/main/Repl.hs @@ -182,9 +182,11 @@ initState mIni = do } where evalText :: (MonadNix e t f m) => Text -> m (NValue t f m) - evalText expr = case parseNixTextLoc expr of - Failure e -> error $ "Impossible happened: Unable to parse expression - '" <> Text.unpack expr <> "' error was " <> show e - Success e -> do evalExprLoc e + evalText expr = + either + (\ e -> error $ "Impossible happened: Unable to parse expression - '" <> Text.unpack expr <> "' error was " <> show e) + (\ e -> do evalExprLoc e) + (parseNixTextLoc expr) type Repl e t f m = HaskelineT (StateT (IState t f m) m) @@ -205,10 +207,10 @@ exec update source = do -- Parser ( returns AST as `NExprLoc` ) case parseExprOrBinding source of - (Failure err, _) -> do + (Left err, _) -> do liftIO $ print err pure Nothing - (Success expr, isBinding) -> do + (Right expr, isBinding) -> do -- Type Inference ( returns Typing Environment ) -- @@ -245,12 +247,14 @@ exec update source = do -- This allows us to handle assignments like @a = 42@ -- which get turned into @{ a = 42; }@ parseExprOrBinding i = - case parseNixTextLoc i of - Success expr -> (Success expr, False) - Failure e -> - case parseNixTextLoc $ toAttrSet i of - Failure _ -> (Failure e, False) -- return the first parsing failure - Success e' -> (Success e', True) + either + (\ e -> + either + (const (Left e, False)) -- return the first parsing failure + (\ e' -> (pure e', True)) + (parseNixTextLoc $ toAttrSet i)) + (\ expr -> (pure expr, False)) + (parseNixTextLoc i) toAttrSet i = "{" <> i <> bool ";" mempty (Text.isSuffixOf ";" i) <> "}" diff --git a/src/Nix.hs b/src/Nix.hs index 1e6885846..eef1c00ff 100644 --- a/src/Nix.hs +++ b/src/Nix.hs @@ -123,9 +123,10 @@ evaluateExpression mpath evaluator handler expr = do ) =<< demand f where parseArg s = - case parseNixText s of - Success x -> x - Failure err -> errorWithoutStackTrace (show err) + either + (errorWithoutStackTrace . show) + id + (parseNixText s) eval' = normalForm <=< nixEvalExpr mpath diff --git a/src/Nix/Builtins.hs b/src/Nix/Builtins.hs index 7969b0843..c2612dbe1 100644 --- a/src/Nix/Builtins.hs +++ b/src/Nix/Builtins.hs @@ -326,7 +326,7 @@ derivation => m (NValue t f m) derivation = foldFix Eval.eval $$(do -- This is compiled in so that we only parse it once at compile-time. - let Success expr = parseNixText [text| + let Right expr = parseNixText [text| drvAttrs @ { outputs ? [ "out" ], ... }: let diff --git a/src/Nix/Effects.hs b/src/Nix/Effects.hs index 7973eea59..4245fea3d 100644 --- a/src/Nix/Effects.hs +++ b/src/Nix/Effects.hs @@ -160,9 +160,10 @@ instance MonadExec IO where if T.null t then pure $ Left $ ErrorCall $ "exec has no output :" <> emsg else - case parseNixTextLoc t of - Failure err -> pure $ Left $ ErrorCall $ "Error parsing output of exec: " <> show err <> " " <> emsg - Success v -> pure $ Right v + either + (\ err -> pure $ Left $ ErrorCall $ "Error parsing output of exec: " <> show err <> " " <> emsg) + (pure . pure) + (parseNixTextLoc t) err -> pure $ Left $ ErrorCall $ "exec failed: " <> show err <> " " <> emsg deriving @@ -204,9 +205,10 @@ instance MonadInstantiate IO where pure $ case exitCode of ExitSuccess -> - case parseNixTextLoc (T.pack out) of - Failure e -> Left $ ErrorCall $ "Error parsing output of nix-instantiate: " <> show e - Success v -> Right v + either + (\ e -> Left $ ErrorCall $ "Error parsing output of nix-instantiate: " <> show e) + pure + (parseNixTextLoc (T.pack out)) status -> Left $ ErrorCall $ "nix-instantiate failed: " <> show status <> ": " <> err deriving diff --git a/src/Nix/Effects/Basic.hs b/src/Nix/Effects/Basic.hs index af7be153e..dc98a8d3b 100644 --- a/src/Nix/Effects/Basic.hs +++ b/src/Nix/Effects/Basic.hs @@ -257,12 +257,14 @@ defaultImportPath path = do maybe (do eres <- parseNixFileLoc path - case eres of - Failure err -> throwError $ ErrorCall . show $ fillSep ["Parse during import failed:", err] - Success expr -> + either + (\ err -> throwError $ ErrorCall . show $ fillSep ["Parse during import failed:", err]) + (\ expr -> do modify (first (M.insert path expr)) pure expr + ) + eres ) pure -- return expr (M.lookup path imports) diff --git a/src/Nix/Parser.hs b/src/Nix/Parser.hs index e6b00fa5e..947fcf4b9 100644 --- a/src/Nix/Parser.hs +++ b/src/Nix/Parser.hs @@ -19,7 +19,7 @@ module Nix.Parser , parseFromFileEx , Parser , parseFromText - , Result(..) + , Result , reservedNames , OperatorInfo(..) , NSpecialOp(..) @@ -566,8 +566,8 @@ reservedNames = type Parser = ParsecT Void Text (State SourcePos) --- This is just a @Either (Doc Void) a@ -data Result a = Success a | Failure (Doc Void) deriving (Show, Functor) +type Result a = Either (Doc Void) a + parseFromFileEx :: MonadFile m => Parser a -> FilePath -> m (Result a) parseFromFileEx p path = @@ -576,16 +576,16 @@ parseFromFileEx p path = pure $ either - (Failure . pretty . errorBundlePretty) - Success + (Left . pretty . errorBundlePretty) + Right $ (`evalState` initialPos path) $ runParserT p path txt parseFromText :: Parser a -> Text -> Result a parseFromText p txt = let file = "" in either - (Failure . pretty . errorBundlePretty) - Success + (Left . pretty . errorBundlePretty) + Right $ (`evalState` initialPos file) $ (`runParserT` file) p txt {- Parser.Operators -} diff --git a/src/Nix/Reduce.hs b/src/Nix/Reduce.hs index 6574c49fa..9c2da8b05 100644 --- a/src/Nix/Reduce.hs +++ b/src/Nix/Reduce.hs @@ -94,29 +94,35 @@ staticImport pann path = do (maybe path (\p -> takeDirectory p path) mfile) imports <- gets fst - case M.lookup path' imports of - Just expr -> pure expr - Nothing -> go path' + maybe + (go path') + pure + (M.lookup path' imports) where go path = do liftIO $ putStrLn $ "Importing file " <> path eres <- liftIO $ parseNixFileLoc path - case eres of - Failure err -> error $ "Parse failed: " <> show err - Success x -> do + either + (\ err -> error $ "Parse failed: " <> show err) + (\ x -> do let pos = SourcePos "Reduce.hs" (mkPos 1) (mkPos 1) span = SrcSpan pos pos - cur = NamedVar (StaticKey "__cur_file" :| mempty) - (Fix (NLiteralPath_ pann path)) - pos + cur = + NamedVar + (StaticKey "__cur_file" :| mempty) + (Fix (NLiteralPath_ pann path)) + pos x' = Fix (NLet_ span [cur] x) modify (first (M.insert path x')) - local (const (pure path, emptyScopes @m @NExprLoc)) $ do - x'' <- foldFix reduce x' - modify (first (M.insert path x'')) - pure x'' + local (const (pure path, emptyScopes @m @NExprLoc)) $ + do + x'' <- foldFix reduce x' + modify (first (M.insert path x'')) + pure x'' + ) + eres -- gatherNames :: NExprLoc -> HashSet VarName -- gatherNames = foldFix $ \case diff --git a/src/Nix/TH.hs b/src/Nix/TH.hs index b1a7c93d3..ef8e38254 100644 --- a/src/Nix/TH.hs +++ b/src/Nix/TH.hs @@ -25,9 +25,11 @@ import Nix.Parser quoteExprExp :: String -> ExpQ quoteExprExp s = do - expr <- case parseNixText (Text.pack s) of - Failure err -> fail $ show err - Success e -> pure e + expr <- + either + (fail . show) + pure + (parseNixText (Text.pack s)) dataToExpQ (const Nothing `extQ` metaExp (freeVars expr) `extQ` (pure . liftText)) expr @@ -37,10 +39,14 @@ quoteExprExp s = do quoteExprPat :: String -> PatQ quoteExprPat s = do - expr <- case parseNixText (Text.pack s) of - Failure err -> fail $ show err - Success e -> pure e - dataToPatQ (const Nothing `extQ` metaPat (freeVars expr)) expr + expr <- + either + (fail . show) + pure + (parseNixText (Text.pack s)) + dataToPatQ + (const Nothing `extQ` metaPat (freeVars expr)) + expr freeVars :: NExpr -> Set VarName freeVars e = case unFix e of diff --git a/tests/EvalTests.hs b/tests/EvalTests.hs index e9075b72d..7122a0cdf 100644 --- a/tests/EvalTests.hs +++ b/tests/EvalTests.hs @@ -23,6 +23,7 @@ import Nix import Nix.Standard import Nix.TH import Nix.Value.Equal +import Nix.Utils import qualified System.Directory as D import System.Environment import System.FilePath @@ -466,10 +467,10 @@ constantEqual expected actual = do assertBool message eq constantEqualText' :: Text -> Text -> Assertion -constantEqualText' expected actual = do - let Success expected' = parseNixTextLoc expected - Success actual' = parseNixTextLoc actual - constantEqual expected' actual' +constantEqualText' expected actual = + do + let (Right expected', Right actual') = both parseNixTextLoc (expected, actual) + constantEqual expected' actual' constantEqualText :: Text -> Text -> Assertion constantEqualText expected actual = do @@ -479,23 +480,30 @@ constantEqualText expected actual = do assertEvalMatchesNix actual assertNixEvalThrows :: Text -> Assertion -assertNixEvalThrows a = do - let Success a' = parseNixTextLoc a - time <- getCurrentTime - let opts = defaultOptions time - errored <- catch - (False <$ runWithBasicEffectsIO opts - (normalForm =<< nixEvalExprLoc mempty a')) - (\(_ :: NixException) -> pure True) - unless errored $ - assertFailure "Did not catch nix exception" +assertNixEvalThrows a = + do + time <- getCurrentTime + let + opts = defaultOptions time + Right a' = parseNixTextLoc a + errored <- + catch + (False <$ + runWithBasicEffectsIO + opts + (normalForm =<< nixEvalExprLoc mempty a') + ) + (\(_ :: NixException) -> pure True) + unless errored $ assertFailure "Did not catch nix exception" freeVarsEqual :: Text -> [VarName] -> Assertion -freeVarsEqual a xs = do - let Success a' = parseNixText a +freeVarsEqual a xs = + do + let + Right a' = parseNixText a xs' = S.fromList xs - free = freeVars a' - assertEqual "" xs' free + free' = freeVars a' + assertEqual "" xs' free' maskedFiles :: [FilePath] maskedFiles = diff --git a/tests/Main.hs b/tests/Main.hs index fd643a2a9..e19111891 100644 --- a/tests/Main.hs +++ b/tests/Main.hs @@ -82,10 +82,13 @@ ensureNixpkgsCanParse = getString k m = let Fix (NStr (DoubleQuoted [Plain str])) = getExpr k m in str - consider path action k = action >>= \case - Failure err -> errorWithoutStackTrace $ - "Parsing " <> path <> " failed: " <> show err - Success expr -> k expr + consider path action k = + do + x <- action + either + (\ err -> errorWithoutStackTrace $ "Parsing " <> path <> " failed: " <> show err) + k + x main :: IO () main = do diff --git a/tests/NixLanguageTests.hs b/tests/NixLanguageTests.hs index 952fcab74..7df857e03 100644 --- a/tests/NixLanguageTests.hs +++ b/tests/NixLanguageTests.hs @@ -104,26 +104,32 @@ genTests = do _ -> error $ "Unexpected: " <> show kind assertParse :: Options -> FilePath -> Assertion -assertParse _opts file = parseNixFileLoc file >>= \case - Success _expr -> pure () -- pure $! runST $ void $ lint opts expr - Failure err -> - assertFailure $ "Failed to parse " <> file <> ":\n" <> show err +assertParse _opts file = + do + x <- parseNixFileLoc file + either + (\ err -> assertFailure $ "Failed to parse " <> file <> ":\n" <> show err) + (const $ pure ()) -- pure $! runST $ void $ lint opts expr + x assertParseFail :: Options -> FilePath -> Assertion assertParseFail opts file = do eres <- parseNixFileLoc file catch - (case eres of - Success expr -> do - _ <- pure $! runST $ void $ lint opts expr - assertFailure - $ "Unexpected success parsing `" - <> file - <> ":\nParsed value: " - <> show expr - Failure _ -> pure () + (either + (const $ pure ()) + (\ expr -> + do + _ <- pure $! runST $ void $ lint opts expr + assertFailure $ + "Unexpected success parsing `" + <> file + <> ":\nParsed value: " + <> show expr + ) + eres ) - $ \(_ :: SomeException) -> pure () + $ \(_ :: SomeException) -> pure () assertLangOk :: Options -> FilePath -> Assertion assertLangOk opts file = do diff --git a/tests/ParserTests.hs b/tests/ParserTests.hs index 692831cad..274970399 100644 --- a/tests/ParserTests.hs +++ b/tests/ParserTests.hs @@ -325,10 +325,11 @@ case_operators = do assertParseFail "+ 3" assertParseFail "foo +" -case_comments = do - Success expected <- parseNixFile "data/let.nix" - assertParseFile "let-comments-multiline.nix" expected - assertParseFile "let-comments.nix" expected +case_comments = + do + Right expected <- parseNixFile "data/let.nix" + assertParseFile "let-comments-multiline.nix" expected + assertParseFile "let-comments.nix" expected case_select_or_precedence = assertParsePrint [text|let @@ -366,39 +367,53 @@ tests = $testGroupGenerator --------------------------------------------------------------------------------- assertParseText :: Text -> NExpr -> Assertion -assertParseText str expected = case parseNixText str of - Success actual -> - assertEqual ("When parsing " <> unpack str) - (stripPositionInfo expected) (stripPositionInfo actual) - Failure err -> +assertParseText str expected = + either + (\ err -> assertFailure $ "Unexpected error parsing `" <> unpack str <> "':\n" <> show err + ) + (assertEqual + ("When parsing " <> unpack str) + (stripPositionInfo expected) + . stripPositionInfo + ) + (parseNixText str) assertParseFile :: FilePath -> NExpr -> Assertion -assertParseFile file expected = do +assertParseFile file expected = + do res <- parseNixFile $ "data/" <> file - case res of - Success actual -> assertEqual ("Parsing data file " <> file) - (stripPositionInfo expected) (stripPositionInfo actual) - Failure err -> - assertFailure $ "Unexpected error parsing data file `" - <> file <> "':\n" <> show err + either + (\ err -> + assertFailure $ "Unexpected error parsing data file `" <> file <> "':\n" <> show err + ) + (assertEqual + ("Parsing data file " <> file) + (stripPositionInfo expected) + . stripPositionInfo + ) + res assertParseFail :: Text -> Assertion -assertParseFail str = case parseNixText str of - Failure _ -> pure () - Success r -> - assertFailure $ "Unexpected success parsing `" - <> unpack str <> ":\nParsed value: " <> show r +assertParseFail str = + either + (const $ pure ()) + (\ r -> + assertFailure $ "Unexpected success parsing `" <> unpack str <> ":\nParsed value: " <> show r + ) + (parseNixText str) -- assertRoundTrip :: Text -> Assertion -- assertRoundTrip src = assertParsePrint src src assertParsePrint :: Text -> Text -> Assertion assertParsePrint src expect = - let Success expr = parseNixTextLoc src - result = renderStrict - . layoutPretty (LayoutOptions $ AvailablePerLine 80 0.4) - . prettyNix - . stripAnnotation - $ expr + let + Right expr = parseNixTextLoc src + result = + renderStrict + . layoutPretty (LayoutOptions $ AvailablePerLine 80 0.4) + . prettyNix + . stripAnnotation $ + expr in assertEqual "" expect result diff --git a/tests/PrettyParseTests.hs b/tests/PrettyParseTests.hs index 5707802b4..4bc30681f 100644 --- a/tests/PrettyParseTests.hs +++ b/tests/PrettyParseTests.hs @@ -185,35 +185,38 @@ prop_prettyparse :: Monad m => NExpr -> PropertyT m () prop_prettyparse p = do let prog = show (prettyNix p) case parse (pack prog) of - Failure s -> do + Left s -> do footnote $ show $ vsep [fillSep ["Parse failed:", pretty (show s)], indent 2 (prettyNix p)] discard - Success v + Right v | equivUpToNormalization p v -> success - | otherwise -> do - let pp = normalise prog + | otherwise -> + do + let + pp = normalise prog pv = normalise (show (prettyNix v)) - footnote - $ show - $ vsep - $ [ "----------------------------------------" - , vsep ["Expr before:", indent 2 (pretty (PS.ppShow p))] - , "----------------------------------------" - , vsep ["Expr after:", indent 2 (pretty (PS.ppShow v))] - , "----------------------------------------" - , vsep ["Pretty before:", indent 2 (pretty prog)] - , "----------------------------------------" - , vsep ["Pretty after:", indent 2 (prettyNix v)] - , "----------------------------------------" - , vsep ["Normalised before:", indent 2 (pretty pp)] - , "----------------------------------------" - , vsep ["Normalised after:", indent 2 (pretty pv)] - , "========================================" - , vsep ["Normalised diff:", pretty (ppDiff (ldiff pp pv))] - , "========================================" - ] - assert (pp == pv) + + footnote $ + show $ + vsep + [ "----------------------------------------" + , vsep ["Expr before:", indent 2 (pretty (PS.ppShow p))] + , "----------------------------------------" + , vsep ["Expr after:", indent 2 (pretty (PS.ppShow v))] + , "----------------------------------------" + , vsep ["Pretty before:", indent 2 (pretty prog)] + , "----------------------------------------" + , vsep ["Pretty after:", indent 2 (prettyNix v)] + , "----------------------------------------" + , vsep ["Normalised before:", indent 2 (pretty pp)] + , "----------------------------------------" + , vsep ["Normalised after:", indent 2 (pretty pv)] + , "========================================" + , vsep ["Normalised diff:", pretty (ppDiff (ldiff pp pv))] + , "========================================" + ] + assert (pp == pv) where parse = parseNixText diff --git a/tests/ReduceExprTests.hs b/tests/ReduceExprTests.hs index c3490252f..6b15287ee 100644 --- a/tests/ReduceExprTests.hs +++ b/tests/ReduceExprTests.hs @@ -26,8 +26,10 @@ tests = testGroup ] assertSucc :: Result a -> IO a -assertSucc (Success a) = pure a -assertSucc (Failure d) = assertFailure $ show d +assertSucc = + either + (assertFailure . show) + pure cmpReduceResult :: Result NExprLoc -> NExpr -> Assertion cmpReduceResult r e = do diff --git a/tests/TestCommon.hs b/tests/TestCommon.hs index 658b1cd19..c0377ac37 100644 --- a/tests/TestCommon.hs +++ b/tests/TestCommon.hs @@ -22,27 +22,34 @@ import System.Process import Test.Tasty.HUnit hnixEvalFile :: Options -> FilePath -> IO (StdValue (StandardT (StdIdT IO))) -hnixEvalFile opts file = do - parseResult <- parseNixFileLoc file - case parseResult of - Failure err -> error $ "Parsing failed for file `" <> file <> "`.\n" <> show err - Success expr -> do - setEnv "TEST_VAR" "foo" - runWithBasicEffects opts - $ catch (evaluateExpression (pure file) nixEvalExprLoc normalForm expr) - $ \case - NixException frames -> - errorWithoutStackTrace - . show - =<< renderFrames @(StdValue (StandardT (StdIdT IO))) - @(StdThunk (StandardT (StdIdT IO))) - frames +hnixEvalFile opts file = + do + parseResult <- parseNixFileLoc file + either + (\ err -> error $ "Parsing failed for file `" <> file <> "`.\n" <> show err) + (\ expr -> + do + setEnv "TEST_VAR" "foo" + runWithBasicEffects opts $ + catch (evaluateExpression (pure file) nixEvalExprLoc normalForm expr) $ + \case + NixException frames -> + errorWithoutStackTrace . show + =<< renderFrames + @(StdValue (StandardT (StdIdT IO))) + @(StdThunk (StandardT (StdIdT IO))) + frames + ) + parseResult hnixEvalText :: Options -> Text -> IO (StdValue (StandardT (StdIdT IO))) -hnixEvalText opts src = case parseNixText src of - Failure err -> error $ "Parsing failed for expression `" <> unpack src <> "`.\n" <> show err - Success expr -> - runWithBasicEffects opts $ normalForm =<< nixEvalExpr mempty expr +hnixEvalText opts src = + either + (\ err -> error $ "Parsing failed for expression `" <> unpack src <> "`.\n" <> show err) + (\ expr -> + runWithBasicEffects opts $ normalForm =<< nixEvalExpr mempty expr + ) + (parseNixText src) nixEvalString :: String -> IO String nixEvalString expr = do From 1940e9146f3e8bddee0e7a22645e2b0e5dc161aa Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Fri, 12 Mar 2021 16:46:30 +0200 Subject: [PATCH 07/30] {Pretty, Reduce, PrettyParseTests}: m refactors --- src/Nix/Pretty.hs | 2 +- src/Nix/Reduce.hs | 7 ++++--- tests/PrettyParseTests.hs | 35 +++++++++++++++++++---------------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/Nix/Pretty.hs b/src/Nix/Pretty.hs index c4b8b2914..44e0a8e1c 100644 --- a/src/Nix/Pretty.hs +++ b/src/Nix/Pretty.hs @@ -14,7 +14,7 @@ module Nix.Pretty where import Control.Applicative ( (<|>) ) -import Control.Monad.Free +import Control.Monad.Free ( Free(Free) ) import Data.Fix ( Fix(..) , foldFix ) import Data.HashMap.Lazy ( toList ) diff --git a/src/Nix/Reduce.hs b/src/Nix/Reduce.hs index 9c2da8b05..5cf41ddf9 100644 --- a/src/Nix/Reduce.hs +++ b/src/Nix/Reduce.hs @@ -235,9 +235,10 @@ reduce e@(NSet_ ann NNonRecursive binds) = ) binds - if usesInherit - then clearScopes @NExprLoc $ Fix . NSet_ ann NNonRecursive <$> traverse sequence binds - else Fix <$> sequence e + bool + (Fix <$> sequence e) + (clearScopes @NExprLoc $ Fix . NSet_ ann NNonRecursive <$> traverse sequence binds) + usesInherit -- Encountering a 'rec set' construction eliminates any hope of inlining -- definitions. diff --git a/tests/PrettyParseTests.hs b/tests/PrettyParseTests.hs index 4bc30681f..08095841d 100644 --- a/tests/PrettyParseTests.hs +++ b/tests/PrettyParseTests.hs @@ -30,6 +30,9 @@ import Test.Tasty import Test.Tasty.Hedgehog import Text.Megaparsec ( Pos ) import qualified Text.Show.Pretty as PS +import Options.Applicative ( Applicative(liftA2) + , liftA3 + ) asciiString :: MonadGen m => m String asciiString = Gen.list (Range.linear 1 15) Gen.lower @@ -112,23 +115,23 @@ genExpr = Gen.sized $ \(Size n) -> Fix <$> if n < 2 , (1, Gen.resize (Size (n `div` 2)) genAssert) ] where - genConstant = NConstant <$> genAtom - genStr = NStr <$> genString - genSym = NSym <$> asciiText - genList = NList <$> fairList genExpr - genSet = NSet NNonRecursive <$> fairList genBinding - genRecSet = NSet NRecursive <$> fairList genBinding + genConstant = NConstant <$> genAtom + genStr = NStr <$> genString + genSym = NSym <$> asciiText + genList = NList <$> fairList genExpr + genSet = NSet NNonRecursive <$> fairList genBinding + genRecSet = NSet NRecursive <$> fairList genBinding genLiteralPath = NLiteralPath . ("./" <>) <$> asciiString - genEnvPath = NEnvPath <$> asciiString - genUnary = NUnary <$> Gen.enumBounded <*> genExpr - genBinary = NBinary <$> Gen.enumBounded <*> genExpr <*> genExpr - genSelect = NSelect <$> genExpr <*> genAttrPath <*> Gen.maybe genExpr - genHasAttr = NHasAttr <$> genExpr <*> genAttrPath - genAbs = NAbs <$> genParams <*> genExpr - genLet = NLet <$> fairList genBinding <*> genExpr - genIf = NIf <$> genExpr <*> genExpr <*> genExpr - genWith = NWith <$> genExpr <*> genExpr - genAssert = NAssert <$> genExpr <*> genExpr + genEnvPath = NEnvPath <$> asciiString + genUnary = liftA2 NUnary Gen.enumBounded genExpr + genBinary = liftA3 NBinary Gen.enumBounded genExpr genExpr + genSelect = liftA3 NSelect genExpr genAttrPath (Gen.maybe genExpr) + genHasAttr = liftA2 NHasAttr genExpr genAttrPath + genAbs = liftA2 NAbs genParams genExpr + genLet = liftA2 NLet (fairList genBinding) genExpr + genIf = liftA3 NIf genExpr genExpr genExpr + genWith = liftA2 NWith genExpr genExpr + genAssert = liftA2 NAssert genExpr genExpr -- | Useful when there are recursive positions at each element of the list as -- it divides the size by the length of the generated list. From 1f9b2b17367adf06981044bf999b3c7360301188 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Fri, 12 Mar 2021 16:47:36 +0200 Subject: [PATCH 08/30] Reduce: m refactor --- src/Nix/Reduce.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Nix/Reduce.hs b/src/Nix/Reduce.hs index 5cf41ddf9..b543520cc 100644 --- a/src/Nix/Reduce.hs +++ b/src/Nix/Reduce.hs @@ -150,9 +150,8 @@ reduce -- | Reduce the variable to its value if defined. -- Leave it as it is otherwise. -reduce (NSym_ ann var) = lookupVar var <&> \case - Nothing -> Fix (NSym_ ann var) - Just v -> v +reduce (NSym_ ann var) = + fromMaybe (Fix (NSym_ ann var)) <$> lookupVar var -- | Reduce binary and integer negation. reduce (NUnary_ uann op arg) = arg >>= \x -> case (op, x) of From 7167d3076cc75e1aa5a09e2fbb481f8dc17b9b32 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Fri, 12 Mar 2021 16:48:06 +0200 Subject: [PATCH 09/30] Thunk.Basic: forceEff: refactor; enabling `ApplicativeDo` Notice, here in `forceEff` I moved the thunk locking closer to where it is needed, so function does a couple of preparation computations before locking the thunk to operate on it. Also notice that the `force` add `forceEff` look like 1 function, and as `forceEff` also probably needs to check for exception when doing an action - they are literally the same function. --- src/Nix/Thunk/Basic.hs | 77 +++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/src/Nix/Thunk/Basic.hs b/src/Nix/Thunk/Basic.hs index ad66333db..1927cd137 100644 --- a/src/Nix/Thunk/Basic.hs +++ b/src/Nix/Thunk/Basic.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} @@ -7,6 +8,7 @@ {-# LANGUAGE TupleSections #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE InstanceSigs #-} +{-# LANGUAGE ApplicativeDo #-} @@ -30,7 +32,7 @@ data Deferred m v = Deferred (m v) | Computed v -- | The type of very basic thunks data NThunkF m v - = Thunk (ThunkId m) (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 Thunk x _ _ == Thunk y _ _ = x == y @@ -51,24 +53,24 @@ instance (MonadBasicThunk m, MonadCatch m) do freshThunkId <- freshId Thunk freshThunkId <$> newVar False <*> newVar (Deferred action) - queryM :: m v -> NThunkF m v -> m v queryM n (Thunk _ active ref) = do - thunkIsAvaliable <- not <$> atomicModifyVar active (True, ) + seizeThunk <- atomicModifyVar active (True, ) bool n go - thunkIsAvaliable - where - go = do - eres <- readVar ref - res <- - case eres of - Computed v -> pure v - Deferred _mv -> n - _ <- atomicModifyVar active (False, ) - pure res + (not seizeThunk) + where + go = do + eres <- readVar ref + res <- + case eres of + Computed v -> pure v + Deferred _mv -> n + _releaseThunk <- atomicModifyVar active (False, ) + pure res + force :: NThunkF m v -> m v force (Thunk n active ref) = @@ -78,46 +80,51 @@ instance (MonadBasicThunk m, MonadCatch m) Computed v -> pure v Deferred action -> do - nowActive <- atomicModifyVar active (True, ) + seizeThunk <- atomicModifyVar active (True, ) bool + (throwM $ ThunkLoop $ show n) (do v <- catch action $ \(e :: SomeException) -> do _ <- atomicModifyVar active (False, ) throwM e writeVar ref (Computed v) - _ <- atomicModifyVar active (False, ) + _freeThunk <- atomicModifyVar active (False, ) pure v ) - (throwM $ ThunkLoop $ show n) - nowActive + (not seizeThunk) forceEff :: NThunkF m v -> m v forceEff (Thunk _ active ref) = do - nowActive <- atomicModifyVar active (True, ) - bool - (do - eres <- readVar ref - case eres of - Computed v -> pure v - Deferred action -> - do + eres <- readVar ref + case eres of + Computed v -> pure v + Deferred action -> + do + seizeThunk <- atomicModifyVar active (True, ) + bool + (pure $ error "Loop detected") + (do v <- action writeVar ref (Computed v) - _ <- atomicModifyVar active (False, ) + _freeThunk <- atomicModifyVar active (False, ) pure v - ) - (pure $ error "Loop detected") - nowActive + ) + (not seizeThunk) further :: NThunkF m v -> m (NThunkF m v) - further t@(Thunk _ _ ref) = do - _ <- atomicModifyVar ref $ - \x -> case x of - Computed _ -> (x, x) - Deferred d -> (Deferred d, x) - pure t + further t@(Thunk _ _ ref) = + do + _ <- + atomicModifyVar + ref + (\ x -> + case x of + Computed _ -> (x, x) + _deferred -> (_deferred, x) + ) + pure t -- * Kleisli functor HOFs From fd03e805db2132829035900b0dcacdc4d214740f Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Fri, 12 Mar 2021 17:00:10 +0200 Subject: [PATCH 10/30] Thunk.Basic: queryM: make it non-blocking So far `queryM` is not used. And locking the thunk computation on static-copying structures to check if variable is computed is weird. Lets allow reading from static structure until we would need locking during reads. --- src/Nix/Thunk/Basic.hs | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/Nix/Thunk/Basic.hs b/src/Nix/Thunk/Basic.hs index 1927cd137..347657ac5 100644 --- a/src/Nix/Thunk/Basic.hs +++ b/src/Nix/Thunk/Basic.hs @@ -53,24 +53,14 @@ instance (MonadBasicThunk m, MonadCatch m) do freshThunkId <- freshId Thunk freshThunkId <$> newVar False <*> newVar (Deferred action) + queryM :: m v -> NThunkF m v -> m v - queryM n (Thunk _ active ref) = + queryM n (Thunk _ _ ref) = do - seizeThunk <- atomicModifyVar active (True, ) - bool - n - go - (not seizeThunk) - where - go = do - eres <- readVar ref - res <- - case eres of - Computed v -> pure v - Deferred _mv -> n - _releaseThunk <- atomicModifyVar active (False, ) - pure res - + (\case + Computed v -> pure v + _deferred -> n + ) =<< readVar ref force :: NThunkF m v -> m v force (Thunk n active ref) = From 68c1a30f2030e5210b2aa590d9ea488f825f7967 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Mon, 15 Mar 2021 20:27:22 +0200 Subject: [PATCH 11/30] treewide: lazify handling: in place replacable (error -> fail) This is was was possible to replace right away in-place. Also added `MonadFail` requirement to `MonadDataErrorContext t f m`, as it was obvious addition to allow to demote some `errors` into `fail`. Reference: https://www.haskellforall.com/2019/12/prefer-to-use-fail-for-io-exceptions.html --- main/Main.hs | 4 ++-- main/Repl.hs | 2 +- src/Nix/Builtins.hs | 6 +++--- src/Nix/Cache.hs | 8 ++++---- src/Nix/Cited/Basic.hs | 4 +--- src/Nix/Effects/Basic.hs | 2 +- src/Nix/Effects/Derivation.hs | 26 +++++++++++++------------- src/Nix/Expr/Strings.hs | 2 +- src/Nix/Expr/Types.hs | 2 +- src/Nix/Frames.hs | 2 +- src/Nix/Lint.hs | 6 +++--- src/Nix/Normal.hs | 2 +- src/Nix/Options/Parser.hs | 6 +++--- src/Nix/Parser.hs | 7 +++---- src/Nix/Reduce.hs | 8 ++++---- src/Nix/Render.hs | 2 +- src/Nix/Render/Frame.hs | 2 +- src/Nix/Value.hs | 7 ++++--- tests/Main.hs | 2 +- tests/NixLanguageTests.hs | 4 ++-- tests/ParserTests.hs | 4 ++-- tests/TestCommon.hs | 4 ++-- 22 files changed, 55 insertions(+), 57 deletions(-) diff --git a/main/Main.hs b/main/Main.hs index eeb4f4361..e43fdce88 100644 --- a/main/Main.hs +++ b/main/Main.hs @@ -143,8 +143,8 @@ main = do && null (argstr opts) ) -> evaluateExpression mpath Nix.nixEvalExprLoc printer expr | otherwise -> processResult printer =<< Nix.nixEvalExprLoc mpath expr - | xml opts = error "Rendering expression trees to XML is not yet implemented" - | json opts = error "Rendering expression trees to JSON is not implemented" + | xml opts = fail "Rendering expression trees to XML is not yet implemented" + | json opts = fail "Rendering expression trees to JSON is not implemented" | verbose opts >= DebugInfo = liftIO $ putStr $ PS.ppShow $ stripAnnotation expr | cache opts , Just path <- mpath = liftIO $ writeCache (addExtension (dropExtension path) "nixc") expr diff --git a/main/Repl.hs b/main/Repl.hs index 6c4d5d7b8..59c174e79 100644 --- a/main/Repl.hs +++ b/main/Repl.hs @@ -184,7 +184,7 @@ initState mIni = do evalText :: (MonadNix e t f m) => Text -> m (NValue t f m) evalText expr = either - (\ e -> error $ "Impossible happened: Unable to parse expression - '" <> Text.unpack expr <> "' error was " <> show e) + (\ e -> fail $ "Impossible happened: Unable to parse expression - '" <> Text.unpack expr <> "' fail was " <> show e) (\ e -> do evalExprLoc e) (parseNixTextLoc expr) diff --git a/src/Nix/Builtins.hs b/src/Nix/Builtins.hs index c2612dbe1..b46a0e491 100644 --- a/src/Nix/Builtins.hs +++ b/src/Nix/Builtins.hs @@ -777,7 +777,7 @@ splitMatches -> [NValue t f m] splitMatches _ [] haystack = [thunkStr haystack] splitMatches _ ([] : _) _ = - error "Error in splitMatches: this should never happen!" + fail "Fail in splitMatches: this should never happen!" splitMatches numDropped (((_, (start, len)) : captures) : mts) haystack = thunkStr before : caps : splitMatches (numDropped + relStart + len) mts @@ -1494,7 +1494,7 @@ placeHolder = fromValue >=> fromStringNoContext >=> \t -> do $ case Base16.decode (text h) of -- The result coming out of hashString is base16 encoded #if MIN_VERSION_base16_bytestring(1,0,0) Right d -> d - Left e -> error $ "Couldn't Base16 decode the text: '" <> show (text h) <> "'.\nThe Left error content: '" <> e <> "'." + Left e -> error $ "Couldn't Base16 decode the text: '" <> show (text h) <> "'.\nThe Left fail content: '" <> e <> "'." #else (d, "") -> d (_, e) -> error $ "Couldn't Base16 decode the text: '" <> show (text h) <> "'.\nUndecodable remainder: '" <> show e <> "'." @@ -1668,7 +1668,7 @@ trace_ msg action = traceEffect @t @f @m . Text.unpack . stringIgnoreContext =<< fromValue msg pure action --- Please, can function remember error context +-- Please, can function remember fail context addErrorContext :: forall e t f m . MonadNix e t f m diff --git a/src/Nix/Cache.hs b/src/Nix/Cache.hs index 1ca44b234..81e007efd 100644 --- a/src/Nix/Cache.hs +++ b/src/Nix/Cache.hs @@ -23,16 +23,16 @@ readCache path = do #if USE_COMPACT eres <- C.unsafeReadCompact path case eres of - Left err -> error $ "Error reading cache file: " <> err + Left err -> fail $ "Error reading cache file: " <> err Right expr -> pure $ C.getCompact expr #else #ifdef MIN_VERSION_serialise eres <- S.deserialiseOrFail <$> BS.readFile path case eres of - Left err -> error $ "Error reading cache file: " <> show err + Left err -> fail $ "Error reading cache file: " <> show err Right expr -> pure expr #else - error "readCache not implemented for this platform" + fail "readCache not implemented for this platform" #endif #endif @@ -44,6 +44,6 @@ writeCache path expr = #ifdef MIN_VERSION_serialise BS.writeFile path (S.serialise expr) #else - error "writeCache not implemented for this platform" + fail "writeCache not implemented for this platform" #endif #endif diff --git a/src/Nix/Cited/Basic.hs b/src/Nix/Cited/Basic.hs index 91cafa1ac..d4b6d157a 100644 --- a/src/Nix/Cited/Basic.hs +++ b/src/Nix/Cited/Basic.hs @@ -150,11 +150,9 @@ displayProvenance => [Provenance m v] -> m a -> m a -displayProvenance ps f = +displayProvenance = list id (\ (Provenance scope e@(Compose (Ann s _)) : _) -> withFrame Info (ForcingExpr scope (wrapExprLoc s e)) ) - ps - f diff --git a/src/Nix/Effects/Basic.hs b/src/Nix/Effects/Basic.hs index dc98a8d3b..d354376c3 100644 --- a/src/Nix/Effects/Basic.hs +++ b/src/Nix/Effects/Basic.hs @@ -98,7 +98,7 @@ findEnvPathM name = do mres <- lookupVar "__nixPath" maybe - (error "impossible") + (fail "impossible") ( (\ nv -> do diff --git a/src/Nix/Effects/Derivation.hs b/src/Nix/Effects/Derivation.hs index bb54d773b..4fc6bf16a 100644 --- a/src/Nix/Effects/Derivation.hs +++ b/src/Nix/Effects/Derivation.hs @@ -140,8 +140,8 @@ unparseDrv Derivation{..} = Text.append "Derive" $ parens mFixed ) , -- inputDrvs - serializeList $ flip fmap (Map.toList $ snd inputs) (\(path, outs) -> - parens [s path, serializeList $ fmap s $ sort outs]) + serializeList $ (\(path, outs) -> + parens [s path, serializeList $ s <$> sort outs]) <$> Map.toList (snd inputs) , -- inputSrcs serializeList (fmap s $ Set.toList $ fst inputs) , s platform @@ -149,15 +149,14 @@ unparseDrv Derivation{..} = Text.append "Derive" $ parens , -- run script args serializeList $ fmap s args , -- env (key value pairs) - serializeList $ flip fmap (Map.toList env) (\(k, v) -> - parens [s k, s v]) + serializeList $ (\(k, v) -> parens [s k, s v]) <$> Map.toList env ] where parens :: [Text] -> Text parens ts = Text.concat ["(", Text.intercalate "," ts, ")"] serializeList :: [Text] -> Text serializeList ls = Text.concat ["[", Text.intercalate "," ls, "]"] - s = (Text.cons '\"') . (`Text.snoc` '\"') . Text.concatMap escape + s = Text.cons '\"' . (`Text.snoc` '\"') . Text.concatMap escape escape :: Char -> Text escape '\\' = "\\\\" escape '\"' = "\\\"" @@ -178,12 +177,12 @@ derivationParser :: Parsec () Text Derivation derivationParser = do _ <- "Derive(" fullOutputs <- serializeList $ - fmap (\[n, p, ht, h] -> (n, p, ht, h)) $ parens s + (\[n, p, ht, h] -> (n, p, ht, h)) <$> parens s _ <- "," inputDrvs <- fmap Map.fromList $ serializeList $ fmap (,) ("(" *> s <* ",") <*> (serializeList s <* ")") _ <- "," - inputSrcs <- fmap Set.fromList $ serializeList s + inputSrcs <- Set.fromList <$> serializeList s _ <- "," platform <- s _ <- "," @@ -191,7 +190,7 @@ derivationParser = do _ <- "," args <- serializeList s _ <- "," - env <- fmap Map.fromList $ serializeList $ fmap (\[a, b] -> (a, b)) $ parens s + env <- fmap Map.fromList $ serializeList $ (\[a, b] -> (a, b)) <$> parens s _ <- ")" eof @@ -213,7 +212,8 @@ derivationParser = do regular = noneOf ['\\', '"'] parens :: Parsec () Text a -> Parsec () Text [a] - parens p = (string "(") *> sepBy p (string ",") <* (string ")") + parens p = + (string "(") *> sepBy p (string ",") <* (string ")") serializeList p = (string "[") *> sepBy p (string ",") <* (string "]") parseFixed :: [(Text, Text, Text, Text)] -> (Maybe Store.SomeNamedDigest, HashMode) @@ -297,11 +297,11 @@ buildDerivationWithContext drvAttrs = do drvName <- getAttr "name" $ extractNixString >=> assertDrvStoreName withFrame' Info (ErrorCall $ "While evaluating derivation " <> show drvName) $ do - useJson <- getAttrOr "__structuredAttrs" False $ pure - ignoreNulls <- getAttrOr "__ignoreNulls" False $ pure + useJson <- getAttrOr "__structuredAttrs" False pure + ignoreNulls <- getAttrOr "__ignoreNulls" False pure args <- getAttrOr "args" mempty $ traverse (fromValue' >=> extractNixString) - builder <- getAttr "builder" $ extractNixString + builder <- getAttr "builder" extractNixString platform <- getAttr "system" $ extractNoCtx >=> assertNonNull mHash <- getAttrOr "outputHash" mempty $ extractNoCtx >=> (pure . pure) hashMode <- getAttrOr "outputHashMode" Flat $ extractNoCtx >=> parseHashMode @@ -311,7 +311,7 @@ buildDerivationWithContext drvAttrs = do maybe (pure Nothing) (\ hash -> do - when (outputs /= ["out"]) $ lift $ throwError $ ErrorCall $ "Multiple outputs are not supported for fixed-output derivations" + when (outputs /= ["out"]) $ lift $ throwError $ ErrorCall "Multiple outputs are not supported for fixed-output derivations" hashType <- getAttr "outputHashAlgo" extractNoCtx digest <- lift $ either (throwError . ErrorCall) pure $ Store.mkNamedDigest hashType hash pure $ pure digest) diff --git a/src/Nix/Expr/Strings.hs b/src/Nix/Expr/Strings.hs index 687936665..08b9f900a 100644 --- a/src/Nix/Expr/Strings.hs +++ b/src/Nix/Expr/Strings.hs @@ -98,7 +98,7 @@ stripIndent xs = dropSpaces 0 x = x dropSpaces n (Plain t : cs) = Plain (T.drop n t) : cs - dropSpaces _ _ = error "stripIndent: impossible" + dropSpaces _ _ = fail "stripIndent: impossible" cleanup (Nothing, Plain y) = T.all (== ' ') y cleanup (Just (Plain x), Plain y) | "\n" `T.isSuffixOf` x = T.all (== ' ') y diff --git a/src/Nix/Expr/Types.hs b/src/Nix/Expr/Types.hs index 0467801a2..b61254fb4 100644 --- a/src/Nix/Expr/Types.hs +++ b/src/Nix/Expr/Types.hs @@ -231,7 +231,7 @@ instance IsString (NString r) where -- In particular, those include: -- -- * The RHS of a @binding@ inside @let@: @let ${"a"} = 3; in ...@ --- produces a syntax error. +-- produces a syntax fail. -- * The attribute names of an 'inherit': @inherit ${"a"};@ is forbidden. -- -- Note: In Nix, a simple string without antiquotes such as @"foo"@ is diff --git a/src/Nix/Frames.hs b/src/Nix/Frames.hs index 2f701ab0c..b2c7fd56a 100644 --- a/src/Nix/Frames.hs +++ b/src/Nix/Frames.hs @@ -61,5 +61,5 @@ throwError :: forall s e m a . (Framed e m, Exception s, MonadThrow m) => s -> m a throwError err = do context <- asks (view hasLens) - traceM "Throwing error..." + traceM "Throwing fail..." throwM $ NixException (NixFrame Error (toException err) : context) diff --git a/src/Nix/Lint.hs b/src/Nix/Lint.hs index 3b8bc1b38..e98374a09 100644 --- a/src/Nix/Lint.hs +++ b/src/Nix/Lint.hs @@ -236,7 +236,7 @@ merge context = go <$> go xs ys -} --- | unify raises an error if the result is would be 'NMany mempty'. +-- | unify raises an fail if the result is would be 'NMany mempty'. unify :: forall e m . MonadLint e m @@ -412,7 +412,7 @@ lintBinaryOp op lsym rarg = NConcat -> [TList y] - _ -> error "Should not be possible" -- symerr or this fun signature should be changed to work in type scope + _ -> fail "Should not be possible" -- symerr or this fun signature should be changed to work in type scope where check lsym rsym xs = do @@ -468,7 +468,7 @@ instance MonadThrow (Lint s) where throwM e = Lint $ ReaderT $ \_ -> throw e instance MonadCatch (Lint s) where - catch _m _h = Lint $ ReaderT $ \_ -> error "Cannot catch in 'Lint s'" + catch _m _h = Lint $ ReaderT $ \_ -> fail "Cannot catch in 'Lint s'" runLintM :: Options -> Lint s a -> ST s a runLintM opts action = do diff --git a/src/Nix/Normal.hs b/src/Nix/Normal.hs index 703b3f70a..6b1c1c0f8 100644 --- a/src/Nix/Normal.hs +++ b/src/Nix/Normal.hs @@ -61,7 +61,7 @@ normalizeValue v = run $ iterNValueM run go (fmap Free . sequenceNValue' run) v (do i <- ask when (i > 2000) - $ error "Exceeded maximum normalization depth of 2000 levels" + $ fail "Exceeded maximum normalization depth of 2000 levels" -- 2021-02-22: NOTE: `normalizeValue` should be adopted to work without fliping of the force (f) lifted (lifted $ \f -> f =<< force t) $ local succ . k ) diff --git a/src/Nix/Options/Parser.hs b/src/Nix/Options/Parser.hs index 195174645..d010c49a5 100644 --- a/src/Nix/Options/Parser.hs +++ b/src/Nix/Options/Parser.hs @@ -132,7 +132,7 @@ nixOptions current = ) <*> switch ( long "check" - <> help "Whether to check for syntax errors after parsing" + <> help "Whether to check for syntax fails after parsing" ) <*> optional (strOption @@ -149,8 +149,8 @@ nixOptions current = <> help "After performing any indicated actions, enter the REPL" ) <*> switch - ( long "ignore-errors" - <> help "Continue parsing files, even if there are errors" + ( long "ignore-fails" + <> help "Continue parsing files, even if there are fails" ) <*> optional (strOption diff --git a/src/Nix/Parser.hs b/src/Nix/Parser.hs index 947fcf4b9..fd915823b 100644 --- a/src/Nix/Parser.hs +++ b/src/Nix/Parser.hs @@ -1,7 +1,6 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveDataTypeable #-} -{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} @@ -724,7 +723,7 @@ getUnaryOperator = (m Map.!) zipWith buildEntry [1 ..] - (nixOperators (error "unused")) + (nixOperators (fail "unused")) buildEntry i = concatMap $ @@ -741,7 +740,7 @@ getBinaryOperator = (m Map.!) zipWith buildEntry [1 ..] - (nixOperators (error "unused")) + (nixOperators (fail "unused")) buildEntry i = concatMap $ @@ -759,7 +758,7 @@ getSpecialOperator o = m Map.! o zipWith buildEntry [1 ..] - (nixOperators (error "unused")) + (nixOperators (fail "unused")) buildEntry i = concatMap $ diff --git a/src/Nix/Reduce.hs b/src/Nix/Reduce.hs index b543520cc..7c1d226a9 100644 --- a/src/Nix/Reduce.hs +++ b/src/Nix/Reduce.hs @@ -104,7 +104,7 @@ staticImport pann path = do eres <- liftIO $ parseNixFileLoc path either - (\ err -> error $ "Parse failed: " <> show err) + (\ err -> fail $ "Parse failed: " <> show err) (\ x -> do let pos = SourcePos "Reduce.hs" (mkPos 1) (mkPos 1) @@ -366,7 +366,7 @@ pruneTree opts = foldFixM $ \(FlaggedF (b, Compose x)) -> do -- The idea behind emitted a binary operator where one side may be -- invalid is that we're trying to emit what will reproduce whatever - -- error the user encountered, which means providing all aspects of + -- fail the user encountered, which means providing all aspects of -- the evaluation path they ultimately followed. NBinary op Nothing (Just rarg) -> pure $ NBinary op nNull rarg NBinary op (Just larg) Nothing -> pure $ NBinary op larg nNull @@ -375,12 +375,12 @@ pruneTree opts = foldFixM $ \(FlaggedF (b, Compose x)) -> do NWith Nothing (Just (Fix (Compose (Ann _ body)))) -> pure body NAssert Nothing _ -> - error "How can an assert be used, but its condition not?" + fail "How can an assert be used, but its condition not?" NAssert _ (Just (Fix (Compose (Ann _ body)))) -> pure body NAssert (Just cond) _ -> pure $ NAssert cond nNull - NIf Nothing _ _ -> error "How can an if be used, but its condition not?" + NIf Nothing _ _ -> fail "How can an if be used, but its condition not?" NIf _ Nothing (Just (Fix (Compose (Ann _ f)))) -> pure f NIf _ (Just (Fix (Compose (Ann _ t)))) Nothing -> pure t diff --git a/src/Nix/Render.hs b/src/Nix/Render.hs index 408eb9999..106cefbfa 100644 --- a/src/Nix/Render.hs +++ b/src/Nix/Render.hs @@ -100,7 +100,7 @@ renderLocation (SrcSpan (SourcePos file begLine begCol) (SourcePos file' endLine , txt ] else pure msg -renderLocation (SrcSpan beg end) msg = fail $ "Don't know how to render range from " <> show beg <>" to " <> show end <>" for error: " <> show msg +renderLocation (SrcSpan beg end) msg = fail $ "Don't know how to render range from " <> show beg <>" to " <> show end <>" for fail: " <> show msg errorContext :: FilePath -> Pos -> Pos -> Pos -> Pos -> Doc a errorContext path bl bc _el _ec = diff --git a/src/Nix/Render/Frame.hs b/src/Nix/Render/Frame.hs index da2da5f5b..a88e842c1 100644 --- a/src/Nix/Render/Frame.hs +++ b/src/Nix/Render/Frame.hs @@ -91,7 +91,7 @@ renderFrame (NixFrame level f) | 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 + | otherwise = fail $ "Unrecognized frame: " <> show f wrapExpr :: NExprF r -> NExpr wrapExpr x = Fix (Fix (NSym "") <$ x) diff --git a/src/Nix/Value.hs b/src/Nix/Value.hs index c42521074..6d539afde 100644 --- a/src/Nix/Value.hs +++ b/src/Nix/Value.hs @@ -55,6 +55,9 @@ import Nix.Thunk import Nix.Utils import Data.Eq.Deriving + +-- * @__NValueF__@: Base functor + -- | An NValueF p m r represents all the possible types of Nix values. -- -- Is is the base functor to form the Free monad of nix expressions. @@ -119,8 +122,6 @@ import Data.Eq.Deriving -- pattern to account for the possibility of an NValue to no be fully -- evaluated yet, as opposed to an NValue'. --- * @__NValueF__@: Base functor - data NValueF p m r = NVConstantF NAtom -- | A string has a value and a context, which can be used to record what a @@ -778,7 +779,7 @@ type MonadDataContext f (m :: * -> *) -- * @MonadDataErrorContext@ type MonadDataErrorContext t f m - = (Show t, Typeable t, Typeable m, Typeable f, MonadDataContext f m) + = (Show t, Typeable t, Typeable m, Typeable f, MonadDataContext f m, MonadFail m) instance MonadDataErrorContext t f m => Exception (ValueFrame t f m) diff --git a/tests/Main.hs b/tests/Main.hs index e19111891..e13bf6abe 100644 --- a/tests/Main.hs +++ b/tests/Main.hs @@ -76,7 +76,7 @@ ensureNixpkgsCanParse = -- parser is fully executed. _ <- consider file (parseNixFileLoc file) $ Exc.evaluate . force pure () - v -> error $ "Unexpected parse from default.nix: " <> show v + v -> fail $ "Unexpected parse from default.nix: " <> show v where getExpr k m = let Just (Just r) = lookup k m in r getString k m = diff --git a/tests/NixLanguageTests.hs b/tests/NixLanguageTests.hs index 7df857e03..6ca819238 100644 --- a/tests/NixLanguageTests.hs +++ b/tests/NixLanguageTests.hs @@ -101,7 +101,7 @@ genTests = do ["parse", "fail"] -> assertParseFail opts $ the files ["eval" , "okay"] -> assertEval opts files ["eval" , "fail"] -> assertEvalFail $ the files - _ -> error $ "Unexpected: " <> show kind + _ -> fail $ "Unexpected: " <> show kind assertParse :: Options -> FilePath -> Assertion assertParse _opts file = @@ -173,7 +173,7 @@ assertEval _opts files = do <> ".flags: " <> show err Opts.Success opts' -> assertLangOk opts' name - Opts.CompletionInvoked _ -> error "unused" + Opts.CompletionInvoked _ -> fail "unused" _ -> assertFailure $ "Unknown test type " <> show files where name = diff --git a/tests/ParserTests.hs b/tests/ParserTests.hs index 274970399..59d806339 100644 --- a/tests/ParserTests.hs +++ b/tests/ParserTests.hs @@ -370,7 +370,7 @@ assertParseText :: Text -> NExpr -> Assertion assertParseText str expected = either (\ err -> - assertFailure $ "Unexpected error parsing `" <> unpack str <> "':\n" <> show err + assertFailure $ "Unexpected fail parsing `" <> unpack str <> "':\n" <> show err ) (assertEqual ("When parsing " <> unpack str) @@ -385,7 +385,7 @@ assertParseFile file expected = res <- parseNixFile $ "data/" <> file either (\ err -> - assertFailure $ "Unexpected error parsing data file `" <> file <> "':\n" <> show err + assertFailure $ "Unexpected fail parsing data file `" <> file <> "':\n" <> show err ) (assertEqual ("Parsing data file " <> file) diff --git a/tests/TestCommon.hs b/tests/TestCommon.hs index c0377ac37..2edd0b21d 100644 --- a/tests/TestCommon.hs +++ b/tests/TestCommon.hs @@ -26,7 +26,7 @@ hnixEvalFile opts file = do parseResult <- parseNixFileLoc file either - (\ err -> error $ "Parsing failed for file `" <> file <> "`.\n" <> show err) + (\ err -> fail $ "Parsing failed for file `" <> file <> "`.\n" <> show err) (\ expr -> do setEnv "TEST_VAR" "foo" @@ -45,7 +45,7 @@ hnixEvalFile opts file = hnixEvalText :: Options -> Text -> IO (StdValue (StandardT (StdIdT IO))) hnixEvalText opts src = either - (\ err -> error $ "Parsing failed for expression `" <> unpack src <> "`.\n" <> show err) + (\ err -> fail $ "Parsing failed for expression `" <> unpack src <> "`.\n" <> show err) (\ expr -> runWithBasicEffects opts $ normalForm =<< nixEvalExpr mempty expr ) From 46b00a72dca1f98cda7cf07e3560cbddc3c7c64c Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 02:09:14 +0200 Subject: [PATCH 12/30] Thunk.Basic: forceEff: update exception processing Seems logical that `forceEff` needs to have the exception catcher on `action` and "Loop detected" is just a ThunkLoop. So now `forceEff == force` --- src/Nix/Thunk/Basic.hs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Nix/Thunk/Basic.hs b/src/Nix/Thunk/Basic.hs index 347657ac5..15e595fe9 100644 --- a/src/Nix/Thunk/Basic.hs +++ b/src/Nix/Thunk/Basic.hs @@ -54,6 +54,7 @@ instance (MonadBasicThunk m, MonadCatch m) freshThunkId <- freshId Thunk freshThunkId <$> newVar False <*> newVar (Deferred action) + -- | Non-blocking query queryM :: m v -> NThunkF m v -> m v queryM n (Thunk _ _ ref) = do @@ -70,7 +71,7 @@ instance (MonadBasicThunk m, MonadCatch m) Computed v -> pure v Deferred action -> do - seizeThunk <- atomicModifyVar active (True, ) + lockThunk <- atomicModifyVar active (True, ) bool (throwM $ ThunkLoop $ show n) (do @@ -82,26 +83,29 @@ instance (MonadBasicThunk m, MonadCatch m) _freeThunk <- atomicModifyVar active (False, ) pure v ) - (not seizeThunk) + (not lockThunk) forceEff :: NThunkF m v -> m v - forceEff (Thunk _ active ref) = + forceEff (Thunk n active ref) = do eres <- readVar ref case eres of Computed v -> pure v Deferred action -> do - seizeThunk <- atomicModifyVar active (True, ) + lockThunk <- atomicModifyVar active (True, ) bool - (pure $ error "Loop detected") + (throwM $ ThunkLoop $ show n) (do - v <- action + v <- catch action $ \(e :: SomeException) -> + do + _ <- atomicModifyVar active (False, ) + throwM e writeVar ref (Computed v) - _freeThunk <- atomicModifyVar active (False, ) + _unlockThunk <- atomicModifyVar active (False, ) pure v ) - (not seizeThunk) + (not lockThunk) further :: NThunkF m v -> m (NThunkF m v) further t@(Thunk _ _ ref) = @@ -168,4 +172,3 @@ instance (MonadBasicThunk m, MonadCatch m) Computed _ -> (x, x) Deferred d -> (Deferred (k d), x) pure t - From 13c354438d9cfa3924df9a535317f255b1818cb9 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 12:14:30 +0200 Subject: [PATCH 13/30] Thunk.Basic: Utils: add internall `deferred` fun --- src/Nix/Thunk/Basic.hs | 43 +++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/Nix/Thunk/Basic.hs b/src/Nix/Thunk/Basic.hs index 15e595fe9..3929a30d7 100644 --- a/src/Nix/Thunk/Basic.hs +++ b/src/Nix/Thunk/Basic.hs @@ -27,8 +27,8 @@ import Nix.Thunk import Nix.Var import Nix.Utils ( bool ) -data Deferred m v = Deferred (m v) | Computed v - deriving (Functor, Foldable, Traversable) +data Deferred m v = Computed v | Deferred (m v) + deriving (Functor, Foldable, Traversable) -- | The type of very basic thunks data NThunkF m v @@ -58,18 +58,17 @@ instance (MonadBasicThunk m, MonadCatch m) queryM :: m v -> NThunkF m v -> m v queryM n (Thunk _ _ ref) = do - (\case - Computed v -> pure v - _deferred -> n - ) =<< readVar ref + deferred + pure + (const n) + =<< readVar ref force :: NThunkF m v -> m v force (Thunk n active ref) = do - eres <- readVar ref - case eres of - Computed v -> pure v - Deferred action -> + deferred + pure + (\ action -> do lockThunk <- atomicModifyVar active (True, ) bool @@ -80,18 +79,19 @@ instance (MonadBasicThunk m, MonadCatch m) _ <- atomicModifyVar active (False, ) throwM e writeVar ref (Computed v) - _freeThunk <- atomicModifyVar active (False, ) + _unlockThunk <- atomicModifyVar active (False, ) pure v ) (not lockThunk) + ) + =<< readVar ref forceEff :: NThunkF m v -> m v forceEff (Thunk n active ref) = do - eres <- readVar ref - case eres of - Computed v -> pure v - Deferred action -> + deferred + pure + (\ action -> do lockThunk <- atomicModifyVar active (True, ) bool @@ -106,6 +106,8 @@ instance (MonadBasicThunk m, MonadCatch m) pure v ) (not lockThunk) + ) + =<< readVar ref further :: NThunkF m v -> m (NThunkF m v) further t@(Thunk _ _ ref) = @@ -172,3 +174,14 @@ instance (MonadBasicThunk m, MonadCatch m) Computed _ -> (x, x) Deferred d -> (Deferred (k d), x) pure t + +-- ** Utils + + +-- | @either@ for @Deferred@ data type +deferred :: (v -> m v) -> (m v -> m v) -> Deferred m v -> m v +deferred f1 f2 def = + case def of + Computed v -> f1 v + Deferred action -> f2 action +{-# inline deferred #-} From 30babb027f6bb966ce0258ff6141d57bad3d5f2e Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 12:15:14 +0200 Subject: [PATCH 14/30] Thunk.Basic: utils: deferred: upd type; use fun for `further` Now it shows that `further` body is actually a `const`. --- src/Nix/Thunk/Basic.hs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Nix/Thunk/Basic.hs b/src/Nix/Thunk/Basic.hs index 3929a30d7..16c88c65f 100644 --- a/src/Nix/Thunk/Basic.hs +++ b/src/Nix/Thunk/Basic.hs @@ -116,9 +116,10 @@ instance (MonadBasicThunk m, MonadCatch m) atomicModifyVar ref (\ x -> - case x of - Computed _ -> (x, x) - _deferred -> (_deferred, x) + deferred + (const (x, x)) + (const (x, x)) + x ) pure t @@ -179,7 +180,7 @@ instance (MonadBasicThunk m, MonadCatch m) -- | @either@ for @Deferred@ data type -deferred :: (v -> m v) -> (m v -> m v) -> Deferred m v -> m v +deferred :: (v -> b) -> (m v -> b) -> Deferred m v -> b deferred f1 f2 def = case def of Computed v -> f1 v From ca5124e3e699a9777ab2bd4d2f7514b48bf457d6 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 12:26:31 +0200 Subject: [PATCH 15/30] Utils: add `dup`; Thunk.Basic: further: define with a `dup` We saw that `further` does not even need to strictly pattern match on a thunk, since the results of bothe matches would be the same, so we can skip matching. --- src/Nix/Thunk/Basic.hs | 11 ++++------- src/Nix/Utils.hs | 6 ++++++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Nix/Thunk/Basic.hs b/src/Nix/Thunk/Basic.hs index 16c88c65f..2f1a71d94 100644 --- a/src/Nix/Thunk/Basic.hs +++ b/src/Nix/Thunk/Basic.hs @@ -25,7 +25,9 @@ import Control.Monad.Catch ( MonadCatch(..) ) import Nix.Thunk import Nix.Var -import Nix.Utils ( bool ) +import Nix.Utils ( bool + , dup + ) data Deferred m v = Computed v | Deferred (m v) deriving (Functor, Foldable, Traversable) @@ -115,12 +117,7 @@ instance (MonadBasicThunk m, MonadCatch m) _ <- atomicModifyVar ref - (\ x -> - deferred - (const (x, x)) - (const (x, x)) - x - ) + dup pure t diff --git a/src/Nix/Utils.hs b/src/Nix/Utils.hs index 37af25fe1..1ba9006e7 100644 --- a/src/Nix/Utils.hs +++ b/src/Nix/Utils.hs @@ -283,3 +283,9 @@ for_ = flip traverse_ both :: (a -> b) -> (a, a) -> (b, b) both f (x,y) = (f x, f y) {-# inline both #-} + + +-- | Duplicates object into a tuple. +dup :: a -> (a, a) +dup x = (x, x) +{-# inline dup #-} From a9a2f8030d15f16e5a78fbdb9dd57ab80bc9c13c Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 12:42:50 +0200 Subject: [PATCH 16/30] Thunk.Basic: force{,Eff}: unify implementation as `forceMain` --- src/Nix/Thunk/Basic.hs | 86 +++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/src/Nix/Thunk/Basic.hs b/src/Nix/Thunk/Basic.hs index 2f1a71d94..20eeb7e43 100644 --- a/src/Nix/Thunk/Basic.hs +++ b/src/Nix/Thunk/Basic.hs @@ -32,6 +32,8 @@ import Nix.Utils ( bool data Deferred m v = Computed v | Deferred (m v) deriving (Functor, Foldable, Traversable) +-- * Data type for thunks: @NThunkF@ + -- | The type of very basic thunks data NThunkF m v = Thunk (ThunkId m) (Var m Bool) (Var m (Deferred m v)) @@ -44,6 +46,9 @@ instance Show (NThunkF m v) where type MonadBasicThunk m = (MonadThunkId m, MonadVar m) + +-- ** @instance MonadThunk NThunkF@ + instance (MonadBasicThunk m, MonadCatch m) => MonadThunk (NThunkF m v) m v where @@ -66,50 +71,10 @@ instance (MonadBasicThunk m, MonadCatch m) =<< readVar ref force :: NThunkF m v -> m v - force (Thunk n active ref) = - do - deferred - pure - (\ action -> - do - lockThunk <- atomicModifyVar active (True, ) - bool - (throwM $ ThunkLoop $ show n) - (do - v <- catch action $ \(e :: SomeException) -> - do - _ <- atomicModifyVar active (False, ) - throwM e - writeVar ref (Computed v) - _unlockThunk <- atomicModifyVar active (False, ) - pure v - ) - (not lockThunk) - ) - =<< readVar ref + force = forceMain forceEff :: NThunkF m v -> m v - forceEff (Thunk n active ref) = - do - deferred - pure - (\ action -> - do - lockThunk <- atomicModifyVar active (True, ) - bool - (throwM $ ThunkLoop $ show n) - (do - v <- catch action $ \(e :: SomeException) -> - do - _ <- atomicModifyVar active (False, ) - throwM e - writeVar ref (Computed v) - _unlockThunk <- atomicModifyVar active (False, ) - pure v - ) - (not lockThunk) - ) - =<< readVar ref + forceEff = forceMain further :: NThunkF m v -> m (NThunkF m v) further t@(Thunk _ _ ref) = @@ -121,7 +86,40 @@ instance (MonadBasicThunk m, MonadCatch m) pure t --- * Kleisli functor HOFs +-- *** United body of `force*` + +forceMain + :: ( MonadBasicThunk m + , MonadCatch m + ) + => NThunkF m v + -> m v +forceMain (Thunk n active ref) = + do + deferred + pure + (\ action -> + do + lockThunk <- atomicModifyVar active (True, ) + bool + (throwM $ ThunkLoop $ show n) + (do + v <- catch action $ \(e :: SomeException) -> + do + _ <- atomicModifyVar active (False, ) + throwM e + writeVar ref (Computed v) + _unlockThunk <- atomicModifyVar active (False, ) + pure v + ) + (not lockThunk) + ) + =<< readVar ref +{-# inline forceMain #-} -- it is big function, but internal, and look at its use. + + + +-- ** Kleisli functor HOFs: @instance MonadThunkF NThunkF@ instance (MonadBasicThunk m, MonadCatch m) => MonadThunkF (NThunkF m v) m v where @@ -173,8 +171,8 @@ instance (MonadBasicThunk m, MonadCatch m) Deferred d -> (Deferred (k d), x) pure t --- ** Utils +-- ** Utils -- | @either@ for @Deferred@ data type deferred :: (v -> b) -> (m v -> b) -> Deferred m v -> b From 0f3efddde1952b4d42a4865d5eaecb7a29073f4a Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 14:24:23 +0200 Subject: [PATCH 17/30] Options.Parser: refactor Just organizing and layouting --- src/Nix/Options/Parser.hs | 89 ++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 38 deletions(-) diff --git a/src/Nix/Options/Parser.hs b/src/Nix/Options/Parser.hs index d010c49a5..67fc63656 100644 --- a/src/Nix/Options/Parser.hs +++ b/src/Nix/Options/Parser.hs @@ -8,7 +8,10 @@ import Data.Char ( isDigit ) import Data.Maybe ( fromMaybe ) import Data.Text ( Text ) import qualified Data.Text as Text -import Data.Time +import Data.Time ( UTCTime + , defaultTimeLocale + , parseTimeOrError + ) import Nix.Options import Options.Applicative hiding ( ParserResult(..) ) import Data.Version ( showVersion ) @@ -16,6 +19,7 @@ import Development.GitRev ( gitCommitDate , gitBranch , gitHash ) import Paths_hnix ( version ) +import Nix.Utils ( bool ) decodeVerbosity :: Int -> Verbosity decodeVerbosity 0 = ErrorsOnly @@ -26,32 +30,37 @@ decodeVerbosity 4 = DebugInfo decodeVerbosity _ = Vomit argPair :: Mod OptionFields (Text, Text) -> Parser (Text, Text) -argPair = option $ str >>= \s -> case Text.findIndex (== '=') s of - Nothing -> - errorWithoutStackTrace "Format of --arg/--argstr in hnix is: name=expr" - Just i -> pure $ second Text.tail $ Text.splitAt i s +argPair = + option $ + do + s <- str + maybe + (errorWithoutStackTrace "Format of --arg/--argstr in hnix is: name=expr") + (pure . second Text.tail . (`Text.splitAt` s)) + (Text.findIndex (== '=') s) nixOptions :: UTCTime -> Parser Options nixOptions current = - Options - <$> (fromMaybe Informational <$> - optional - (option + Options <$> + (fromMaybe Informational <$> + optional + (option - (do - a <- str - if all isDigit a - then pure $ decodeVerbosity (read a) - else fail "Argument to -v/--verbose must be a number" - ) - - ( short 'v' - <> long "verbose" - <> help "Verbose output" - ) + (do + a <- str + bool + (fail "Argument to -v/--verbose must be a number") + (pure $ decodeVerbosity $ read a) + (all isDigit a) + ) + ( short 'v' + <> long "verbose" + <> help "Verbose output" ) + ) + ) <*> switch ( long "trace" <> help "Enable tracing code (even more can be seen if built with --flags=tracing)" @@ -194,26 +203,30 @@ versionOpt :: Parser (a -> a) versionOpt = shortVersionOpt <*> debugVersionOpt where shortVersionOpt :: Parser (a -> a) - shortVersionOpt = infoOption - (showVersion version) - ( long "version" - <> help "Show release version" - ) + shortVersionOpt = + infoOption + (showVersion version) + ( long "version" + <> help "Show release version" + ) -- 2020-09-13: NOTE: Does not work for direct `nix-build`s, works for `nix-shell` `cabal` builds. debugVersionOpt :: Parser (a -> a) - debugVersionOpt = infoOption - ( concat - [ "Version: ", showVersion version - , "\nCommit: ", $(gitHash) - , "\n date: ", $(gitCommitDate) - , "\n branch: ", $(gitBranch) - ] - ) - ( long "long-version" - <> help "Show long debug version form" - ) + debugVersionOpt = + infoOption + ( concat + [ "Version: ", showVersion version + , "\nCommit: ", $(gitHash) + , "\n date: ", $(gitCommitDate) + , "\n branch: ", $(gitBranch) + ] + ) + ( long "long-version" + <> help "Show long debug version form" + ) nixOptionsInfo :: UTCTime -> ParserInfo Options -nixOptionsInfo current = info (helper <*> versionOpt <*> nixOptions current) - (fullDesc <> progDesc "" <> header "hnix") +nixOptionsInfo current = + info + (helper <*> versionOpt <*> nixOptions current) + (fullDesc <> progDesc "" <> header "hnix") From 20021cee01e111ffa9da4a2f5cfdd0838814893a Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 14:40:24 +0200 Subject: [PATCH 18/30] cabal: flag optimize: add ApplicativeDo At this point it optimizes things greatly. --- hnix.cabal | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hnix.cabal b/hnix.cabal index 3a30b7a87..524926319 100644 --- a/hnix.cabal +++ b/hnix.cabal @@ -450,6 +450,8 @@ library , xml >= 1.3.14 && < 1.4 if flag(optimize) ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O2 + default-extensions: + ApplicativeDo if !impl(ghcjs) exposed-modules: Nix.Options.Parser @@ -463,6 +465,8 @@ library default-language: Haskell2010 executable hnix + default-extensions: + ApplicativeDo main-is: Main.hs other-modules: Repl @@ -498,6 +502,8 @@ executable hnix , unordered-containers if flag(optimize) ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O2 + default-extensions: + ApplicativeDo if impl(ghc < 8.10) -- GHC < 8.10 comes with haskeline < 0.8, which we don't support. -- To simplify CI, we just disable the component. @@ -556,6 +562,8 @@ test-suite hnix-tests , unordered-containers if flag(optimize) ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O2 + default-extensions: + ApplicativeDo if impl(ghcjs) buildable: False default-language: Haskell2010 @@ -590,6 +598,8 @@ benchmark hnix-benchmarks , unordered-containers if flag(optimize) ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O2 + default-extensions: + ApplicativeDo if impl(ghcjs) buildable: False default-language: Haskell2010 From b938c3795cf10d18a951cc0850b4f2c728db6907 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 14:41:12 +0200 Subject: [PATCH 19/30] cabal: flag optimize: add O3 as it works-out good --- hnix.cabal | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hnix.cabal b/hnix.cabal index 524926319..30d690c27 100644 --- a/hnix.cabal +++ b/hnix.cabal @@ -449,9 +449,9 @@ library , vector >= 0.12.0 && < 0.13 , xml >= 1.3.14 && < 1.4 if flag(optimize) - ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O2 default-extensions: ApplicativeDo + ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O3 if !impl(ghcjs) exposed-modules: Nix.Options.Parser @@ -501,9 +501,9 @@ executable hnix , transformers , unordered-containers if flag(optimize) - ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O2 default-extensions: ApplicativeDo + ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O3 if impl(ghc < 8.10) -- GHC < 8.10 comes with haskeline < 0.8, which we don't support. -- To simplify CI, we just disable the component. @@ -561,9 +561,9 @@ test-suite hnix-tests , unix , unordered-containers if flag(optimize) - ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O2 default-extensions: ApplicativeDo + ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O3 if impl(ghcjs) buildable: False default-language: Haskell2010 @@ -597,9 +597,9 @@ benchmark hnix-benchmarks , transformers , unordered-containers if flag(optimize) - ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O2 default-extensions: ApplicativeDo + ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O3 if impl(ghcjs) buildable: False default-language: Haskell2010 From 05983cbffd647421b2c1d28487bce4fa469f4de3 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 14:42:01 +0200 Subject: [PATCH 20/30] cabal: enable optimizations by default --- hnix.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hnix.cabal b/hnix.cabal index 30d690c27..aba8a1a97 100644 --- a/hnix.cabal +++ b/hnix.cabal @@ -332,7 +332,7 @@ source-repository head flag optimize description: Enable all optimization flags manual: True - default: False + default: True flag profiling description: Enable profiling From b258c40df5f80508f22275f7dfb11fd14f349587 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 14:53:43 +0200 Subject: [PATCH 21/30] cabal: layout --- hnix.cabal | 756 ++++++++++++++++++++++++++--------------------------- 1 file changed, 377 insertions(+), 379 deletions(-) diff --git a/hnix.cabal b/hnix.cabal index aba8a1a97..0e1552dc9 100644 --- a/hnix.cabal +++ b/hnix.cabal @@ -13,317 +13,317 @@ build-type: Simple cabal-version: >= 1.10 data-dir: data/ data-files: - nix/corepkgs/buildenv.nix - nix/corepkgs/unpack-channel.nix - nix/corepkgs/derivation.nix - nix/corepkgs/fetchurl.nix - nix/corepkgs/imported-drv-to-derivation.nix + nix/corepkgs/buildenv.nix + nix/corepkgs/unpack-channel.nix + nix/corepkgs/derivation.nix + nix/corepkgs/fetchurl.nix + nix/corepkgs/imported-drv-to-derivation.nix extra-source-files: - ChangeLog.md - ReadMe.md - License - data/nix/corepkgs/buildenv.nix - data/nix/corepkgs/unpack-channel.nix - data/nix/corepkgs/derivation.nix - data/nix/corepkgs/fetchurl.nix - data/nix/corepkgs/imported-drv-to-derivation.nix - data/nix/tests/lang/binary-data - data/nix/tests/lang/data - data/nix/tests/lang/dir1/a.nix - data/nix/tests/lang/dir2/a.nix - data/nix/tests/lang/dir2/b.nix - data/nix/tests/lang/dir3/a.nix - data/nix/tests/lang/dir3/b.nix - data/nix/tests/lang/dir3/c.nix - data/nix/tests/lang/dir4/a.nix - data/nix/tests/lang/dir4/c.nix - data/nix/tests/lang/eval-fail-abort.nix - data/nix/tests/lang/eval-fail-antiquoted-path.nix - data/nix/tests/lang/eval-fail-assert.nix - data/nix/tests/lang/eval-fail-bad-antiquote-1.nix - data/nix/tests/lang/eval-fail-bad-antiquote-2.nix - data/nix/tests/lang/eval-fail-bad-antiquote-3.nix - data/nix/tests/lang/eval-fail-blackhole.nix - data/nix/tests/lang/eval-fail-deepseq.nix - data/nix/tests/lang/eval-fail-hashfile-missing.nix - data/nix/tests/lang/eval-fail-missing-arg.nix - data/nix/tests/lang/eval-fail-path-slash.nix - data/nix/tests/lang/eval-fail-remove.nix - data/nix/tests/lang/eval-fail-scope-5.nix - data/nix/tests/lang/eval-fail-seq.nix - data/nix/tests/lang/eval-fail-substring.nix - data/nix/tests/lang/eval-fail-to-path.nix - data/nix/tests/lang/eval-fail-undeclared-arg.nix - data/nix/tests/lang/eval-okay-any-all.exp - data/nix/tests/lang/eval-okay-any-all.nix - data/nix/tests/lang/eval-okay-arithmetic.exp - data/nix/tests/lang/eval-okay-arithmetic.nix - data/nix/tests/lang/eval-okay-attrnames.exp - data/nix/tests/lang/eval-okay-attrnames.nix - data/nix/tests/lang/eval-okay-attrs2.exp - data/nix/tests/lang/eval-okay-attrs2.nix - data/nix/tests/lang/eval-okay-attrs3.exp - data/nix/tests/lang/eval-okay-attrs3.nix - data/nix/tests/lang/eval-okay-attrs4.exp - data/nix/tests/lang/eval-okay-attrs4.nix - data/nix/tests/lang/eval-okay-attrs5.exp - data/nix/tests/lang/eval-okay-attrs5.nix - data/nix/tests/lang/eval-okay-attrs.exp - data/nix/tests/lang/eval-okay-attrs.nix - data/nix/tests/lang/eval-okay-autoargs.exp - data/nix/tests/lang/eval-okay-autoargs.flags - data/nix/tests/lang/eval-okay-autoargs.nix - data/nix/tests/lang/eval-okay-backslash-newline-1.exp - data/nix/tests/lang/eval-okay-backslash-newline-1.nix - data/nix/tests/lang/eval-okay-backslash-newline-2.exp - data/nix/tests/lang/eval-okay-backslash-newline-2.nix - data/nix/tests/lang/eval-okay-builtins-add.exp - data/nix/tests/lang/eval-okay-builtins-add.nix - data/nix/tests/lang/eval-okay-builtins.exp - data/nix/tests/lang/eval-okay-builtins.nix - data/nix/tests/lang/eval-okay-callable-attrs.exp - data/nix/tests/lang/eval-okay-callable-attrs.nix - data/nix/tests/lang/eval-okay-catattrs.exp - data/nix/tests/lang/eval-okay-catattrs.nix - data/nix/tests/lang/eval-okay-closure.exp.xml - data/nix/tests/lang/eval-okay-closure.nix - data/nix/tests/lang/eval-okay-comments.exp - data/nix/tests/lang/eval-okay-comments.nix - data/nix/tests/lang/eval-okay-concat.exp - data/nix/tests/lang/eval-okay-concatmap.exp - data/nix/tests/lang/eval-okay-concatmap.nix - data/nix/tests/lang/eval-okay-concat.nix - data/nix/tests/lang/eval-okay-concatstringssep.exp - data/nix/tests/lang/eval-okay-concatstringssep.nix - data/nix/tests/lang/eval-okay-context.exp - data/nix/tests/lang/eval-okay-context-introspection.exp - data/nix/tests/lang/eval-okay-context-introspection.nix - data/nix/tests/lang/eval-okay-context.nix - data/nix/tests/lang/eval-okay-curpos.exp - data/nix/tests/lang/eval-okay-curpos.nix - data/nix/tests/lang/eval-okay-deepseq.exp - data/nix/tests/lang/eval-okay-deepseq.nix - data/nix/tests/lang/eval-okay-delayed-with.exp - data/nix/tests/lang/eval-okay-delayed-with-inherit.exp - data/nix/tests/lang/eval-okay-delayed-with-inherit.nix - data/nix/tests/lang/eval-okay-delayed-with.nix - data/nix/tests/lang/eval-okay-dynamic-attrs-2.exp - data/nix/tests/lang/eval-okay-dynamic-attrs-2.nix - data/nix/tests/lang/eval-okay-dynamic-attrs-bare.exp - data/nix/tests/lang/eval-okay-dynamic-attrs-bare.nix - data/nix/tests/lang/eval-okay-dynamic-attrs.exp - data/nix/tests/lang/eval-okay-dynamic-attrs.nix - data/nix/tests/lang/eval-okay-elem.exp - data/nix/tests/lang/eval-okay-elem.nix - data/nix/tests/lang/eval-okay-empty-args.exp - data/nix/tests/lang/eval-okay-empty-args.nix - data/nix/tests/lang/eval-okay-eq-derivations.exp - data/nix/tests/lang/eval-okay-eq-derivations.nix - data/nix/tests/lang/eval-okay-eq.exp.disabled - data/nix/tests/lang/eval-okay-eq.nix - data/nix/tests/lang/eval-okay-filter.exp - data/nix/tests/lang/eval-okay-filter.nix - data/nix/tests/lang/eval-okay-flatten.exp - data/nix/tests/lang/eval-okay-flatten.nix - data/nix/tests/lang/eval-okay-float.exp - data/nix/tests/lang/eval-okay-float.nix - data/nix/tests/lang/eval-okay-fromjson.exp - data/nix/tests/lang/eval-okay-fromjson.nix - data/nix/tests/lang/eval-okay-fromTOML.exp - data/nix/tests/lang/eval-okay-fromTOML.nix - data/nix/tests/lang/eval-okay-functionargs.exp.xml - data/nix/tests/lang/eval-okay-functionargs.nix - data/nix/tests/lang/eval-okay-getattrpos.exp - data/nix/tests/lang/eval-okay-getattrpos.nix - data/nix/tests/lang/eval-okay-getattrpos-undefined.exp - data/nix/tests/lang/eval-okay-getattrpos-undefined.nix - data/nix/tests/lang/eval-okay-getenv.exp - data/nix/tests/lang/eval-okay-getenv.nix - data/nix/tests/lang/eval-okay-hash.exp - data/nix/tests/lang/eval-okay-hashfile.exp - data/nix/tests/lang/eval-okay-hashfile.nix - data/nix/tests/lang/eval-okay-hashstring.exp - data/nix/tests/lang/eval-okay-hashstring.nix - data/nix/tests/lang/eval-okay-if.exp - data/nix/tests/lang/eval-okay-if.nix - data/nix/tests/lang/eval-okay-import.exp - data/nix/tests/lang/eval-okay-import.nix - data/nix/tests/lang/eval-okay-ind-string.exp - data/nix/tests/lang/eval-okay-ind-string.nix - data/nix/tests/lang/eval-okay-let.exp - data/nix/tests/lang/eval-okay-let.nix - data/nix/tests/lang/eval-okay-list.exp - data/nix/tests/lang/eval-okay-list.nix - data/nix/tests/lang/eval-okay-listtoattrs.exp - data/nix/tests/lang/eval-okay-listtoattrs.nix - data/nix/tests/lang/eval-okay-logic.exp - data/nix/tests/lang/eval-okay-logic.nix - data/nix/tests/lang/eval-okay-mapattrs.exp - data/nix/tests/lang/eval-okay-mapattrs.nix - data/nix/tests/lang/eval-okay-map.exp - data/nix/tests/lang/eval-okay-map.nix - data/nix/tests/lang/eval-okay-nested-with.exp - data/nix/tests/lang/eval-okay-nested-with.nix - data/nix/tests/lang/eval-okay-new-let.exp - data/nix/tests/lang/eval-okay-new-let.nix - data/nix/tests/lang/eval-okay-null-dynamic-attrs.exp - data/nix/tests/lang/eval-okay-null-dynamic-attrs.nix - data/nix/tests/lang/eval-okay-overrides.exp - data/nix/tests/lang/eval-okay-overrides.nix - data/nix/tests/lang/eval-okay-partition.exp - data/nix/tests/lang/eval-okay-partition.nix - data/nix/tests/lang/eval-okay-pathexists.exp - data/nix/tests/lang/eval-okay-pathexists.nix - data/nix/tests/lang/eval-okay-path.nix - data/nix/tests/lang/eval-okay-patterns.exp - data/nix/tests/lang/eval-okay-patterns.nix - data/nix/tests/lang/eval-okay-readDir.exp - data/nix/tests/lang/eval-okay-readDir.nix - data/nix/tests/lang/eval-okay-readfile.exp - data/nix/tests/lang/eval-okay-readfile.nix - data/nix/tests/lang/eval-okay-redefine-builtin.exp - data/nix/tests/lang/eval-okay-redefine-builtin.nix - data/nix/tests/lang/eval-okay-regex-match.exp - data/nix/tests/lang/eval-okay-regex-match.nix - data/nix/tests/lang/eval-okay-regex-split.exp - data/nix/tests/lang/eval-okay-regex-split.nix - data/nix/tests/lang/eval-okay-remove.exp - data/nix/tests/lang/eval-okay-remove.nix - data/nix/tests/lang/eval-okay-replacestrings.exp - data/nix/tests/lang/eval-okay-replacestrings.nix - data/nix/tests/lang/eval-okay-scope-1.exp - data/nix/tests/lang/eval-okay-scope-1.nix - data/nix/tests/lang/eval-okay-scope-2.exp - data/nix/tests/lang/eval-okay-scope-2.nix - data/nix/tests/lang/eval-okay-scope-3.exp - data/nix/tests/lang/eval-okay-scope-3.nix - data/nix/tests/lang/eval-okay-scope-4.exp - data/nix/tests/lang/eval-okay-scope-4.nix - data/nix/tests/lang/eval-okay-scope-6.exp - data/nix/tests/lang/eval-okay-scope-6.nix - data/nix/tests/lang/eval-okay-scope-7.exp - data/nix/tests/lang/eval-okay-scope-7.nix - data/nix/tests/lang/eval-okay-search-path.exp - data/nix/tests/lang/eval-okay-search-path.flags - data/nix/tests/lang/eval-okay-search-path.nix - data/nix/tests/lang/eval-okay-seq.exp - data/nix/tests/lang/eval-okay-seq.nix - data/nix/tests/lang/eval-okay-sort.exp - data/nix/tests/lang/eval-okay-sort.nix - data/nix/tests/lang/eval-okay-splitversion.exp - data/nix/tests/lang/eval-okay-splitversion.nix - data/nix/tests/lang/eval-okay-string.exp - data/nix/tests/lang/eval-okay-string.nix - data/nix/tests/lang/eval-okay-strings-as-attrs-names.exp - data/nix/tests/lang/eval-okay-strings-as-attrs-names.nix - data/nix/tests/lang/eval-okay-substring.exp - data/nix/tests/lang/eval-okay-substring.nix - data/nix/tests/lang/eval-okay-tail-call-1.exp-disabled - data/nix/tests/lang/eval-okay-tail-call-1.nix - data/nix/tests/lang/eval-okay-tojson.exp - data/nix/tests/lang/eval-okay-tojson.nix - data/nix/tests/lang/eval-okay-toxml2.exp - data/nix/tests/lang/eval-okay-toxml2.nix - data/nix/tests/lang/eval-okay-toxml.exp - data/nix/tests/lang/eval-okay-toxml.nix - data/nix/tests/lang/eval-okay-tryeval.exp - data/nix/tests/lang/eval-okay-tryeval.nix - data/nix/tests/lang/eval-okay-types.exp - data/nix/tests/lang/eval-okay-types.nix - data/nix/tests/lang/eval-okay-versions.exp - data/nix/tests/lang/eval-okay-versions.nix - data/nix/tests/lang/eval-okay-with.exp - data/nix/tests/lang/eval-okay-with.nix - data/nix/tests/lang/eval-okay-xml.exp.xml - data/nix/tests/lang/eval-okay-xml.nix - data/nix/tests/lang/imported2.nix - data/nix/tests/lang/imported.nix - data/nix/tests/lang/lib.nix - data/nix/tests/lang/parse-fail-dup-attrs-1.nix - data/nix/tests/lang/parse-fail-dup-attrs-2.nix - data/nix/tests/lang/parse-fail-dup-attrs-3.nix - data/nix/tests/lang/parse-fail-dup-attrs-4.nix - data/nix/tests/lang/parse-fail-dup-attrs-7.nix - data/nix/tests/lang/parse-fail-dup-formals.nix - data/nix/tests/lang/parse-fail-mixed-nested-attrs1.nix - data/nix/tests/lang/parse-fail-mixed-nested-attrs2.nix - data/nix/tests/lang/parse-fail-patterns-1.nix - data/nix/tests/lang/parse-fail-regression-20060610.nix - data/nix/tests/lang/parse-fail-uft8.nix - data/nix/tests/lang/parse-fail-undef-var-2.nix - data/nix/tests/lang/parse-fail-undef-var.nix - data/nix/tests/lang/parse-okay-1.nix - data/nix/tests/lang/parse-okay-crlf.nix - data/nix/tests/lang/parse-okay-dup-attrs-5.nix - data/nix/tests/lang/parse-okay-dup-attrs-6.nix - data/nix/tests/lang/parse-okay-mixed-nested-attrs-1.nix - data/nix/tests/lang/parse-okay-mixed-nested-attrs-2.nix - data/nix/tests/lang/parse-okay-mixed-nested-attrs-3.nix - data/nix/tests/lang/parse-okay-regression-20041027.nix - data/nix/tests/lang/parse-okay-regression-751.nix - data/nix/tests/lang/parse-okay-subversion.nix - data/nix/tests/lang/parse-okay-url.nix - data/nix/tests/lang/readDir/bar - data/nix/tests/lang/readDir/foo/git-hates-directories - data/nix/tests/local.mk - data/nixpkgs-all-packages.nix - data/let-comments.nix - data/let-comments-multiline.nix - data/simple-pretty.nix - data/simple.nix - data/nixpkgs-all-packages-pretty.nix - data/let.nix - tests/eval-compare/builtins.appendContext.nix - tests/eval-compare/builtins.eq-bottom-00.nix - tests/eval-compare/builtins.fetchurl-01.nix - tests/eval-compare/builtins.fromJSON-01.nix - tests/eval-compare/builtins.getContext.nix - tests/eval-compare/builtins.lessThan-01.nix - tests/eval-compare/builtins.mapAttrs-01.nix - tests/eval-compare/builtins.pathExists.nix - tests/eval-compare/builtins.replaceStrings-01.nix - tests/eval-compare/builtins.split-01.nix - tests/eval-compare/builtins.split-02.nix - tests/eval-compare/builtins.split-03.nix - tests/eval-compare/builtins.split-04.nix - tests/eval-compare/builtins.string.store.nix - tests/eval-compare/builtins.toJSON.nix - tests/eval-compare/current-system.nix - tests/eval-compare/ellipsis.nix - tests/eval-compare/ind-string-01.nix - tests/eval-compare/ind-string-02.nix - tests/eval-compare/ind-string-03.nix - tests/eval-compare/ind-string-04.nix - tests/eval-compare/ind-string-05.nix - tests/eval-compare/ind-string-06.nix - tests/eval-compare/ind-string-07.nix - tests/eval-compare/ind-string-08.nix - tests/eval-compare/ind-string-09.nix - tests/eval-compare/ind-string-10.nix - tests/eval-compare/ind-string-11.nix - tests/eval-compare/ind-string-12.nix - tests/eval-compare/ind-string-13.nix - tests/eval-compare/ind-string-14.nix - tests/eval-compare/ind-string-15.nix - tests/eval-compare/ind-string-16.nix - tests/eval-compare/ind-string-17.nix - tests/eval-compare/paths-01.nix - tests/eval-compare/placeholder.nix - tests/files/attrs.nix - tests/files/callLibs.nix - tests/files/eighty.nix - tests/files/file.nix - tests/files/file2.nix - tests/files/findFile.nix - tests/files/force.nix - tests/files/goodbye.nix - tests/files/hello.nix - tests/files/hello2.nix - tests/files/if-then.nix - tests/files/lint.nix - tests/files/loop.nix - tests/files/test.nix - tests/files/with.nix + ChangeLog.md + ReadMe.md + License + data/nix/corepkgs/buildenv.nix + data/nix/corepkgs/unpack-channel.nix + data/nix/corepkgs/derivation.nix + data/nix/corepkgs/fetchurl.nix + data/nix/corepkgs/imported-drv-to-derivation.nix + data/nix/tests/lang/binary-data + data/nix/tests/lang/data + data/nix/tests/lang/dir1/a.nix + data/nix/tests/lang/dir2/a.nix + data/nix/tests/lang/dir2/b.nix + data/nix/tests/lang/dir3/a.nix + data/nix/tests/lang/dir3/b.nix + data/nix/tests/lang/dir3/c.nix + data/nix/tests/lang/dir4/a.nix + data/nix/tests/lang/dir4/c.nix + data/nix/tests/lang/eval-fail-abort.nix + data/nix/tests/lang/eval-fail-antiquoted-path.nix + data/nix/tests/lang/eval-fail-assert.nix + data/nix/tests/lang/eval-fail-bad-antiquote-1.nix + data/nix/tests/lang/eval-fail-bad-antiquote-2.nix + data/nix/tests/lang/eval-fail-bad-antiquote-3.nix + data/nix/tests/lang/eval-fail-blackhole.nix + data/nix/tests/lang/eval-fail-deepseq.nix + data/nix/tests/lang/eval-fail-hashfile-missing.nix + data/nix/tests/lang/eval-fail-missing-arg.nix + data/nix/tests/lang/eval-fail-path-slash.nix + data/nix/tests/lang/eval-fail-remove.nix + data/nix/tests/lang/eval-fail-scope-5.nix + data/nix/tests/lang/eval-fail-seq.nix + data/nix/tests/lang/eval-fail-substring.nix + data/nix/tests/lang/eval-fail-to-path.nix + data/nix/tests/lang/eval-fail-undeclared-arg.nix + data/nix/tests/lang/eval-okay-any-all.exp + data/nix/tests/lang/eval-okay-any-all.nix + data/nix/tests/lang/eval-okay-arithmetic.exp + data/nix/tests/lang/eval-okay-arithmetic.nix + data/nix/tests/lang/eval-okay-attrnames.exp + data/nix/tests/lang/eval-okay-attrnames.nix + data/nix/tests/lang/eval-okay-attrs2.exp + data/nix/tests/lang/eval-okay-attrs2.nix + data/nix/tests/lang/eval-okay-attrs3.exp + data/nix/tests/lang/eval-okay-attrs3.nix + data/nix/tests/lang/eval-okay-attrs4.exp + data/nix/tests/lang/eval-okay-attrs4.nix + data/nix/tests/lang/eval-okay-attrs5.exp + data/nix/tests/lang/eval-okay-attrs5.nix + data/nix/tests/lang/eval-okay-attrs.exp + data/nix/tests/lang/eval-okay-attrs.nix + data/nix/tests/lang/eval-okay-autoargs.exp + data/nix/tests/lang/eval-okay-autoargs.flags + data/nix/tests/lang/eval-okay-autoargs.nix + data/nix/tests/lang/eval-okay-backslash-newline-1.exp + data/nix/tests/lang/eval-okay-backslash-newline-1.nix + data/nix/tests/lang/eval-okay-backslash-newline-2.exp + data/nix/tests/lang/eval-okay-backslash-newline-2.nix + data/nix/tests/lang/eval-okay-builtins-add.exp + data/nix/tests/lang/eval-okay-builtins-add.nix + data/nix/tests/lang/eval-okay-builtins.exp + data/nix/tests/lang/eval-okay-builtins.nix + data/nix/tests/lang/eval-okay-callable-attrs.exp + data/nix/tests/lang/eval-okay-callable-attrs.nix + data/nix/tests/lang/eval-okay-catattrs.exp + data/nix/tests/lang/eval-okay-catattrs.nix + data/nix/tests/lang/eval-okay-closure.exp.xml + data/nix/tests/lang/eval-okay-closure.nix + data/nix/tests/lang/eval-okay-comments.exp + data/nix/tests/lang/eval-okay-comments.nix + data/nix/tests/lang/eval-okay-concat.exp + data/nix/tests/lang/eval-okay-concatmap.exp + data/nix/tests/lang/eval-okay-concatmap.nix + data/nix/tests/lang/eval-okay-concat.nix + data/nix/tests/lang/eval-okay-concatstringssep.exp + data/nix/tests/lang/eval-okay-concatstringssep.nix + data/nix/tests/lang/eval-okay-context.exp + data/nix/tests/lang/eval-okay-context-introspection.exp + data/nix/tests/lang/eval-okay-context-introspection.nix + data/nix/tests/lang/eval-okay-context.nix + data/nix/tests/lang/eval-okay-curpos.exp + data/nix/tests/lang/eval-okay-curpos.nix + data/nix/tests/lang/eval-okay-deepseq.exp + data/nix/tests/lang/eval-okay-deepseq.nix + data/nix/tests/lang/eval-okay-delayed-with.exp + data/nix/tests/lang/eval-okay-delayed-with-inherit.exp + data/nix/tests/lang/eval-okay-delayed-with-inherit.nix + data/nix/tests/lang/eval-okay-delayed-with.nix + data/nix/tests/lang/eval-okay-dynamic-attrs-2.exp + data/nix/tests/lang/eval-okay-dynamic-attrs-2.nix + data/nix/tests/lang/eval-okay-dynamic-attrs-bare.exp + data/nix/tests/lang/eval-okay-dynamic-attrs-bare.nix + data/nix/tests/lang/eval-okay-dynamic-attrs.exp + data/nix/tests/lang/eval-okay-dynamic-attrs.nix + data/nix/tests/lang/eval-okay-elem.exp + data/nix/tests/lang/eval-okay-elem.nix + data/nix/tests/lang/eval-okay-empty-args.exp + data/nix/tests/lang/eval-okay-empty-args.nix + data/nix/tests/lang/eval-okay-eq-derivations.exp + data/nix/tests/lang/eval-okay-eq-derivations.nix + data/nix/tests/lang/eval-okay-eq.exp.disabled + data/nix/tests/lang/eval-okay-eq.nix + data/nix/tests/lang/eval-okay-filter.exp + data/nix/tests/lang/eval-okay-filter.nix + data/nix/tests/lang/eval-okay-flatten.exp + data/nix/tests/lang/eval-okay-flatten.nix + data/nix/tests/lang/eval-okay-float.exp + data/nix/tests/lang/eval-okay-float.nix + data/nix/tests/lang/eval-okay-fromjson.exp + data/nix/tests/lang/eval-okay-fromjson.nix + data/nix/tests/lang/eval-okay-fromTOML.exp + data/nix/tests/lang/eval-okay-fromTOML.nix + data/nix/tests/lang/eval-okay-functionargs.exp.xml + data/nix/tests/lang/eval-okay-functionargs.nix + data/nix/tests/lang/eval-okay-getattrpos.exp + data/nix/tests/lang/eval-okay-getattrpos.nix + data/nix/tests/lang/eval-okay-getattrpos-undefined.exp + data/nix/tests/lang/eval-okay-getattrpos-undefined.nix + data/nix/tests/lang/eval-okay-getenv.exp + data/nix/tests/lang/eval-okay-getenv.nix + data/nix/tests/lang/eval-okay-hash.exp + data/nix/tests/lang/eval-okay-hashfile.exp + data/nix/tests/lang/eval-okay-hashfile.nix + data/nix/tests/lang/eval-okay-hashstring.exp + data/nix/tests/lang/eval-okay-hashstring.nix + data/nix/tests/lang/eval-okay-if.exp + data/nix/tests/lang/eval-okay-if.nix + data/nix/tests/lang/eval-okay-import.exp + data/nix/tests/lang/eval-okay-import.nix + data/nix/tests/lang/eval-okay-ind-string.exp + data/nix/tests/lang/eval-okay-ind-string.nix + data/nix/tests/lang/eval-okay-let.exp + data/nix/tests/lang/eval-okay-let.nix + data/nix/tests/lang/eval-okay-list.exp + data/nix/tests/lang/eval-okay-list.nix + data/nix/tests/lang/eval-okay-listtoattrs.exp + data/nix/tests/lang/eval-okay-listtoattrs.nix + data/nix/tests/lang/eval-okay-logic.exp + data/nix/tests/lang/eval-okay-logic.nix + data/nix/tests/lang/eval-okay-mapattrs.exp + data/nix/tests/lang/eval-okay-mapattrs.nix + data/nix/tests/lang/eval-okay-map.exp + data/nix/tests/lang/eval-okay-map.nix + data/nix/tests/lang/eval-okay-nested-with.exp + data/nix/tests/lang/eval-okay-nested-with.nix + data/nix/tests/lang/eval-okay-new-let.exp + data/nix/tests/lang/eval-okay-new-let.nix + data/nix/tests/lang/eval-okay-null-dynamic-attrs.exp + data/nix/tests/lang/eval-okay-null-dynamic-attrs.nix + data/nix/tests/lang/eval-okay-overrides.exp + data/nix/tests/lang/eval-okay-overrides.nix + data/nix/tests/lang/eval-okay-partition.exp + data/nix/tests/lang/eval-okay-partition.nix + data/nix/tests/lang/eval-okay-pathexists.exp + data/nix/tests/lang/eval-okay-pathexists.nix + data/nix/tests/lang/eval-okay-path.nix + data/nix/tests/lang/eval-okay-patterns.exp + data/nix/tests/lang/eval-okay-patterns.nix + data/nix/tests/lang/eval-okay-readDir.exp + data/nix/tests/lang/eval-okay-readDir.nix + data/nix/tests/lang/eval-okay-readfile.exp + data/nix/tests/lang/eval-okay-readfile.nix + data/nix/tests/lang/eval-okay-redefine-builtin.exp + data/nix/tests/lang/eval-okay-redefine-builtin.nix + data/nix/tests/lang/eval-okay-regex-match.exp + data/nix/tests/lang/eval-okay-regex-match.nix + data/nix/tests/lang/eval-okay-regex-split.exp + data/nix/tests/lang/eval-okay-regex-split.nix + data/nix/tests/lang/eval-okay-remove.exp + data/nix/tests/lang/eval-okay-remove.nix + data/nix/tests/lang/eval-okay-replacestrings.exp + data/nix/tests/lang/eval-okay-replacestrings.nix + data/nix/tests/lang/eval-okay-scope-1.exp + data/nix/tests/lang/eval-okay-scope-1.nix + data/nix/tests/lang/eval-okay-scope-2.exp + data/nix/tests/lang/eval-okay-scope-2.nix + data/nix/tests/lang/eval-okay-scope-3.exp + data/nix/tests/lang/eval-okay-scope-3.nix + data/nix/tests/lang/eval-okay-scope-4.exp + data/nix/tests/lang/eval-okay-scope-4.nix + data/nix/tests/lang/eval-okay-scope-6.exp + data/nix/tests/lang/eval-okay-scope-6.nix + data/nix/tests/lang/eval-okay-scope-7.exp + data/nix/tests/lang/eval-okay-scope-7.nix + data/nix/tests/lang/eval-okay-search-path.exp + data/nix/tests/lang/eval-okay-search-path.flags + data/nix/tests/lang/eval-okay-search-path.nix + data/nix/tests/lang/eval-okay-seq.exp + data/nix/tests/lang/eval-okay-seq.nix + data/nix/tests/lang/eval-okay-sort.exp + data/nix/tests/lang/eval-okay-sort.nix + data/nix/tests/lang/eval-okay-splitversion.exp + data/nix/tests/lang/eval-okay-splitversion.nix + data/nix/tests/lang/eval-okay-string.exp + data/nix/tests/lang/eval-okay-string.nix + data/nix/tests/lang/eval-okay-strings-as-attrs-names.exp + data/nix/tests/lang/eval-okay-strings-as-attrs-names.nix + data/nix/tests/lang/eval-okay-substring.exp + data/nix/tests/lang/eval-okay-substring.nix + data/nix/tests/lang/eval-okay-tail-call-1.exp-disabled + data/nix/tests/lang/eval-okay-tail-call-1.nix + data/nix/tests/lang/eval-okay-tojson.exp + data/nix/tests/lang/eval-okay-tojson.nix + data/nix/tests/lang/eval-okay-toxml2.exp + data/nix/tests/lang/eval-okay-toxml2.nix + data/nix/tests/lang/eval-okay-toxml.exp + data/nix/tests/lang/eval-okay-toxml.nix + data/nix/tests/lang/eval-okay-tryeval.exp + data/nix/tests/lang/eval-okay-tryeval.nix + data/nix/tests/lang/eval-okay-types.exp + data/nix/tests/lang/eval-okay-types.nix + data/nix/tests/lang/eval-okay-versions.exp + data/nix/tests/lang/eval-okay-versions.nix + data/nix/tests/lang/eval-okay-with.exp + data/nix/tests/lang/eval-okay-with.nix + data/nix/tests/lang/eval-okay-xml.exp.xml + data/nix/tests/lang/eval-okay-xml.nix + data/nix/tests/lang/imported2.nix + data/nix/tests/lang/imported.nix + data/nix/tests/lang/lib.nix + data/nix/tests/lang/parse-fail-dup-attrs-1.nix + data/nix/tests/lang/parse-fail-dup-attrs-2.nix + data/nix/tests/lang/parse-fail-dup-attrs-3.nix + data/nix/tests/lang/parse-fail-dup-attrs-4.nix + data/nix/tests/lang/parse-fail-dup-attrs-7.nix + data/nix/tests/lang/parse-fail-dup-formals.nix + data/nix/tests/lang/parse-fail-mixed-nested-attrs1.nix + data/nix/tests/lang/parse-fail-mixed-nested-attrs2.nix + data/nix/tests/lang/parse-fail-patterns-1.nix + data/nix/tests/lang/parse-fail-regression-20060610.nix + data/nix/tests/lang/parse-fail-uft8.nix + data/nix/tests/lang/parse-fail-undef-var-2.nix + data/nix/tests/lang/parse-fail-undef-var.nix + data/nix/tests/lang/parse-okay-1.nix + data/nix/tests/lang/parse-okay-crlf.nix + data/nix/tests/lang/parse-okay-dup-attrs-5.nix + data/nix/tests/lang/parse-okay-dup-attrs-6.nix + data/nix/tests/lang/parse-okay-mixed-nested-attrs-1.nix + data/nix/tests/lang/parse-okay-mixed-nested-attrs-2.nix + data/nix/tests/lang/parse-okay-mixed-nested-attrs-3.nix + data/nix/tests/lang/parse-okay-regression-20041027.nix + data/nix/tests/lang/parse-okay-regression-751.nix + data/nix/tests/lang/parse-okay-subversion.nix + data/nix/tests/lang/parse-okay-url.nix + data/nix/tests/lang/readDir/bar + data/nix/tests/lang/readDir/foo/git-hates-directories + data/nix/tests/local.mk + data/nixpkgs-all-packages.nix + data/let-comments.nix + data/let-comments-multiline.nix + data/simple-pretty.nix + data/simple.nix + data/nixpkgs-all-packages-pretty.nix + data/let.nix + tests/eval-compare/builtins.appendContext.nix + tests/eval-compare/builtins.eq-bottom-00.nix + tests/eval-compare/builtins.fetchurl-01.nix + tests/eval-compare/builtins.fromJSON-01.nix + tests/eval-compare/builtins.getContext.nix + tests/eval-compare/builtins.lessThan-01.nix + tests/eval-compare/builtins.mapAttrs-01.nix + tests/eval-compare/builtins.pathExists.nix + tests/eval-compare/builtins.replaceStrings-01.nix + tests/eval-compare/builtins.split-01.nix + tests/eval-compare/builtins.split-02.nix + tests/eval-compare/builtins.split-03.nix + tests/eval-compare/builtins.split-04.nix + tests/eval-compare/builtins.string.store.nix + tests/eval-compare/builtins.toJSON.nix + tests/eval-compare/current-system.nix + tests/eval-compare/ellipsis.nix + tests/eval-compare/ind-string-01.nix + tests/eval-compare/ind-string-02.nix + tests/eval-compare/ind-string-03.nix + tests/eval-compare/ind-string-04.nix + tests/eval-compare/ind-string-05.nix + tests/eval-compare/ind-string-06.nix + tests/eval-compare/ind-string-07.nix + tests/eval-compare/ind-string-08.nix + tests/eval-compare/ind-string-09.nix + tests/eval-compare/ind-string-10.nix + tests/eval-compare/ind-string-11.nix + tests/eval-compare/ind-string-12.nix + tests/eval-compare/ind-string-13.nix + tests/eval-compare/ind-string-14.nix + tests/eval-compare/ind-string-15.nix + tests/eval-compare/ind-string-16.nix + tests/eval-compare/ind-string-17.nix + tests/eval-compare/paths-01.nix + tests/eval-compare/placeholder.nix + tests/files/attrs.nix + tests/files/callLibs.nix + tests/files/eighty.nix + tests/files/file.nix + tests/files/file2.nix + tests/files/findFile.nix + tests/files/force.nix + tests/files/goodbye.nix + tests/files/hello.nix + tests/files/hello2.nix + tests/files/if-then.nix + tests/files/lint.nix + tests/files/loop.nix + tests/files/test.nix + tests/files/with.nix source-repository head type: git @@ -341,58 +341,58 @@ flag profiling library exposed-modules: - Nix - Nix.Atoms - Nix.Builtins - Nix.Cache - Nix.Cited - Nix.Cited.Basic - Nix.Context - Nix.Convert - Nix.Effects - Nix.Effects.Basic - Nix.Effects.Derivation - Nix.Eval - Nix.Exec - Nix.Expr - Nix.Expr.Shorthands - Nix.Expr.Strings - Nix.Expr.Types - Nix.Expr.Types.Annotated - Nix.Frames - Nix.Fresh - Nix.Fresh.Basic - Nix.Json - Nix.Lint - Nix.Normal - Nix.Options - Nix.Parser - Nix.Pretty - Nix.Reduce - Nix.Render - Nix.Render.Frame - Nix.Scope - Nix.Standard - Nix.String - Nix.String.Coerce - Nix.TH - Nix.Thunk - Nix.Thunk.Basic - Nix.Type.Assumption - Nix.Type.Env - Nix.Type.Infer - Nix.Type.Type - Nix.Utils - Nix.Utils.Fix1 - Nix.Value - Nix.Value.Equal - Nix.Value.Monad - Nix.Var - Nix.XML + Nix + Nix.Atoms + Nix.Builtins + Nix.Cache + Nix.Cited + Nix.Cited.Basic + Nix.Context + Nix.Convert + Nix.Effects + Nix.Effects.Basic + Nix.Effects.Derivation + Nix.Eval + Nix.Exec + Nix.Expr + Nix.Expr.Shorthands + Nix.Expr.Strings + Nix.Expr.Types + Nix.Expr.Types.Annotated + Nix.Frames + Nix.Fresh + Nix.Fresh.Basic + Nix.Json + Nix.Lint + Nix.Normal + Nix.Options + Nix.Parser + Nix.Pretty + Nix.Reduce + Nix.Render + Nix.Render.Frame + Nix.Scope + Nix.Standard + Nix.String + Nix.String.Coerce + Nix.TH + Nix.Thunk + Nix.Thunk.Basic + Nix.Type.Assumption + Nix.Type.Env + Nix.Type.Infer + Nix.Type.Type + Nix.Utils + Nix.Utils.Fix1 + Nix.Value + Nix.Value.Equal + Nix.Value.Monad + Nix.Var + Nix.XML other-modules: - Paths_hnix + Paths_hnix hs-source-dirs: - src + src ghc-options: -Wall -fprint-potential-instances build-depends: aeson >= 1.4.2 && < 1.6 @@ -454,7 +454,7 @@ library ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -O3 if !impl(ghcjs) exposed-modules: - Nix.Options.Parser + Nix.Options.Parser build-depends: base16-bytestring >= 0.1.1 && < 1.1 , pretty-show >= 1.9.5 && < 1.11 @@ -465,15 +465,13 @@ library default-language: Haskell2010 executable hnix - default-extensions: - ApplicativeDo + hs-source-dirs: + main main-is: Main.hs other-modules: - Repl - Paths_hnix - hs-source-dirs: - main ghc-options: -Wall -rtsopts + Repl + Paths_hnix build-depends: aeson , base @@ -516,16 +514,16 @@ test-suite hnix-tests type: exitcode-stdio-1.0 main-is: Main.hs other-modules: - EvalTests - NixLanguageTests - ParserTests - PrettyParseTests - PrettyTests - ReduceExprTests - TestCommon - Paths_hnix + EvalTests + NixLanguageTests + ParserTests + PrettyParseTests + PrettyTests + ReduceExprTests + TestCommon + Paths_hnix hs-source-dirs: - tests + tests ghc-options: -Wall -threaded build-depends: Diff @@ -572,10 +570,10 @@ benchmark hnix-benchmarks type: exitcode-stdio-1.0 main-is: Main.hs other-modules: - ParserBench - Paths_hnix + ParserBench + Paths_hnix hs-source-dirs: - benchmarks + benchmarks ghc-options: -Wall build-depends: base From 749c64373f9629603dd9558d56466b27e1ecfe09 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 14:53:54 +0200 Subject: [PATCH 22/30] cabal: hnix: disable default -rtsopts --- hnix.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hnix.cabal b/hnix.cabal index 0e1552dc9..adcc71571 100644 --- a/hnix.cabal +++ b/hnix.cabal @@ -469,9 +469,9 @@ executable hnix main main-is: Main.hs other-modules: - ghc-options: -Wall -rtsopts Repl Paths_hnix + ghc-options: -Wall build-depends: aeson , base From d8898eadd4559f95439ef61a85660dcdcc2907b7 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 15:35:58 +0200 Subject: [PATCH 23/30] Utils: loebM: function is used much, optimization It can be inlined. It also appears just 2 times in the code, but in Eval code. --- src/Nix/Utils.hs | 8 +++++--- src/Nix/Utils/Fix1.hs | 23 +++++++++++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/Nix/Utils.hs b/src/Nix/Utils.hs index 1ba9006e7..1149c86a9 100644 --- a/src/Nix/Utils.hs +++ b/src/Nix/Utils.hs @@ -64,17 +64,19 @@ type Transform f a = (Fix f -> a) -> Fix f -> a (<&>) :: Functor f => f a -> (a -> c) -> f c (<&>) = flip (<$>) -{-# inline (<&>)#-} +{-# inline (<&>) #-} (??) :: Functor f => f (a -> b) -> a -> f b fab ?? a = fmap ($ a) fab -{-# inline (??)#-} +{-# inline (??) #-} loeb :: Functor f => f (f a -> a) -> f a loeb x = go where go = fmap ($ go) x loebM :: (MonadFix m, Traversable t) => t (t a -> m a) -> m (t a) -loebM f = mfix $ \a -> traverse ($ a) f +-- Sectioning here insures optimization happening. +loebM f = mfix $ \a -> (`traverse` f) ($ a) +{-# inline loebM #-} para :: Functor f => (f (Fix f, a) -> a) -> Fix f -> a para f = f . fmap (id &&& para f) . unFix diff --git a/src/Nix/Utils/Fix1.hs b/src/Nix/Utils/Fix1.hs index 921187c9f..1b2e2fe11 100644 --- a/src/Nix/Utils/Fix1.hs +++ b/src/Nix/Utils/Fix1.hs @@ -19,9 +19,11 @@ import Control.Monad ( MonadPlus ) import Control.Monad.Fix ( MonadFix ) import Control.Monad.IO.Class ( MonadIO ) import Control.Monad.Trans.Class ( MonadTrans - , lift ) + , lift + ) import Control.Monad.Ref ( MonadAtomicRef(..) - , MonadRef(..) ) + , MonadRef(..) + ) import Control.Monad.Catch ( MonadCatch , MonadMask , MonadThrow ) @@ -90,16 +92,25 @@ deriving instance MonadState s (t (Fix1T t m) m) type MonadFix1T t m = (MonadTrans (Fix1T t), Monad (t (Fix1T t m) m)) -instance (MonadFix1T t m, MonadRef m) - => MonadRef (Fix1T t m) where +instance + ( MonadFix1T t m + , MonadRef m + ) + => MonadRef (Fix1T t m) + where type Ref (Fix1T t m) = Ref m + newRef = lift . newRef readRef = lift . readRef writeRef r = lift . writeRef r -instance (MonadFix1T t m, MonadAtomicRef m) - => MonadAtomicRef (Fix1T t m) where +instance + ( MonadFix1T t m + , MonadAtomicRef m + ) + => MonadAtomicRef (Fix1T t m) + where atomicModifyRef r = lift . atomicModifyRef r {- From 919e8ecadbe85f006a6e93aafbea68075eabc38b Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 17:47:01 +0200 Subject: [PATCH 24/30] cabal: stopping GHC 8.4 support https://github.com/haskell-nix/hnix/issues/885 --- .github/workflows/Cabal-Linux.yml | 2 +- .github/workflows/On-Release-Cabal-Linux.yml | 2 +- hnix.cabal | 2 +- src/Nix/Reduce.hs | 7 ++++++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/Cabal-Linux.yml b/.github/workflows/Cabal-Linux.yml index 606adc371..768319ba1 100644 --- a/.github/workflows/Cabal-Linux.yml +++ b/.github/workflows/Cabal-Linux.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ghc: [ "8.10", "8.4" ] + ghc: [ "8.10", "8.6" ] steps: - name: "Git checkout" diff --git a/.github/workflows/On-Release-Cabal-Linux.yml b/.github/workflows/On-Release-Cabal-Linux.yml index b59b6a5af..330e12c5c 100644 --- a/.github/workflows/On-Release-Cabal-Linux.yml +++ b/.github/workflows/On-Release-Cabal-Linux.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: # Since CI by default tests boundary GHCs, test middle versions of GHCs - ghc: [ "8.8", "8.6"] + ghc: [ "8.8" ] steps: - name: "Git checkout" uses: actions/checkout@v2 diff --git a/hnix.cabal b/hnix.cabal index adcc71571..2dfcc238a 100644 --- a/hnix.cabal +++ b/hnix.cabal @@ -397,7 +397,7 @@ library build-depends: aeson >= 1.4.2 && < 1.6 , array >= 0.4 && < 0.6 - , base >= 4.11 && < 5 + , base >= 4.12 && < 5 , binary >= 0.8.5 && < 0.9 , bytestring >= 0.10.8 && < 0.11 , comonad >= 5.0.4 && < 5.1 diff --git a/src/Nix/Reduce.hs b/src/Nix/Reduce.hs index 7c1d226a9..1fd36a42f 100644 --- a/src/Nix/Reduce.hs +++ b/src/Nix/Reduce.hs @@ -40,7 +40,12 @@ import Control.Monad.Fail import Control.Monad.Fix import Control.Monad.IO.Class import Control.Monad.Reader -import Control.Monad.State.Strict +import Control.Monad.State.Strict ( MonadState + , StateT + , gets + , modify + , evalStateT + ) import Data.Bifunctor ( first ) import Data.Fix ( Fix(..), foldFix, foldFixM ) import Data.HashMap.Lazy ( HashMap ) From 2f9d12e1b7bba5db4dc093f9020ae34590fd3b20 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Sun, 14 Mar 2021 23:21:06 +0200 Subject: [PATCH 25/30] Value: fx MonadFail for GHC 8.6 --- src/Nix/Reduce.hs | 52 +++++++++++++++++++++++++++++++++++------------ src/Nix/Utils.hs | 3 +++ src/Nix/Value.hs | 4 ++++ 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/Nix/Reduce.hs b/src/Nix/Reduce.hs index 1fd36a42f..a7750fdc9 100644 --- a/src/Nix/Reduce.hs +++ b/src/Nix/Reduce.hs @@ -32,14 +32,20 @@ module Nix.Reduce import Control.Applicative import Control.Arrow ( second ) -import Control.Monad -import Control.Monad.Catch +import Control.Monad ( MonadPlus + , join + ) +import Control.Monad.Catch ( MonadCatch(catch) ) #if !MIN_VERSION_base(4,13,0) +import Prelude hiding ( fail ) import Control.Monad.Fail #endif -import Control.Monad.Fix -import Control.Monad.IO.Class -import Control.Monad.Reader +import Control.Monad.Fix ( MonadFix ) +import Control.Monad.IO.Class ( MonadIO(liftIO) ) +import Control.Monad.Reader ( MonadReader(local) + , ReaderT(runReaderT) + , asks + ) import Control.Monad.State.Strict ( MonadState , StateT , gets @@ -47,11 +53,18 @@ import Control.Monad.State.Strict ( MonadState , evalStateT ) import Data.Bifunctor ( first ) -import Data.Fix ( Fix(..), foldFix, foldFixM ) +import Data.Fix ( Fix(..) + , foldFix + , foldFixM + ) import Data.HashMap.Lazy ( HashMap ) import qualified Data.HashMap.Lazy as M import qualified Data.HashMap.Strict as MS -import Data.IORef +import Data.IORef ( IORef + , newIORef + , readIORef + , writeIORef + ) import Data.List.NonEmpty ( NonEmpty(..) ) import qualified Data.List.NonEmpty as NE import Data.Maybe ( fromMaybe @@ -74,12 +87,25 @@ import System.Directory import System.FilePath newtype Reducer m a = Reducer - { runReducer :: ReaderT (Maybe FilePath, Scopes (Reducer m) NExprLoc) - (StateT (HashMap FilePath NExprLoc, MS.HashMap Text Text) m) a } - deriving (Functor, Applicative, Alternative, Monad, MonadPlus, - MonadFix, MonadIO, MonadFail, - MonadReader (Maybe FilePath, Scopes (Reducer m) NExprLoc), - MonadState (HashMap FilePath NExprLoc, MS.HashMap Text Text)) + { runReducer :: + ReaderT + ( Maybe FilePath + , Scopes (Reducer m) NExprLoc + ) + ( StateT + ( HashMap FilePath NExprLoc + , MS.HashMap Text Text + ) + m + ) + a + } + deriving + ( Functor, Applicative, Alternative + , Monad, MonadPlus, MonadFix, MonadIO, MonadFail + , MonadReader (Maybe FilePath, Scopes (Reducer m) NExprLoc) + , MonadState (HashMap FilePath NExprLoc, MS.HashMap Text Text) + ) staticImport :: forall m diff --git a/src/Nix/Utils.hs b/src/Nix/Utils.hs index 1149c86a9..df2cd31ce 100644 --- a/src/Nix/Utils.hs +++ b/src/Nix/Utils.hs @@ -40,6 +40,9 @@ import Prelude as X hiding ( putStr , putStrLn , print +#if !MIN_VERSION_base(4,13,0) + , fail +#endif ) trace :: String -> a -> a trace = const id diff --git a/src/Nix/Value.hs b/src/Nix/Value.hs index 6d539afde..0540c859d 100644 --- a/src/Nix/Value.hs +++ b/src/Nix/Value.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE ConstraintKinds #-} @@ -34,6 +35,9 @@ import Control.Monad.Free ( Free(..) import Control.Monad.Trans.Class ( MonadTrans , lift ) +#if !MIN_VERSION_base(4,13,0) +import Control.Monad.Fail +#endif import qualified Data.Aeson as Aeson import Data.Functor.Classes ( Show1 , liftShowsPrec From df119a7e62ff7f66f6aa5424848f3a8af9094a69 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Mon, 15 Mar 2021 00:23:18 +0200 Subject: [PATCH 26/30] Thunk.Basic: refactoring the thunk lock/unlock procedure --- src/Nix/Thunk/Basic.hs | 63 ++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/src/Nix/Thunk/Basic.hs b/src/Nix/Thunk/Basic.hs index 20eeb7e43..f548f1d82 100644 --- a/src/Nix/Thunk/Basic.hs +++ b/src/Nix/Thunk/Basic.hs @@ -32,11 +32,25 @@ import Nix.Utils ( bool data Deferred m v = Computed v | Deferred (m v) deriving (Functor, Foldable, Traversable) +-- | It is a reference (@ref-tf: Ref m@), and as such also holds @Bool@ lock. +type ThunkRef m = (Var m Bool) + +-- | Reference (@ref-tf: Ref m v@) to a value that thunk holds. +type ThunkValueRef m v = Var m (Deferred m v) + +-- | @ref-tf@ lock instruction for @Ref m@ (@ThunkRef@). +lock :: Bool -> (Bool, Bool) +lock = (True, ) + +-- | @ref-tf@ unlock instruction for @Ref m@ (@ThunkRef@). +unlock :: Bool -> (Bool, Bool) +unlock = (False, ) + -- * Data type for thunks: @NThunkF@ -- | The type of very basic thunks data NThunkF m v - = Thunk (ThunkId m) (Var m Bool) (Var m (Deferred m v)) + = Thunk (ThunkId m) (ThunkRef m) (ThunkValueRef m v) instance (Eq v, Eq (ThunkId m)) => Eq (NThunkF m v) where Thunk x _ _ == Thunk y _ _ = x == y @@ -52,16 +66,19 @@ type MonadBasicThunk m = (MonadThunkId m, MonadVar m) instance (MonadBasicThunk m, MonadCatch m) => MonadThunk (NThunkF m v) m v where + -- | Return thunk ID thunkId :: NThunkF m v -> ThunkId m thunkId (Thunk n _ _) = n + -- | Create new thunk thunk :: m v -> m (NThunkF m v) thunk action = do freshThunkId <- freshId Thunk freshThunkId <$> newVar False <*> newVar (Deferred action) - -- | Non-blocking query + -- | Non-blocking query, return value if @Computed@, + -- return first argument otherwise. queryM :: m v -> NThunkF m v -> m v queryM n (Thunk _ _ ref) = do @@ -88,33 +105,34 @@ instance (MonadBasicThunk m, MonadCatch m) -- *** United body of `force*` +-- | If @m v@ is @Computed@ - returns is forceMain :: ( MonadBasicThunk m , MonadCatch m ) => NThunkF m v -> m v -forceMain (Thunk n active ref) = +forceMain (Thunk n thunkRef thunkValRef) = do deferred pure (\ action -> do - lockThunk <- atomicModifyVar active (True, ) + lockedIt <- atomicModifyVar thunkRef lock bool (throwM $ ThunkLoop $ show n) (do v <- catch action $ \(e :: SomeException) -> do - _ <- atomicModifyVar active (False, ) + _unlockedIt <- atomicModifyVar thunkRef unlock throwM e - writeVar ref (Computed v) - _unlockThunk <- atomicModifyVar active (False, ) + writeVar thunkValRef (Computed v) + _unlockedIt <- atomicModifyVar thunkRef unlock pure v ) - (not lockThunk) + (not lockedIt) ) - =<< readVar ref + =<< readVar thunkValRef {-# inline forceMain #-} -- it is big function, but internal, and look at its use. @@ -129,22 +147,23 @@ instance (MonadBasicThunk m, MonadCatch m) -> m r -> NThunkF m v -> m r - queryMF k n (Thunk _ active ref) = + queryMF k n (Thunk _ thunkRef thunkValRef) = do - thunkIsAvaliable <- not <$> atomicModifyVar active (True, ) + lockedIt <- atomicModifyVar thunkRef (True, ) bool n go - thunkIsAvaliable + (not lockedIt) where go = do - eres <- readVar ref + eres <- readVar thunkValRef res <- - case eres of - Computed v -> k v - Deferred _mv -> n - _ <- atomicModifyVar active (False, ) + deferred + k + (const n) + eres + _unlockedIt <- atomicModifyVar thunkRef (False, ) pure res forceF @@ -165,10 +184,12 @@ instance (MonadBasicThunk m, MonadCatch m) -> m (NThunkF m v) furtherF k t@(Thunk _ _ ref) = do - _ <- atomicModifyVar ref $ - \x -> case x of - Computed _ -> (x, x) - Deferred d -> (Deferred (k d), x) + _modifiedIt <- atomicModifyVar ref $ + \x -> + deferred + (const (x, x)) + (\ d -> (Deferred (k d), x)) + x pure t From ea18e59049acab0bdc4cc089756945e23bd3f6d3 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Mon, 15 Mar 2021 00:47:52 +0200 Subject: [PATCH 27/30] Thunk.Basic: more refactor for locking mechanism; module organization --- main/Repl.hs | 6 ++--- src/Nix/Thunk/Basic.hs | 61 +++++++++++++++++++++++++++++++----------- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/main/Repl.hs b/main/Repl.hs index 59c174e79..65b23b65a 100644 --- a/main/Repl.hs +++ b/main/Repl.hs @@ -184,9 +184,9 @@ initState mIni = do evalText :: (MonadNix e t f m) => Text -> m (NValue t f m) evalText expr = either - (\ e -> fail $ "Impossible happened: Unable to parse expression - '" <> Text.unpack expr <> "' fail was " <> show e) - (\ e -> do evalExprLoc e) - (parseNixTextLoc expr) + (\ e -> fail $ "Impossible happened: Unable to parse expression - '" <> Text.unpack expr <> "' fail was " <> show e) + (\ e -> do evalExprLoc e) + (parseNixTextLoc expr) type Repl e t f m = HaskelineT (StateT (IState t f m) m) diff --git a/src/Nix/Thunk/Basic.hs b/src/Nix/Thunk/Basic.hs index f548f1d82..2d077873b 100644 --- a/src/Nix/Thunk/Basic.hs +++ b/src/Nix/Thunk/Basic.hs @@ -29,13 +29,32 @@ import Nix.Utils ( bool , dup ) + +-- * Data type @Deferred@ + +-- | Data is computed OR in a lazy thunk state which +-- is still not evaluated. data Deferred m v = Computed v | Deferred (m v) deriving (Functor, Foldable, Traversable) --- | It is a reference (@ref-tf: Ref m@), and as such also holds @Bool@ lock. +-- ** Utils + +-- | @Deferred (Computed|Deferred)@ analog of @either@. +deferred :: (v -> b) -> (m v -> b) -> Deferred m v -> b +deferred f1 f2 def = + case def of + Computed v -> f1 v + Deferred action -> f2 action +{-# inline deferred #-} + + +-- * Thunk references & lock handling + +-- | Thunk resource reference (@ref-tf: Ref m@), and as such also also hold +-- a @Bool@ lock flag. type ThunkRef m = (Var m Bool) --- | Reference (@ref-tf: Ref m v@) to a value that thunk holds. +-- | Reference (@ref-tf: Ref m v@) to a value that the thunk holds. type ThunkValueRef m v = Var m (Deferred m v) -- | @ref-tf@ lock instruction for @Ref m@ (@ThunkRef@). @@ -46,6 +65,25 @@ lock = (True, ) unlock :: Bool -> (Bool, Bool) unlock = (False, ) +-- | Takes @ref-tf: Ref m@ reference, returns Bool result of the operation. +lockThunk + :: ( MonadBasicThunk m + , MonadCatch m + ) + => ThunkRef m + -> m Bool +lockThunk r = atomicModifyVar r lock + +-- | Takes @ref-tf: Ref m@ reference, returns Bool result of the operation. +unlockThunk + :: ( MonadBasicThunk m + , MonadCatch m + ) + => ThunkRef m + -> m Bool +unlockThunk r = atomicModifyVar r unlock + + -- * Data type for thunks: @NThunkF@ -- | The type of very basic thunks @@ -118,16 +156,16 @@ forceMain (Thunk n thunkRef thunkValRef) = pure (\ action -> do - lockedIt <- atomicModifyVar thunkRef lock + lockedIt <- lockThunk thunkRef bool (throwM $ ThunkLoop $ show n) (do v <- catch action $ \(e :: SomeException) -> do - _unlockedIt <- atomicModifyVar thunkRef unlock + _unlockedIt <- unlockThunk thunkRef throwM e writeVar thunkValRef (Computed v) - _unlockedIt <- atomicModifyVar thunkRef unlock + _unlockedIt <- unlockThunk thunkRef pure v ) (not lockedIt) @@ -149,7 +187,7 @@ instance (MonadBasicThunk m, MonadCatch m) -> m r queryMF k n (Thunk _ thunkRef thunkValRef) = do - lockedIt <- atomicModifyVar thunkRef (True, ) + lockedIt <- lockThunk thunkRef bool n go @@ -163,7 +201,7 @@ instance (MonadBasicThunk m, MonadCatch m) k (const n) eres - _unlockedIt <- atomicModifyVar thunkRef (False, ) + _unlockedIt <- unlockThunk thunkRef pure res forceF @@ -193,12 +231,3 @@ instance (MonadBasicThunk m, MonadCatch m) pure t --- ** Utils - --- | @either@ for @Deferred@ data type -deferred :: (v -> b) -> (m v -> b) -> Deferred m v -> b -deferred f1 f2 def = - case def of - Computed v -> f1 v - Deferred action -> f2 action -{-# inline deferred #-} From 71100407faa8bb63047456783b972adf32cd3526 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Mon, 15 Mar 2021 02:00:57 +0200 Subject: [PATCH 28/30] Reduce: refactor --- src/Nix/Reduce.hs | 103 ++++++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 41 deletions(-) diff --git a/src/Nix/Reduce.hs b/src/Nix/Reduce.hs index a7750fdc9..7c60594c3 100644 --- a/src/Nix/Reduce.hs +++ b/src/Nix/Reduce.hs @@ -185,12 +185,14 @@ reduce (NSym_ ann var) = fromMaybe (Fix (NSym_ ann var)) <$> lookupVar var -- | Reduce binary and integer negation. -reduce (NUnary_ uann op arg) = arg >>= \x -> case (op, x) of - (NNeg, Fix (NConstant_ cann (NInt n))) -> - pure $ Fix $ NConstant_ cann (NInt (negate n)) - (NNot, Fix (NConstant_ cann (NBool b))) -> - pure $ Fix $ NConstant_ cann (NBool (not b)) - _ -> pure $ Fix $ NUnary_ uann op x +reduce (NUnary_ uann op arg) = + do + x <- arg + pure $ Fix $ + case (op, x) of + (NNeg, Fix (NConstant_ cann (NInt n))) -> NConstant_ cann (NInt (negate n)) + (NNot, Fix (NConstant_ cann (NBool b))) -> NConstant_ cann (NBool (not b)) + _ -> NUnary_ uann op x -- | Reduce function applications. -- @@ -199,25 +201,31 @@ reduce (NUnary_ uann op arg) = arg >>= \x -> case (op, x) of -- * Reduce a lambda function by adding its name to the local -- scope and recursively reducing its body. reduce (NBinary_ bann NApp fun arg) = fun >>= \case - f@(Fix (NSym_ _ "import")) -> arg >>= \case - -- Fix (NEnvPath_ pann origPath) -> staticImport pann origPath - Fix (NLiteralPath_ pann origPath) -> staticImport pann origPath - v -> pure $ Fix $ NBinary_ bann NApp f v - - Fix (NAbs_ _ (Param name) body) -> do - x <- arg - pushScope (M.singleton name x) (foldFix reduce body) + f@(Fix (NSym_ _ "import")) -> + (\case + -- Fix (NEnvPath_ pann origPath) -> staticImport pann origPath + Fix (NLiteralPath_ pann origPath) -> staticImport pann origPath + v -> pure $ Fix $ NBinary_ bann NApp f v + ) =<< arg + + Fix (NAbs_ _ (Param name) body) -> + do + x <- arg + pushScope + (M.singleton name x) + (foldFix reduce body) f -> Fix . NBinary_ bann NApp f <$> arg -- | Reduce an integer addition to its result. -reduce (NBinary_ bann op larg rarg) = do - lval <- larg - rval <- rarg - case (op, lval, rval) of - (NPlus, Fix (NConstant_ ann (NInt x)), Fix (NConstant_ _ (NInt y))) -> - pure $ Fix (NConstant_ ann (NInt (x + y))) - _ -> pure $ Fix $ NBinary_ bann op lval rval +reduce (NBinary_ bann op larg rarg) = + do + lval <- larg + rval <- rarg + pure $ Fix $ + case (op, lval, rval) of + (NPlus, Fix (NConstant_ ann (NInt x)), Fix (NConstant_ _ (NInt y))) -> NConstant_ ann (NInt (x + y)) + _ -> NBinary_ bann op lval rval -- | Reduce a select on a Set by substituting the set to the selected value. -- @@ -235,7 +243,7 @@ reduce base@(NSelect_ _ _ attrs _) sId = Fix <$> sequence base -- The selection AttrPath is composed of StaticKeys. sAttrPath (StaticKey _ : xs) = sAttrPath xs - sAttrPath [] = True + sAttrPath [] = True sAttrPath _ = False -- Find appropriate bind in set's binds. findBind [] _ = Nothing @@ -322,22 +330,28 @@ reduce (NLet_ ann binds body) = -- | Reduce an if to the relevant path if -- the condition is a boolean constant. -reduce e@(NIf_ _ b t f) = b >>= \case - Fix (NConstant_ _ (NBool b')) -> if b' then t else f - _ -> Fix <$> sequence e +reduce e@(NIf_ _ b t f) = + (\case + Fix (NConstant_ _ (NBool b')) -> if b' then t else f + _ -> Fix <$> sequence e + ) =<< b -- | Reduce an assert atom to its encapsulated -- symbol if the assertion is a boolean constant. -reduce e@(NAssert_ _ b body) = b >>= \case - Fix (NConstant_ _ (NBool b')) | b' -> body - _ -> Fix <$> sequence e +reduce e@(NAssert_ _ b body) = + (\case + Fix (NConstant_ _ (NBool b')) | b' -> body + _ -> Fix <$> sequence e + ) =<< b reduce (NAbs_ ann params body) = do params' <- sequence params -- Make sure that variable definitions in scope do not override function -- arguments. - let args = case params' of - Param name -> M.singleton name (Fix (NSym_ ann name)) + let + args = + case params' of + Param name -> M.singleton name (Fix (NSym_ ann name)) ParamSet pset _ _ -> M.fromList $ fmap (\(k, _) -> (k, Fix (NSym_ ann k))) pset Fix . NAbs_ ann params' <$> pushScope args body @@ -346,7 +360,7 @@ reduce v = Fix <$> sequence v -- newtype FlaggedF f r = FlaggedF { flagged :: (IORef Bool, f r) } newtype FlaggedF f r = FlaggedF (IORef Bool, f r) - deriving (Functor, Foldable, Traversable) + deriving (Functor, Foldable, Traversable) instance Show (f r) => Show (FlaggedF f r) where show (FlaggedF (_, x)) = show x @@ -362,9 +376,16 @@ flagExprLoc = foldFixM $ \x -> do -- stripFlags = foldFix $ Fix . snd . flagged pruneTree :: MonadIO n => Options -> Flagged NExprLocF -> n (Maybe NExprLoc) -pruneTree opts = foldFixM $ \(FlaggedF (b, Compose x)) -> do - used <- liftIO $ readIORef b - pure $ if used then Fix . Compose <$> traverse prune x else Nothing +pruneTree opts = + foldFixM $ + \(FlaggedF (b, Compose x)) -> + do + used <- liftIO $ readIORef b + pure $ + bool + Nothing + (Fix . Compose <$> traverse prune x) + used where prune :: NExprF (Maybe NExprLoc) -> Maybe (NExprF NExprLoc) prune = \case @@ -389,7 +410,7 @@ pruneTree opts = foldFixM $ \(FlaggedF (b, Compose x)) -> do -- These are the only short-circuiting binary operators NBinary NAnd (Just (Fix (Compose (Ann _ larg)))) _ -> pure larg - NBinary NOr (Just (Fix (Compose (Ann _ larg)))) _ -> pure larg + NBinary NOr (Just (Fix (Compose (Ann _ larg)))) _ -> pure larg -- If the function was never called, it means its argument was in a -- thunk that was forced elsewhere. @@ -427,16 +448,16 @@ pruneTree opts = foldFixM $ \(FlaggedF (b, Compose x)) -> do :: Antiquoted Text (Maybe NExprLoc) -> Maybe (Antiquoted Text NExprLoc) pruneAntiquotedText (Plain v) = pure (Plain v) pruneAntiquotedText EscapedNewline = pure EscapedNewline - pruneAntiquotedText (Antiquoted Nothing ) = Nothing pruneAntiquotedText (Antiquoted (Just k)) = pure (Antiquoted k) + pruneAntiquotedText (Antiquoted Nothing ) = Nothing pruneAntiquoted :: Antiquoted (NString (Maybe NExprLoc)) (Maybe NExprLoc) -> Maybe (Antiquoted (NString NExprLoc) NExprLoc) pruneAntiquoted (Plain v) = pure (Plain (pruneString v)) pruneAntiquoted EscapedNewline = pure EscapedNewline - pruneAntiquoted (Antiquoted Nothing ) = Nothing pruneAntiquoted (Antiquoted (Just k)) = pure (Antiquoted k) + pruneAntiquoted (Antiquoted Nothing ) = Nothing pruneKeyName :: NKeyName (Maybe NExprLoc) -> NKeyName NExprLoc pruneKeyName (StaticKey n) = StaticKey n @@ -453,12 +474,12 @@ pruneTree opts = foldFixM $ \(FlaggedF (b, Compose x)) -> do | otherwise = ParamSet (fmap (second (fmap (fromMaybe nNull))) xs) b n pruneBinding :: Binding (Maybe NExprLoc) -> Maybe (Binding NExprLoc) - pruneBinding (NamedVar _ Nothing _) = Nothing - pruneBinding (NamedVar xs (Just x) pos) = + pruneBinding (NamedVar _ Nothing _) = Nothing + pruneBinding (NamedVar xs (Just x) pos) = pure (NamedVar (NE.map pruneKeyName xs) x pos) pruneBinding (Inherit _ [] _) = Nothing - pruneBinding (Inherit (join -> Nothing) _ _) = Nothing - pruneBinding (Inherit (join -> m) xs pos) = + pruneBinding (Inherit (join -> Nothing) _ _) = Nothing + pruneBinding (Inherit (join -> m) xs pos) = pure (Inherit m (fmap pruneKeyName xs) pos) reducingEvalExpr From f2f8fb326de20477aa1f4b2283a7ddc6f29641b2 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Mon, 15 Mar 2021 20:37:31 +0200 Subject: [PATCH 29/30] ChangeLog: add patch updates --- ChangeLog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 38d31cb82..515940a81 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -142,6 +142,11 @@ * [(link)](https://github.com/haskell-nix/hnix/pull/878/files) `Nix.Pretty`: `mkNixDoc`: got unflipped. * [(link)](https://github.com/haskell-nix/hnix/pull/886/commits/381b0e5df9cc620a25533ff1c84045a4ea37a833) `Nix.Value`: Data constructor for `NValue' t f m a` changed (`NValue -> NValue'`). + + * [(link)](https://github.com/haskell-nix/hnix/pull/884/files) `Nix.Parser`: `Parser`: Data type was equivalent to `Either`, so became a type synonim for `Either`. + + * [(link)](https://github.com/haskell-nix/hnix/pull/884/files) `Nix.Thunk.Basic`: `instance MonadThunk (NThunkF m v) m v`: `queryM`: implementation no longer blocks the thunk resource it only reads from. + * Additional: * [(link)](https://github.com/haskell-nix/hnix/commit/7e6cd97bf3288cb584241611fdb25bf85d7e0ba7) `cabal.project`: freed from the `cryptohash-sha512` override, Hackage trustees made a revision. From c30b164b23e18d2ea5ba10813b5e7d69c7fd9d69 Mon Sep 17 00:00:00 2001 From: Anton-Latukha Date: Mon, 15 Mar 2021 20:40:37 +0200 Subject: [PATCH 30/30] treewide: clean-up `ApplicativeDo` after it enabled by default --- src/Nix/Effects/Basic.hs | 1 - src/Nix/Exec.hs | 2 -- src/Nix/Lint.hs | 1 - src/Nix/Parser.hs | 1 - src/Nix/Reduce.hs | 1 - src/Nix/Thunk/Basic.hs | 1 - 6 files changed, 7 deletions(-) diff --git a/src/Nix/Effects/Basic.hs b/src/Nix/Effects/Basic.hs index d354376c3..c997e0f90 100644 --- a/src/Nix/Effects/Basic.hs +++ b/src/Nix/Effects/Basic.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE ApplicativeDo #-} {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-} diff --git a/src/Nix/Exec.hs b/src/Nix/Exec.hs index 8ce214618..7f00fd741 100644 --- a/src/Nix/Exec.hs +++ b/src/Nix/Exec.hs @@ -1,5 +1,4 @@ {-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE ApplicativeDo #-} {-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} @@ -14,7 +13,6 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE ApplicativeDo #-} {-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -fno-warn-name-shadowing #-} diff --git a/src/Nix/Lint.hs b/src/Nix/Lint.hs index e98374a09..57d8eb3fe 100644 --- a/src/Nix/Lint.hs +++ b/src/Nix/Lint.hs @@ -13,7 +13,6 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE InstanceSigs #-} -{-# LANGUAGE ApplicativeDo #-} {-# OPTIONS_GHC -fno-warn-name-shadowing #-} {-# OPTIONS_GHC -Wno-missing-methods #-} diff --git a/src/Nix/Parser.hs b/src/Nix/Parser.hs index fd915823b..84df7a2f1 100644 --- a/src/Nix/Parser.hs +++ b/src/Nix/Parser.hs @@ -4,7 +4,6 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ApplicativeDo #-} {-# OPTIONS_GHC -fno-warn-name-shadowing #-} {-# OPTIONS_GHC -Wno-missing-signatures #-} diff --git a/src/Nix/Reduce.hs b/src/Nix/Reduce.hs index 7c60594c3..f7b3ca155 100644 --- a/src/Nix/Reduce.hs +++ b/src/Nix/Reduce.hs @@ -1,6 +1,5 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE ApplicativeDo #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} diff --git a/src/Nix/Thunk/Basic.hs b/src/Nix/Thunk/Basic.hs index 2d077873b..a435f7708 100644 --- a/src/Nix/Thunk/Basic.hs +++ b/src/Nix/Thunk/Basic.hs @@ -8,7 +8,6 @@ {-# LANGUAGE TupleSections #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE InstanceSigs #-} -{-# LANGUAGE ApplicativeDo #-}