less prototype, less bad code implementation of CCHM type theory
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

199 lines
6.0 KiB

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DeriveAnyClass #-}
module Elab.Monad where
import Control.Monad.Reader
import Control.Exception
import Data.Text.Prettyprint.Doc.Render.Terminal (AnsiStyle)
import qualified Data.Map.Strict as Map
import Data.Text.Prettyprint.Doc
import Data.Map.Strict (Map)
import Data.Sequence (Seq)
import Data.Text (Text)
import Data.Set (Set)
import Data.Typeable
import Data.IORef
import qualified Presyntax.Presyntax as P
import Syntax
data ElabEnv =
ElabEnv { getEnv :: Map Name (NFType, Value)
, nameMap :: Map Text Name
, pingPong :: {-# UNPACK #-} !Int
, commHook :: Doc AnsiStyle -> IO ()
, currentSpan :: Maybe (P.Posn, P.Posn)
, currentFile :: Maybe Text
, whereBound :: Map Name (P.Posn, P.Posn)
, definedNames :: Set Name
, boundaries :: Map Name Boundary
, unsolvedMetas :: {-# UNPACK #-} !(IORef (Map MV [(Seq Projection, Value)]))
, loadedFiles :: [String]
}
newtype ElabM a = ElabM { runElab :: ElabEnv -> IO a }
deriving (Functor, Applicative, Monad, MonadReader ElabEnv, MonadIO)
via ReaderT ElabEnv IO
emptyEnv :: IO ElabEnv
emptyEnv = do
u <- newIORef mempty
pure $ ElabEnv { getEnv = mempty
, nameMap = mempty
, pingPong = 0
, commHook = const (pure ())
, currentSpan = Nothing
, currentFile = Nothing
, whereBound = mempty
, definedNames = mempty
, boundaries = mempty
, unsolvedMetas = u
, loadedFiles = []
}
addBoundary :: Name -> Boundary -> ElabM a -> ElabM a
addBoundary nm boundary = local (\e -> e { boundaries = Map.insert nm boundary (boundaries e)} )
assume :: Name -> Value -> (Name -> ElabM a) -> ElabM a
assume nm ty k = defineInternal nm ty VVar k
define :: Name -> Value -> Value -> (Name -> ElabM a) -> ElabM a
define nm vty val = defineInternal nm vty (const val)
makeLetDef :: Name -> Value -> Value -> (Name -> ElabM a) -> ElabM a
makeLetDef nm vty val = defineInternal nm vty (\nm -> GluedVl (HVar nm) mempty val)
replaceLetDef :: Name -> Value -> Value -> ElabM a -> ElabM a
replaceLetDef nm vty val = redefine nm vty (GluedVl (HVar nm) mempty val)
assumes :: [Name] -> Value -> ([Name] -> ElabM a) -> ElabM a
assumes nms ty k = do
let
go acc [] k = k acc
go acc (x:xs) k = assume x ty $ \n -> go (n:acc) xs k
in go [] nms k
defineInternal :: Name -> Value -> (Name -> Value) -> (Name -> ElabM a) -> ElabM a
defineInternal nm vty val k =
do
env <- ask
let (env', name') = go env
local (const env') (k name')
where
go x =
let
nm' = case Map.lookup (getNameText nm) (nameMap x) of
Just name -> incName nm name
Nothing -> nm
in ( x { getEnv = Map.insert nm' (vty, val nm') (getEnv x)
, nameMap = Map.insert (getNameText nm) nm' (nameMap x)
, whereBound = maybe (whereBound x) (flip (Map.insert nm') (whereBound x)) (currentSpan x)
}
, nm')
redefine :: Name -> Value -> Value -> ElabM a -> ElabM a
redefine nm vty val = local go where
go x = x { getEnv = Map.insert nm (vty, val) (getEnv x)
, nameMap = Map.insert (getNameText nm) nm (nameMap x)
, whereBound = maybe (whereBound x) (flip (Map.insert nm) (whereBound x)) (currentSpan x)
}
getValue :: Name -> ElabM Value
getValue nm = do
vl <- asks (Map.lookup nm . getEnv)
case vl of
Just v -> pure (snd v)
Nothing -> throwElab $ NotInScope nm
getNfType :: Name -> ElabM NFType
getNfType nm = do
vl <- asks (Map.lookup nm . getEnv)
case vl of
Just v -> pure (fst v)
Nothing -> throwElab $ NotInScope nm
getNameFor :: Text -> ElabM Name
getNameFor x = do
vl <- asks (Map.lookup x . nameMap)
case vl of
Just v -> pure v
Nothing -> liftIO . throwIO $ NotInScope (Bound x 0)
switch :: ElabM a -> ElabM a
switch k =
do
depth <- asks pingPong
when (depth >= 128) $ throwElab StackOverflow
local go k
where go e = e { pingPong = pingPong e + 1 }
newtype NotInScope = NotInScope { nameNotInScope :: Name }
deriving (Show, Typeable)
deriving anyclass (Exception)
data AttachedNote = AttachedNote { getNote :: Doc AnsiStyle, getExc :: SomeException }
deriving (Show, Typeable)
deriving anyclass (Exception)
withNote :: ElabM a -> Doc AnsiStyle -> ElabM a
withNote k note = do
env <- ask
liftIO $
runElab k env
`catch` \e -> throwIO (AttachedNote note e)
data WhileChecking = WhileChecking { startPos :: P.Posn, endPos :: P.Posn, exc :: SomeException }
deriving (Show, Typeable, Exception)
withSpan :: P.Posn -> P.Posn -> ElabM a -> ElabM a
withSpan a b k = do
env <- ask
liftIO $
runElab k env{ currentSpan = Just (a, b) }
`catches` [ Handler $ \e@WhileChecking{} -> throwIO e
, Handler $ \e -> throwIO (WhileChecking a b e)
]
data SeeAlso = SeeAlso { saStartPos :: P.Posn, saEndPos :: P.Posn, saExc :: SomeException }
deriving (Show, Typeable, Exception)
seeAlso :: ElabM a -> Name -> ElabM a
seeAlso k nm = do
env <- ask
case Map.lookup nm (whereBound env) of
Just l ->
liftIO $ runElab k env
`catch` \e -> throwIO (SeeAlso (fst l) (snd l) e)
Nothing -> k
catchElab :: Exception e => ElabM a -> (e -> ElabM a) -> ElabM a
catchElab k h = do
env <- ask
liftIO $ runElab k env `catch` \e -> runElab (h e) env
tryElab :: Exception e => ElabM a -> ElabM (Either e a)
tryElab k = do
env <- ask
liftIO $ (Right <$> runElab k env) `catch` \e -> pure (Left e)
throwElab :: Exception e => e -> ElabM a
throwElab = liftIO . throwIO
incName :: Name -> Name -> Name
incName (Bound x _) n = Bound x (getNameNum n + 1)
incName (Defined x _) n = Defined x (getNameNum n + 1)
incName (ConName x _ s a) n = ConName x (getNameNum n + 1) s a