module HsDev.Tools.Ghc.Worker (
ghcWorker, ghciWorker,
withFlags, modifyFlags, addCmdOpts,
importModules, preludeModules,
evaluate,
clearTargets, makeTarget, loadTargets,
listPackages, spanRegion,
withCurrentDirectory,
Ghc,
module Control.Concurrent.Worker
) where
import Control.Monad
import Control.Monad.Catch
import Control.Monad.Except
import Data.Dynamic
import Data.Maybe
import Data.Time.Clock (getCurrentTime)
import Data.Version (showVersion)
import GHC
import GHC.Paths
import Packages
import StringBuffer
import System.Directory (getCurrentDirectory, setCurrentDirectory)
import Text.Read
import Control.Concurrent.Worker
import HsDev.Symbols.Location (Position(..), Region(..), region, ModulePackage)
ghcWorker :: [String] -> Ghc () -> IO (Worker Ghc)
ghcWorker opts initialize = startWorker (runGhc (Just libdir)) ghcInit id where
ghcInit f = do
fs <- getSessionDynFlags
defaultCleanupHandler fs $ do
(fs', _, _) <- parseDynamicFlags fs (map noLoc opts)
let fs'' = fs' {
ghcMode = CompManager,
ghcLink = LinkInMemory,
hscTarget = HscInterpreted }
_ <- setSessionDynFlags fs''
_ <- liftIO $ initPackages fs''
initialize
f
ghciWorker :: IO (Worker Ghc)
ghciWorker = ghcWorker [] (importModules preludeModules)
withFlags :: Ghc a -> Ghc a
withFlags = gbracket getSessionDynFlags (\fs -> setSessionDynFlags fs >> return ()) . const
modifyFlags :: (DynFlags -> DynFlags) -> Ghc ()
modifyFlags f = do
fs <- getSessionDynFlags
let
fs' = f fs
_ <- setSessionDynFlags fs'
_ <- liftIO $ initPackages fs'
return ()
addCmdOpts :: [String] -> Ghc DynFlags
addCmdOpts opts = do
fs <- getSessionDynFlags
(fs', _, _) <- parseDynamicFlags fs (map noLoc opts)
_ <- setSessionDynFlags fs'
(fs'', _) <- liftIO $ initPackages fs'
return fs''
importModules :: [String] -> Ghc ()
importModules mods = mapM parseImportDecl ["import " ++ m | m <- mods] >>= setContext . map IIDecl
preludeModules :: [String]
preludeModules = ["Prelude", "Data.List", "Control.Monad", "HsDev.Tools.Ghc.Prelude"]
evaluate :: String -> Ghc String
evaluate expr = liftM fromDynamic (dynCompileExpr $ "show (" ++ expr ++ ")") >>=
maybe (fail "evaluate fail") return
clearTargets :: Ghc ()
clearTargets = loadTargets []
makeTarget :: String -> Maybe String -> Ghc Target
makeTarget name Nothing = guessTarget name Nothing
makeTarget name (Just cts) = do
t <- guessTarget name Nothing
tm <- liftIO getCurrentTime
return t { targetContents = Just (stringToStringBuffer cts, tm) }
loadTargets :: [Target] -> Ghc ()
loadTargets ts = setTargets ts >> load LoadAllTargets >> return ()
listPackages :: Ghc [ModulePackage]
listPackages = liftM (mapMaybe readPackage . fromMaybe [] . pkgDatabase) getSessionDynFlags
readPackage :: PackageConfig -> Maybe ModulePackage
readPackage pc = readMaybe $ packageNameString pc ++ "-" ++ showVersion (packageVersion pc)
spanRegion :: SrcSpan -> Region
spanRegion (RealSrcSpan s) = Position (srcSpanStartLine s) (srcSpanStartCol s) `region` Position (srcSpanEndLine s) (srcSpanEndCol s)
spanRegion _ = Position 0 0 `region` Position 0 0
withCurrentDirectory :: FilePath -> Ghc a -> Ghc a
withCurrentDirectory dir act = gbracket (liftIO getCurrentDirectory) (liftIO . setCurrentDirectory) $
const (liftIO (setCurrentDirectory dir) >> act)
instance MonadThrow Ghc where
throwM = liftIO . throwM
instance MonadCatch Ghc where
catch = gcatch