Run the renamed source plugin after each HsGroup
[ghc.git] / compiler / main / Plugins.hs
1 {-# LANGUAGE RankNTypes #-}
2 {-# LANGUAGE CPP #-}
3 module Plugins (
4 FrontendPlugin(..), defaultFrontendPlugin, FrontendPluginAction
5 , Plugin(..), CommandLineOption, LoadedPlugin(..), lpModuleName
6 , defaultPlugin, keepRenamedSource, withPlugins, withPlugins_
7 , PluginRecompile(..)
8 , purePlugin, impurePlugin, flagRecompile
9 ) where
10
11 import GhcPrelude
12
13 import {-# SOURCE #-} CoreMonad ( CoreToDo, CoreM )
14 import qualified TcRnTypes
15 import TcRnTypes ( TcGblEnv, IfM, TcM, tcg_rn_decls, tcg_rn_exports )
16 import HsSyn
17 import DynFlags
18 import HscTypes
19 import GhcMonad
20 import DriverPhases
21 import Module ( ModuleName, Module(moduleName))
22 import Fingerprint
23 import Data.List
24 import Outputable (Outputable(..), text, (<+>))
25
26 #if __GLASGOW_HASKELL__ < 840
27 --Qualified import so we can define a Semigroup instance
28 -- but it doesn't clash with Outputable.<>
29 import qualified Data.Semigroup
30 #endif
31
32 import Control.Monad
33
34 -- | Command line options gathered from the -PModule.Name:stuff syntax
35 -- are given to you as this type
36 type CommandLineOption = String
37
38 -- | 'Plugin' is the compiler plugin data type. Try to avoid
39 -- constructing one of these directly, and just modify some fields of
40 -- 'defaultPlugin' instead: this is to try and preserve source-code
41 -- compatibility when we add fields to this.
42 --
43 -- Nonetheless, this API is preliminary and highly likely to change in
44 -- the future.
45 data Plugin = Plugin {
46 installCoreToDos :: CorePlugin
47 -- ^ Modify the Core pipeline that will be used for compilation.
48 -- This is called as the Core pipeline is built for every module
49 -- being compiled, and plugins get the opportunity to modify the
50 -- pipeline in a nondeterministic order.
51 , tcPlugin :: TcPlugin
52 -- ^ An optional typechecker plugin, which may modify the
53 -- behaviour of the constraint solver.
54 , pluginRecompile :: [CommandLineOption] -> IO PluginRecompile
55 -- ^ Specify how the plugin should affect recompilation.
56 , parsedResultAction :: [CommandLineOption] -> ModSummary -> HsParsedModule
57 -> Hsc HsParsedModule
58 -- ^ Modify the module when it is parsed. This is called by
59 -- HscMain when the parsing is successful.
60 , renamedResultAction :: [CommandLineOption] -> TcGblEnv
61 -> HsGroup GhcRn -> TcM (TcGblEnv, HsGroup GhcRn)
62 -- ^ Modify each group after it is renamed. This is called after each
63 -- `HsGroup` has been renamed.
64 , typeCheckResultAction :: [CommandLineOption] -> ModSummary -> TcGblEnv
65 -> TcM TcGblEnv
66 -- ^ Modify the module when it is type checked. This is called add the
67 -- very end of typechecking.
68 , spliceRunAction :: [CommandLineOption] -> LHsExpr GhcTc
69 -> TcM (LHsExpr GhcTc)
70 -- ^ Modify the TH splice or quasiqoute before it is run.
71 , interfaceLoadAction :: forall lcl . [CommandLineOption] -> ModIface
72 -> IfM lcl ModIface
73 -- ^ Modify an interface that have been loaded. This is called by
74 -- LoadIface when an interface is successfully loaded. Not applied to
75 -- the loading of the plugin interface. Tools that rely on information from
76 -- modules other than the currently compiled one should implement this
77 -- function.
78 }
79
80 -- Note [Source plugins]
81 -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
82 -- The `Plugin` datatype have been extended by fields that allow access to the
83 -- different inner representations that are generated during the compilation
84 -- process. These fields are `parsedResultAction`, `renamedResultAction`,
85 -- `typeCheckResultAction`, `spliceRunAction` and `interfaceLoadAction`.
86 --
87 -- The main purpose of these plugins is to help tool developers. They allow
88 -- development tools to extract the information about the source code of a big
89 -- Haskell project during the normal build procedure. In this case the plugin
90 -- acts as the tools access point to the compiler that can be controlled by
91 -- compiler flags. This is important because the manipulation of compiler flags
92 -- is supported by most build environment.
93 --
94 -- For the full discussion, check the full proposal at:
95 -- https://ghc.haskell.org/trac/ghc/wiki/ExtendedPluginsProposal
96
97
98 -- | A plugin with its arguments. The result of loading the plugin.
99 data LoadedPlugin = LoadedPlugin {
100 lpPlugin :: Plugin
101 -- ^ the actual callable plugin
102 , lpModule :: Module
103 -- ^ the module containing the plugin
104 , lpArguments :: [CommandLineOption]
105 -- ^ command line arguments for the plugin
106 }
107
108 lpModuleName :: LoadedPlugin -> ModuleName
109 lpModuleName = moduleName . lpModule
110
111
112 data PluginRecompile = ForceRecompile | NoForceRecompile | MaybeRecompile Fingerprint
113
114 instance Outputable PluginRecompile where
115 ppr ForceRecompile = text "ForceRecompile"
116 ppr NoForceRecompile = text "NoForceRecompile"
117 ppr (MaybeRecompile fp) = text "MaybeRecompile" <+> ppr fp
118
119 instance Semigroup PluginRecompile where
120 ForceRecompile <> _ = ForceRecompile
121 NoForceRecompile <> r = r
122 MaybeRecompile fp <> NoForceRecompile = MaybeRecompile fp
123 MaybeRecompile fp <> MaybeRecompile fp' = MaybeRecompile (fingerprintFingerprints [fp, fp'])
124 MaybeRecompile _fp <> ForceRecompile = ForceRecompile
125
126 instance Monoid PluginRecompile where
127 mempty = NoForceRecompile
128 #if __GLASGOW_HASKELL__ < 840
129 mappend = (Data.Semigroup.<>)
130 #endif
131
132 type CorePlugin = [CommandLineOption] -> [CoreToDo] -> CoreM [CoreToDo]
133 type TcPlugin = [CommandLineOption] -> Maybe TcRnTypes.TcPlugin
134
135 purePlugin, impurePlugin, flagRecompile :: [CommandLineOption] -> IO PluginRecompile
136 purePlugin _args = return NoForceRecompile
137
138 impurePlugin _args = return ForceRecompile
139
140 flagRecompile =
141 return . MaybeRecompile . fingerprintFingerprints . map fingerprintString . sort
142
143 -- | Default plugin: does nothing at all! For compatibility reasons
144 -- you should base all your plugin definitions on this default value.
145 defaultPlugin :: Plugin
146 defaultPlugin = Plugin {
147 installCoreToDos = const return
148 , tcPlugin = const Nothing
149 , pluginRecompile = impurePlugin
150 , renamedResultAction = \_ env grp -> return (env, grp)
151 , parsedResultAction = \_ _ -> return
152 , typeCheckResultAction = \_ _ -> return
153 , spliceRunAction = \_ -> return
154 , interfaceLoadAction = \_ -> return
155 }
156
157
158 -- | A renamer plugin which mades the renamed source available in
159 -- a typechecker plugin.
160 keepRenamedSource :: [CommandLineOption] -> TcGblEnv
161 -> HsGroup GhcRn -> TcM (TcGblEnv, HsGroup GhcRn)
162 keepRenamedSource _ gbl_env group =
163 return (gbl_env { tcg_rn_decls = update (tcg_rn_decls gbl_env)
164 , tcg_rn_exports = update_exports (tcg_rn_exports gbl_env) }, group)
165 where
166 update_exports Nothing = Just []
167 update_exports m = m
168
169 update Nothing = Just emptyRnGroup
170 update m = m
171
172
173 type PluginOperation m a = Plugin -> [CommandLineOption] -> a -> m a
174 type ConstPluginOperation m a = Plugin -> [CommandLineOption] -> a -> m ()
175
176 -- | Perform an operation by using all of the plugins in turn.
177 withPlugins :: Monad m => DynFlags -> PluginOperation m a -> a -> m a
178 withPlugins df transformation input
179 = foldM (\arg (LoadedPlugin p _ opts) -> transformation p opts arg)
180 input (plugins df)
181
182 -- | Perform a constant operation by using all of the plugins in turn.
183 withPlugins_ :: Monad m => DynFlags -> ConstPluginOperation m a -> a -> m ()
184 withPlugins_ df transformation input
185 = mapM_ (\(LoadedPlugin p _ opts) -> transformation p opts input)
186 (plugins df)
187
188 type FrontendPluginAction = [String] -> [(String, Maybe Phase)] -> Ghc ()
189 data FrontendPlugin = FrontendPlugin {
190 frontend :: FrontendPluginAction
191 }
192 defaultFrontendPlugin :: FrontendPlugin
193 defaultFrontendPlugin = FrontendPlugin { frontend = \_ _ -> return () }