module HsDev.Tools.Ghc.Worker (
	ghcWorker,
	waitGhc,
	evaluate,
	try,

	Ghc,

	module Control.Concurrent.Worker
	) where

import Control.Arrow (left)
import Control.Concurrent
import Control.Exception (SomeException)
import Control.Monad
import Control.Monad.Error
import Data.Dynamic
import Exception (gtry)
import GHC
import GHC.Paths
import Packages

import Control.Concurrent.Worker

ghcWorker :: IO (Worker (Ghc ()))
ghcWorker = worker_ (runGhc (Just libdir)) ghcInit try where
	ghcInit f = do
		fs <- getSessionDynFlags
		defaultCleanupHandler fs $ do
			(fs', _, _) <- parseDynamicFlags fs (map noLoc [])
			let fs'' = fs' {
				ghcMode = CompManager,
				ghcLink = LinkInMemory,
				hscTarget = HscInterpreted }
			_ <- setSessionDynFlags fs''
			_ <- liftIO $ initPackages fs''
			mapM parseImportDecl ["import " ++ m | m <- startMods] >>= setContext . map IIDecl
			f
	startMods :: [String]
	startMods = ["Prelude", "Data.List", "Control.Monad", "HsDev.Tools.Ghc.Prelude"]

waitGhc :: Worker (Ghc ()) -> Ghc a -> ErrorT String IO a
waitGhc w act = ErrorT $ do
	var <- newEmptyMVar
	sendWork w $ try act >>= liftIO . putMVar var
	takeMVar var

evaluate :: String -> Ghc String
evaluate expr = liftM fromDynamic (dynCompileExpr $ "show (" ++ expr ++ ")") >>=
	maybe (fail "evaluate fail") return

try :: Ghc a -> Ghc (Either String a)
try = liftM (left (show :: SomeException -> String)) . gtry