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