module Hint.Base (
MonadInterpreter(..), RunGhc,
GhcError(..), InterpreterError(..), mayFail, catchIE,
InterpreterSession, SessionData(..), GhcErrLogger,
InterpreterState(..), fromState, onState,
InterpreterConfiguration(..),
ImportList(..), ModuleQualification(..), ModuleImport(..),
runGhc1, runGhc2,
ModuleName, PhantomModule(..),
findModule, moduleIsLoaded,
withDynFlags,
ghcVersion,
debug, showGHC
) where
import Control.Monad.Trans
import Control.Monad.Catch as MC
import Data.IORef
import Data.Dynamic
import qualified Data.List
import qualified Hint.GHC as GHC
import Hint.Extension
ghcVersion :: Int
ghcVersion :: Int
ghcVersion = __GLASGOW_HASKELL__
class (MonadIO m, MonadMask m) => MonadInterpreter m where
fromSession :: FromSession m a
modifySessionRef :: ModifySessionRef m a
runGhc :: RunGhc m a
type FromSession m a = (InterpreterSession -> a) -> m a
type ModifySessionRef m a = (InterpreterSession -> IORef a) -> (a -> a) -> m a
data InterpreterError = UnknownError String
| WontCompile [GhcError]
| NotAllowed String
| GhcException String
deriving (Int -> InterpreterError -> ShowS
[InterpreterError] -> ShowS
InterpreterError -> String
(Int -> InterpreterError -> ShowS)
-> (InterpreterError -> String)
-> ([InterpreterError] -> ShowS)
-> Show InterpreterError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [InterpreterError] -> ShowS
$cshowList :: [InterpreterError] -> ShowS
show :: InterpreterError -> String
$cshow :: InterpreterError -> String
showsPrec :: Int -> InterpreterError -> ShowS
$cshowsPrec :: Int -> InterpreterError -> ShowS
Show, Typeable)
data InterpreterState = St {
InterpreterState -> [PhantomModule]
activePhantoms :: [PhantomModule],
InterpreterState -> [PhantomModule]
zombiePhantoms :: [PhantomModule],
#if defined(NEED_PHANTOM_DIRECTORY)
InterpreterState -> Maybe String
phantomDirectory :: Maybe FilePath,
#endif
InterpreterState -> PhantomModule
hintSupportModule :: PhantomModule,
InterpreterState -> Maybe PhantomModule
importQualHackMod :: Maybe PhantomModule,
InterpreterState -> [ModuleImport]
qualImports :: [ModuleImport],
InterpreterState -> [(Extension, Bool)]
defaultExts :: [(Extension, Bool)],
InterpreterState -> InterpreterConfiguration
configuration :: InterpreterConfiguration
}
data ImportList = NoImportList | ImportList [String] | HidingList [String]
deriving (ImportList -> ImportList -> Bool
(ImportList -> ImportList -> Bool)
-> (ImportList -> ImportList -> Bool) -> Eq ImportList
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ImportList -> ImportList -> Bool
$c/= :: ImportList -> ImportList -> Bool
== :: ImportList -> ImportList -> Bool
$c== :: ImportList -> ImportList -> Bool
Eq, Int -> ImportList -> ShowS
[ImportList] -> ShowS
ImportList -> String
(Int -> ImportList -> ShowS)
-> (ImportList -> String)
-> ([ImportList] -> ShowS)
-> Show ImportList
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ImportList] -> ShowS
$cshowList :: [ImportList] -> ShowS
show :: ImportList -> String
$cshow :: ImportList -> String
showsPrec :: Int -> ImportList -> ShowS
$cshowsPrec :: Int -> ImportList -> ShowS
Show)
data ModuleQualification = NotQualified | ImportAs String | QualifiedAs (Maybe String)
deriving (ModuleQualification -> ModuleQualification -> Bool
(ModuleQualification -> ModuleQualification -> Bool)
-> (ModuleQualification -> ModuleQualification -> Bool)
-> Eq ModuleQualification
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ModuleQualification -> ModuleQualification -> Bool
$c/= :: ModuleQualification -> ModuleQualification -> Bool
== :: ModuleQualification -> ModuleQualification -> Bool
$c== :: ModuleQualification -> ModuleQualification -> Bool
Eq, Int -> ModuleQualification -> ShowS
[ModuleQualification] -> ShowS
ModuleQualification -> String
(Int -> ModuleQualification -> ShowS)
-> (ModuleQualification -> String)
-> ([ModuleQualification] -> ShowS)
-> Show ModuleQualification
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ModuleQualification] -> ShowS
$cshowList :: [ModuleQualification] -> ShowS
show :: ModuleQualification -> String
$cshow :: ModuleQualification -> String
showsPrec :: Int -> ModuleQualification -> ShowS
$cshowsPrec :: Int -> ModuleQualification -> ShowS
Show)
data ModuleImport = ModuleImport { ModuleImport -> String
modName :: String
, ModuleImport -> ModuleQualification
modQual :: ModuleQualification
, ModuleImport -> ImportList
modImp :: ImportList
} deriving (Int -> ModuleImport -> ShowS
[ModuleImport] -> ShowS
ModuleImport -> String
(Int -> ModuleImport -> ShowS)
-> (ModuleImport -> String)
-> ([ModuleImport] -> ShowS)
-> Show ModuleImport
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ModuleImport] -> ShowS
$cshowList :: [ModuleImport] -> ShowS
show :: ModuleImport -> String
$cshow :: ModuleImport -> String
showsPrec :: Int -> ModuleImport -> ShowS
$cshowsPrec :: Int -> ModuleImport -> ShowS
Show)
data InterpreterConfiguration = Conf {
InterpreterConfiguration -> [String]
searchFilePath :: [FilePath],
InterpreterConfiguration -> [Extension]
languageExts :: [Extension],
InterpreterConfiguration -> Bool
allModsInScope :: Bool
}
type InterpreterSession = SessionData ()
instance Exception InterpreterError
where
displayException :: InterpreterError -> String
displayException (UnknownError err :: String
err) = "UnknownError: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
err
displayException (WontCompile es :: [GhcError]
es) = [String] -> String
unlines ([String] -> String)
-> ([GhcError] -> [String]) -> [GhcError] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [String]
forall a. Eq a => [a] -> [a]
Data.List.nub ([String] -> [String])
-> ([GhcError] -> [String]) -> [GhcError] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GhcError -> String) -> [GhcError] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map GhcError -> String
errMsg ([GhcError] -> String) -> [GhcError] -> String
forall a b. (a -> b) -> a -> b
$ [GhcError]
es
displayException (NotAllowed err :: String
err) = "NotAllowed: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
err
displayException (GhcException err :: String
err) = "GhcException: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
err
type RunGhc m a =
(forall n.(MonadIO n, MonadMask n) => GHC.GhcT n a)
-> m a
type RunGhc1 m a b =
(forall n.(MonadIO n, MonadMask n) => a -> GHC.GhcT n b)
-> (a -> m b)
type RunGhc2 m a b c =
(forall n.(MonadIO n, MonadMask n) => a -> b -> GHC.GhcT n c)
-> (a -> b -> m c)
data SessionData a = SessionData {
SessionData a -> IORef InterpreterState
internalState :: IORef InterpreterState,
SessionData a -> a
versionSpecific :: a,
SessionData a -> IORef [GhcError]
ghcErrListRef :: IORef [GhcError],
SessionData a -> GhcErrLogger
ghcErrLogger :: GhcErrLogger
}
newtype GhcError = GhcError{GhcError -> String
errMsg :: String} deriving Int -> GhcError -> ShowS
[GhcError] -> ShowS
GhcError -> String
(Int -> GhcError -> ShowS)
-> (GhcError -> String) -> ([GhcError] -> ShowS) -> Show GhcError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [GhcError] -> ShowS
$cshowList :: [GhcError] -> ShowS
show :: GhcError -> String
$cshow :: GhcError -> String
showsPrec :: Int -> GhcError -> ShowS
$cshowsPrec :: Int -> GhcError -> ShowS
Show
mapGhcExceptions :: MonadInterpreter m
=> (String -> InterpreterError)
-> m a
-> m a
mapGhcExceptions :: (String -> InterpreterError) -> m a -> m a
mapGhcExceptions buildEx :: String -> InterpreterError
buildEx action :: m a
action =
m a
action
m a -> (InterpreterError -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
`MC.catch` (\err :: InterpreterError
err -> case InterpreterError
err of
GhcException s :: String
s -> InterpreterError -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (String -> InterpreterError
buildEx String
s)
_ -> InterpreterError -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM InterpreterError
err)
catchIE :: MonadInterpreter m => m a -> (InterpreterError -> m a) -> m a
catchIE :: m a -> (InterpreterError -> m a) -> m a
catchIE = m a -> (InterpreterError -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
MC.catch
type GhcErrLogger = GHC.LogAction
type ModuleName = String
runGhc1 :: MonadInterpreter m => RunGhc1 m a b
runGhc1 :: RunGhc1 m a b
runGhc1 f :: forall (n :: * -> *). (MonadIO n, MonadMask n) => a -> GhcT n b
f a :: a
a = RunGhc m b
forall (m :: * -> *) a. MonadInterpreter m => RunGhc m a
runGhc (a -> GhcT n b
forall (n :: * -> *). (MonadIO n, MonadMask n) => a -> GhcT n b
f a
a)
runGhc2 :: MonadInterpreter m => RunGhc2 m a b c
runGhc2 :: RunGhc2 m a b c
runGhc2 f :: forall (n :: * -> *).
(MonadIO n, MonadMask n) =>
a -> b -> GhcT n c
f a :: a
a = RunGhc1 m b c
forall (m :: * -> *) a b. MonadInterpreter m => RunGhc1 m a b
runGhc1 (a -> b -> GhcT n c
forall (n :: * -> *).
(MonadIO n, MonadMask n) =>
a -> b -> GhcT n c
f a
a)
fromState :: MonadInterpreter m => (InterpreterState -> a) -> m a
fromState :: (InterpreterState -> a) -> m a
fromState f :: InterpreterState -> a
f = do IORef InterpreterState
ref_st <- FromSession m (IORef InterpreterState)
forall (m :: * -> *) a. MonadInterpreter m => FromSession m a
fromSession SessionData () -> IORef InterpreterState
forall a. SessionData a -> IORef InterpreterState
internalState
IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> m a) -> IO a -> m a
forall a b. (a -> b) -> a -> b
$ InterpreterState -> a
f (InterpreterState -> a) -> IO InterpreterState -> IO a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` IORef InterpreterState -> IO InterpreterState
forall a. IORef a -> IO a
readIORef IORef InterpreterState
ref_st
onState :: MonadInterpreter m => (InterpreterState -> InterpreterState) -> m ()
onState :: (InterpreterState -> InterpreterState) -> m ()
onState f :: InterpreterState -> InterpreterState
f = ModifySessionRef m InterpreterState
forall (m :: * -> *) a. MonadInterpreter m => ModifySessionRef m a
modifySessionRef SessionData () -> IORef InterpreterState
forall a. SessionData a -> IORef InterpreterState
internalState InterpreterState -> InterpreterState
f m InterpreterState -> m () -> m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
mayFail :: MonadInterpreter m => m (Maybe a) -> m a
mayFail :: m (Maybe a) -> m a
mayFail action :: m (Maybe a)
action =
do
Maybe a
maybe_res <- m (Maybe a)
action
[GhcError]
es <- ModifySessionRef m [GhcError]
forall (m :: * -> *) a. MonadInterpreter m => ModifySessionRef m a
modifySessionRef SessionData () -> IORef [GhcError]
forall a. SessionData a -> IORef [GhcError]
ghcErrListRef ([GhcError] -> [GhcError] -> [GhcError]
forall a b. a -> b -> a
const [])
case (Maybe a
maybe_res, [GhcError] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [GhcError]
es) of
(Nothing, True) -> InterpreterError -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (InterpreterError -> m a) -> InterpreterError -> m a
forall a b. (a -> b) -> a -> b
$ String -> InterpreterError
UnknownError "Got no error message"
(Nothing, False) -> InterpreterError -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (InterpreterError -> m a) -> InterpreterError -> m a
forall a b. (a -> b) -> a -> b
$ [GhcError] -> InterpreterError
WontCompile ([GhcError] -> [GhcError]
forall a. [a] -> [a]
reverse [GhcError]
es)
(Just a :: a
a, _) -> a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a
debug :: MonadInterpreter m => String -> m ()
debug :: String -> m ()
debug = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (String -> IO ()) -> String -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO ()
putStrLn (String -> IO ()) -> ShowS -> String -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ("!! " String -> ShowS
forall a. [a] -> [a] -> [a]
++)
showGHC :: (MonadInterpreter m, GHC.Outputable a) => a -> m String
showGHC :: a -> m String
showGHC a :: a
a
= do PrintUnqualified
unqual <- RunGhc m PrintUnqualified
forall (m :: * -> *) a. MonadInterpreter m => RunGhc m a
runGhc forall (n :: * -> *).
(MonadIO n, MonadMask n) =>
GhcT n PrintUnqualified
forall (m :: * -> *). GhcMonad m => m PrintUnqualified
GHC.getPrintUnqual
(DynFlags -> m String) -> m String
forall (m :: * -> *) a.
MonadInterpreter m =>
(DynFlags -> m a) -> m a
withDynFlags ((DynFlags -> m String) -> m String)
-> (DynFlags -> m String) -> m String
forall a b. (a -> b) -> a -> b
$ \df :: DynFlags
df ->
String -> m String
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> m String) -> String -> m String
forall a b. (a -> b) -> a -> b
$ DynFlags -> PrintUnqualified -> SDoc -> String
GHC.showSDocForUser DynFlags
df PrintUnqualified
unqual (a -> SDoc
forall a. Outputable a => a -> SDoc
GHC.ppr a
a)
data PhantomModule = PhantomModule{PhantomModule -> String
pmName :: ModuleName, PhantomModule -> String
pmFile :: FilePath}
deriving (PhantomModule -> PhantomModule -> Bool
(PhantomModule -> PhantomModule -> Bool)
-> (PhantomModule -> PhantomModule -> Bool) -> Eq PhantomModule
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PhantomModule -> PhantomModule -> Bool
$c/= :: PhantomModule -> PhantomModule -> Bool
== :: PhantomModule -> PhantomModule -> Bool
$c== :: PhantomModule -> PhantomModule -> Bool
Eq, Int -> PhantomModule -> ShowS
[PhantomModule] -> ShowS
PhantomModule -> String
(Int -> PhantomModule -> ShowS)
-> (PhantomModule -> String)
-> ([PhantomModule] -> ShowS)
-> Show PhantomModule
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PhantomModule] -> ShowS
$cshowList :: [PhantomModule] -> ShowS
show :: PhantomModule -> String
$cshow :: PhantomModule -> String
showsPrec :: Int -> PhantomModule -> ShowS
$cshowsPrec :: Int -> PhantomModule -> ShowS
Show)
findModule :: MonadInterpreter m => ModuleName -> m GHC.Module
findModule :: String -> m Module
findModule mn :: String
mn = (String -> InterpreterError) -> m Module -> m Module
forall (m :: * -> *) a.
MonadInterpreter m =>
(String -> InterpreterError) -> m a -> m a
mapGhcExceptions String -> InterpreterError
NotAllowed (m Module -> m Module) -> m Module -> m Module
forall a b. (a -> b) -> a -> b
$
RunGhc2 m ModuleName (Maybe FastString) Module
forall (m :: * -> *) a b c. MonadInterpreter m => RunGhc2 m a b c
runGhc2 forall (n :: * -> *).
(MonadIO n, MonadMask n) =>
ModuleName -> Maybe FastString -> GhcT n Module
forall (m :: * -> *).
GhcMonad m =>
ModuleName -> Maybe FastString -> m Module
GHC.findModule ModuleName
mod_name Maybe FastString
forall a. Maybe a
Nothing
where mod_name :: ModuleName
mod_name = String -> ModuleName
GHC.mkModuleName String
mn
moduleIsLoaded :: MonadInterpreter m => ModuleName -> m Bool
moduleIsLoaded :: String -> m Bool
moduleIsLoaded mn :: String
mn = (String -> m Module
forall (m :: * -> *). MonadInterpreter m => String -> m Module
findModule String
mn m Module -> m Bool -> m Bool
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True)
m Bool -> (InterpreterError -> m Bool) -> m Bool
forall (m :: * -> *) a.
MonadInterpreter m =>
m a -> (InterpreterError -> m a) -> m a
`catchIE` (\e :: InterpreterError
e -> case InterpreterError
e of
NotAllowed{} -> Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
WontCompile{} -> Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
_ -> InterpreterError -> m Bool
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM InterpreterError
e)
withDynFlags :: MonadInterpreter m => (GHC.DynFlags -> m a) -> m a
withDynFlags :: (DynFlags -> m a) -> m a
withDynFlags action :: DynFlags -> m a
action
= do DynFlags
df <- RunGhc m DynFlags
forall (m :: * -> *) a. MonadInterpreter m => RunGhc m a
runGhc forall (n :: * -> *). (MonadIO n, MonadMask n) => GhcT n DynFlags
forall (m :: * -> *). GhcMonad m => m DynFlags
GHC.getSessionDynFlags
DynFlags -> m a
action DynFlags
df