{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE DerivingVia #-} module Elaboration.Monad where import Control.Monad.Except import Control.Monad.Reader import Control.Applicative import qualified Data.HashMap.Strict as HashMap import qualified Data.Sequence as Seq import Data.HashMap.Strict (HashMap) import Data.Text (Text) import Syntax import Value data ElabState = ElabState { elabEnv :: {-# UNPACK #-} !Env , elabLevel :: {-# UNPACK #-} !Level , elabSwitches :: {-# UNPACK #-} !Int , elabNames :: HashMap Text (Level, VTy) , elabConstrs :: HashMap Text VTy , elabBound :: [BoundDef] , elabSourcePos :: ((Int, Int), (Int, Int)) } deriving (Eq) emptyElabState :: ElabState emptyElabState = ElabState emptyEnv (Lvl 0) 0 mempty mempty [] ((0, 0), (0, 0)) getNames :: MonadReader ElabState m => m [Text] getNames = asks (map go . elabBound) where go (BDBound n) = n go (BDDefined n) = n data ElabError = NotInScope Text | NotFunction [Text] Term | NotEqual [Text] Term Term | CantSolveMeta [Text] Term Term deriving (Show) data ProgError = ProgError { peErr :: ElabError , peSL :: !Int , peSC :: !Int , peEL :: !Int , peEC :: !Int } deriving (Show) newtype ElabM a = ElabM { runElab :: ElabState -> IO (Either [ProgError] a) } deriving ( Functor , Applicative , Monad , Alternative , MonadPlus , MonadReader ElabState , MonadError [ProgError] , MonadIO ) via ReaderT ElabState (ExceptT [ProgError] IO) typeError :: ElabError -> ElabM a typeError err = do (s, e) <- asks elabSourcePos throwError [uncurry (uncurry (ProgError err) s) e] assumeLocal :: Text -> VTy -> ElabM a -> ElabM a assumeLocal name tipe = local go where go r = r { elabLevel = succ (elabLevel r) , elabNames = HashMap.insert name (elabLevel r, tipe) (elabNames r) , elabEnv = (elabEnv r) { locals = VGlued (HVar (Bound (unLvl (elabLevel r)))) mempty Nothing Seq.<| locals (elabEnv r) } , elabBound = BDBound name:elabBound r } defineLocal :: Text -> VTy -> Value -> ElabM a -> ElabM a defineLocal name tipe val = local go where go r = r { elabLevel = succ (elabLevel r) , elabNames = HashMap.insert name (elabLevel r, tipe) (elabNames r) , elabEnv = (elabEnv r) { locals = val Seq.<| locals (elabEnv r) } , elabBound = BDDefined name:elabBound r }