{-# LANGUAGE ScopedTypeVariables, RecordWildCards, CPP #-}
module HIE.Bios.Ghc.Api (
withGHC
, withGHC'
, withGhcT
, initializeFlagsWithCradle
, initializeFlagsWithCradleWithMessage
, getDynamicFlags
, getSystemLibDir
, withDynFlags
, withCmdFlags
, setNoWarningFlags
, setAllWarningFlags
, setDeferTypeErrors
) where
import CoreMonad (liftIO)
import Exception (ghandle, SomeException(..), ExceptionMonad(..), throwIO)
import GHC (Ghc, LoadHowMuch(..), GhcMonad, GhcT)
import DynFlags
import qualified GHC as G
import qualified MonadUtils as G
import qualified HscMain as G
import qualified GhcMake as G
import Control.Monad (void)
import System.Exit (exitSuccess)
import System.IO (hPutStr, hPrint, stderr)
import System.IO.Unsafe (unsafePerformIO)
import qualified HIE.Bios.Ghc.Gap as Gap
import HIE.Bios.Types
import HIE.Bios.Environment
import HIE.Bios.Flags
withGHC :: FilePath
-> Ghc a
-> IO a
withGHC file body = ghandle ignore $ withGHC' body
where
ignore :: SomeException -> IO a
ignore e = do
hPutStr stderr $ file ++ ":0:0:Error:"
hPrint stderr e
exitSuccess
withGHC' :: Ghc a -> IO a
withGHC' body = do
mlibdir <- getSystemLibDir
G.runGhc mlibdir body
withGhcT :: (Exception.ExceptionMonad m, G.MonadIO m, Monad m) => GhcT m a -> m a
withGhcT body = do
mlibdir <- G.liftIO $ getSystemLibDir
G.runGhcT mlibdir body
initializeFlagsWithCradle ::
GhcMonad m
=> FilePath
-> Cradle
-> m ()
initializeFlagsWithCradle = initializeFlagsWithCradleWithMessage (Just G.batchMsg)
initializeFlagsWithCradleWithMessage ::
GhcMonad m
=> Maybe G.Messager
-> FilePath
-> Cradle
-> m ()
initializeFlagsWithCradleWithMessage msg fp cradle = do
compOpts <- liftIO $ getCompilerOptions fp cradle
case compOpts of
Left err -> liftIO $ throwIO err
Right opts -> initSessionWithMessage msg opts
initSessionWithMessage :: (GhcMonad m)
=> Maybe G.Messager
-> CompilerOptions
-> m ()
initSessionWithMessage msg compOpts = do
targets <- initSession compOpts
G.setTargets targets
mod_graph <- G.depanal [] True
void $ G.load' LoadAllTargets msg mod_graph
withDynFlags ::
(GhcMonad m)
=> (DynFlags -> DynFlags) -> m a -> m a
withDynFlags setFlag body = G.gbracket setup teardown (\_ -> body)
where
setup = do
dflag <- G.getSessionDynFlags
void $ G.setSessionDynFlags (setFlag dflag)
return dflag
teardown = void . G.setSessionDynFlags
withCmdFlags ::
(GhcMonad m)
=> [String] -> m a -> m a
withCmdFlags flags body = G.gbracket setup teardown (\_ -> body)
where
setup = do
(dflag, _) <- G.getSessionDynFlags >>= addCmdOpts flags
void $ G.setSessionDynFlags dflag
return dflag
teardown = void . G.setSessionDynFlags
setDeferTypeErrors :: DynFlags -> DynFlags
setDeferTypeErrors
= foldDFlags (flip wopt_set) [Opt_WarnTypedHoles, Opt_WarnDeferredTypeErrors, Opt_WarnDeferredOutOfScopeVariables]
. foldDFlags setGeneralFlag' [Opt_DeferTypedHoles, Opt_DeferTypeErrors, Opt_DeferOutOfScopeVariables]
foldDFlags :: (a -> DynFlags -> DynFlags) -> [a] -> DynFlags -> DynFlags
foldDFlags f xs x = foldr f x xs
setNoWarningFlags :: DynFlags -> DynFlags
setNoWarningFlags df = df { warningFlags = Gap.emptyWarnFlags}
setAllWarningFlags :: DynFlags -> DynFlags
setAllWarningFlags df = df { warningFlags = allWarningFlags }
{-# NOINLINE allWarningFlags #-}
allWarningFlags :: Gap.WarnFlags
allWarningFlags = unsafePerformIO $ do
mlibdir <- getSystemLibDir
G.runGhcT mlibdir $ do
df <- G.getSessionDynFlags
(df', _) <- addCmdOpts ["-Wall"] df
return $ G.warningFlags df'