diff --git a/main/Main.hs b/main/Main.hs index 9bb4c408f..4339ceedf 100644 --- a/main/Main.hs +++ b/main/Main.hs @@ -126,8 +126,8 @@ main' opts@Options{..} = runWithBasicEffectsIO opts execContentsFilesOrRepl expr' <- liftIO $ reduceExpr mpath expr either (\ err -> errorWithoutStackTrace $ "Type error: " <> ppShow err) - (\ ty -> liftIO $ putStrLn $ "Type of expression: " <> ppShow - (fromJust $ Map.lookup "it" (coerce ty :: Map Text [Scheme])) + (\ ty -> liftIO $ putStrLn $ "Type of expression: " <> + ppShow (fromJust $ Map.lookup @VarName @[Scheme] "it" (coerce ty)) ) (HM.inferTop mempty [("it", stripAnnotation expr')]) @@ -234,7 +234,7 @@ main' opts@Options{..} = runWithBasicEffectsIO opts execContentsFilesOrRepl (pure . pure . Free) nv ) - (sortWith fst $ M.toList s) + (sortWith fst $ M.toList $ M.mapKeys coerce s) traverse_ (\ (k, mv) -> do diff --git a/main/Repl.hs b/main/Repl.hs index c3e655d82..2485c003c 100644 --- a/main/Repl.hs +++ b/main/Repl.hs @@ -281,11 +281,16 @@ printValue val = do browse :: (MonadNix e t f m, MonadIO m) => Text -> Repl e t f m () -browse _ = do - st <- get - for_ (Data.HashMap.Lazy.toList $ replCtx st) $ \(k, v) -> do - liftIO $ Text.putStr $ k <> " = " - printValue v +browse _ = + do + st <- get + traverse_ + (\(k, v) -> + do + liftIO $ Text.putStr $ coerce k <> " = " + printValue v + ) + (Data.HashMap.Lazy.toList $ replCtx st) -- | @:load@ command load @@ -313,7 +318,7 @@ typeof args = do maybe (exec False line) (pure . pure) - (Data.HashMap.Lazy.lookup line (replCtx st)) + (Data.HashMap.Lazy.lookup (coerce line) (replCtx st)) traverse_ printValueType mVal @@ -398,7 +403,7 @@ completeFunc reversedPrev word candidates ) ) - (Data.HashMap.Lazy.lookup var (replCtx s)) + (Data.HashMap.Lazy.lookup (coerce var) (replCtx s)) -- Builtins, context variables | otherwise = @@ -439,10 +444,10 @@ completeFunc reversedPrev word (("." <> f) <>) . algebraicComplete fs <=< demand ) - (Data.HashMap.Lazy.lookup f m) + (Data.HashMap.Lazy.lookup (coerce f) m) in case val of - NVSet xs _ -> withMap xs + NVSet xs _ -> withMap (Data.HashMap.Lazy.mapKeys coerce xs) _ -> stub -- | HelpOption inspired by Dhall Repl diff --git a/src/Nix.hs b/src/Nix.hs index 69111b519..745221e65 100644 --- a/src/Nix.hs +++ b/src/Nix.hs @@ -104,7 +104,7 @@ evaluateExpression evaluateExpression mpath evaluator handler expr = do opts :: Options <- asks $ view hasLens - args <- + (coerce -> args) <- (traverse . traverse) eval' $ (second parseArg <$> arg opts) @@ -137,23 +137,23 @@ processResult h val = do opts :: Options <- asks $ view hasLens maybe (h val) - (\ (Text.splitOn "." -> keys) -> processKeys keys val) + (\ (coerce . Text.splitOn "." -> keys) -> processKeys keys val) (attr opts) where - processKeys :: [Text] -> NValue t f m -> m a + processKeys :: [VarName] -> NValue t f m -> m a processKeys kys v = list (h v) - (\ (k : ks) -> + (\ ((k : ks) :: [VarName]) -> do v' <- demand v case (k, v') of - (Text.decimal -> Right (n,""), NVList xs) -> processKeys ks $ xs !! n + (Text.decimal . coerce -> Right (n,""), NVList xs) -> processKeys ks $ xs !! n (_, NVSet xs _) -> maybe - (errorWithoutStackTrace $ toString $ "Set does not contain key '" <> k <> "'") + (errorWithoutStackTrace $ "Set does not contain key ''" <> show k <> "''.") (processKeys ks) (M.lookup k xs) - (_, _) -> errorWithoutStackTrace $ toString $ "Expected a set or list for selector '" <> k <> "', but got: " <> show v + (_, _) -> errorWithoutStackTrace $ "Expected a set or list for selector '" <> show k <> "', but got: " <> show v ) kys diff --git a/src/Nix/Builtins.hs b/src/Nix/Builtins.hs index d2f176873..87a6d3362 100644 --- a/src/Nix/Builtins.hs +++ b/src/Nix/Builtins.hs @@ -101,7 +101,7 @@ data BuiltinType = Normal | TopLevel data Builtin v = Builtin { _kind :: BuiltinType - , mapping :: (Text, v) + , mapping :: (VarName, v) } -- *** @class ToBuiltin@ and its instances @@ -124,7 +124,7 @@ instance ) => ToBuiltin t f m (a -> b) where toBuiltin name f = - pure $ nvBuiltin name $ toBuiltin name . f <=< fromValue . Deeper + pure $ nvBuiltin (coerce name) $ toBuiltin name . f <=< fromValue . Deeper -- *** @WValue@ closure wrapper to have @Ord@ @@ -213,10 +213,10 @@ foldNixPath z f = [n, p] -> f (toString p) (pure n) ty rest _ -> throwError $ ErrorCall $ "Unexpected entry in NIX_PATH: " <> show x -attrsetGet :: MonadNix e t f m => Text -> AttrSet (NValue t f m) -> m (NValue t f m) +attrsetGet :: MonadNix e t f m => VarName -> AttrSet (NValue t f m) -> m (NValue t f m) attrsetGet k s = maybe - (throwError $ ErrorCall $ "Attribute '" <> toString k <> "' required") + (throwError $ ErrorCall $ toString @Text $ "Attribute '" <> coerce k <> "' required") pure (M.lookup k s) @@ -440,8 +440,8 @@ hasAttrNix -> m (NValue t f m) hasAttrNix x y = do - key <- fromStringNoContext =<< fromValue x - (aset, _) <- fromValue @(AttrSet (NValue t f m), AttrSet SourcePos) y + (coerce -> key) <- fromStringNoContext =<< fromValue x + (aset, _) <- fromValue @(AttrSet (NValue t f m), KeyMap SourcePos) y toValue $ M.member key aset @@ -456,8 +456,8 @@ getAttrNix -> m (NValue t f m) getAttrNix x y = do - key <- fromStringNoContext =<< fromValue x - (aset, _) <- fromValue @(AttrSet (NValue t f m), AttrSet SourcePos) y + (coerce -> key) <- fromStringNoContext =<< fromValue x + (aset, _) <- fromValue @(AttrSet (NValue t f m), KeyMap SourcePos) y attrsetGet key aset @@ -633,7 +633,7 @@ parseDrvNameNix drvname = toValue @(AttrSet (NValue t f m)) $ M.fromList - [ ( "name" :: Text + [ ( "name" :: VarName , mkNVStr name ) , ( "version" @@ -720,7 +720,7 @@ substringNix start len str = attrNamesNix :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m) attrNamesNix = - (fmap (coerce :: CoerceDeeperToNValue t f m) . toValue . fmap makeNixStringWithoutContext . sort . M.keys) + (fmap (coerce :: CoerceDeeperToNValue t f m) . toValue . fmap (makeNixStringWithoutContext . coerce @VarName @Text) . sort . M.keys) <=< fromValue @(AttrSet (NValue t f m)) attrValuesNix @@ -731,7 +731,7 @@ attrValuesNix nvattrs = toValue $ snd <$> sortOn - (fst @Text @(NValue t f m)) + (fst @VarName @(NValue t f m)) (M.toList attrs) mapNix @@ -764,7 +764,7 @@ mapAttrsNix f xs = applyFunToKeyVal (key, val) = do - runFunForKey <- callFunc f $ nvStrWithoutContext key + runFunForKey <- callFunc f $ nvStrWithoutContext (coerce key) callFunc runFunForKey val newVals <- @@ -799,7 +799,7 @@ catAttrsNix attrName xs = nvList . catMaybes <$> traverse - (fmap (M.lookup n) . fromValue <=< demand) + (fmap (M.lookup (coerce @Text @VarName n)) . fromValue <=< demand) l baseNameOfNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m) @@ -1074,11 +1074,12 @@ removeAttrsNix -> m (NValue t f m) removeAttrsNix set v = do - (m, p) <- fromValue @(AttrSet (NValue t f m), AttrSet SourcePos) set + (m, p) <- fromValue @(AttrSet (NValue t f m), KeyMap SourcePos) set (nsToRemove :: [NixString]) <- fromValue $ Deeper v - toRemove <- traverse fromStringNoContext nsToRemove - toValue (go m toRemove, go p toRemove) + toRemove <- traverse (fmap (coerce @Text @VarName) . fromStringNoContext) nsToRemove + toValue (go @VarName m toRemove, go @Text p (coerce @VarName <$> toRemove)) where + go :: forall k v . (Eq k, Hashable k) => HashMap k v -> [k] -> HashMap k v go = foldl' (flip M.delete) intersectAttrsNix @@ -1089,8 +1090,8 @@ intersectAttrsNix -> m (NValue t f m) intersectAttrsNix set1 set2 = do - (s1, p1) <- fromValue @(AttrSet (NValue t f m), AttrSet SourcePos) set1 - (s2, p2) <- fromValue @(AttrSet (NValue t f m), AttrSet SourcePos) set2 + (s1, p1) <- fromValue @(AttrSet (NValue t f m), KeyMap SourcePos) set1 + (s2, p2) <- fromValue @(AttrSet (NValue t f m), KeyMap SourcePos) set2 pure $ nvSet (p2 `M.intersection` p1) (s2 `M.intersection` s1) @@ -1122,7 +1123,7 @@ toFileNix name s = (stringIgnoreContext s') let - t = toText @FilePath $ coerce mres + t = coerce $ toText @FilePath $ coerce mres sc = StringContext t DirectPath toValue $ makeNixStringWithSingletonContext t sc @@ -1371,7 +1372,7 @@ listToAttrsNix lst = (\ nvattrset -> do a <- fromValue @(AttrSet (NValue t f m)) =<< demand nvattrset - name <- fromStringNoContext =<< fromValue =<< demand =<< attrsetGet "name" a + (coerce -> name) <- fromStringNoContext =<< fromValue =<< demand =<< attrsetGet "name" a val <- attrsetGet "value" a pure (name, val) @@ -1480,7 +1481,7 @@ readDirNix nvpath = | isSymbolicLink s -> FileTypeSymlink | otherwise -> FileTypeUnknown - pure (toText item, t) + pure (coerce @Text @VarName $ toText item, t) -- function indeed binds filepaths as keys (VarNames) in Nix attrset. itemsWithTypes <- traverse @@ -1503,8 +1504,10 @@ fromJSONNix nvjson = (A.eitherDecodeStrict' @A.Value $ encodeUtf8 jText) where + -- jsonToNValue :: MonadNix e t f m => A.Value -> f (NValue t f m) + jsonToNValue :: (A.Value -> m (NValue t f m)) jsonToNValue = \case - A.Object m -> nvSet mempty <$> traverse jsonToNValue m + A.Object m -> nvSet mempty <$> traverse jsonToNValue (M.mapKeys coerce m) A.Array l -> nvList <$> traverse jsonToNValue (V.toList l) A.String s -> pure $ nvStrWithoutContext s A.Number n -> @@ -1876,36 +1879,36 @@ builtinsList = sequence arity2 :: (a -> b -> c) -> (a -> b -> Prim m c) arity2 f = ((Prim . pure) .) . f - mkBuiltin :: BuiltinType -> Text -> m (NValue t f m) -> m (Builtin (NValue t f m)) + mkBuiltin :: BuiltinType -> VarName -> m (NValue t f m) -> m (Builtin (NValue t f m)) mkBuiltin t n v = wrap t n <$> mkThunk n v where - wrap :: BuiltinType -> Text -> v -> Builtin v + wrap :: BuiltinType -> VarName -> v -> Builtin v wrap t n f = Builtin t (n, f) - mkThunk :: Text -> m (NValue t f m) -> m (NValue t f m) + mkThunk :: VarName -> m (NValue t f m) -> m (NValue t f m) mkThunk n = defer . withFrame Info (ErrorCall $ "While calling builtin " <> toString n <> "\n") hAdd - :: ( Text + :: ( VarName -> fun -> m (NValue t f m) ) -> BuiltinType - -> Text + -> VarName -> fun -> m (Builtin (NValue t f m)) hAdd f t n v = mkBuiltin t n $ f n v add0 :: BuiltinType - -> Text + -> VarName -> m (NValue t f m) -> m (Builtin (NValue t f m)) add0 = hAdd (\ _ x -> x) add :: BuiltinType - -> Text + -> VarName -> ( NValue t f m -> m (NValue t f m) ) @@ -1914,7 +1917,7 @@ builtinsList = sequence add2 :: BuiltinType - -> Text + -> VarName -> ( NValue t f m -> NValue t f m -> m (NValue t f m) @@ -1924,7 +1927,7 @@ builtinsList = sequence add3 :: BuiltinType - -> Text + -> VarName -> ( NValue t f m -> NValue t f m -> NValue t f m @@ -1936,10 +1939,10 @@ builtinsList = sequence add' :: ToBuiltin t f m a => BuiltinType - -> Text + -> VarName -> a -> m (Builtin (NValue t f m)) - add' = hAdd toBuiltin + add' = hAdd (toBuiltin . coerce) -- * Exported @@ -1985,6 +1988,11 @@ builtins = lst <- ([("builtins", ref)] <>) <$> topLevelBuiltins pushScope (M.fromList lst) currentScopes where + buildMap + :: ( MonadNix e t f m + , Scoped (NValue t f m) m + ) + => m (HashMap VarName (NValue t f m)) buildMap = fmap (M.fromList . fmap mapping) builtinsList topLevelBuiltins = mapping <<$>> fullBuiltinsList @@ -1992,5 +2000,5 @@ builtins = where nameBuiltins b@(Builtin TopLevel _) = b nameBuiltins (Builtin Normal nB) = - Builtin TopLevel $ first ("__" <>) nB + Builtin TopLevel $ first (coerce @Text . ("__" <>) . coerce @VarName) nB diff --git a/src/Nix/Convert.hs b/src/Nix/Convert.hs index d20491903..e99c6be72 100644 --- a/src/Nix/Convert.hs +++ b/src/Nix/Convert.hs @@ -195,7 +195,7 @@ instance ( Convertible e t f m \case NVStr' ns -> pure $ pure ns NVPath' p -> - (\path -> pure $ makeNixStringWithSingletonContext path (StringContext path DirectPath)) . toText @FilePath . coerce <$> + (\path -> pure $ makeNixStringWithSingletonContext path (StringContext path DirectPath)) . fromString . coerce <$> addPath p NVSet' s _ -> maybe @@ -285,7 +285,7 @@ instance ( Convertible e t f m fromValue = fromMayToDeeperValue TSet instance Convertible e t f m - => FromValue (AttrSet (NValue t f m), AttrSet SourcePos) m + => FromValue (AttrSet (NValue t f m), KeyMap SourcePos) m (NValue' t f m (NValue t f m)) where fromValueMay = @@ -299,7 +299,7 @@ instance Convertible e t f m instance ( Convertible e t f m , FromValue a m (NValue t f m) ) - => FromValue (AttrSet a, AttrSet SourcePos) m + => FromValue (AttrSet a, KeyMap SourcePos) m (Deeper (NValue' t f m (NValue t f m))) where fromValueMay = @@ -376,7 +376,7 @@ instance ( Convertible e t f m f' <- toValue $ makeNixStringWithoutContext $ toText f l' <- toValue $ unPos l c' <- toValue $ unPos c - let pos = M.fromList [("file" :: Text, f'), ("line", l'), ("column", c')] + let pos = M.fromList [("file" :: VarName, f'), ("line", l'), ("column", c')] pure $ nvSet' mempty pos -- | With 'ToValue', we can always act recursively @@ -400,12 +400,12 @@ instance (Convertible e t f m, ToValue a m (NValue t f m)) stub instance Convertible e t f m - => ToValue (AttrSet (NValue t f m), AttrSet SourcePos) m + => ToValue (AttrSet (NValue t f m), KeyMap SourcePos) m (NValue' t f m (NValue t f m)) where toValue (s, p) = pure $ nvSet' p s instance (Convertible e t f m, ToValue a m (NValue t f m)) - => ToValue (AttrSet a, AttrSet SourcePos) m + => ToValue (AttrSet a, KeyMap SourcePos) m (Deeper (NValue' t f m (NValue t f m))) where toValue (s, p) = liftA2 (\ v s -> Deeper $ nvSet' s v) diff --git a/src/Nix/Effects/Basic.hs b/src/Nix/Effects/Basic.hs index bfe57a067..4bd4f7f0f 100644 --- a/src/Nix/Effects/Basic.hs +++ b/src/Nix/Effects/Basic.hs @@ -126,16 +126,16 @@ findPathBy findPathBy finder ls name = do mpath <- foldM go mempty ls maybe - (throwError $ ErrorCall $ "file '" <> name <> "' was not found in the Nix search path (add it's using $NIX_PATH or -I)") + (throwError $ ErrorCall $ "file ''" <> name <> "'' was not found in the Nix search path (add it's using $NIX_PATH or -I)") pure mpath where - go :: Maybe FilePath -> NValue t f m -> m (Maybe FilePath) + go :: MonadNix e t f m => Maybe FilePath -> NValue t f m -> m (Maybe FilePath) go mp = maybe (\ nv -> do - (s :: HashMap Text (NValue t f m)) <- fromValue =<< demand nv + (s :: HashMap VarName (NValue t f m)) <- fromValue =<< demand nv p <- resolvePath s nvpath <- demand p (Path path) <- fromValue nvpath diff --git a/src/Nix/Effects/Derivation.hs b/src/Nix/Effects/Derivation.hs index bac19d135..cb2cb88ae 100644 --- a/src/Nix/Effects/Derivation.hs +++ b/src/Nix/Effects/Derivation.hs @@ -3,6 +3,7 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE PackageImports #-} -- 2021-07-05: Due to hashing Haskell IT system situation, in HNix we currently ended-up with 2 hash package dependencies @{hashing, cryptonite}@ +{-# LANGUAGE ViewPatterns #-} module Nix.Effects.Derivation ( defaultDerivationStrict ) where @@ -24,6 +25,7 @@ import Text.Megaparsec.Char import qualified "cryptonite" Crypto.Hash as Hash -- 2021-07-05: Attrocity of Haskell hashing situation, in HNix we ended-up with 2 hash package dependencies @{hashing, cryptonite}@ import Nix.Atoms +import Nix.Expr.Types hiding ( Recursive ) import Nix.Convert import Nix.Effects import Nix.Exec ( MonadNix @@ -43,6 +45,7 @@ import qualified System.Nix.StorePath as Store import Prelude hiding (readFile) +-- 2021-07-17: NOTE: Derivation consists of @"keys"@ @"vals"@ (of text), so underlining type boundary currently stops here. data Derivation = Derivation { name :: Text , outputs :: Map Text Text @@ -79,7 +82,7 @@ writeDerivation drv@Derivation{inputs, name} = do -- | Traverse the graph of inputDrvs to replace fixed output derivations with their fixed output hash. -- this avoids propagating changes to their .drv when the output hash stays the same. -hashDerivationModulo :: (MonadNix e t f m, MonadState (b, AttrSet Text) m) => Derivation -> m (Hash.Digest Hash.SHA256) +hashDerivationModulo :: (MonadNix e t f m, MonadState (b, KeyMap Text) m) => Derivation -> m (Hash.Digest Hash.SHA256) hashDerivationModulo Derivation { mFixed = Just (Store.SomeDigest (digest :: Hash.Digest hashType)) @@ -238,9 +241,9 @@ derivationParser = do _ -> (Nothing, Flat) -defaultDerivationStrict :: forall e t f m b. (MonadNix e t f m, MonadState (b, AttrSet Text) m) => NValue t f m -> m (NValue t f m) +defaultDerivationStrict :: forall e t f m b. (MonadNix e t f m, MonadState (b, KeyMap Text) m) => NValue t f m -> m (NValue t f m) defaultDerivationStrict val = do - s <- fromValue @(AttrSet (NValue t f m)) val + s <- M.mapKeys coerce <$> fromValue @(AttrSet (NValue t f m)) val (drv, ctx) <- runWithStringContextT' $ buildDerivationWithContext s drvName <- makeStorePathName $ name drv let @@ -278,22 +281,22 @@ defaultDerivationStrict val = do , env = ifNotJsonModEnv (outputs' <>) } - drvPath <- pathToText <$> writeDerivation drv' + (coerce @Text @VarName -> drvPath) <- pathToText <$> writeDerivation drv' -- Memoize here, as it may be our last chance in case of readonly stores. drvHash <- Store.encodeDigestWith Store.Base16 <$> hashDerivationModulo drv' - modify $ second $ MS.insert drvPath drvHash + modify $ second $ MS.insert (coerce drvPath) drvHash let outputsWithContext = Map.mapWithKey - (\out path -> makeNixStringWithSingletonContext path $ StringContext drvPath $ DerivationOutput out) + (\out (coerce -> path) -> makeNixStringWithSingletonContext path $ StringContext drvPath $ DerivationOutput out) (outputs drv') drvPathWithContext = makeNixStringWithSingletonContext drvPath $ StringContext drvPath AllOutputs attrSet = nvStr <$> M.fromList (("drvPath", drvPathWithContext) : Map.toList outputsWithContext) -- TODO: Add location information for all the entries. -- here --v - pure $ nvSet mempty attrSet + pure $ nvSet mempty (M.mapKeys coerce attrSet) where @@ -303,10 +306,13 @@ defaultDerivationStrict val = do name <- makeStorePathName $ Store.unStorePathName n <> if o == "out" then "" else "-" <> o pure $ pathToText $ Store.makeStorePath "/nix/store" ("output:" <> encodeUtf8 o) h name + toStorePaths :: HashSet StringContext -> (Set Text, Map Text [Text]) toStorePaths ctx = foldl (flip addToInputs) (mempty, mempty) ctx + + addToInputs :: Bifunctor p => StringContext -> p (Set Text) (Map Text [Text]) -> p (Set Text) (Map Text [Text]) addToInputs (StringContext path kind) = case kind of - DirectPath -> first (Set.insert path) - DerivationOutput o -> second (Map.insertWith (<>) path [o]) + DirectPath -> first (Set.insert (coerce path)) + DerivationOutput o -> second (Map.insertWith (<>) (coerce path) [o]) AllOutputs -> -- TODO: recursive lookup. See prim_derivationStrict -- XXX: When is this really used ? @@ -316,7 +322,7 @@ defaultDerivationStrict val = do -- | Build a derivation in a context collecting string contexts. -- This is complex from a typing standpoint, but it allows to perform the -- full computation without worrying too much about all the string's contexts. -buildDerivationWithContext :: forall e t f m. (MonadNix e t f m) => AttrSet (NValue t f m) -> WithStringContextT m Derivation +buildDerivationWithContext :: forall e t f m. (MonadNix e t f m) => KeyMap (NValue t f m) -> WithStringContextT m Derivation buildDerivationWithContext drvAttrs = do -- Parse name first, so we can add an informative frame drvName <- getAttr "name" $ assertDrvStoreName <=< extractNixString @@ -362,7 +368,7 @@ buildDerivationWithContext drvAttrs = do env <- if useJson then do - jsonString :: NixString <- lift $ nvalueToJSONNixString $ nvSet mempty $ + jsonString :: NixString <- lift $ nvalueToJSONNixString $ nvSet mempty $ M.mapKeys coerce $ deleteKeys [ "args", "__ignoreNulls", "__structuredAttrs" ] attrs rawString :: Text <- extractNixString jsonString pure $ one ("__json", rawString) @@ -386,7 +392,7 @@ buildDerivationWithContext drvAttrs = do withFrame' :: (Framed e m, Exception s) => NixLevel -> s -> WithStringContextT m a -> WithStringContextT m a withFrame' level f = join . lift . withFrame level f . pure - -- shortcuts to get the (forced) value of an AttrSet field + -- shortcuts to get the (forced) value of an KeyMap field getAttrOr' :: forall v a. (MonadNix e t f m, FromValue v m (NValue' t f m (NValue t f m))) => Text -> m a -> (v -> WithStringContextT m a) -> WithStringContextT m a @@ -431,6 +437,6 @@ buildDerivationWithContext drvAttrs = do -- Other helpers - deleteKeys :: [Text] -> AttrSet a -> AttrSet a + deleteKeys :: [Text] -> KeyMap a -> KeyMap a deleteKeys keys attrSet = foldl' (flip M.delete) attrSet keys diff --git a/src/Nix/Eval.hs b/src/Nix/Eval.hs index 86074f352..bc901e469 100644 --- a/src/Nix/Eval.hs +++ b/src/Nix/Eval.hs @@ -24,10 +24,10 @@ import Nix.Utils import Nix.Value.Monad class (Show v, Monad m) => MonadEval v m where - freeVariable :: Text -> m v - synHole :: Text -> m v - attrMissing :: NonEmpty Text -> Maybe v -> m v - evaledSym :: Text -> v -> m v + freeVariable :: VarName -> m v + synHole :: VarName -> m v + attrMissing :: NonEmpty VarName -> Maybe v -> m v + evaledSym :: VarName -> v -> m v evalCurPos :: m v evalConstant :: NAtom -> m v evalString :: NString (m v) -> m v @@ -60,9 +60,9 @@ class (Show v, Monad m) => MonadEval v m where evalListElem :: [m v] -> Int -> m v -> m v evalList :: [v] -> m v evalSetElem :: AttrSet (m v) -> Text -> m v -> m v - evalSet :: AttrSet v -> AttrSet SourcePos -> m v + evalSet :: AttrSet v -> KeyMap SourcePos -> m v evalRecSetElem :: AttrSet (m v) -> Text -> m v -> m v - evalRecSet :: AttrSet v -> AttrSet SourcePos -> m v + evalRecSet :: AttrSet v -> KeyMap SourcePos -> m v evalLetElem :: Text -> m v -> m v evalLet :: m v -> m v -} @@ -76,8 +76,8 @@ type MonadNixEval v m , ToValue Bool m v , ToValue [v] m v , FromValue NixString m v - , ToValue (AttrSet v, AttrSet SourcePos) m v - , FromValue (AttrSet v, AttrSet SourcePos) m v + , ToValue (AttrSet v, KeyMap SourcePos) m v + , FromValue (AttrSet v, KeyMap SourcePos) m v ) data EvalFrame m v @@ -134,7 +134,7 @@ eval (NSelect aset attr alt ) = let useAltOrReportMissing (s, ks) = fromMaybe (attrMissing ks $ pure s) alt eAttr <- evalSelect aset attr - either useAltOrReportMissing id eAttr + either useAltOrReportMissing id (coerce eAttr) eval (NHasAttr aset attr) = do @@ -209,19 +209,19 @@ evalWithAttrSet aset body = do -- sure the action it evaluates is to force a thunk, so its value is only -- computed once. deferredAset <- defer $ withScopes scope aset - let attrSet = fst <$> (fromValue @(AttrSet v, AttrSet SourcePos) =<< demand deferredAset) + let attrSet = fst <$> (fromValue @(AttrSet v, KeyMap SourcePos) =<< demand deferredAset) pushWeakScope attrSet body attrSetAlter :: forall v m . MonadNixEval v m - => [Text] + => [VarName] -> SourcePos -> AttrSet (m v) - -> AttrSet SourcePos + -> KeyMap SourcePos -> m v - -> m (AttrSet (m v), AttrSet SourcePos) + -> m (AttrSet (m v), KeyMap SourcePos) attrSetAlter [] _ _ _ _ = evalError @v $ ErrorCall "invalid selector with no components" attrSetAlter (k : ks) pos m p val = bool @@ -230,22 +230,22 @@ attrSetAlter (k : ks) pos m p val = (recurse mempty mempty) (\x -> do - (st, sp) <- fromValue @(AttrSet v, AttrSet SourcePos) =<< x + (st, sp) <- fromValue @(AttrSet v, KeyMap SourcePos) =<< x recurse (demand <$> st) sp ) (M.lookup k m) ) (not $ null ks) where - go = pure (M.insert k val m, M.insert k pos p) + go = pure (M.insert k val m, M.insert (coerce k) pos p) recurse st sp = (\(st', _) -> (M.insert k - (toValue @(AttrSet v, AttrSet SourcePos) =<< (, mempty) <$> sequence st') + (toValue @(AttrSet v, KeyMap SourcePos) =<< (, mempty) <$> sequence st') m - , M.insert k pos p + , M.insert (coerce k) pos p ) ) <$> attrSetAlter ks pos st sp val @@ -293,7 +293,7 @@ evalBinds . MonadNixEval v m => Bool -> [Binding (m v)] - -> m (AttrSet v, AttrSet SourcePos) + -> m (AttrSet v, KeyMap SourcePos) evalBinds recursive binds = do scope <- currentScopes :: m (Scopes m v) @@ -303,8 +303,8 @@ evalBinds recursive binds = where buildResult :: Scopes m v - -> [([Text], SourcePos, m v)] - -> m (AttrSet v, AttrSet SourcePos) + -> [([VarName], SourcePos, m v)] + -> m (AttrSet v, KeyMap SourcePos) buildResult scope bindings = do (s, p) <- foldM insert (mempty, mempty) bindings @@ -323,7 +323,7 @@ evalBinds recursive binds = encapsulate f attrs = mkThunk $ pushScope attrs f - applyBindToAdt :: Scopes m v -> Binding (m v) -> m [([Text], SourcePos, m v)] + applyBindToAdt :: Scopes m v -> Binding (m v) -> m [([VarName], SourcePos, m v)] applyBindToAdt _ (NamedVar (StaticKey "__overrides" :| []) finalValue pos) = do (o', p') <- fromValue =<< finalValue @@ -331,7 +331,7 @@ evalBinds recursive binds = pure $ (\ (k, v) -> ( [k] - , fromMaybe pos $ M.lookup k p' + , fromMaybe pos $ M.lookup @Text (coerce k) p' , demand v ) ) <$> M.toList o' @@ -345,11 +345,11 @@ evalBinds recursive binds = ) <$> processAttrSetKeys pathExpr where - processAttrSetKeys :: NAttrPath (m v) -> m ([Text], SourcePos, m v) + processAttrSetKeys :: NAttrPath (m v) -> m ([VarName], SourcePos, m v) processAttrSetKeys (h :| t) = maybe -- Empty attrset - return a stub. - (pure ( mempty, nullPos, toValue @(AttrSet v, AttrSet SourcePos) (mempty, mempty)) ) + (pure ( mempty, nullPos, toValue @(AttrSet v, KeyMap SourcePos) (mempty, mempty)) ) (\ k -> list -- No more keys in the attrset - return the result @@ -372,7 +372,7 @@ evalBinds recursive binds = where processScope :: NKeyName (m v) - -> m (Maybe ([Text], SourcePos, m v)) + -> m (Maybe ([VarName], SourcePos, m v)) processScope nkeyname = (\ mkey -> do @@ -387,7 +387,7 @@ evalBinds recursive binds = (withScopes scope $ lookupVar key) (\ s -> do - (attrset, _) <- fromValue @(AttrSet v, AttrSet SourcePos) =<< s + (attrset, _) <- fromValue @(AttrSet v, KeyMap SourcePos) =<< s clearScopes @v $ pushScope attrset $ lookupVar key ) @@ -407,7 +407,7 @@ evalSelect . MonadNixEval v m => m v -> NAttrPath (m v) - -> m (Either (v, NonEmpty Text) (m v)) + -> m (Either (v, NonEmpty VarName) (m v)) evalSelect aset attr = do s <- aset @@ -416,13 +416,14 @@ evalSelect aset attr = extract s path where + extract :: v -> NonEmpty VarName -> m (Either (v, NonEmpty VarName) (m v)) extract x path@(k :| ks) = do x' <- fromValueMay x case x' of Nothing -> pure $ Left (x, path) - Just (s :: AttrSet v, p :: AttrSet SourcePos) + Just (s :: AttrSet v, p :: KeyMap SourcePos) | Just t <- M.lookup k s -> do list @@ -438,7 +439,7 @@ evalGetterKeyName :: forall v m . (MonadEval v m, FromValue NixString m v) => NKeyName (m v) - -> m Text + -> m VarName evalGetterKeyName = maybe (evalError @v $ ErrorCall "value is null while a string was expected") @@ -450,14 +451,14 @@ evalGetterKeyName = evalSetterKeyName :: (MonadEval v m, FromValue NixString m v) => NKeyName (m v) - -> m (Maybe Text) + -> m (Maybe VarName) evalSetterKeyName = \case StaticKey k -> pure $ pure k DynamicKey k -> maybe - mempty - (pure . stringIgnoreContext) + Nothing + (pure . coerce . stringIgnoreContext) <$> runAntiquoted "\n" assembleString (fromValueMay =<<) k assembleString @@ -489,7 +490,7 @@ buildArgument params arg = Param name -> M.singleton name <$> argThunk ParamSet s isVariadic m -> do - (args, _) <- fromValue @(AttrSet v, AttrSet SourcePos) =<< arg + (args, _) <- fromValue @(AttrSet v, KeyMap SourcePos) =<< arg let inject = maybe @@ -510,12 +511,12 @@ buildArgument params arg = assemble :: Scopes m v -> Bool - -> Text + -> VarName -> These v (Maybe (m v)) -> Maybe (AttrSet v -> m v) assemble scope isVariadic k = \case - That Nothing -> pure $ const $ evalError @v $ ErrorCall $ "Missing value for parameter: " <> show k + That Nothing -> pure $ const $ evalError @v $ ErrorCall $ "Missing value for parameter: ''" <> show k That (Just f) -> pure $ \args -> defer $ withScopes scope $ pushScope args f This _ | isVariadic -> Nothing diff --git a/src/Nix/Exec.hs b/src/Nix/Exec.hs index 903256227..9ec33bf37 100644 --- a/src/Nix/Exec.hs +++ b/src/Nix/Exec.hs @@ -86,7 +86,7 @@ nvListP p l = addProvenance p $ nvList l nvSetP :: MonadCited t f m => Provenance m (NValue t f m) - -> AttrSet SourcePos + -> KeyMap SourcePos -> AttrSet (NValue t f m) -> NValue t f m nvSetP p x s = addProvenance p $ nvSet x s @@ -102,7 +102,7 @@ nvClosureP p x f = addProvenance p $ nvClosure x f nvBuiltinP :: MonadCited t f m => Provenance m (NValue t f m) - -> Text + -> VarName -> (NValue t f m -> m (NValue t f m)) -> NValue t f m nvBuiltinP p name f = addProvenance p $ nvBuiltin name f @@ -168,13 +168,13 @@ instance MonadNix e t f m => MonadEval (NValue t f m) m where ) ms where - attr = Text.intercalate "." $ NE.toList ks + attr = Text.intercalate "." $ NE.toList $ coerce <$> ks evalCurPos = do scope <- currentScopes span@(SrcSpan delta _) <- currentPos addProvenance @_ @_ @(NValue t f m) - (Provenance scope $ NSym_ span "__curPos") <$> + (Provenance scope $ NSym_ span (coerce @Text "__curPos")) <$> toValue delta evaledSym name val = do @@ -299,7 +299,7 @@ callFunc fun arg = NVBuiltin name f -> do span <- currentPos - withFrame Info ((Calling @m @(NValue t f m)) name span) $ f arg -- Is this cool? + withFrame Info ((Calling @m @(NValue t f m)) (coerce name) span) $ f arg -- Is this cool? (NVSet m _) | Just f <- M.lookup "__functor" m -> (`callFunc` arg) =<< (`callFunc` fun') =<< demand f _x -> throwError $ ErrorCall $ "Attempt to call non-function: " <> show _x diff --git a/src/Nix/Expr/Shorthands.hs b/src/Nix/Expr/Shorthands.hs index f361a202e..765bc5bae 100644 --- a/src/Nix/Expr/Shorthands.hs +++ b/src/Nix/Expr/Shorthands.hs @@ -67,7 +67,7 @@ mkSynHole :: Text -> NExpr mkSynHole = Fix . mkSynHoleF mkSelector :: Text -> NAttrPath NExpr -mkSelector = (:| mempty) . StaticKey +mkSelector = (:| mempty) . StaticKey . coerce -- | Put an unary operator. mkOp :: NUnaryOp -> NExpr -> NExpr @@ -88,7 +88,7 @@ mkOp2 :: NBinaryOp -> NExpr -> NExpr -> NExpr mkOp2 op a = Fix . NBinary op a mkParamset :: [(Text, Maybe NExpr)] -> Bool -> Params NExpr -mkParamset params variadic = ParamSet params variadic mempty +mkParamset params variadic = ParamSet (coerce params) variadic Nothing -- | Put a recursive set. -- @@ -175,7 +175,7 @@ mkFunction :: Params NExpr -> NExpr -> NExpr mkFunction params = Fix . NAbs params -- | General dot-reference with optional alternative if the jey does not exist. -getRefOrDefault :: NExpr -> VarName -> Maybe NExpr -> NExpr +getRefOrDefault :: NExpr -> Text -> Maybe NExpr -> NExpr getRefOrDefault obj name alt = Fix $ NSelect obj (mkSelector name) alt -- ** Base functor builders for basic expressions builders *sic @@ -211,11 +211,11 @@ mkRelPathF = mkPathF False -- | Unfixed @mkSym@. mkSymF :: Text -> NExprF a -mkSymF = NSym +mkSymF = NSym . coerce -- | Unfixed @mkSynHole@. mkSynHoleF :: Text -> NExprF a -mkSynHoleF = NSynHole +mkSynHoleF = NSynHole . coerce -- * Other @@ -300,7 +300,7 @@ infix 9 @. -- | Dot-reference into an attribute set with alternative if the key does not exist. -- -- > s.x or y -(@.<|>) :: NExpr -> VarName -> NExpr -> NExpr +(@.<|>) :: NExpr -> Text -> NExpr -> NExpr (@.<|>) obj name alt = getRefOrDefault obj name $ pure alt infix 9 @.<|> diff --git a/src/Nix/Expr/Types.hs b/src/Nix/Expr/Types.hs index 2eb1b6a6d..0993abee2 100644 --- a/src/Nix/Expr/Types.hs +++ b/src/Nix/Expr/Types.hs @@ -5,6 +5,7 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -Wno-missing-signatures #-} @@ -112,11 +113,25 @@ instance FromJSON SourcePos -- * Types in this section -- * Fixpoint nature -type VarName = Text +newtype VarName = VarName Text + deriving + ( Eq, Ord, Generic + , Typeable, Data, NFData, Serialise, Binary, ToJSON, FromJSON + , Show, Read, Hashable + ) + +instance IsString VarName where + fromString = coerce . fromString @Text +instance ToString VarName where + toString = toString @Text . coerce -- ** @Params@ +-- 2021-07-16: NOTE: Should replace @ParamSet@ List +-- | > Hashmap VarName -- type synonym +type AttrSet = HashMap VarName + -- This uses an association list because nix XML serialization preserves the -- order of the param set. type ParamSet r = [(VarName, Maybe r)] @@ -620,11 +635,11 @@ hashAt = alterF where alterF :: (Functor f) - => Text + => VarName -> (Maybe v -> f (Maybe v)) -> AttrSet v -> f (AttrSet v) - alterF k f m = + alterF (coerce -> k) f m = maybe (MapL.delete k m) (\ v -> MapL.insert k v m) @@ -662,7 +677,7 @@ class NExprAnn ann g | g -> ann where ekey :: NExprAnn ann g - => NonEmpty Text + => NonEmpty VarName -> SourcePos -> Lens' (Fix g) (Maybe (Fix g)) ekey keys pos f e@(Fix x) | (NSet NonRecursive xs, ann) <- fromNExpr x = diff --git a/src/Nix/Expr/Types/Annotated.hs b/src/Nix/Expr/Types/Annotated.hs index 1354de1e2..a9305342a 100644 --- a/src/Nix/Expr/Types/Annotated.hs +++ b/src/Nix/Expr/Types/Annotated.hs @@ -243,6 +243,6 @@ pattern NWith_ ann x y = AnnFP ann (NWith x y) pattern NAssert_ :: SrcSpan -> r -> r -> NExprLocF r pattern NAssert_ ann x y = AnnFP ann (NAssert x y) -pattern NSynHole_ :: SrcSpan -> Text -> NExprLocF r +pattern NSynHole_ :: SrcSpan -> VarName -> NExprLocF r pattern NSynHole_ ann x = AnnFP ann (NSynHole x) {-# complete NConstant_, NStr_, NSym_, NList_, NSet_, NLiteralPath_, NEnvPath_, NUnary_, NBinary_, NSelect_, NHasAttr_, NAbs_, NLet_, NIf_, NWith_, NAssert_, NSynHole_ #-} diff --git a/src/Nix/Json.hs b/src/Nix/Json.hs index cf125531b..393562211 100644 --- a/src/Nix/Json.hs +++ b/src/Nix/Json.hs @@ -14,6 +14,7 @@ import Nix.String import Nix.Utils import Nix.Value import Nix.Value.Monad +import Nix.Expr.Types nvalueToJSONNixString :: MonadNix e t f m => NValue t f m -> m NixString nvalueToJSONNixString = @@ -37,15 +38,16 @@ nvalueToJSON = \case NVList l -> A.Array . V.fromList <$> traverse intoJson l NVSet m _ -> maybe - (A.Object <$> traverse intoJson m) + (A.Object <$> traverse intoJson (HM.mapKeys (coerce @VarName @Text) m)) intoJson (HM.lookup "outPath" m) NVPath p -> do fp <- lift $ coerce <$> addPath p - addSingletonStringContext $ StringContext (toText @FilePath fp) DirectPath + addSingletonStringContext $ StringContext (fromString fp) DirectPath pure $ A.toJSON fp v -> lift $ throwError $ CoercionToJson v where + intoJson :: MonadNix e t f m => NValue t f m -> WithStringContextT m A.Value intoJson nv = join $ lift $ nvalueToJSON <$> demand nv diff --git a/src/Nix/Lint.hs b/src/Nix/Lint.hs index ca4995944..5abbd5a8e 100644 --- a/src/Nix/Lint.hs +++ b/src/Nix/Lint.hs @@ -53,7 +53,7 @@ data NTypeF (m :: Type -> Type) r = TConstant [TAtom] | TStr | TList r - | TSet (Maybe (HashMap Text r)) + | TSet (Maybe (AttrSet r)) | TClosure (Params ()) | TPath | TBuiltin Text (Symbolic m -> m r) @@ -273,9 +273,9 @@ instance ToValue [Symbolic m] m (Symbolic m) where instance FromValue NixString m (Symbolic m) where -instance FromValue (AttrSet (Symbolic m), AttrSet SourcePos) m (Symbolic m) where +instance FromValue (AttrSet (Symbolic m), KeyMap SourcePos) m (Symbolic m) where -instance ToValue (AttrSet (Symbolic m), AttrSet SourcePos) m (Symbolic m) where +instance ToValue (AttrSet (Symbolic m), KeyMap SourcePos) m (Symbolic m) where instance (MonadThunkId m, MonadAtomicRef m, MonadCatch m) => MonadValue (Symbolic m) m where @@ -297,7 +297,7 @@ instance (MonadThunkId m, MonadAtomicRef m, MonadCatch m) instance MonadLint e m => MonadEval (Symbolic m) m where - freeVariable var = symerr $ "Undefined variable '" <> var <> "'" + freeVariable var = symerr $ "Undefined variable '" <> coerce var <> "'" attrMissing ks ms = evalError @(Symbolic m) $ ErrorCall $ toString $ @@ -306,7 +306,7 @@ instance MonadLint e m => MonadEval (Symbolic m) m where (\ s -> "Could not look up attribute " <> attr <> " in " <> show s) ms where - attr = Text.intercalate "." (NE.toList ks) + attr = Text.intercalate "." $ NE.toList $ coerce <$> ks evalCurPos = do f <- mkSymbolic [TPath] @@ -428,25 +428,29 @@ lintApp -> Symbolic m -> m (Symbolic m) -> m (HashMap VarName (Symbolic m), Symbolic m) -lintApp context fun arg = unpackSymbolic fun >>= \case - NAny -> - throwError $ ErrorCall "Cannot apply something not known to be a function" - NMany xs -> do - (args, ys) <- fmap unzip $ forM xs $ \case - TClosure _params -> arg >>= unpackSymbolic >>= \case - NAny -> do - error "NYI" - - NMany [TSet (Just _)] -> do - error "NYI" - - NMany _ -> throwError $ ErrorCall "NYI: lintApp NMany not set" - TBuiltin _ _f -> throwError $ ErrorCall "NYI: lintApp builtin" - TSet _m -> throwError $ ErrorCall "NYI: lintApp Set" - _x -> throwError $ ErrorCall "Attempt to call non-function" - - y <- everyPossible - (head args, ) <$> foldM (unify context) y ys +lintApp context fun arg = + (\case + NAny -> + throwError $ ErrorCall "Cannot apply something not known to be a function" + NMany xs -> do + (args, ys) <- fmap unzip $ forM xs $ \case + TClosure _params -> + (\case + NAny -> do + error "NYI" + + NMany [TSet (Just _)] -> do + error "NYI" + + NMany _ -> throwError $ ErrorCall "NYI: lintApp NMany not set" + ) =<< unpackSymbolic =<< arg + TBuiltin _ _f -> throwError $ ErrorCall "NYI: lintApp builtin" + TSet _m -> throwError $ ErrorCall "NYI: lintApp Set" + _x -> throwError $ ErrorCall "Attempt to call non-function" + + y <- everyPossible + (head args, ) <$> foldM (unify context) y ys + ) =<< unpackSymbolic fun newtype Lint s a = Lint { runLint :: ReaderT (Context (Lint s) (Symbolic (Lint s))) (FreshIdT Int (ST s)) a } @@ -462,10 +466,10 @@ newtype Lint s a = Lint ) instance MonadThrow (Lint s) where - throwM e = Lint $ ReaderT $ \_ -> throw e + throwM e = Lint $ ReaderT $ const (throw e) instance MonadCatch (Lint s) where - catch _m _h = Lint $ ReaderT $ \_ -> fail "Cannot catch in 'Lint s'" + catch _m _h = Lint $ ReaderT $ const (fail "Cannot catch in 'Lint s'") runLintM :: Options -> Lint s a -> ST s a runLintM opts action = do diff --git a/src/Nix/Parser.hs b/src/Nix/Parser.hs index 6184bc572..9d25b50c0 100644 --- a/src/Nix/Parser.hs +++ b/src/Nix/Parser.hs @@ -1,5 +1,6 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -fno-warn-name-shadowing #-} @@ -186,10 +187,10 @@ nixToplevelForm = keywords <+> nixLambda <+> nixExpr keywords = nixLet <+> nixIf <+> nixAssert <+> nixWith nixSym :: Parser NExprLoc -nixSym = annotateLocation1 $ mkSymF <$> identifier +nixSym = annotateLocation1 $ mkSymF . coerce <$> identifier nixSynHole :: Parser NExprLoc -nixSynHole = annotateLocation1 $ mkSynHoleF <$> (char '^' *> identifier) +nixSynHole = annotateLocation1 $ mkSynHoleF . coerce <$> (char '^' *> identifier) nixInt :: Parser NExprLoc nixInt = annotateLocation1 (mkIntF <$> integer "integer") @@ -416,7 +417,7 @@ argExpr = -- Collects the parameters within curly braces. Returns the parameters and -- a boolean indicating if the parameters are variadic. - getParams :: Parser ([(Text, Maybe NExprLoc)], Bool) + getParams :: Parser (ParamSet NExprLoc, Bool) getParams = go mempty where -- Attempt to parse `...`. If this succeeds, stop and return True. @@ -517,9 +518,9 @@ reserved :: Text -> Parser () reserved n = lexeme $ try $ string n *> lookAhead (void (satisfy reservedEnd) <|> eof) -identifier :: Parser Text +identifier :: Parser VarName identifier = lexeme $ try $ do - ident <- + (coerce -> ident) <- liftA2 cons (satisfy (\x -> isAlpha x || x == '_')) (takeWhileP mempty identLetter) @@ -558,7 +559,7 @@ integer = lexeme Lexer.decimal float :: Parser Double float = lexeme Lexer.float -reservedNames :: HashSet Text +reservedNames :: HashSet VarName reservedNames = HashSet.fromList ["let", "in", "if", "then", "else", "assert", "with", "rec", "inherit"] diff --git a/src/Nix/Pretty.hs b/src/Nix/Pretty.hs index add2aa43c..3bf83cd64 100644 --- a/src/Nix/Pretty.hs +++ b/src/Nix/Pretty.hs @@ -127,12 +127,15 @@ prettyString (Indented _ parts) = group $ nest 2 $ vcat prettyPart EscapedNewline = "\\n" prettyPart (Antiquoted r) = "${" <> withoutParens r <> "}" +prettyVarName :: VarName -> Doc ann +prettyVarName = pretty @Text . coerce + prettyParams :: Params (NixDoc ann) -> Doc ann -prettyParams (Param n ) = pretty n +prettyParams (Param n ) = prettyVarName n prettyParams (ParamSet s v mname) = prettyParamSet s v <> maybe mempty - (\ name -> + (\ (coerce -> name) -> bool mempty ("@" <> pretty name) @@ -150,8 +153,8 @@ prettyParamSet args var = where prettySetArg (n, maybeDef) = maybe - (pretty n) - (\x -> pretty n <> " ? " <> withoutParens x) + (prettyVarName n) + (\x -> prettyVarName n <> " ? " <> withoutParens x) maybeDef prettyVariadic = [ "..." | var ] sep = align ", " @@ -170,8 +173,8 @@ prettyBind (Inherit s ns _p) = prettyKeyName :: NKeyName (NixDoc ann) -> Doc ann prettyKeyName (StaticKey "") = "\"\"" -prettyKeyName (StaticKey key) | HashSet.member key reservedNames = "\"" <> pretty key <> "\"" -prettyKeyName (StaticKey key) = pretty key +prettyKeyName (StaticKey key) | HashSet.member key reservedNames = "\"" <> prettyVarName key <> "\"" +prettyKeyName (StaticKey key) = prettyVarName key prettyKeyName (DynamicKey key) = runAntiquoted (DoubleQuoted [Plain "\n"]) @@ -273,7 +276,7 @@ exprFNixDoc = \case ("./" <> _txt) _txt (any (`isPrefixOf` _txt) ["/", "~/", "./", "../"]) - NSym name -> simpleExpr $ pretty name + NSym name -> simpleExpr $ prettyVarName name NLet binds body -> leastPrecedence $ group $ @@ -295,7 +298,7 @@ exprFNixDoc = \case prettyAddScope "with " scope body NAssert cond body -> prettyAddScope "assert " cond body - NSynHole name -> simpleExpr $ pretty ("^" <> name) + NSynHole name -> simpleExpr $ pretty @Text ("^" <> coerce name) where prettyContainer h f t c = list @@ -319,12 +322,12 @@ valueToExpr = iterNValueByDiscardWith thk (Fix . phi) phi (NVStr' ns ) = NStr $ DoubleQuoted [Plain (stringIgnoreContext ns)] phi (NVList' l ) = NList l phi (NVSet' s p) = NSet NonRecursive - [ NamedVar (StaticKey k :| mempty) v (fromMaybe nullPos (M.lookup k p)) + [ NamedVar (StaticKey k :| mempty) v (fromMaybe nullPos (M.lookup (coerce k) p)) | (k, v) <- toList s ] phi (NVClosure' _ _) = NSym "" phi (NVPath' p ) = NLiteralPath p - phi (NVBuiltin' name _) = NSym $ "builtins." <> name + phi (NVBuiltin' name _) = NSym $ coerce @Text $ "builtins." <> coerce name prettyNValue :: forall t f m ann . MonadDataContext f m => NValue t f m -> Doc ann @@ -400,4 +403,4 @@ printNix = iterNValueByDiscardWith thk phi where surround s = "\"" <> s <> "\"" phi NVClosure'{} = "<>" phi (NVPath' fp ) = fp - phi (NVBuiltin' name _) = toString $ "< name <> ">>" + phi (NVBuiltin' name _) = toString @Text $ "< coerce name <> ">>" diff --git a/src/Nix/Scope.hs b/src/Nix/Scope.hs index b6dca8f98..4e24d3738 100644 --- a/src/Nix/Scope.hs +++ b/src/Nix/Scope.hs @@ -10,6 +10,7 @@ import qualified Data.HashMap.Lazy as M import qualified Text.Show import Lens.Family2 import Nix.Utils +import Nix.Expr.Types newtype Scope a = Scope { getScope :: AttrSet a } deriving (Functor, Foldable, Traversable, Eq) @@ -20,7 +21,7 @@ instance Show (Scope a) where newScope :: AttrSet a -> Scope a newScope = Scope -scopeLookup :: Text -> [Scope a] -> Maybe a +scopeLookup :: VarName -> [Scope a] -> Maybe a scopeLookup key = foldr go Nothing where go @@ -52,7 +53,7 @@ class Scoped a m | m -> a where currentScopes :: m (Scopes m a) clearScopes :: m r -> m r pushScopes :: Scopes m a -> m r -> m r - lookupVar :: Text -> m (Maybe a) + lookupVar :: VarName -> m (Maybe a) currentScopesReader :: forall m a e @@ -101,7 +102,7 @@ lookupVarReader . ( MonadReader e m , Has e (Scopes m a) ) - => Text + => VarName -> m (Maybe a) lookupVarReader k = do diff --git a/src/Nix/String.hs b/src/Nix/String.hs index b3ef68ee9..262d43709 100644 --- a/src/Nix/String.hs +++ b/src/Nix/String.hs @@ -37,6 +37,9 @@ import Control.Monad.Writer ( WriterT(..), MonadWriter(tell) import qualified Data.HashMap.Lazy as M import qualified Data.HashSet as S import qualified Data.Text as Text +import Nix.Expr.Types ( VarName(..) + , AttrSet + ) -- * Types @@ -46,7 +49,7 @@ import qualified Data.Text as Text -- | A Nix 'StringContext' ... data StringContext = StringContext - { scPath :: !Text + { scPath :: !VarName , scFlavor :: !ContextFlavor } deriving (Eq, Ord, Show, Generic) @@ -127,8 +130,8 @@ makeNixStringWithoutContext = (`NixString` mempty) -- | Create NixString using a singleton context makeNixStringWithSingletonContext - :: Text -> StringContext -> NixString -makeNixStringWithSingletonContext s c = NixString s $ one c + :: VarName -> StringContext -> NixString +makeNixStringWithSingletonContext s c = NixString (coerce @VarName @Text s) $ one c -- | Create NixString from a Text and context makeNixString :: Text -> S.HashSet StringContext -> NixString @@ -172,7 +175,7 @@ extractNixString (NixString s c) = -- this really should be 2 args, then with @toStringContexts path@ laziness it would tail recurse. -- for now tuple dissected internaly with laziness preservation. -toStringContexts :: (Text, NixLikeContextValue) -> [StringContext] +toStringContexts :: (VarName, NixLikeContextValue) -> [StringContext] toStringContexts ~(path, nlcv) = go nlcv where @@ -190,7 +193,7 @@ toStringContexts ~(path, nlcv) = mkCtxFor = StringContext path mkLstCtxFor t c = mkCtxFor t : go c -toNixLikeContextValue :: StringContext -> (Text, NixLikeContextValue) +toNixLikeContextValue :: StringContext -> (VarName, NixLikeContextValue) toNixLikeContextValue sc = ( scPath sc , case scFlavor sc of diff --git a/src/Nix/String/Coerce.hs b/src/Nix/String/Coerce.hs index 07741881b..d6a07528f 100644 --- a/src/Nix/String/Coerce.hs +++ b/src/Nix/String/Coerce.hs @@ -116,5 +116,5 @@ coerceToString call ctsm clevel = go t (StringContext t DirectPath) where - t = toText @FilePath $ coerce sp + t = fromString $ coerce sp diff --git a/src/Nix/TH.hs b/src/Nix/TH.hs index 526465219..41e2ab558 100644 --- a/src/Nix/TH.hs +++ b/src/Nix/TH.hs @@ -117,7 +117,7 @@ freeVars e = case unFix e of staticKey :: NKeyName r -> Maybe VarName staticKey (StaticKey varname) = pure varname - staticKey (DynamicKey _ ) = mempty + staticKey (DynamicKey _ ) = Nothing pathFree :: NAttrPath NExpr -> Set VarName pathFree = foldMap mapFreeVars diff --git a/src/Nix/Type/Infer.hs b/src/Nix/Type/Infer.hs index 726a6b645..9f59a19b1 100644 --- a/src/Nix/Type/Infer.hs +++ b/src/Nix/Type/Infer.hs @@ -122,7 +122,7 @@ allSameType = allSame data TypeError = UnificationFail Type Type | InfiniteType TVar Type - | UnboundVariables [Text] + | UnboundVariables [VarName] | Ambigious [Constraint] | UnificationMismatch [Type] [Type] deriving (Eq, Show, Ord) @@ -335,7 +335,7 @@ instance instance MonadInfer m => FromValue ( AttrSet (Judgment s) - , AttrSet SourcePos + , KeyMap SourcePos ) (InferT s m) (Judgment s) where fromValueMay (Judgment _ _ (TSet _ xs)) = @@ -350,7 +350,7 @@ instance <=< fromValueMay instance MonadInfer m - => ToValue (AttrSet (Judgment s), AttrSet SourcePos) + => ToValue (AttrSet (Judgment s), KeyMap SourcePos) (InferT s m) (Judgment s) where toValue (xs, _) = liftA3 @@ -773,7 +773,7 @@ liftInfer = InferT . lift . lift . lift infer :: MonadInfer m => NExpr -> InferT s m (Judgment s) infer = foldFix Eval.eval -inferTop :: Env -> [(Text, NExpr)] -> Either InferError Env +inferTop :: Env -> [(VarName, NExpr)] -> Either InferError Env inferTop env [] = pure env inferTop env ((name, ex) : xs) = either diff --git a/src/Nix/Type/Type.hs b/src/Nix/Type/Type.hs index a04e362ab..e8aa9e9f6 100644 --- a/src/Nix/Type/Type.hs +++ b/src/Nix/Type/Type.hs @@ -5,7 +5,7 @@ module Nix.Type.Type where import Prelude hiding ( Type, TVar ) import Data.Foldable ( foldr1 ) -import Nix.Utils ( AttrSet ) +import Nix.Expr.Types ( AttrSet ) -- | Hindrey-Milner type interface diff --git a/src/Nix/Utils.hs b/src/Nix/Utils.hs index ccb62e7fa..0a6e51933 100644 --- a/src/Nix/Utils.hs +++ b/src/Nix/Utils.hs @@ -37,7 +37,7 @@ traceM = const pass $(makeLensesBy (\n -> pure $ "_" <> n) ''Fix) -- | > Hashmap Text -- type synonym -type AttrSet = HashMap Text +type KeyMap = HashMap Text -- | F-algebra defines how to reduce the fixed-point of a functor to a value. -- > type Alg f a = f a -> a diff --git a/src/Nix/Value.hs b/src/Nix/Value.hs index 8deb3a3af..db6c4cf6d 100644 --- a/src/Nix/Value.hs +++ b/src/Nix/Value.hs @@ -124,8 +124,8 @@ data NValueF p m r -- Quite frequently actions/processing happens with values -- (for example - forcing of values & recreation of the monad), -- but SourcePos does not change then - -- That would be good to flip all 'AttrSet.* AttrSet SourcePos' - | NVSetF (AttrSet r) (AttrSet SourcePos) + -- That would be good to flip all 'AttrSet.* KeyMap SourcePos' + | NVSetF (AttrSet r) (KeyMap SourcePos) | NVClosureF (Params ()) (p -> m r) -- ^ A function is a closed set of parameters representing the "call -- signature", used at application time to check the type of arguments @@ -138,7 +138,7 @@ data NValueF p m r -- Note that 'm r' is being used here because effectively a function -- and its set of default arguments is "never fully evaluated". This -- enforces in the type that it must be re-evaluated for each call. - | NVBuiltinF Text (p -> m r) + | NVBuiltinF VarName (p -> m r) -- ^ A builtin function is itself already in normal form. Also, it may -- or may not choose to evaluate its argument in the production of a -- result. @@ -445,10 +445,11 @@ nvList' = NValue' . pure . NVListF -- | Haskell key-value to the Nix key-value, nvSet' :: Applicative f - => AttrSet SourcePos + => KeyMap SourcePos -> AttrSet r -> NValue' t f m r -nvSet' x s = NValue' $ pure $ NVSetF s x +-- 2021-07-16: NOTE: that the arguments are flipped. +nvSet' p s = NValue' $ pure $ NVSetF s p -- | Haskell closure to the Nix closure, @@ -463,7 +464,7 @@ nvClosure' x f = NValue' $ pure $ NVClosureF x f -- | Haskell functions to the Nix functions! nvBuiltin' :: (Applicative f, Functor m) - => Text + => VarName -> (NValue t f m -> m r) -> NValue' t f m r nvBuiltin' name f = NValue' $ pure $ NVBuiltinF name f @@ -627,11 +628,10 @@ nvList = Free . nvList' nvSet :: Applicative f - => AttrSet SourcePos + => KeyMap SourcePos -> AttrSet (NValue t f m) -> NValue t f m -nvSet x s = Free $ nvSet' x s - +nvSet p s = Free $ nvSet' p s nvClosure :: (Applicative f, Functor m) => Params () @@ -643,7 +643,7 @@ nvClosure x f = Free $ nvClosure' x f nvBuiltin :: (Applicative f, Functor m) - => Text + => VarName -> (NValue t f m -> m (NValue t f m) ) @@ -654,7 +654,7 @@ nvBuiltin name f = Free $ nvBuiltin' name f builtin :: forall m f t . (MonadThunk t m (NValue t f m), MonadDataContext f m) - => Text + => VarName -> ( NValue t f m -> m (NValue t f m) ) @@ -664,7 +664,7 @@ builtin name f = pure $ nvBuiltin name $ \a -> f a builtin2 :: (MonadThunk t m (NValue t f m), MonadDataContext f m) - => Text + => VarName -> ( NValue t f m -> NValue t f m -> m (NValue t f m) @@ -675,7 +675,7 @@ builtin2 name f = builtin name $ \a -> builtin name $ \b -> f a b builtin3 :: (MonadThunk t m (NValue t f m), MonadDataContext f m) - => Text + => VarName -> ( NValue t f m -> NValue t f m -> NValue t f m diff --git a/src/Nix/Value/Equal.hs b/src/Nix/Value/Equal.hs index 4556e84ac..623c20887 100644 --- a/src/Nix/Value/Equal.hs +++ b/src/Nix/Value/Equal.hs @@ -25,6 +25,7 @@ import Nix.Frames import Nix.String import Nix.Thunk import Nix.Value +import Nix.Expr.Types ( AttrSet ) checkComparable :: ( Framed e m diff --git a/tests/ParserTests.hs b/tests/ParserTests.hs index 2349eeae8..8a6aaa14f 100644 --- a/tests/ParserTests.hs +++ b/tests/ParserTests.hs @@ -286,10 +286,11 @@ case_lambda_or_uri_syntax_mistakes = case_lambda_pattern = checks - ( mkFunction (fixed args mempty) $ var "b" + ( mkFunction (fixed args Nothing) $ var "b" , "{b, c ? 1}: b" + -- Fix (NAbs (ParamSet [("b",Nothing),("c",Just (Fix (NConstant (NInt 1))))] False Nothing) (Fix (NSym "b"))) ) - ( mkFunction (fixed args2 mempty) $ var "b" + ( mkFunction (fixed args2 Nothing) $ var "b" , "{ b ? x: x }: b" ) ( mkFunction (fixed args $ pure "a") $ var "b" @@ -301,7 +302,7 @@ case_lambda_pattern = ( mkFunction (variadic vargs $ pure "a") $ var "c" , "{b,c?1,...}@a: c" ) - ( mkFunction (variadic mempty mempty) $ mkInt 1 + ( mkFunction (variadic mempty Nothing) $ mkInt 1 , "{...}: 1" ) where diff --git a/tests/PrettyParseTests.hs b/tests/PrettyParseTests.hs index 65142803c..c19530521 100644 --- a/tests/PrettyParseTests.hs +++ b/tests/PrettyParseTests.hs @@ -44,7 +44,7 @@ genSourcePos = genKeyName :: Gen (NKeyName NExpr) genKeyName = - Gen.choice [DynamicKey <$> genAntiquoted genString, StaticKey <$> asciiText] + Gen.choice [DynamicKey <$> genAntiquoted genString, StaticKey . coerce <$> asciiText] genAntiquoted :: Gen a -> Gen (Antiquoted a NExpr) genAntiquoted gen = @@ -81,8 +81,8 @@ genAttrPath = genParams :: Gen (Params NExpr) genParams = Gen.choice - [ Param <$> asciiText - , liftA3 ParamSet + [ Param . coerce <$> asciiText + , liftA3 (\ a b c -> ParamSet (coerce a) b (coerce <$> c)) (Gen.list (Range.linear 0 10) (liftA2 (,) asciiText $ Gen.maybe genExpr)) Gen.bool (Gen.choice [stub, pure <$> asciiText]) @@ -124,7 +124,7 @@ genExpr = where genConstant = NConstant <$> genAtom genStr = NStr <$> genString - genSym = NSym <$> asciiText + genSym = NSym . coerce <$> asciiText genList = NList <$> fairList genExpr genSet = NSet NonRecursive <$> fairList genBinding genRecSet = NSet Recursive <$> fairList genBinding @@ -193,7 +193,7 @@ normalize = foldFix $ \case normAntiquotedText (Plain "''\n") = EscapedNewline normAntiquotedText r = r - normParams (ParamSet binds var (Just "")) = ParamSet binds var mempty + normParams (ParamSet binds var (Just "")) = ParamSet binds var (coerce @Text <$> mempty) normParams r = r -- | Test that parse . pretty == id up to attribute position information.