|
{-# LANGUAGE DeriveAnyClass #-}
|
|
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
|
{-# LANGUAGE DerivingVia #-}
|
|
module Elab.Monad where
|
|
|
|
import Control.Monad.Reader
|
|
import Control.Exception
|
|
|
|
import qualified Data.Map.Strict as Map
|
|
import Data.Map.Strict (Map)
|
|
import Data.Typeable
|
|
|
|
import Syntax
|
|
|
|
newtype ElabEnv = ElabEnv { getEnv :: Map Name (NFType, Value) }
|
|
|
|
newtype ElabM a = ElabM { runElab :: ElabEnv -> IO a }
|
|
deriving (Functor, Applicative, Monad, MonadReader ElabEnv, MonadIO)
|
|
via ReaderT ElabEnv IO
|
|
|
|
newtype NotInScope = NotInScope { getName :: Name }
|
|
deriving (Show, Typeable)
|
|
deriving anyclass (Exception)
|
|
|
|
emptyEnv :: ElabEnv
|
|
emptyEnv = ElabEnv mempty
|
|
|
|
assume :: Name -> Value -> ElabM a -> ElabM a
|
|
assume nm ty = local go where
|
|
go = ElabEnv . Map.insert nm (ty, VVar nm) . getEnv
|
|
|
|
define :: Name -> Value -> Value -> ElabM a -> ElabM a
|
|
define nm ty vl = local go where
|
|
go = ElabEnv . Map.insert nm (ty, vl) . getEnv
|
|
|
|
getValue :: Name -> ElabM Value
|
|
getValue nm = do
|
|
vl <- asks (Map.lookup nm . getEnv)
|
|
case vl of
|
|
Just v -> pure (snd v)
|
|
Nothing -> liftIO . throwIO $ NotInScope nm
|
|
|
|
getNfType :: Name -> ElabM NFType
|
|
getNfType nm = do
|
|
vl <- asks (Map.lookup nm . getEnv)
|
|
case vl of
|
|
Just v -> pure (fst v)
|
|
Nothing -> liftIO . throwIO $ NotInScope nm
|