module GHC.Server.Commands (clientCall) where
import GHC.Server.IO
import GHC.Server.Import
import Data.Dynamic
import Data.List
import Data.Maybe
import GHC.Compat
clientCall :: (Ghc () -> IO ()) -> Cmd -> Chan ResultType -> IO ()
clientCall runGhc cmd results =
do case cmd of
Ping i ->
endResult results (Pong i)
LoadTarget string ->
withGhc (do target <- guessTarget string Nothing
setTargets [target]
result <- load LoadAllTargets
loaded <- getModuleGraph >>= filterM isLoaded . map ms_mod_name
mapM parseImportDecl
(necessaryImports ++ loadedImports loaded)
>>= setContext
io (endResult results (LoadResult result)))
Eval expr ->
withGhc (do tryImportOrDecls results expr)
TypeOf expr ->
withGhc (do typ <- exprType expr
df <- getSessionDynFlags
io (endResult results (TypeResult (unlines (formatType df typ)))))
KindOf expr ->
withGhc (do typ <- typeKind expr
df <- getSessionDynFlags
io (endResult results (KindResult (unlines (formatType df typ)))))
InfoOf ident ->
withGhc (do names <- parseName ident
df <- getSessionDynFlags
infos <- fmap (concatMap (\(t,f,cs) -> sdoc df t : sdoc df f : map (sdoc df) cs)
. catMaybes)
(mapM getInfo names)
io (endResult results (InfoResult (unlines infos))))
Set flag ->
withGhc (do setFlag flag
io (endResult results Unit))
PackageConf pkgconf ->
withGhc (do setFlag ("-package-conf=" ++ pkgconf)
df <- getSessionDynFlags
(dflags,_pkgs) <- io (initPackages df)
setSessionDynFlags dflags
io (endResult results Unit))
where loadedImports = map (\m -> "import " ++ moduleNameString m)
unlines = intercalate "\n"
withGhc = runGhc . addLogsToResults results
tryImportOrDecls :: Chan ResultType -> String -> Ghc ()
tryImportOrDecls results expr =
do dflags <- getSessionDynFlags
result <- gtry (parseImportDecl expr)
case result of
Right imp ->
do addToContext imp
ctx <- getContext
io (addResult results (EvalImport (map (sdoc dflags) ctx)))
Left (_ :: SomeException) ->
do typeResult <- gtry (exprType expr)
case typeResult of
Left (err :: SomeException) ->
do enames <- gtry (runDecls expr)
case enames of
Right names ->
io (endResult results (DeclResult (map (sdoc dflags) names)))
Left (err :: SomeException) ->
tryEvaluating results expr
Right ty ->
do io (addResult results (TypeResult (sdoc dflags ty)))
logger (Debug ("Got type: " ++ sdoc dflags ty))
tryEvaluating results expr
tryEvaluating :: Chan ResultType -> String -> Ghc ()
tryEvaluating results expr =
do dyn <- tryDynCompileExpr (exprPure expr)
case fmap fromDynamic dyn of
Right (Just str) ->
do logger (Debug ("Running showable expression value..."))
io (endResult results (EvalResult str))
_ ->
tryRunning results expr
tryRunning :: Chan ResultType -> String -> Ghc ()
tryRunning results stmt =
do dyn <- tryDynCompileExpr (exprIOShowable stmt)
case fmap fromDynamic dyn of
Right (Just (constrain -> action)) ->
do logger (Debug ("Running IO action returning Show instance..."))
result <- liftIO (action handleStdin)
io (endResult results (EvalResult result))
_ ->
do dyn <- tryDynCompileExpr (exprIOUnknown stmt)
case fmap fromDynamic dyn of
Right (Just (constrain -> action)) ->
do logger (Debug ("Running IO action returning unshowable value..."))
() <- liftIO (action handleStdin)
io (endResult results Unit)
_ ->
runStatement results stmt
where constrain action =
asTypeOf action (runIO (return undefined))
handleStdin bytes =
addResult results (EvalStdout bytes)
runStatement :: Chan ResultType -> String -> Ghc ()
runStatement results stmt =
do logger (Debug ("runStmt"))
result <- runStmt stmt RunToCompletion
logger (Debug ("Got result."))
dflags <- getSessionDynFlags
case result of
RunOk names -> io (endResult results (DeclResult (map (sdoc dflags) names)))
RunException e -> throw e
RunBreak{} -> return ()
exprPure :: String -> String
exprPure expr =
concat
[before
,(let ls = lines expr
in intercalate "\n" (take 1 ls ++
map (replicate (length before) ' ' ++)
(drop 1 ls)))
,")"]
where before = "Prelude.show ("
exprIOShowable :: String -> String
exprIOShowable expr =
concat
[before
,(let ls = lines expr
in intercalate "\n" (take 1 ls ++
map (replicate (length before) ' ' ++)
(drop 1 ls)))
,") >>= return . show)"]
where before = "GHC.Server.IO.runIO (("
exprIOUnknown :: String -> String
exprIOUnknown expr =
concat
[before
,(let ls = lines expr
in intercalate "\n" (take 1 ls ++
map (replicate (length before) ' ' ++)
(drop 1 ls)))
,") >> return ())"]
where before = "GHC.Server.IO.runIO (("
tryDynCompileExpr :: GhcMonad m => String -> m (Either SomeException Dynamic)
tryDynCompileExpr expr =
gcatch (fmap Right (dynCompileExpr expr))
(\(e::SomeException) -> return (Left e))
setFlag :: GhcMonad m => String -> m ()
setFlag flag = do
df <- getSessionDynFlags
(dflags,_,_) <- parseDynamicFlags df (map (mkGeneralLocated "flag") [flag])
void (setSessionDynFlags dflags)
addLogsToResults :: GhcMonad m => Chan ResultType -> m b -> m b
addLogsToResults results m = do
dflags <- getSessionDynFlags
setLogAction addLog
result <- m
setSessionDynFlags dflags
return result
where addLog dflags severity span _style msg =
addResult results (LogResult severity span (showSDoc dflags msg))
sdoc :: Outputable a => DynFlags -> a -> String
sdoc dflags = showSDocForUser dflags neverQualify . ppr
formatType :: DynFlags -> Type -> [String]
formatType dflags = lines . sdoc dflags . snd . splitForAllTys
endResult :: Chan ResultType -> Result -> IO ()
endResult chan r = writeChan chan (EndResult r)
addResult :: Chan ResultType -> Result -> IO ()
addResult chan r = writeChan chan (Result r)