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.

162 lines
4.8 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.Set (Set)
  14. import Data.Typeable
  15. import qualified Presyntax.Presyntax as P
  16. import Syntax
  17. data ElabEnv =
  18. ElabEnv { getEnv :: Map Name (NFType, Value)
  19. , nameMap :: Map Text Name
  20. , pingPong :: Int
  21. , commHook :: Value -> IO ()
  22. , currentSpan :: Maybe (P.Posn, P.Posn)
  23. , whereBound :: Map Name (P.Posn, P.Posn)
  24. , definedNames :: Set Name
  25. }
  26. newtype ElabM a = ElabM { runElab :: ElabEnv -> IO a }
  27. deriving (Functor, Applicative, Monad, MonadReader ElabEnv, MonadIO)
  28. via ReaderT ElabEnv IO
  29. emptyEnv :: ElabEnv
  30. emptyEnv = ElabEnv mempty mempty 0 (const (pure ())) Nothing mempty mempty
  31. assume :: Name -> Value -> (Name -> ElabM a) -> ElabM a
  32. assume nm ty k = defineInternal nm ty VVar k
  33. define :: Name -> Value -> Value -> (Name -> ElabM a) -> ElabM a
  34. define nm vty val = defineInternal nm vty (const val)
  35. assumes :: [Name] -> Value -> ([Name] -> ElabM a) -> ElabM a
  36. assumes nms ty k = do
  37. let
  38. go acc [] k = k acc
  39. go acc (x:xs) k = assume x ty $ \n -> go (n:acc) xs k
  40. in go [] nms k
  41. defineInternal :: Name -> Value -> (Name -> Value) -> (Name -> ElabM a) -> ElabM a
  42. defineInternal nm vty val k =
  43. do
  44. env <- ask
  45. let (env', name') = go env
  46. local (const env') (k name')
  47. where
  48. go x =
  49. let
  50. nm' = case Map.lookup (getNameText nm) (nameMap x) of
  51. Just name -> incName nm name
  52. Nothing -> nm
  53. in ( x { getEnv = Map.insert nm' (vty, val nm') (getEnv x)
  54. , nameMap = Map.insert (getNameText nm) nm' (nameMap x)
  55. , whereBound = maybe (whereBound x) (flip (Map.insert nm') (whereBound x)) (currentSpan x)
  56. }
  57. , nm')
  58. redefine :: Name -> Value -> Value -> ElabM a -> ElabM a
  59. redefine nm vty val = local go where
  60. go x = x { getEnv = Map.insert nm (vty, val) (getEnv x)
  61. , nameMap = Map.insert (getNameText nm) nm (nameMap x)
  62. , whereBound = maybe (whereBound x) (flip (Map.insert nm) (whereBound x)) (currentSpan x)
  63. }
  64. getValue :: Name -> ElabM Value
  65. getValue nm = do
  66. vl <- asks (Map.lookup nm . getEnv)
  67. case vl of
  68. Just v -> pure (snd v)
  69. Nothing -> throwElab $ NotInScope nm
  70. getNfType :: Name -> ElabM NFType
  71. getNfType nm = do
  72. vl <- asks (Map.lookup nm . getEnv)
  73. case vl of
  74. Just v -> pure (fst v)
  75. Nothing -> throwElab $ NotInScope nm
  76. getNameFor :: Text -> ElabM Name
  77. getNameFor x = do
  78. vl <- asks (Map.lookup x . nameMap)
  79. case vl of
  80. Just v -> pure v
  81. Nothing -> liftIO . throwIO $ NotInScope (Bound x 0)
  82. switch :: ElabM a -> ElabM a
  83. switch k =
  84. do
  85. depth <- asks pingPong
  86. when (depth >= 128) $ throwElab StackOverflow
  87. local go k
  88. where go e = e { pingPong = pingPong e + 1 }
  89. newtype NotInScope = NotInScope { nameNotInScope :: Name }
  90. deriving (Show, Typeable)
  91. deriving anyclass (Exception)
  92. data AttachedNote = AttachedNote { getNote :: Doc AnsiStyle, getExc :: SomeException }
  93. deriving (Show, Typeable)
  94. deriving anyclass (Exception)
  95. withNote :: ElabM a -> Doc AnsiStyle -> ElabM a
  96. withNote k note = do
  97. env <- ask
  98. liftIO $
  99. runElab k env
  100. `catch` \e -> throwIO (AttachedNote note e)
  101. data WhileChecking = WhileChecking { startPos :: P.Posn, endPos :: P.Posn, exc :: SomeException }
  102. deriving (Show, Typeable, Exception)
  103. withSpan :: P.Posn -> P.Posn -> ElabM a -> ElabM a
  104. withSpan a b k = do
  105. env <- ask
  106. liftIO $
  107. runElab k env{ currentSpan = Just (a, b) }
  108. `catches` [ Handler $ \e@WhileChecking{} -> throwIO e
  109. , Handler $ \e -> throwIO (WhileChecking a b e)
  110. ]
  111. data SeeAlso = SeeAlso { saStartPos :: P.Posn, saEndPos :: P.Posn, saExc :: SomeException }
  112. deriving (Show, Typeable, Exception)
  113. seeAlso :: ElabM a -> Name -> ElabM a
  114. seeAlso k nm = do
  115. env <- ask
  116. case Map.lookup nm (whereBound env) of
  117. Just l ->
  118. liftIO $ runElab k env
  119. `catch` \e -> throwIO (SeeAlso (fst l) (snd l) e)
  120. Nothing -> k
  121. catchElab :: Exception e => ElabM a -> (e -> ElabM a) -> ElabM a
  122. catchElab k h = do
  123. env <- ask
  124. liftIO $ runElab k env `catch` \e -> runElab (h e) env
  125. tryElab :: Exception e => ElabM a -> ElabM (Either e a)
  126. tryElab k = do
  127. env <- ask
  128. liftIO $ (Right <$> runElab k env) `catch` \e -> pure (Left e)
  129. throwElab :: Exception e => e -> ElabM a
  130. throwElab = liftIO . throwIO
  131. incName :: Name -> Name -> Name
  132. incName (Bound x _) n = Bound x (getNameNum n + 1)
  133. incName (Defined x k) n = Defined x (getNameNum n + 1)