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.

138 lines
4.3 KiB

  1. {-# LANGUAGE DeriveAnyClass #-}
  2. {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  3. {-# LANGUAGE DerivingVia #-}
  4. {-# LANGUAGE DeriveAnyClass #-}
  5. module Elab.Monad where
  6. import Control.Monad.Reader
  7. import Control.Exception
  8. import Data.Text.Prettyprint.Doc.Render.Terminal (AnsiStyle)
  9. import qualified Data.Map.Strict as Map
  10. import Data.Text.Prettyprint.Doc
  11. import Data.Map.Strict (Map)
  12. import Data.Text (Text)
  13. import Data.Typeable
  14. import Syntax
  15. import qualified Presyntax.Presyntax as P
  16. data ElabEnv =
  17. ElabEnv { getEnv :: Map Name (NFType, Value)
  18. , nameMap :: Map Text Name
  19. , pingPong :: Int
  20. , commHook :: Value -> IO ()
  21. , currentSpan :: Maybe (P.Posn, P.Posn)
  22. , whereBound :: Map Name (P.Posn, P.Posn)
  23. }
  24. newtype ElabM a = ElabM { runElab :: ElabEnv -> IO a }
  25. deriving (Functor, Applicative, Monad, MonadReader ElabEnv, MonadIO)
  26. via ReaderT ElabEnv IO
  27. emptyEnv :: ElabEnv
  28. emptyEnv = ElabEnv mempty mempty 0 (const (pure ())) Nothing mempty
  29. assume :: Name -> Value -> ElabM a -> ElabM a
  30. assume nm ty = local go where
  31. go x = x { getEnv = Map.insert nm (ty, VVar nm) (getEnv x)
  32. , nameMap = Map.insert (getNameText nm) nm (nameMap x)
  33. , whereBound = maybe (whereBound x) (flip (Map.insert nm) (whereBound x)) (currentSpan x)
  34. }
  35. assumes :: [Name] -> Value -> ElabM a -> ElabM a
  36. assumes nm ty = local go where
  37. go x = x { getEnv = Map.union (Map.fromList (map (\v -> (v, (ty, VVar v))) nm)) (getEnv x)
  38. , nameMap = Map.union (Map.fromList (map ((,) <$> getNameText <*> id) nm)) (nameMap x)
  39. , whereBound = maybe (whereBound x) (\l -> Map.union (Map.fromList (zip nm (repeat l))) (whereBound x)) (currentSpan x)
  40. }
  41. getNameText :: Name -> Text
  42. getNameText (Bound x) = x
  43. getNameText (Defined x) = x
  44. define :: Name -> Value -> Value -> ElabM a -> ElabM a
  45. define nm ty vl = local go where
  46. go x = x { getEnv = Map.insert nm (ty, vl) (getEnv x), nameMap = Map.insert (getNameText nm) nm (nameMap x) }
  47. getValue :: Name -> ElabM Value
  48. getValue nm = do
  49. vl <- asks (Map.lookup nm . getEnv)
  50. case vl of
  51. Just v -> pure (snd v)
  52. Nothing -> liftIO . throwIO $ NotInScope nm
  53. getNfType :: Name -> ElabM NFType
  54. getNfType nm = do
  55. vl <- asks (Map.lookup nm . getEnv)
  56. case vl of
  57. Just v -> pure (fst v)
  58. Nothing -> liftIO . throwIO $ NotInScope nm
  59. getNameFor :: Text -> ElabM Name
  60. getNameFor x = do
  61. vl <- asks (Map.lookup x . nameMap)
  62. case vl of
  63. Just v -> pure v
  64. Nothing -> liftIO . throwIO $ NotInScope (Bound x)
  65. switch :: ElabM a -> ElabM a
  66. switch k =
  67. do
  68. depth <- asks pingPong
  69. when (depth >= 128) $ liftIO $ throwIO StackOverflow
  70. local go k
  71. where go e = e { pingPong = pingPong e + 1 }
  72. newtype NotInScope = NotInScope { nameNotInScope :: Name }
  73. deriving (Show, Typeable)
  74. deriving anyclass (Exception)
  75. data AttachedNote = AttachedNote { getNote :: Doc AnsiStyle, getExc :: SomeException }
  76. deriving (Show, Typeable)
  77. deriving anyclass (Exception)
  78. withNote :: ElabM a -> Doc AnsiStyle -> ElabM a
  79. withNote k note = do
  80. env <- ask
  81. liftIO $
  82. runElab k env
  83. `catch` \e -> throwIO (AttachedNote note e)
  84. data WhileChecking = WhileChecking { startPos :: P.Posn, endPos :: P.Posn, exc :: SomeException }
  85. deriving (Show, Typeable, Exception)
  86. withSpan :: P.Posn -> P.Posn -> ElabM a -> ElabM a
  87. withSpan a b k = do
  88. env <- ask
  89. liftIO $
  90. runElab k env{ currentSpan = Just (a, b) }
  91. `catches` [ Handler $ \e@WhileChecking{} -> throwIO e
  92. , Handler $ \e -> throwIO (WhileChecking a b e)
  93. ]
  94. data SeeAlso = SeeAlso { saStartPos :: P.Posn, saEndPos :: P.Posn, saExc :: SomeException }
  95. deriving (Show, Typeable, Exception)
  96. seeAlso :: ElabM a -> Name -> ElabM a
  97. seeAlso k nm = do
  98. env <- ask
  99. case Map.lookup nm (whereBound env) of
  100. Just l ->
  101. liftIO $ runElab k env
  102. `catch` \e -> throwIO (SeeAlso (fst l) (snd l) e)
  103. Nothing -> k
  104. catchElab :: Exception e => ElabM a -> (e -> ElabM a) -> ElabM a
  105. catchElab k h = do
  106. env <- ask
  107. liftIO $ runElab k env `catch` \e -> runElab (h e) env
  108. tryElab :: Exception e => ElabM a -> ElabM (Either e a)
  109. tryElab k = do
  110. env <- ask
  111. liftIO $ (Right <$> runElab k env) `catch` \e -> pure (Left e)
  112. throwElab :: Exception e => e -> ElabM a
  113. throwElab = liftIO . throwIO