1 {-# OPTIONS_GHC -funbox-strict-fields #-}
2 -- -----------------------------------------------------------------------------
4 -- (c) The University of Glasgow, 2010
6 -- The Session type and related functionality
8 -- -----------------------------------------------------------------------------
11 -- * 'Ghc' monad stuff
18 Session(..), withSession, modifySession, withTempSession,
32 -- -----------------------------------------------------------------------------
33 -- | A monad that has all the features needed by GHC API calls.
35 -- In short, a GHC monad
37 -- - allows embedding of IO actions,
39 -- - can log warnings,
41 -- - allows handling of (extensible) exceptions, and
43 -- - maintains a current session.
45 -- If you do not use 'Ghc' or 'GhcT', make sure to call 'GHC.initGhcMonad'
46 -- before any call to the GHC API functions can occur.
48 class (Functor m, MonadIO m, ExceptionMonad m) => GhcMonad m where
49 getSession :: m HscEnv
50 setSession :: HscEnv -> m ()
53 -- | Call the argument with the current session.
54 withSession :: GhcMonad m => (HscEnv -> m a) -> m a
55 withSession f = getSession >>= f
57 -- | Grabs the DynFlags from the Session
58 getSessionDynFlags :: GhcMonad m => m DynFlags
59 getSessionDynFlags = withSession (return . hsc_dflags)
61 -- | Set the current session to the result of applying the current session to
63 modifySession :: GhcMonad m => (HscEnv -> HscEnv) -> m ()
64 modifySession f = do h <- getSession
67 withSavedSession :: GhcMonad m => m a -> m a
68 withSavedSession m = do
69 saved_session <- getSession
70 m `gfinally` setSession saved_session
72 -- | Call an action with a temporarily modified Session.
73 withTempSession :: GhcMonad m => (HscEnv -> HscEnv) -> m a -> m a
75 withSavedSession $ modifySession f >> m
77 -- -----------------------------------------------------------------------------
78 -- | A monad that allows logging of warnings.
80 logWarnings :: GhcMonad m => WarningMessages -> m ()
81 logWarnings warns = do
82 dflags <- getSessionDynFlags
83 liftIO $ printOrThrowWarnings dflags warns
85 -- -----------------------------------------------------------------------------
86 -- | A minimal implementation of a 'GhcMonad'. If you need a custom monad,
87 -- e.g., to maintain additional state consider wrapping this monad or using
89 newtype Ghc a = Ghc { unGhc :: Session -> IO a }
91 -- | The Session is a handle to the complete state of a compilation
92 -- session. A compilation session consists of a set of modules
93 -- constituting the current program or library, the context for
94 -- interactive evaluation, and various caches.
95 data Session = Session !(IORef HscEnv)
97 instance Functor Ghc where
98 fmap f m = Ghc $ \s -> f `fmap` unGhc m s
100 instance Monad Ghc where
101 return a = Ghc $ \_ -> return a
102 m >>= g = Ghc $ \s -> do a <- unGhc m s; unGhc (g a) s
104 instance MonadIO Ghc where
105 liftIO ioA = Ghc $ \_ -> ioA
107 instance ExceptionMonad Ghc where
109 Ghc $ \s -> unGhc act s `gcatch` \e -> unGhc (handle e) s
110 gblock (Ghc m) = Ghc $ \s -> gblock (m s)
111 gunblock (Ghc m) = Ghc $ \s -> gunblock (m s)
113 Ghc $ \s -> gmask $ \io_restore ->
115 g_restore (Ghc m) = Ghc $ \s -> io_restore (m s)
117 unGhc (f g_restore) s
119 instance GhcMonad Ghc where
120 getSession = Ghc $ \(Session r) -> readIORef r
121 setSession s' = Ghc $ \(Session r) -> writeIORef r s'
123 -- | Reflect a computation in the 'Ghc' monad into the 'IO' monad.
125 -- You can use this to call functions returning an action in the 'Ghc' monad
126 -- inside an 'IO' action. This is needed for some (too restrictive) callback
127 -- arguments of some library functions:
129 -- > libFunc :: String -> (Int -> IO a) -> IO a
130 -- > ghcFunc :: Int -> Ghc a
132 -- > ghcFuncUsingLibFunc :: String -> Ghc a -> Ghc a
133 -- > ghcFuncUsingLibFunc str =
134 -- > reifyGhc $ \s ->
135 -- > libFunc $ \i -> do
136 -- > reflectGhc (ghcFunc i) s
138 reflectGhc :: Ghc a -> Session -> IO a
139 reflectGhc m = unGhc m
141 -- > Dual to 'reflectGhc'. See its documentation.
142 reifyGhc :: (Session -> IO a) -> Ghc a
143 reifyGhc act = Ghc $ act
145 -- -----------------------------------------------------------------------------
146 -- | A monad transformer to add GHC specific features to another monad.
148 -- Note that the wrapped monad must support IO and handling of exceptions.
149 newtype GhcT m a = GhcT { unGhcT :: Session -> m a }
150 liftGhcT :: Monad m => m a -> GhcT m a
151 liftGhcT m = GhcT $ \_ -> m
153 instance Functor m => Functor (GhcT m) where
154 fmap f m = GhcT $ \s -> f `fmap` unGhcT m s
156 instance Monad m => Monad (GhcT m) where
157 return x = GhcT $ \_ -> return x
158 m >>= k = GhcT $ \s -> do a <- unGhcT m s; unGhcT (k a) s
160 instance MonadIO m => MonadIO (GhcT m) where
161 liftIO ioA = GhcT $ \_ -> liftIO ioA
163 instance ExceptionMonad m => ExceptionMonad (GhcT m) where
165 GhcT $ \s -> unGhcT act s `gcatch` \e -> unGhcT (handle e) s
166 gblock (GhcT m) = GhcT $ \s -> gblock (m s)
167 gunblock (GhcT m) = GhcT $ \s -> gunblock (m s)
169 GhcT $ \s -> gmask $ \io_restore ->
171 g_restore (GhcT m) = GhcT $ \s -> io_restore (m s)
173 unGhcT (f g_restore) s
175 instance (Functor m, ExceptionMonad m, MonadIO m) => GhcMonad (GhcT m) where
176 getSession = GhcT $ \(Session r) -> liftIO $ readIORef r
177 setSession s' = GhcT $ \(Session r) -> liftIO $ writeIORef r s'