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

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