content: {-# LANGUAGE FlexibleInstances #-}
  
  {- |
  Module      : Language.Egison.RState
  Licence     : MIT
  
  This module defines runtime state.
  -}
  
  module Language.Egison.RState
      ( RState (..)
      , RuntimeT
      , RuntimeM
      , MonadRuntime (..)
      , runRuntimeT
      , evalRuntimeT
      ) where
  
  import           Control.Monad.Trans.Class        (lift)
  import           Control.Monad.Trans.Reader
  import           Control.Monad.Trans.State.Strict
  
  import           Language.Egison.AST
  import           Language.Egison.CmdOptions
  
  --
  -- Runtime State
  --
  
  data RState = RState
    { indexCounter :: Int
    , exprOps      :: [Op]
    , patternOps   :: [Op]
    }
  
  initialRState :: RState
  initialRState = RState
    { indexCounter = 0
    , exprOps = reservedExprOp
    , patternOps = reservedPatternOp
    }
  
  type RuntimeT m = ReaderT EgisonOpts (StateT RState m)
  
  type RuntimeM = RuntimeT IO
  
  class (Applicative m, Monad m) => MonadRuntime m where
    fresh :: m String
  
  instance Monad m => MonadRuntime (RuntimeT m) where
    fresh = do
      st <- lift get
      lift (modify (\st -> st { indexCounter = indexCounter st + 1 }))
      return $ "$_" ++ show (indexCounter st)
  
  runRuntimeT :: Monad m => EgisonOpts -> RuntimeT m a -> m (a, RState)
  runRuntimeT opts = flip runStateT initialRState . flip runReaderT opts
  
  evalRuntimeT :: Monad m => EgisonOpts -> RuntimeT m a -> m a
  evalRuntimeT opts = flip evalStateT initialRState . flip runReaderT opts
  