hint-0.2.4: src/Hint/Context.hs
module Hint.Context (
ModuleName,
loadModules, getLoadedModules, setTopLevelModules,
setImports,
reset
)
where
import Data.List
import Control.Monad.Error
import Hint.Base
import Hint.Conversions
import qualified GHC
-- | Tries to load all the requested modules from their source file.
-- Modules my be indicated by their ModuleName (e.g. \"My.Module\") or
-- by the full path to its source file.
--
-- The interpreter is 'reset' both before loading the modules and in the event
-- of an error.
loadModules :: [String] -> Interpreter ()
loadModules fs =
do
ghc_session <- fromSessionState ghcSession
--
-- first, unload everything
reset
--
let doLoad = mayFail $ do
targets <- mapM (\f -> GHC.guessTarget f Nothing) fs
--
GHC.setTargets ghc_session targets
res <- GHC.load ghc_session GHC.LoadAllTargets
return $ guard (isSucceeded res) >> Just ()
--
doLoad `catchError` (\e -> reset >> throwError e)
--
return ()
-- | Returns the list of modules loaded with 'loadModules'.
getLoadedModules :: Interpreter [ModuleName]
getLoadedModules = liftM (map modNameFromSummary) getLoadedModSummaries
modNameFromSummary :: GHC.ModSummary -> ModuleName
modNameFromSummary = fromGhcRep_ . GHC.ms_mod
getLoadedModSummaries :: Interpreter [GHC.ModSummary]
getLoadedModSummaries =
do ghc_session <- fromSessionState ghcSession
--
all_mod_summ <- liftIO $ GHC.getModuleGraph ghc_session
filterM (liftIO . GHC.isLoaded ghc_session . GHC.ms_mod_name) all_mod_summ
-- | Sets the modules whose context is used during evaluation. All bindings
-- of these modules are in scope, not only those exported.
--
-- Modules must be interpreted to use this function.
setTopLevelModules :: [ModuleName] -> Interpreter ()
setTopLevelModules ms =
do
ghc_session <- fromSessionState ghcSession
--
loaded_mods_ghc <- getLoadedModSummaries
--
let not_loaded = ms \\ map modNameFromSummary loaded_mods_ghc
when (not . null $ not_loaded) $
throwError $ NotAllowed ("These modules have not been loaded:\n" ++
unlines not_loaded)
--
ms_mods <- mapM findModule ms
--
let mod_is_interpr = GHC.moduleIsInterpreted ghc_session
not_interpreted <- liftIO $ filterM (liftM not . mod_is_interpr) ms_mods
when (not . null $ not_interpreted) $
throwError $ NotAllowed ("These modules are not interpreted:\n" ++
unlines (map fromGhcRep_ not_interpreted))
--
liftIO $ do
(_, old_imports) <- GHC.getContext ghc_session
GHC.setContext ghc_session ms_mods old_imports
-- | Sets the modules whose exports must be in context.
setImports :: [ModuleName] -> Interpreter ()
setImports ms =
do
ghc_session <- fromSessionState ghcSession
--
ms_mods <- mapM findModule ms
--
liftIO $ do
(old_top_level, _) <- GHC.getContext ghc_session
GHC.setContext ghc_session old_top_level ms_mods
-- | All imported modules are cleared from the context, and
-- loaded modules are unloaded. It is similar to a @:load@ in
-- GHCi, but observe that not even the Prelude will be in
-- context after a reset.
reset :: Interpreter ()
reset =
do
ghc_session <- fromSessionState ghcSession
--
-- Remove all modules from context
liftIO $ GHC.setContext ghc_session [] []
--
-- Unload all previously loaded modules
liftIO $ GHC.setTargets ghc_session []
liftIO $ GHC.load ghc_session GHC.LoadAllTargets
--
-- At this point, GHCi would call rts_revertCAFs and
-- reset the buffering of stdin, stdout and stderr.
-- Should we do any of these?
--
-- liftIO $ rts_revertCAFs
--
return ()
-- SHOULD WE CALL THIS WHEN MODULES ARE LOADED / UNLOADED?
-- foreign import ccall "revertCAFs" rts_revertCAFs :: IO ()