3 #include "HsVersions.h"
6 import {-#SOURCE#-} Debugger
9 import Panic hiding (showException)
13 import Control.Exception as Exception
16 import Data.Int ( Int64 )
21 import Control.Monad as Monad
24 -----------------------------------------------------------------------------
27 data GHCiState = GHCiState
33 session :: GHC.Session,
34 options :: [GHCiOption],
39 = ShowTiming -- show time/allocs after evaluation
40 | ShowType -- show the type of expressions
41 | RevertCAFs -- revert CAFs after every evaluation
44 newtype GHCi a = GHCi { unGHCi :: IORef GHCiState -> IO a }
46 startGHCi :: GHCi a -> GHCiState -> IO a
47 startGHCi g state = do ref <- newIORef state; unGHCi g ref
49 instance Monad GHCi where
50 (GHCi m) >>= k = GHCi $ \s -> m s >>= \a -> unGHCi (k a) s
51 return a = GHCi $ \s -> return a
53 ghciHandleDyn :: Typeable t => (t -> GHCi a) -> GHCi a -> GHCi a
54 ghciHandleDyn h (GHCi m) = GHCi $ \s ->
55 Exception.catchDyn (m s) (\e -> unGHCi (h e) s)
57 getGHCiState = GHCi $ \r -> readIORef r
58 setGHCiState s = GHCi $ \r -> writeIORef r s
61 getSession = getGHCiState >>= return . session
62 getPrelude = getGHCiState >>= return . prelude
64 GLOBAL_VAR(saved_sess, no_saved_sess, GHC.Session)
65 no_saved_sess = error "no saved_ses"
66 saveSession = getSession >>= io . writeIORef saved_sess
67 splatSavedSession = io (writeIORef saved_sess no_saved_sess)
68 restoreSession = readIORef saved_sess
72 io (GHC.getSessionDynFlags s)
73 setDynFlags dflags = do
75 io (GHC.setSessionDynFlags s dflags)
77 isOptionSet :: GHCiOption -> GHCi Bool
79 = do st <- getGHCiState
80 return (opt `elem` options st)
82 setOption :: GHCiOption -> GHCi ()
84 = do st <- getGHCiState
85 setGHCiState (st{ options = opt : filter (/= opt) (options st) })
87 unsetOption :: GHCiOption -> GHCi ()
89 = do st <- getGHCiState
90 setGHCiState (st{ options = filter (/= opt) (options st) })
93 io m = GHCi { unGHCi = \s -> m >>= return }
95 showForUser :: SDoc -> GHCi String
98 unqual <- io (GHC.getPrintUnqual session)
99 return $! showSDocForUser unqual doc
101 -----------------------------------------------------------------------------
102 -- User code exception handling
104 -- This is the exception handler for exceptions generated by the
105 -- user's code and exceptions coming from children sessions;
106 -- it normally just prints out the exception. The
107 -- handler must be recursive, in case showing the exception causes
108 -- more exceptions to be raised.
110 -- Bugfix: if the user closed stdout or stderr, the flushing will fail,
111 -- raising another exception. We therefore don't put the recursive
112 -- handler arond the flushing operation, so if stderr is closed
113 -- GHCi will just die gracefully rather than going into an infinite loop.
114 handler exception = do
116 io installSignalHandlers
117 ghciHandle handler (showException exception >> return False)
119 showException (DynException dyn) =
120 case fromDynamic dyn of
121 Nothing -> io (putStrLn ("*** Exception: (unknown)"))
122 Just Interrupted -> io (putStrLn "Interrupted.")
123 Just (CmdLineError s) -> io (putStrLn s) -- omit the location for CmdLineError
124 Just ph@PhaseFailed{} -> io (putStrLn (showGhcException ph "")) -- ditto
125 Just other_ghc_ex -> io (print other_ghc_ex)
127 showException other_exception
128 = io (putStrLn ("*** Exception: " ++ show other_exception))
130 -----------------------------------------------------------------------------
131 -- recursive exception handlers
133 -- Don't forget to unblock async exceptions in the handler, or if we're
134 -- in an exception loop (eg. let a = error a in a) the ^C exception
135 -- may never be delivered. Thanks to Marcin for pointing out the bug.
137 ghciHandle :: (Exception -> GHCi a) -> GHCi a -> GHCi a
138 ghciHandle h (GHCi m) = GHCi $ \s ->
139 Exception.catch (m s)
140 (\e -> unGHCi (ghciUnblock (h e)) s)
142 ghciUnblock :: GHCi a -> GHCi a
143 ghciUnblock (GHCi a) = GHCi $ \s -> Exception.unblock (a s)
145 -----------------------------------------------------------------------------
146 -- timing & statistics
148 timeIt :: GHCi a -> GHCi a
150 = do b <- isOptionSet ShowTiming
153 else do allocs1 <- io $ getAllocations
154 time1 <- io $ getCPUTime
156 allocs2 <- io $ getAllocations
157 time2 <- io $ getCPUTime
158 io $ printTimes (fromIntegral (allocs2 - allocs1))
162 foreign import ccall unsafe "getAllocations" getAllocations :: IO Int64
163 -- defined in ghc/rts/Stats.c
165 printTimes :: Integer -> Integer -> IO ()
166 printTimes allocs psecs
167 = do let secs = (fromIntegral psecs / (10^12)) :: Float
168 secs_str = showFFloat (Just 2) secs
170 parens (text (secs_str "") <+> text "secs" <> comma <+>
171 text (show allocs) <+> text "bytes")))
173 -----------------------------------------------------------------------------
180 -- Have to turn off buffering again, because we just
181 -- reverted stdout, stderr & stdin to their defaults.
183 foreign import ccall "revertCAFs" rts_revertCAFs :: IO ()
184 -- Make it "safe", just in case
186 -----------------------------------------------------------------------------
187 -- To flush buffers for the *interpreted* computation we need
188 -- to refer to *its* stdout/stderr handles
190 GLOBAL_VAR(flush_interp, error "no flush_interp", IO ())
191 GLOBAL_VAR(turn_off_buffering, error "no flush_stdout", IO ())
193 no_buf_cmd = "System.IO.hSetBuffering System.IO.stdout System.IO.NoBuffering" ++
194 " Prelude.>> System.IO.hSetBuffering System.IO.stderr System.IO.NoBuffering"
195 flush_cmd = "System.IO.hFlush System.IO.stdout Prelude.>> System.IO.hFlush System.IO.stderr"
197 initInterpBuffering :: Session -> IO ()
198 initInterpBuffering session
199 = do maybe_hval <- GHC.compileExpr session no_buf_cmd
202 Just hval -> writeIORef turn_off_buffering (unsafeCoerce# hval :: IO ())
203 other -> panic "interactiveUI:setBuffering"
205 maybe_hval <- GHC.compileExpr session flush_cmd
207 Just hval -> writeIORef flush_interp (unsafeCoerce# hval :: IO ())
208 _ -> panic "interactiveUI:flush"
213 flushInterpBuffers :: GHCi ()
215 = io $ do Monad.join (readIORef flush_interp)
218 turnOffBuffering :: IO ()
220 = do Monad.join (readIORef turn_off_buffering)