{-# LANGUAGE CPP #-}

-- | Types used by the runtime interpreter
module GHC.Runtime.Interpreter.Types
   ( Interp(..)
   , IServ(..)
   , IServInstance(..)
   , IServConfig(..)
   , IServState(..)
   )
where

import GhcPrelude

import GHCi.RemoteTypes
import GHCi.Message         ( Pipe )
import UniqFM
import Foreign

import Control.Concurrent
import System.Process   ( ProcessHandle, CreateProcess )

-- | Runtime interpreter
data Interp
   = ExternalInterp !IServ -- ^ External interpreter
#if defined(HAVE_INTERNAL_INTERPRETER)
   | InternalInterp        -- ^ Internal interpreter
#endif

-- | External interpreter
--
-- The external interpreter is spawned lazily (on first use) to avoid slowing
-- down sessions that don't require it. The contents of the MVar reflects the
-- state of the interpreter (running or not).
newtype IServ = IServ (MVar IServState)

-- | State of an external interpreter
data IServState
   = IServPending !IServConfig    -- ^ Not spawned yet
   | IServRunning !IServInstance  -- ^ Running

-- | Configuration needed to spawn an external interpreter
data IServConfig = IServConfig
  { iservConfProgram :: !String   -- ^ External program to run
  , iservConfOpts    :: ![String] -- ^ Command-line options
  , iservConfHook    :: !(Maybe (CreateProcess -> IO ProcessHandle)) -- ^ Hook
  , iservConfTrace   :: IO ()   -- ^ Trace action executed after spawn
  }

-- | External interpreter instance
data IServInstance = IServInstance
  { iservPipe              :: !Pipe
  , iservProcess           :: !ProcessHandle
  , iservLookupSymbolCache :: !(UniqFM (Ptr ()))
  , iservPendingFrees      :: ![HValueRef]
      -- ^ Values that need to be freed before the next command is sent.
      -- Threads can append values to this list asynchronously (by modifying the
      -- IServ state MVar).

  , iservConfig            :: !IServConfig
      -- ^ Config used to spawn the external interpreter
  }