{-# LANGUAGE TypeFamilies #-}
module Nix.Type.Env
  ( Env(..)
  , empty
  , lookup
  , remove
  , extend
  , extends
  , merge
  , mergeEnvs
  , singleton
  , keys
  , fromList
  , toList
  )
where

import           Prelude                 hiding ( empty
                                                , toList
                                                , fromList
                                                )

import           Nix.Type.Type

import qualified Data.Map                      as Map


-- * Typing Environment

newtype Env = TypeEnv (Map.Map Name [Scheme])
  deriving (Env -> Env -> Bool
(Env -> Env -> Bool) -> (Env -> Env -> Bool) -> Eq Env
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Env -> Env -> Bool
$c/= :: Env -> Env -> Bool
== :: Env -> Env -> Bool
$c== :: Env -> Env -> Bool
Eq, Int -> Env -> ShowS
[Env] -> ShowS
Env -> String
(Int -> Env -> ShowS)
-> (Env -> String) -> ([Env] -> ShowS) -> Show Env
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Env] -> ShowS
$cshowList :: [Env] -> ShowS
show :: Env -> String
$cshow :: Env -> String
showsPrec :: Int -> Env -> ShowS
$cshowsPrec :: Int -> Env -> ShowS
Show)

instance Semigroup Env where
  -- | Right-biased merge (override). Analogous to @//@ in @Nix@
  -- Since nature of environment is to update & grow.
  <> :: Env -> Env -> Env
(<>) = Env -> Env -> Env
mergeRight

instance Monoid Env where
  mempty :: Env
mempty = Env
empty

instance One Env where
  type OneItem Env = (Name, Scheme)
  one :: OneItem Env -> Env
one = (Name -> Scheme -> Env) -> (Name, Scheme) -> Env
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Name -> Scheme -> Env
singleton

empty :: Env
empty :: Env
empty = Map Name [Scheme] -> Env
TypeEnv Map Name [Scheme]
forall a. Monoid a => a
mempty

extend :: Env -> (Name, [Scheme]) -> Env
extend :: Env -> (Name, [Scheme]) -> Env
extend Env
env (Name
x, [Scheme]
s) = Map Name [Scheme] -> Env
TypeEnv (Map Name [Scheme] -> Env) -> Map Name [Scheme] -> Env
forall a b. (a -> b) -> a -> b
$ Name -> [Scheme] -> Map Name [Scheme] -> Map Name [Scheme]
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Name
x [Scheme]
s (Map Name [Scheme] -> Map Name [Scheme])
-> Map Name [Scheme] -> Map Name [Scheme]
forall a b. (a -> b) -> a -> b
$ Env -> Map Name [Scheme]
coerce Env
env

remove :: Env -> Name -> Env
remove :: Env -> Name -> Env
remove (TypeEnv Map Name [Scheme]
env) Name
var = Map Name [Scheme] -> Env
TypeEnv (Map Name [Scheme] -> Env) -> Map Name [Scheme] -> Env
forall a b. (a -> b) -> a -> b
$ Name -> Map Name [Scheme] -> Map Name [Scheme]
forall k a. Ord k => k -> Map k a -> Map k a
Map.delete Name
var Map Name [Scheme]
env

extends :: Env -> [(Name, [Scheme])] -> Env
extends :: Env -> [(Name, [Scheme])] -> Env
extends Env
env [(Name, [Scheme])]
xs = Map Name [Scheme] -> Env
TypeEnv (Map Name [Scheme] -> Env) -> Map Name [Scheme] -> Env
forall a b. (a -> b) -> a -> b
$ [(Name, [Scheme])] -> Map Name [Scheme]
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(Name, [Scheme])]
xs Map Name [Scheme] -> Map Name [Scheme] -> Map Name [Scheme]
forall a. Semigroup a => a -> a -> a
<> Env -> Map Name [Scheme]
coerce Env
env

lookup :: Name -> Env -> Maybe [Scheme]
lookup :: Name -> Env -> Maybe [Scheme]
lookup Name
key (TypeEnv Map Name [Scheme]
tys) = Name -> Map Name [Scheme] -> Maybe [Scheme]
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Name
key Map Name [Scheme]
tys

merge :: Env -> Env -> Env
merge :: Env -> Env -> Env
merge (TypeEnv Map Name [Scheme]
a) (TypeEnv Map Name [Scheme]
b) = Map Name [Scheme] -> Env
TypeEnv (Map Name [Scheme] -> Env) -> Map Name [Scheme] -> Env
forall a b. (a -> b) -> a -> b
$ Map Name [Scheme]
a Map Name [Scheme] -> Map Name [Scheme] -> Map Name [Scheme]
forall a. Semigroup a => a -> a -> a
<> Map Name [Scheme]
b

mergeRight :: Env -> Env -> Env
mergeRight :: Env -> Env -> Env
mergeRight (TypeEnv Map Name [Scheme]
a) (TypeEnv Map Name [Scheme]
b) = Map Name [Scheme] -> Env
TypeEnv (Map Name [Scheme] -> Env) -> Map Name [Scheme] -> Env
forall a b. (a -> b) -> a -> b
$ Map Name [Scheme]
b Map Name [Scheme] -> Map Name [Scheme] -> Map Name [Scheme]
forall a. Semigroup a => a -> a -> a
<> Map Name [Scheme]
a

mergeEnvs :: [Env] -> Env
mergeEnvs :: [Env] -> Env
mergeEnvs = (Env -> Env -> Env) -> Env -> [Env] -> Env
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Env -> Env -> Env
forall a. Semigroup a => a -> a -> a
(<>) Env
forall a. Monoid a => a
mempty

singleton :: Name -> Scheme -> Env
singleton :: Name -> Scheme -> Env
singleton Name
x Scheme
y = Map Name [Scheme] -> Env
TypeEnv (Map Name [Scheme] -> Env) -> Map Name [Scheme] -> Env
forall a b. (a -> b) -> a -> b
$ OneItem (Map Name [Scheme]) -> Map Name [Scheme]
forall x. One x => OneItem x -> x
one (Name
x, [Scheme
y])

keys :: Env -> [Name]
keys :: Env -> [Name]
keys (TypeEnv Map Name [Scheme]
env) = Map Name [Scheme] -> [Name]
forall k a. Map k a -> [k]
Map.keys Map Name [Scheme]
env

fromList :: [(Name, [Scheme])] -> Env
fromList :: [(Name, [Scheme])] -> Env
fromList [(Name, [Scheme])]
xs = Map Name [Scheme] -> Env
TypeEnv (Map Name [Scheme] -> Env) -> Map Name [Scheme] -> Env
forall a b. (a -> b) -> a -> b
$ [(Name, [Scheme])] -> Map Name [Scheme]
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(Name, [Scheme])]
xs

toList :: Env -> [(Name, [Scheme])]
toList :: Env -> [(Name, [Scheme])]
toList (TypeEnv Map Name [Scheme]
env) = Map Name [Scheme] -> [(Name, [Scheme])]
forall k a. Map k a -> [(k, a)]
Map.toList Map Name [Scheme]
env