hnix/src/Nix/Scope.hs

96 lines
2.8 KiB
Haskell
Raw Permalink Normal View History

2018-04-07 21:02:50 +02:00
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
2018-11-17 22:21:03 +01:00
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2018-04-07 21:02:50 +02:00
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Nix.Scope where
import Control.Applicative
import Control.Monad.Reader
import qualified Data.HashMap.Lazy as M
import Data.Text ( Text )
import Lens.Family2
2018-04-07 21:02:50 +02:00
import Nix.Utils
newtype Scope a = Scope { getScope :: AttrSet a }
deriving (Functor, Foldable, Traversable, Eq)
2018-04-07 21:02:50 +02:00
instance Show (Scope a) where
show (Scope m) = show (M.keys m)
2018-04-07 21:02:50 +02:00
newScope :: AttrSet a -> Scope a
2018-04-07 21:02:50 +02:00
newScope = Scope
scopeLookup :: Text -> [Scope a] -> Maybe a
scopeLookup key = foldr go Nothing
where go (Scope m) rest = M.lookup key m <|> rest
2018-04-07 21:02:50 +02:00
data Scopes m a = Scopes
{ lexicalScopes :: [Scope a]
, dynamicScopes :: [m (Scope a)]
}
2018-04-07 21:02:50 +02:00
instance Show (Scopes m a) where
show (Scopes m a) =
"Scopes: " ++ show m ++ ", and " ++ show (length a) ++ " with-scopes"
instance Semigroup (Scopes m a) where
Scopes ls lw <> Scopes rs rw = Scopes (ls <> rs) (lw <> rw)
instance Monoid (Scopes m a) where
mempty = emptyScopes
mappend = (<>)
2018-04-07 21:02:50 +02:00
emptyScopes :: forall m a . Scopes m a
emptyScopes = Scopes [] []
2018-04-07 21:02:50 +02:00
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)
2018-11-17 22:21:03 +01:00
currentScopesReader
:: forall m a e . (MonadReader e m, Has e (Scopes m a)) => m (Scopes m a)
2018-11-17 22:21:03 +01:00
currentScopesReader = asks (view hasLens)
2018-04-07 21:02:50 +02:00
clearScopesReader
:: forall m a e r . (MonadReader e m, Has e (Scopes m a)) => m r -> m r
clearScopesReader = local (set hasLens (emptyScopes @m @a))
2018-04-07 21:02:50 +02:00
pushScope :: Scoped a m => AttrSet a -> m r -> m r
pushScope s = pushScopes (Scopes [Scope s] [])
2018-04-07 21:02:50 +02:00
pushWeakScope :: (Functor m, Scoped a m) => m (AttrSet a) -> m r -> m r
pushWeakScope s = pushScopes (Scopes [] [Scope <$> s])
2018-04-07 21:02:50 +02:00
pushScopesReader
:: (MonadReader e m, Has e (Scopes m a)) => Scopes m a -> m r -> m r
2018-11-17 22:21:03 +01:00
pushScopesReader s = local (over hasLens (s <>))
2018-04-07 21:02:50 +02:00
lookupVarReader
:: forall m a e . (MonadReader e m, Has e (Scopes m a)) => Text -> m (Maybe a)
2018-11-17 22:21:03 +01:00
lookupVarReader k = do
mres <- asks (scopeLookup k . lexicalScopes @m . view hasLens)
case mres of
Just sym -> pure $ Just sym
Nothing -> do
ws <- asks (dynamicScopes . view hasLens)
foldr
(\x rest -> do
mres' <- M.lookup k . getScope <$> x
case mres' of
Just sym -> pure $ Just sym
Nothing -> rest
)
(pure Nothing)
ws
2018-04-07 21:02:50 +02:00
withScopes :: Scoped a m => Scopes m a -> m r -> m r
2018-11-17 22:21:03 +01:00
withScopes scope = clearScopes . pushScopes scope