-- {-# LANGUAGE CPP #-}

module Agda.TypeChecking.Monad.Open
        ( makeOpen
        , makeClosed
        , getOpen
        , tryOpen
        ) where

import Control.Applicative
import Control.Monad
import Data.List

import Agda.TypeChecking.Substitute
import Agda.TypeChecking.Monad.Base

import {-# SOURCE #-} Agda.TypeChecking.Monad.Context

import Agda.Utils.Except ( MonadError(catchError) )

-- | Create an open term in the current context.
makeOpen :: a -> TCM (Open a)
makeOpen x = do
    ctx <- getContextId
    return $ OpenThing ctx x

-- | Create an open term which is closed.
makeClosed :: a -> Open a
makeClosed = OpenThing []

-- | Extract the value from an open term. Must be done in an extension of the
--   context in which the term was created.
getOpen :: Subst a => Open a -> TCM a
getOpen (OpenThing []  x) = return x
getOpen (OpenThing ctx x) = do
  ctx' <- getContextId
  unless (ctx `isSuffixOf` ctx') $ fail $ "thing out of context (" ++ show ctx ++ " is not a sub context of " ++ show ctx' ++ ")"
  return $ raise (genericLength ctx' - genericLength ctx) x

-- | Try to use an 'Open' the current context.
--   Returns 'Nothing' if current context is not an extension of the
--   context in which the 'Open' was created.
tryOpen :: Subst a => Open a -> TCM (Maybe a)
tryOpen o =
  (Just <$> getOpen o)
  `catchError` \_ -> return Nothing
