2018-03-31 23:43:08 +02:00
|
|
|
{-# LANGUAGE AllowAmbiguousTypes #-}
|
|
|
|
{-# LANGUAGE ConstraintKinds #-}
|
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
|
|
{-# LANGUAGE TypeApplications #-}
|
|
|
|
|
2018-03-30 22:30:28 +02:00
|
|
|
module Nix.Scope where
|
|
|
|
|
|
|
|
import Control.Applicative
|
2018-03-31 23:43:08 +02:00
|
|
|
import Control.Monad.Reader
|
|
|
|
import Data.HashMap.Lazy (HashMap)
|
|
|
|
import qualified Data.HashMap.Lazy as M
|
2018-03-30 22:30:28 +02:00
|
|
|
import Data.Text (Text)
|
|
|
|
import Nix.Utils
|
|
|
|
|
|
|
|
data Scope a = Scope
|
2018-03-31 23:43:08 +02:00
|
|
|
{ _scopeMap :: HashMap Text a
|
2018-03-30 22:30:28 +02:00
|
|
|
, scopeWeak :: Bool
|
|
|
|
}
|
|
|
|
deriving Functor
|
|
|
|
|
|
|
|
instance Show (Scope a) where
|
2018-03-31 23:43:08 +02:00
|
|
|
show (Scope xs _) = show $ M.keys xs
|
2018-03-30 22:30:28 +02:00
|
|
|
|
2018-03-31 23:43:08 +02:00
|
|
|
newScope :: HashMap Text a -> Scope a
|
2018-03-30 22:30:28 +02:00
|
|
|
newScope m = Scope m False
|
|
|
|
|
2018-03-31 23:43:08 +02:00
|
|
|
newWeakScope :: HashMap Text a -> Scope a
|
2018-03-30 22:30:28 +02:00
|
|
|
newWeakScope m = Scope m True
|
|
|
|
|
2018-03-31 23:43:08 +02:00
|
|
|
scopeLookup :: Text -> [Scope v] -> Maybe v
|
2018-03-30 23:55:30 +02:00
|
|
|
scopeLookup key = para go Nothing
|
2018-03-30 22:30:28 +02:00
|
|
|
where
|
2018-03-31 23:43:08 +02:00
|
|
|
go (Scope m False) _ rest = M.lookup key m <|> rest
|
2018-03-30 22:30:28 +02:00
|
|
|
go (Scope m True) ms rest =
|
|
|
|
-- If the symbol lookup is in a weak scope, first see if there are any
|
|
|
|
-- matching symbols from the *non-weak* scopes after this one. If so,
|
|
|
|
-- prefer that, otherwise perform the lookup here. This way, if there
|
|
|
|
-- are several weaks scopes in a row, followed by non-weak scopes,
|
|
|
|
-- we'll first prefer the symbol from the non-weak scopes, and then
|
|
|
|
-- prefer it from the first weak scope that matched.
|
2018-03-30 23:55:30 +02:00
|
|
|
scopeLookup key (filter (not . scopeWeak) ms)
|
2018-03-31 23:43:08 +02:00
|
|
|
<|> M.lookup key m <|> rest
|
|
|
|
|
|
|
|
type Scopes v = [Scope v]
|
|
|
|
|
|
|
|
type Scoped e v m = (MonadReader e m, Has e (Scopes v))
|
|
|
|
|
|
|
|
emptyScopes :: Scopes v
|
|
|
|
emptyScopes = []
|
|
|
|
|
|
|
|
currentScopes :: Scoped e v m => m (Scopes v)
|
|
|
|
currentScopes = asks (view hasLens)
|
|
|
|
|
|
|
|
clearScopes :: forall v m e r. Scoped e v m => m r -> m r
|
|
|
|
clearScopes = local (set hasLens ([] :: [Scope v]))
|
|
|
|
|
|
|
|
pushScope :: forall v m e r. Scoped e v m => HashMap Text v -> m r -> m r
|
|
|
|
pushScope s = local (over hasLens (Scope s False :))
|
|
|
|
|
|
|
|
pushWeakScope :: Scoped e v m => HashMap Text v -> m r -> m r
|
|
|
|
pushWeakScope s = local (over hasLens (Scope s True :))
|
|
|
|
|
|
|
|
pushScopes :: Scoped e v m => Scopes v -> m r -> m r
|
|
|
|
pushScopes s = local (over hasLens (s ++))
|
|
|
|
|
|
|
|
lookupVar :: Scoped e v m => Text -> m (Maybe v)
|
|
|
|
lookupVar k = asks (scopeLookup k . view hasLens)
|
|
|
|
|
|
|
|
withScopes :: forall v m e a. Scoped e v m => Scopes v -> m a -> m a
|
|
|
|
withScopes scope = clearScopes @v . pushScopes scope
|