1 {-# OPTIONS -#include "Linker.h" #-}
2 -----------------------------------------------------------------------------
4 -- GHC Interactive User Interface
6 -- (c) The GHC Team 2005
8 -----------------------------------------------------------------------------
14 #include "HsVersions.h"
18 import GHC ( Session, verbosity, dopt, DynFlag(..),
19 mkModule, pprModule, Type, Module, SuccessFlag(..),
20 TyThing(..), Name, LoadHowMuch(..),
21 GhcException(..), showGhcException )
24 -- following all needed for :info... ToDo: remove
25 import IfaceSyn ( IfaceDecl(..), IfaceClassOp(..), IfaceConDecls(..),
26 IfaceConDecl(..), IfaceType,
27 pprIfaceDeclHead, pprParendIfaceType,
28 pprIfaceForAllPart, pprIfaceType )
29 import FunDeps ( pprFundeps )
30 import SrcLoc ( SrcLoc, pprDefnLoc )
31 import OccName ( OccName, parenSymOcc, occNameUserString )
32 import BasicTypes ( StrictnessMark(..), defaultFixity, failed )
34 -- Other random utilities
35 import Panic ( panic, installSignalHandlers )
37 import StaticFlags ( opt_IgnoreDotGhci )
38 import Linker ( showLinkerState )
39 import Util ( removeSpaces, handle, global, toArgs,
40 looksLikeModuleName, prefixMatch )
42 #ifndef mingw32_HOST_OS
43 import Util ( handle )
45 #if __GLASGOW_HASKELL__ > 504
49 import GHC.ConsoleHandler ( flushConsole )
53 import Control.Concurrent ( yield ) -- Used in readline loop
54 import System.Console.Readline as Readline
59 import Control.Exception as Exception
61 -- import Control.Concurrent
65 import Data.Int ( Int64 )
66 import Data.Maybe ( isJust )
69 import System.Environment
70 import System.Exit ( exitWith, ExitCode(..) )
71 import System.Directory
73 import System.IO.Error as IO
75 import Control.Monad as Monad
76 import Foreign.StablePtr ( newStablePtr )
78 import GHC.Exts ( unsafeCoerce# )
79 import GHC.IOBase ( IOErrorType(InvalidArgument) )
81 import Data.IORef ( IORef, newIORef, readIORef, writeIORef )
83 import System.Posix.Internals ( setNonBlockingFD )
85 -----------------------------------------------------------------------------
89 " / _ \\ /\\ /\\/ __(_)\n"++
90 " / /_\\// /_/ / / | | GHC Interactive, version " ++ cProjectVersion ++ ", for Haskell 98.\n"++
91 "/ /_\\\\/ __ / /___| | http://www.haskell.org/ghc/\n"++
92 "\\____/\\/ /_/\\____/|_| Type :? for help.\n"
94 GLOBAL_VAR(commands, builtin_commands, [(String, String -> GHCi Bool)])
96 builtin_commands :: [(String, String -> GHCi Bool)]
98 ("add", keepGoingPaths addModule),
99 ("browse", keepGoing browseCmd),
100 ("cd", keepGoing changeDirectory),
101 ("def", keepGoing defineMacro),
102 ("help", keepGoing help),
103 ("?", keepGoing help),
104 ("info", keepGoing info),
105 ("load", keepGoingPaths loadModule_),
106 ("module", keepGoing setContext),
107 ("reload", keepGoing reloadModule),
108 ("set", keepGoing setCmd),
109 ("show", keepGoing showCmd),
110 ("type", keepGoing typeOfExpr),
111 ("kind", keepGoing kindOfType),
112 ("unset", keepGoing unsetOptions),
113 ("undef", keepGoing undefineMacro),
117 keepGoing :: (String -> GHCi ()) -> (String -> GHCi Bool)
118 keepGoing a str = a str >> return False
120 keepGoingPaths :: ([FilePath] -> GHCi ()) -> (String -> GHCi Bool)
121 keepGoingPaths a str = a (toArgs str) >> return False
123 shortHelpText = "use :? for help.\n"
125 -- NOTE: spaces at the end of each line to workaround CPP/string gap bug.
127 " Commands available from the prompt:\n" ++
129 " <stmt> evaluate/run <stmt>\n" ++
130 " :add <filename> ... add module(s) to the current target set\n" ++
131 " :browse [*]<module> display the names defined by <module>\n" ++
132 " :cd <dir> change directory to <dir>\n" ++
133 " :def <cmd> <expr> define a command :<cmd>\n" ++
134 " :help, :? display this list of commands\n" ++
135 " :info [<name> ...] display information about the given names\n" ++
136 " :load <filename> ... load module(s) and their dependents\n" ++
137 " :module [+/-] [*]<mod> ... set the context for expression evaluation\n" ++
138 " :reload reload the current module set\n" ++
140 " :set <option> ... set options\n" ++
141 " :set args <arg> ... set the arguments returned by System.getArgs\n" ++
142 " :set prog <progname> set the value returned by System.getProgName\n" ++
144 " :show modules show the currently loaded modules\n" ++
145 " :show bindings show the current bindings made at the prompt\n" ++
147 " :type <expr> show the type of <expr>\n" ++
148 " :kind <type> show the kind of <type>\n" ++
149 " :undef <cmd> undefine user-defined command :<cmd>\n" ++
150 " :unset <option> ... unset options\n" ++
151 " :quit exit GHCi\n" ++
152 " :!<command> run the shell command <command>\n" ++
154 " Options for ':set' and ':unset':\n" ++
156 " +r revert top-level expressions after each evaluation\n" ++
157 " +s print timing/memory stats after each evaluation\n" ++
158 " +t print type after evaluation\n" ++
159 " -<flags> most GHC command line flags can also be set here\n" ++
160 " (eg. -v2, -fglasgow-exts, etc.)\n"
163 interactiveUI :: Session -> [FilePath] -> Maybe String -> IO ()
164 interactiveUI session srcs maybe_expr = do
166 -- HACK! If we happen to get into an infinite loop (eg the user
167 -- types 'let x=x in x' at the prompt), then the thread will block
168 -- on a blackhole, and become unreachable during GC. The GC will
169 -- detect that it is unreachable and send it the NonTermination
170 -- exception. However, since the thread is unreachable, everything
171 -- it refers to might be finalized, including the standard Handles.
172 -- This sounds like a bug, but we don't have a good solution right
179 hSetBuffering stdout NoBuffering
181 -- Initialise buffering for the *interpreted* I/O system
182 initInterpBuffering session
184 -- We don't want the cmd line to buffer any input that might be
185 -- intended for the program, so unbuffer stdin.
186 hSetBuffering stdin NoBuffering
188 -- initial context is just the Prelude
189 GHC.setContext session [] [prelude_mod]
195 #if defined(mingw32_HOST_OS)
196 -- The win32 Console API mutates the first character of
197 -- type-ahead when reading from it in a non-buffered manner. Work
198 -- around this by flushing the input buffer of type-ahead characters.
200 GHC.ConsoleHandler.flushConsole stdin
202 startGHCi (runGHCi srcs maybe_expr)
203 GHCiState{ progname = "<interactive>",
209 Readline.resetTerminal Nothing
214 runGHCi :: [FilePath] -> Maybe String -> GHCi ()
215 runGHCi paths maybe_expr = do
216 let read_dot_files = not opt_IgnoreDotGhci
218 when (read_dot_files) $ do
221 exists <- io (doesFileExist file)
223 dir_ok <- io (checkPerms ".")
224 file_ok <- io (checkPerms file)
225 when (dir_ok && file_ok) $ do
226 either_hdl <- io (IO.try (openFile "./.ghci" ReadMode))
229 Right hdl -> fileLoop hdl False
231 when (read_dot_files) $ do
232 -- Read in $HOME/.ghci
233 either_dir <- io (IO.try (getEnv "HOME"))
237 cwd <- io (getCurrentDirectory)
238 when (dir /= cwd) $ do
239 let file = dir ++ "/.ghci"
240 ok <- io (checkPerms file)
242 either_hdl <- io (IO.try (openFile file ReadMode))
245 Right hdl -> fileLoop hdl False
247 -- Perform a :load for files given on the GHCi command line
248 -- When in -e mode, if the load fails then we want to stop
249 -- immediately rather than going on to evaluate the expression.
250 when (not (null paths)) $ do
251 ok <- ghciHandle (\e -> do showException e; return Failed) $
253 when (isJust maybe_expr && failed ok) $
254 io (exitWith (ExitFailure 1))
256 -- if verbosity is greater than 0, or we are connected to a
257 -- terminal, display the prompt in the interactive loop.
258 is_tty <- io (hIsTerminalDevice stdin)
259 dflags <- getDynFlags
260 let show_prompt = verbosity dflags > 0 || is_tty
264 -- enter the interactive loop
265 interactiveLoop is_tty show_prompt
267 -- just evaluate the expression we were given
272 io $ do when (verbosity dflags > 0) $ putStrLn "Leaving GHCi."
275 interactiveLoop is_tty show_prompt = do
276 -- Ignore ^C exceptions caught here
277 ghciHandleDyn (\e -> case e of
278 Interrupted -> ghciUnblock (
279 #if defined(mingw32_HOST_OS)
282 interactiveLoop is_tty show_prompt)
283 _other -> return ()) $ do
285 -- read commands from stdin
289 else fileLoop stdin show_prompt
291 fileLoop stdin show_prompt
295 -- NOTE: We only read .ghci files if they are owned by the current user,
296 -- and aren't world writable. Otherwise, we could be accidentally
297 -- running code planted by a malicious third party.
299 -- Furthermore, We only read ./.ghci if . is owned by the current user
300 -- and isn't writable by anyone else. I think this is sufficient: we
301 -- don't need to check .. and ../.. etc. because "." always refers to
302 -- the same directory while a process is running.
304 checkPerms :: String -> IO Bool
306 #ifdef mingw32_HOST_OS
309 Util.handle (\_ -> return False) $ do
310 st <- getFileStatus name
312 if fileOwner st /= me then do
313 putStrLn $ "WARNING: " ++ name ++ " is owned by someone else, IGNORING!"
316 let mode = fileMode st
317 if (groupWriteMode == (mode `intersectFileModes` groupWriteMode))
318 || (otherWriteMode == (mode `intersectFileModes` otherWriteMode))
320 putStrLn $ "*** WARNING: " ++ name ++
321 " is writable by someone else, IGNORING!"
326 fileLoop :: Handle -> Bool -> GHCi ()
327 fileLoop hdl prompt = do
328 session <- getSession
329 (mod,imports) <- io (GHC.getContext session)
330 when prompt (io (putStr (mkPrompt mod imports)))
331 l <- io (IO.try (hGetLine hdl))
333 Left e | isEOFError e -> return ()
334 | InvalidArgument <- etype -> return ()
335 | otherwise -> io (ioError e)
336 where etype = ioeGetErrorType e
337 -- treat InvalidArgument in the same way as EOF:
338 -- this can happen if the user closed stdin, or
339 -- perhaps did getContents which closes stdin at
342 case removeSpaces l of
343 "" -> fileLoop hdl prompt
344 l -> do quit <- runCommand l
345 if quit then return () else fileLoop hdl prompt
347 stringLoop :: [String] -> GHCi ()
348 stringLoop [] = return ()
349 stringLoop (s:ss) = do
350 case removeSpaces s of
352 l -> do quit <- runCommand l
353 if quit then return () else stringLoop ss
355 mkPrompt toplevs exports
356 = showSDoc (hsep (map (\m -> char '*' <> pprModule m) toplevs)
357 <+> hsep (map pprModule exports)
361 readlineLoop :: GHCi ()
363 session <- getSession
364 (mod,imports) <- io (GHC.getContext session)
366 l <- io (readline (mkPrompt mod imports)
367 `finally` setNonBlockingFD 0)
368 -- readline sometimes puts stdin into blocking mode,
369 -- so we need to put it back for the IO library
373 case removeSpaces l of
378 if quit then return () else readlineLoop
381 runCommand :: String -> GHCi Bool
382 runCommand c = ghciHandle handler (doCommand c)
384 -- This version is for the GHC command-line option -e. The only difference
385 -- from runCommand is that it catches the ExitException exception and
386 -- exits, rather than printing out the exception.
387 runCommandEval c = ghciHandle handleEval (doCommand c)
389 handleEval (ExitException code) = io (exitWith code)
390 handleEval e = do showException e
391 io (exitWith (ExitFailure 1))
393 -- This is the exception handler for exceptions generated by the
394 -- user's code; it normally just prints out the exception. The
395 -- handler must be recursive, in case showing the exception causes
396 -- more exceptions to be raised.
398 -- Bugfix: if the user closed stdout or stderr, the flushing will fail,
399 -- raising another exception. We therefore don't put the recursive
400 -- handler arond the flushing operation, so if stderr is closed
401 -- GHCi will just die gracefully rather than going into an infinite loop.
402 handler :: Exception -> GHCi Bool
403 handler exception = do
405 io installSignalHandlers
406 ghciHandle handler (showException exception >> return False)
408 showException (DynException dyn) =
409 case fromDynamic dyn of
410 Nothing -> io (putStrLn ("*** Exception: (unknown)"))
411 Just Interrupted -> io (putStrLn "Interrupted.")
412 Just (CmdLineError s) -> io (putStrLn s) -- omit the location for CmdLineError
413 Just ph@PhaseFailed{} -> io (putStrLn (showGhcException ph "")) -- ditto
414 Just other_ghc_ex -> io (print other_ghc_ex)
416 showException other_exception
417 = io (putStrLn ("*** Exception: " ++ show other_exception))
419 doCommand (':' : command) = specialCommand command
421 = do timeIt (do nms <- runStmt stmt; finishEvalExpr nms)
424 runStmt :: String -> GHCi [Name]
426 | null (filter (not.isSpace) stmt) = return []
428 = do st <- getGHCiState
429 session <- getSession
430 result <- io $ withProgName (progname st) $ withArgs (args st) $
431 GHC.runStmt session stmt
433 GHC.RunFailed -> return []
434 GHC.RunException e -> throw e -- this is caught by runCommand(Eval)
435 GHC.RunOk names -> return names
437 -- possibly print the type and revert CAFs after evaluating an expression
439 = do b <- isOptionSet ShowType
440 session <- getSession
441 when b (mapM_ (showTypeOfName session) names)
444 io installSignalHandlers
445 b <- isOptionSet RevertCAFs
446 io (when b revertCAFs)
449 showTypeOfName :: Session -> Name -> GHCi ()
450 showTypeOfName session n
451 = do maybe_tything <- io (GHC.lookupName session n)
452 case maybe_tything of
454 Just thing -> showTyThing thing
456 showForUser :: SDoc -> GHCi String
458 session <- getSession
459 unqual <- io (GHC.getPrintUnqual session)
460 return $! showSDocForUser unqual doc
462 specialCommand :: String -> GHCi Bool
463 specialCommand ('!':str) = shellEscape (dropWhile isSpace str)
464 specialCommand str = do
465 let (cmd,rest) = break isSpace str
466 cmds <- io (readIORef commands)
467 case [ (s,f) | (s,f) <- cmds, prefixMatch cmd s ] of
468 [] -> io (hPutStr stdout ("unknown command ':" ++ cmd ++ "'\n"
469 ++ shortHelpText) >> return False)
470 [(_,f)] -> f (dropWhile isSpace rest)
471 cs -> io (hPutStrLn stdout ("prefix " ++ cmd ++
472 " matches multiple commands (" ++
473 foldr1 (\a b -> a ++ ',':b) (map fst cs)
474 ++ ")") >> return False)
476 noArgs c = throwDyn (CmdLineError ("command '" ++ c ++ "' takes no arguments"))
479 -----------------------------------------------------------------------------
480 -- To flush buffers for the *interpreted* computation we need
481 -- to refer to *its* stdout/stderr handles
483 GLOBAL_VAR(flush_interp, error "no flush_interp", IO ())
484 GLOBAL_VAR(turn_off_buffering, error "no flush_stdout", IO ())
486 no_buf_cmd = "System.IO.hSetBuffering System.IO.stdout System.IO.NoBuffering" ++
487 " Prelude.>> System.IO.hSetBuffering System.IO.stderr System.IO.NoBuffering"
488 flush_cmd = "System.IO.hFlush System.IO.stdout Prelude.>> System.IO.hFlush IO.stderr"
490 initInterpBuffering :: Session -> IO ()
491 initInterpBuffering session
492 = do maybe_hval <- GHC.compileExpr session no_buf_cmd
495 Just hval -> writeIORef turn_off_buffering (unsafeCoerce# hval :: IO ())
496 other -> panic "interactiveUI:setBuffering"
498 maybe_hval <- GHC.compileExpr session flush_cmd
500 Just hval -> writeIORef flush_interp (unsafeCoerce# hval :: IO ())
501 _ -> panic "interactiveUI:flush"
503 turnOffBuffering -- Turn it off right now
508 flushInterpBuffers :: GHCi ()
510 = io $ do Monad.join (readIORef flush_interp)
513 turnOffBuffering :: IO ()
515 = do Monad.join (readIORef turn_off_buffering)
518 -----------------------------------------------------------------------------
521 help :: String -> GHCi ()
522 help _ = io (putStr helpText)
524 info :: String -> GHCi ()
525 info "" = throwDyn (CmdLineError "syntax: ':i <thing-you-want-info-about>'")
526 info s = do { let names = words s
527 ; session <- getSession
528 ; dflags <- getDynFlags
529 ; let exts = dopt Opt_GlasgowExts dflags
530 ; mapM_ (infoThing exts session) names }
532 infoThing exts session name
533 = do { stuff <- io (GHC.getInfo session name)
534 ; unqual <- io (GHC.getPrintUnqual session)
535 ; io (putStrLn (showSDocForUser unqual $
536 vcat (intersperse (text "") (map (showThing exts) stuff)))) }
538 showThing :: Bool -> GHC.GetInfoResult -> SDoc
539 showThing exts (wanted_str, thing, fixity, src_loc, insts)
540 = vcat [ showWithLoc src_loc (showDecl exts want_name thing),
542 vcat (map show_inst insts)]
544 want_name occ = wanted_str == occNameUserString occ
547 | fix == defaultFixity = empty
548 | otherwise = ppr fix <+> text wanted_str
550 show_inst (inst_ty, loc)
551 = showWithLoc loc (ptext SLIT("instance") <+> ppr inst_ty)
553 showWithLoc :: SrcLoc -> SDoc -> SDoc
555 = hang doc 2 (char '\t' <> comment <+> pprDefnLoc loc)
556 -- The tab tries to make them line up a bit
558 comment = ptext SLIT("--")
561 -- Now there is rather a lot of goop just to print declarations in a
562 -- civilised way with "..." for the parts we are less interested in.
564 showDecl :: Bool -> (OccName -> Bool) -> IfaceDecl -> SDoc
565 showDecl exts want_name (IfaceForeign {ifName = tc})
566 = ppr tc <+> ptext SLIT("is a foreign type")
568 showDecl exts want_name (IfaceId {ifName = var, ifType = ty})
569 = ppr var <+> dcolon <+> showIfaceType exts ty
571 showDecl exts want_name (IfaceSyn {ifName = tycon, ifTyVars = tyvars, ifSynRhs = mono_ty})
572 = hang (ptext SLIT("type") <+> pprIfaceDeclHead [] tycon tyvars)
573 2 (equals <+> ppr mono_ty)
575 showDecl exts want_name (IfaceData {ifName = tycon,
576 ifTyVars = tyvars, ifCons = condecls, ifCtxt = context})
577 = hang (pp_nd <+> pprIfaceDeclHead context tycon tyvars)
578 2 (add_bars (ppr_trim show_con cs))
580 show_con (IfVanillaCon { ifConOcc = con_name, ifConInfix = is_infix, ifConArgTys = tys,
581 ifConStricts = strs, ifConFields = flds})
582 | want_name tycon || want_name con_name || any want_name flds
583 = Just (show_guts con_name is_infix tys_w_strs flds)
584 | otherwise = Nothing
586 tys_w_strs = tys `zip` (strs ++ repeat NotMarkedStrict)
587 show_con (IfGadtCon { ifConOcc = con_name, ifConTyVars = tvs, ifConCtxt = theta,
588 ifConArgTys = arg_tys, ifConResTys = res_tys, ifConStricts = strs })
589 | want_name tycon || want_name con_name
590 = Just (ppr_bndr con_name <+> colon <+> pprIfaceForAllPart tvs theta pp_tau)
591 | otherwise = Nothing
593 tys_w_strs = arg_tys `zip` (strs ++ repeat NotMarkedStrict)
594 pp_tau = foldr add pp_res_ty tys_w_strs
595 pp_res_ty = ppr_bndr tycon <+> hsep (map pprParendIfaceType res_tys)
596 add bty pp_ty = ppr_bangty bty <+> arrow <+> pp_ty
598 show_guts con True [ty1, ty2] flds = sep [ppr_bangty ty1, ppr con, ppr_bangty ty2]
599 show_guts con _ tys [] = ppr_bndr con <+> sep (map ppr_bangty tys)
600 show_guts con _ tys flds
601 = ppr_bndr con <+> braces (sep (punctuate comma (ppr_trim show_fld (tys `zip` flds))))
603 show_fld (bty, fld) | want_name tycon || want_name con || want_name fld
604 = Just (ppr_bndr fld <+> dcolon <+> ppr_bangty bty)
605 | otherwise = Nothing
607 (pp_nd, cs) = case condecls of
608 IfAbstractTyCon -> (ptext SLIT("data"), [])
609 IfDataTyCon cs -> (ptext SLIT("data"), cs)
610 IfNewTyCon c -> (ptext SLIT("newtype"),[c])
613 add_bars [c] = equals <+> c
614 add_bars (c:cs) = equals <+> sep (c : map (char '|' <+>) cs)
616 ppr_bangty (ty, str) = ppr_str str <> pprParendIfaceType ty
617 ppr_str MarkedStrict = char '!'
618 ppr_str MarkedUnboxed = ptext SLIT("!!")
619 ppr_str NotMarkedStrict = empty
621 showDecl exts want_name (IfaceClass {ifCtxt = context, ifName = clas, ifTyVars = tyvars,
622 ifFDs = fds, ifSigs = sigs})
623 = hang (ptext SLIT("class") <+> pprIfaceDeclHead context clas tyvars
624 <+> pprFundeps fds <+> opt_where)
625 2 (vcat (ppr_trim show_op sigs))
627 opt_where | null sigs = empty
628 | otherwise = ptext SLIT("where")
629 show_op (IfaceClassOp op dm ty)
630 | want_name clas || want_name op
631 = Just (ppr_bndr op <+> dcolon <+> showIfaceType exts ty)
635 showIfaceType :: Bool -> IfaceType -> SDoc
636 showIfaceType True ty = pprIfaceType ty -- -fglasgow-exts: print with the foralls
637 showIfaceType False ty = ppr ty -- otherwise, print without the foralls
639 ppr_trim :: (a -> Maybe SDoc) -> [a] -> [SDoc]
641 = snd (foldr go (False, []) xs)
643 go x (eliding, so_far)
644 | Just doc <- show x = (False, doc : so_far)
645 | otherwise = if eliding then (True, so_far)
646 else (True, ptext SLIT("...") : so_far)
648 ppr_bndr :: OccName -> SDoc
649 -- Wrap operators in ()
650 ppr_bndr occ = parenSymOcc occ (ppr occ)
653 -----------------------------------------------------------------------------
656 addModule :: [FilePath] -> GHCi ()
658 io (revertCAFs) -- always revert CAFs on load/add.
659 files <- mapM expandPath files
660 targets <- mapM (io . GHC.guessTarget) files
661 session <- getSession
662 io (mapM_ (GHC.addTarget session) targets)
663 ok <- io (GHC.load session LoadAllTargets)
666 changeDirectory :: String -> GHCi ()
667 changeDirectory dir = do
668 session <- getSession
669 graph <- io (GHC.getModuleGraph session)
670 when (not (null graph)) $
671 io $ putStr "Warning: changing directory causes all loaded modules to be unloaded,\nbecause the search path has changed.\n"
672 io (GHC.setTargets session [])
673 io (GHC.load session LoadAllTargets)
674 setContextAfterLoad []
675 io (GHC.workingDirectoryChanged session)
676 dir <- expandPath dir
677 io (setCurrentDirectory dir)
679 defineMacro :: String -> GHCi ()
681 let (macro_name, definition) = break isSpace s
682 cmds <- io (readIORef commands)
684 then throwDyn (CmdLineError "invalid macro name")
686 if (macro_name `elem` map fst cmds)
687 then throwDyn (CmdLineError
688 ("command '" ++ macro_name ++ "' is already defined"))
691 -- give the expression a type signature, so we can be sure we're getting
692 -- something of the right type.
693 let new_expr = '(' : definition ++ ") :: String -> IO String"
695 -- compile the expression
697 maybe_hv <- io (GHC.compileExpr cms new_expr)
700 Just hv -> io (writeIORef commands --
701 ((macro_name, keepGoing (runMacro hv)) : cmds))
703 runMacro :: GHC.HValue{-String -> IO String-} -> String -> GHCi ()
705 str <- io ((unsafeCoerce# fun :: String -> IO String) s)
706 stringLoop (lines str)
708 undefineMacro :: String -> GHCi ()
709 undefineMacro macro_name = do
710 cmds <- io (readIORef commands)
711 if (macro_name `elem` map fst builtin_commands)
712 then throwDyn (CmdLineError
713 ("command '" ++ macro_name ++ "' cannot be undefined"))
715 if (macro_name `notElem` map fst cmds)
716 then throwDyn (CmdLineError
717 ("command '" ++ macro_name ++ "' not defined"))
719 io (writeIORef commands (filter ((/= macro_name) . fst) cmds))
722 loadModule :: [FilePath] -> GHCi SuccessFlag
723 loadModule fs = timeIt (loadModule' fs)
725 loadModule_ :: [FilePath] -> GHCi ()
726 loadModule_ fs = do loadModule fs; return ()
728 loadModule' :: [FilePath] -> GHCi SuccessFlag
729 loadModule' files = do
730 session <- getSession
733 io (GHC.setTargets session [])
734 io (GHC.load session LoadAllTargets)
737 files <- mapM expandPath files
738 targets <- io (mapM GHC.guessTarget files)
740 -- NOTE: we used to do the dependency anal first, so that if it
741 -- fails we didn't throw away the current set of modules. This would
742 -- require some re-working of the GHC interface, so we'll leave it
743 -- as a ToDo for now.
745 io (GHC.setTargets session targets)
746 ok <- io (GHC.load session LoadAllTargets)
751 reloadModule :: String -> GHCi ()
753 io (revertCAFs) -- always revert CAFs on reload.
754 session <- getSession
755 ok <- io (GHC.load session LoadAllTargets)
758 io (revertCAFs) -- always revert CAFs on reload.
759 session <- getSession
760 ok <- io (GHC.load session (LoadUpTo (mkModule m)))
763 afterLoad ok session = do
764 io (revertCAFs) -- always revert CAFs on load.
765 graph <- io (GHC.getModuleGraph session)
766 let mods = map GHC.ms_mod graph
767 mods' <- filterM (io . GHC.isLoaded session) mods
768 setContextAfterLoad mods'
769 modulesLoadedMsg ok mods'
771 setContextAfterLoad [] = do
772 session <- getSession
773 io (GHC.setContext session [] [prelude_mod])
774 setContextAfterLoad (m:_) = do
775 session <- getSession
776 b <- io (GHC.moduleIsInterpreted session m)
777 if b then io (GHC.setContext session [m] [])
778 else io (GHC.setContext session [] [m])
780 modulesLoadedMsg :: SuccessFlag -> [Module] -> GHCi ()
781 modulesLoadedMsg ok mods = do
782 dflags <- getDynFlags
783 when (verbosity dflags > 0) $ do
785 | null mods = text "none."
787 punctuate comma (map pprModule mods)) <> text "."
790 io (putStrLn (showSDoc (text "Failed, modules loaded: " <> mod_commas)))
792 io (putStrLn (showSDoc (text "Ok, modules loaded: " <> mod_commas)))
795 typeOfExpr :: String -> GHCi ()
797 = do cms <- getSession
798 maybe_ty <- io (GHC.exprType cms str)
801 Just ty -> do ty' <- cleanType ty
802 tystr <- showForUser (ppr ty')
803 io (putStrLn (str ++ " :: " ++ tystr))
805 kindOfType :: String -> GHCi ()
807 = do cms <- getSession
808 maybe_ty <- io (GHC.typeKind cms str)
811 Just ty -> do tystr <- showForUser (ppr ty)
812 io (putStrLn (str ++ " :: " ++ tystr))
814 quit :: String -> GHCi Bool
817 shellEscape :: String -> GHCi Bool
818 shellEscape str = io (system str >> return False)
820 -----------------------------------------------------------------------------
821 -- Browsing a module's contents
823 browseCmd :: String -> GHCi ()
826 ['*':m] | looksLikeModuleName m -> browseModule m False
827 [m] | looksLikeModuleName m -> browseModule m True
828 _ -> throwDyn (CmdLineError "syntax: :browse <module>")
830 browseModule m exports_only = do
833 let modl = mkModule m
834 is_interpreted <- io (GHC.moduleIsInterpreted s modl)
835 when (not is_interpreted && not exports_only) $
836 throwDyn (CmdLineError ("module '" ++ m ++ "' is not interpreted"))
838 -- Temporarily set the context to the module we're interested in,
839 -- just so we can get an appropriate PrintUnqualified
840 (as,bs) <- io (GHC.getContext s)
841 io (if exports_only then GHC.setContext s [] [prelude_mod,modl]
842 else GHC.setContext s [modl] [])
843 io (GHC.setContext s as bs)
845 things <- io (GHC.browseModule s modl exports_only)
846 unqual <- io (GHC.getPrintUnqual s)
848 dflags <- getDynFlags
849 let exts = dopt Opt_GlasgowExts dflags
850 io (putStrLn (showSDocForUser unqual (
851 vcat (map (showDecl exts (const True)) things)
854 -----------------------------------------------------------------------------
855 -- Setting the module context
858 | all sensible mods = fn mods
859 | otherwise = throwDyn (CmdLineError "syntax: :module [+/-] [*]M1 ... [*]Mn")
861 (fn, mods) = case str of
862 '+':stuff -> (addToContext, words stuff)
863 '-':stuff -> (removeFromContext, words stuff)
864 stuff -> (newContext, words stuff)
866 sensible ('*':m) = looksLikeModuleName m
867 sensible m = looksLikeModuleName m
870 session <- getSession
871 (as,bs) <- separate session mods [] []
872 let bs' = if null as && prelude_mod `notElem` bs then prelude_mod:bs else bs
873 io (GHC.setContext session as bs')
875 separate :: Session -> [String] -> [Module] -> [Module]
876 -> GHCi ([Module],[Module])
877 separate session [] as bs = return (as,bs)
878 separate session (('*':m):ms) as bs = do
879 let modl = mkModule m
880 b <- io (GHC.moduleIsInterpreted session modl)
881 if b then separate session ms (modl:as) bs
882 else throwDyn (CmdLineError ("module '" ++ m ++ "' is not interpreted"))
883 separate session (m:ms) as bs = separate session ms as (mkModule m:bs)
885 prelude_mod = mkModule "Prelude"
888 addToContext mods = do
890 (as,bs) <- io (GHC.getContext cms)
892 (as',bs') <- separate cms mods [] []
894 let as_to_add = as' \\ (as ++ bs)
895 bs_to_add = bs' \\ (as ++ bs)
897 io (GHC.setContext cms (as ++ as_to_add) (bs ++ bs_to_add))
900 removeFromContext mods = do
902 (as,bs) <- io (GHC.getContext cms)
904 (as_to_remove,bs_to_remove) <- separate cms mods [] []
906 let as' = as \\ (as_to_remove ++ bs_to_remove)
907 bs' = bs \\ (as_to_remove ++ bs_to_remove)
909 io (GHC.setContext cms as' bs')
911 ----------------------------------------------------------------------------
914 -- set options in the interpreter. Syntax is exactly the same as the
915 -- ghc command line, except that certain options aren't available (-C,
918 -- This is pretty fragile: most options won't work as expected. ToDo:
919 -- figure out which ones & disallow them.
921 setCmd :: String -> GHCi ()
923 = do st <- getGHCiState
924 let opts = options st
925 io $ putStrLn (showSDoc (
926 text "options currently set: " <>
929 else hsep (map (\o -> char '+' <> text (optToStr o)) opts)
933 ("args":args) -> setArgs args
934 ("prog":prog) -> setProg prog
935 wds -> setOptions wds
939 setGHCiState st{ args = args }
943 setGHCiState st{ progname = prog }
945 io (hPutStrLn stderr "syntax: :set prog <progname>")
948 do -- first, deal with the GHCi opts (+s, +t, etc.)
949 let (plus_opts, minus_opts) = partition isPlus wds
950 mapM_ setOpt plus_opts
952 -- then, dynamic flags
953 dflags <- getDynFlags
954 (dflags',leftovers) <- io $ GHC.parseDynamicFlags dflags minus_opts
957 -- update things if the users wants more packages
959 let new_packages = pkgs_after \\ pkgs_before
960 when (not (null new_packages)) $
961 newPackages new_packages
964 if (not (null leftovers))
965 then throwDyn (CmdLineError ("unrecognised flags: " ++
970 unsetOptions :: String -> GHCi ()
972 = do -- first, deal with the GHCi opts (+s, +t, etc.)
974 (minus_opts, rest1) = partition isMinus opts
975 (plus_opts, rest2) = partition isPlus rest1
977 if (not (null rest2))
978 then io (putStrLn ("unknown option: '" ++ head rest2 ++ "'"))
981 mapM_ unsetOpt plus_opts
983 -- can't do GHC flags for now
984 if (not (null minus_opts))
985 then throwDyn (CmdLineError "can't unset GHC command-line flags")
988 isMinus ('-':s) = True
991 isPlus ('+':s) = True
995 = case strToGHCiOpt str of
996 Nothing -> io (putStrLn ("unknown option: '" ++ str ++ "'"))
997 Just o -> setOption o
1000 = case strToGHCiOpt str of
1001 Nothing -> io (putStrLn ("unknown option: '" ++ str ++ "'"))
1002 Just o -> unsetOption o
1004 strToGHCiOpt :: String -> (Maybe GHCiOption)
1005 strToGHCiOpt "s" = Just ShowTiming
1006 strToGHCiOpt "t" = Just ShowType
1007 strToGHCiOpt "r" = Just RevertCAFs
1008 strToGHCiOpt _ = Nothing
1010 optToStr :: GHCiOption -> String
1011 optToStr ShowTiming = "s"
1012 optToStr ShowType = "t"
1013 optToStr RevertCAFs = "r"
1016 newPackages new_pkgs = do -- The new packages are already in v_Packages
1017 session <- getSession
1018 io (GHC.setTargets session [])
1019 io (GHC.load session Nothing)
1020 dflags <- getDynFlags
1021 io (linkPackages dflags new_pkgs)
1022 setContextAfterLoad []
1025 -- ---------------------------------------------------------------------------
1030 ["modules" ] -> showModules
1031 ["bindings"] -> showBindings
1032 ["linker"] -> io showLinkerState
1033 _ -> throwDyn (CmdLineError "syntax: :show [modules|bindings]")
1036 session <- getSession
1037 let show_one ms = do m <- io (GHC.showModule session ms)
1039 graph <- io (GHC.getModuleGraph session)
1040 mapM_ show_one graph
1044 unqual <- io (GHC.getPrintUnqual s)
1045 bindings <- io (GHC.getBindings s)
1046 mapM_ showTyThing bindings
1049 showTyThing (AnId id) = do
1050 ty' <- cleanType (GHC.idType id)
1051 str <- showForUser (ppr id <> text " :: " <> ppr ty')
1053 showTyThing _ = return ()
1055 -- if -fglasgow-exts is on we show the foralls, otherwise we don't.
1056 cleanType :: Type -> GHCi Type
1058 dflags <- getDynFlags
1059 if dopt Opt_GlasgowExts dflags
1061 else return $! GHC.dropForAlls ty
1063 -----------------------------------------------------------------------------
1066 data GHCiState = GHCiState
1070 session :: GHC.Session,
1071 options :: [GHCiOption]
1075 = ShowTiming -- show time/allocs after evaluation
1076 | ShowType -- show the type of expressions
1077 | RevertCAFs -- revert CAFs after every evaluation
1080 newtype GHCi a = GHCi { unGHCi :: IORef GHCiState -> IO a }
1082 startGHCi :: GHCi a -> GHCiState -> IO a
1083 startGHCi g state = do ref <- newIORef state; unGHCi g ref
1085 instance Monad GHCi where
1086 (GHCi m) >>= k = GHCi $ \s -> m s >>= \a -> unGHCi (k a) s
1087 return a = GHCi $ \s -> return a
1089 ghciHandleDyn :: Typeable t => (t -> GHCi a) -> GHCi a -> GHCi a
1090 ghciHandleDyn h (GHCi m) = GHCi $ \s ->
1091 Exception.catchDyn (m s) (\e -> unGHCi (h e) s)
1093 getGHCiState = GHCi $ \r -> readIORef r
1094 setGHCiState s = GHCi $ \r -> writeIORef r s
1096 -- for convenience...
1097 getSession = getGHCiState >>= return . session
1101 io (GHC.getSessionDynFlags s)
1102 setDynFlags dflags = do
1104 io (GHC.setSessionDynFlags s dflags)
1106 isOptionSet :: GHCiOption -> GHCi Bool
1108 = do st <- getGHCiState
1109 return (opt `elem` options st)
1111 setOption :: GHCiOption -> GHCi ()
1113 = do st <- getGHCiState
1114 setGHCiState (st{ options = opt : filter (/= opt) (options st) })
1116 unsetOption :: GHCiOption -> GHCi ()
1118 = do st <- getGHCiState
1119 setGHCiState (st{ options = filter (/= opt) (options st) })
1121 io :: IO a -> GHCi a
1122 io m = GHCi { unGHCi = \s -> m >>= return }
1124 -----------------------------------------------------------------------------
1125 -- recursive exception handlers
1127 -- Don't forget to unblock async exceptions in the handler, or if we're
1128 -- in an exception loop (eg. let a = error a in a) the ^C exception
1129 -- may never be delivered. Thanks to Marcin for pointing out the bug.
1131 ghciHandle :: (Exception -> GHCi a) -> GHCi a -> GHCi a
1132 ghciHandle h (GHCi m) = GHCi $ \s ->
1133 Exception.catch (m s)
1134 (\e -> unGHCi (ghciUnblock (h e)) s)
1136 ghciUnblock :: GHCi a -> GHCi a
1137 ghciUnblock (GHCi a) = GHCi $ \s -> Exception.unblock (a s)
1139 -----------------------------------------------------------------------------
1140 -- timing & statistics
1142 timeIt :: GHCi a -> GHCi a
1144 = do b <- isOptionSet ShowTiming
1147 else do allocs1 <- io $ getAllocations
1148 time1 <- io $ getCPUTime
1150 allocs2 <- io $ getAllocations
1151 time2 <- io $ getCPUTime
1152 io $ printTimes (fromIntegral (allocs2 - allocs1))
1156 foreign import ccall unsafe "getAllocations" getAllocations :: IO Int64
1157 -- defined in ghc/rts/Stats.c
1159 printTimes :: Integer -> Integer -> IO ()
1160 printTimes allocs psecs
1161 = do let secs = (fromIntegral psecs / (10^12)) :: Float
1162 secs_str = showFFloat (Just 2) secs
1163 putStrLn (showSDoc (
1164 parens (text (secs_str "") <+> text "secs" <> comma <+>
1165 text (show allocs) <+> text "bytes")))
1167 -----------------------------------------------------------------------------
1174 -- Have to turn off buffering again, because we just
1175 -- reverted stdout, stderr & stdin to their defaults.
1177 foreign import ccall "revertCAFs" rts_revertCAFs :: IO ()
1178 -- Make it "safe", just in case
1180 -- -----------------------------------------------------------------------------
1183 expandPath :: String -> GHCi String
1185 case dropWhile isSpace path of
1187 tilde <- io (getEnv "HOME") -- will fail if HOME not defined
1188 return (tilde ++ '/':d)