module Agda.TypeChecking.Monad.Open ( makeOpen , getOpen , tryGetOpen , isClosed ) where import Control.Applicative import Control.Monad.Trans import Control.Monad.Trans.Maybe import qualified Data.Map as Map import qualified Data.Set as Set import Agda.Syntax.Internal import Agda.TypeChecking.Substitute import Agda.TypeChecking.Monad.Base import Agda.TypeChecking.Monad.State (currentModuleNameHash) import {-# SOURCE #-} Agda.TypeChecking.Monad.Context import Agda.Utils.Lens import Agda.Utils.Maybe -- | Create an open term in the current context. makeOpen :: (ReadTCState m, MonadTCEnv m) => a -> m (Open a) makeOpen x = do cp <- viewTC eCurrentCheckpoint env <- viewTC eCheckpoints m <- currentModuleNameHash return $ OpenThing cp env m x -- | Extract the value from an open term. The checkpoint at which it was -- created must be in scope. getOpen :: (TermSubst a, MonadTCEnv m) => Open a -> m a getOpen (OpenThing cp _ _ x) = do sub <- checkpointSubstitution cp return $ applySubst sub x -- | Extract the value from an open term. If the checkpoint is no longer in scope use the provided -- function to pull the object to the most recent common checkpoint. The function is given the -- substitution from the common ancestor to the checkpoint of the thing. tryGetOpen :: (TermSubst a, ReadTCState m, MonadTCEnv m) => (Substitution -> a -> Maybe a) -> Open a -> m (Maybe a) tryGetOpen extract open = do OpenThing cp env _ x <- restrict open -- Strip the env if from another module runMaybeT $ do (`applySubst` x) <$> (liftMaybe =<< viewTC (eCheckpoints . key cp)) <|> do -- Checkpoint no longer in scope curEnv <- lift $ viewTC eCheckpoints parent <- findParent env curEnv let Just subToOld = Map.lookup parent env Just subToCur = Map.lookup parent curEnv (applySubst subToCur) <$> liftMaybe (extract subToOld x) where -- If this comes from a different file, the checkpoints refer to checkpoints in that file and -- not in the current file. To avoid confusing them we set the checkpoint to -1 and only keep -- checkpoint 0 (which is shared between files) in the environment. restrict o@(OpenThing cp env m x) = do cur <- currentModuleNameHash if m == cur then return o else return $ OpenThing (-1) (Map.filterWithKey (\ k _ -> k == 0) env) m x findParent m1 m2 | Set.null keys = empty | otherwise = return $ Set.findMax keys where keys = Set.intersection (Map.keysSet m1) (Map.keysSet m2) -- | An 'Open' is closed if it has checkpoint 0. isClosed :: Open a -> Bool isClosed (OpenThing cp _ _ _) = cp == 0