summaryrefslogtreecommitdiff
path: root/docs/users_guide/extending_ghc.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/users_guide/extending_ghc.rst')
-rw-r--r--docs/users_guide/extending_ghc.rst203
1 files changed, 203 insertions, 0 deletions
diff --git a/docs/users_guide/extending_ghc.rst b/docs/users_guide/extending_ghc.rst
index bb31b0783a..7ed258a090 100644
--- a/docs/users_guide/extending_ghc.rst
+++ b/docs/users_guide/extending_ghc.rst
@@ -600,6 +600,209 @@ the plugin to create equality axioms for use in evidence terms, but GHC
does not check their consistency, and inconsistent axiom sets may lead
to segfaults or other runtime misbehaviour.
+.. _source-plugins:
+
+Source plugins
+~~~~~~~~~~~~~~
+
+In additional to core and type checker plugins, you can install plugins that can
+access different representations of the source code. The main purpose of these
+plugins is to make it easier to implement development tools.
+
+There are several different access points that you can use for defining plugins
+that access the representations. All these fields receive the list of
+``CommandLineOption`` strings that are passed to the compiler using the
+``-fplugin-opt`` flags.
+
+::
+
+ plugin :: Plugin
+ plugin = defaultPlugin {
+ parsedResultAction = parsed
+ , typeCheckResultAction = typechecked
+ , spliceRunAction = spliceRun
+ , interfaceLoadAction = interfaceLoad
+ , renamedResultAction = renamed
+ }
+
+Parsed representation
+^^^^^^^^^^^^^^^^^^^^^
+
+When you want to define a plugin that uses the syntax tree of the source code,
+you would like to override the ``parsedResultAction`` field. This access point
+enables you to get access to information about the lexical tokens and comments
+in the source code as well as the original syntax tree of the compiled module.
+
+::
+
+ parsed :: [CommandLineOption] -> ModSummary -> HsParsedModule
+ -> Hsc HsParsedModule
+
+The ``ModSummary`` contains useful
+meta-information about the compiled module. The ``HsParsedModule`` contains the
+lexical and syntactical information we mentioned before. The result that you
+return will change the result of the parsing. If you don't want to change the
+result, just return the ``HsParsedModule`` that you received as the argument.
+
+Type checked representation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When you want to define a plugin that needs semantic information about the
+source code, use the ``typeCheckResultAction`` field. For example, if your
+plugin have to decide if two names are referencing the same definition or it has
+to check the type of a function it is using semantic information. In this case
+you need to access the renamed or type checked version of the syntax tree with
+``typeCheckResultAction``
+
+::
+
+ typechecked :: [CommandLineOption] -> ModSummary -> TcGblEnv -> Hsc TcGblEnv
+
+By overriding the ``renamedResultAction`` field with a ``Just`` function, you
+can request the compiler to keep the renamed syntax tree and give it to your
+processing function. This is important because some parts of the renamed
+syntax tree (for example, imports) are not found in the typechecked one.
+The ``renamedResultAction`` is set to ``Nothing`` by default.
+
+::
+
+ rename :: Maybe ([CommandLineOption] -> ModSummary -> Hsc ())
+
+
+Evaluated code
+^^^^^^^^^^^^^^
+
+When the compiler type checks the source code, :ref:`template-haskell` Splices
+and :ref:`th-quasiquotation` will be replaced by the syntax tree fragments
+generated from them. However for tools that operate on the source code the
+code generator is usually more interesting than the generated code. For this
+reason we included ``spliceRunAction``. This field is invoked on each expression
+before they are evaluated. The input is type checked, so semantic information is
+available for these syntax tree fragments. If you return a different expression
+you can change the code that is generated.
+
+
+::
+
+ spliceRun :: [CommandLineOption] -> LHsExpr GhcTc -> TcM (LHsExpr GhcTc)
+
+
+However take care that the generated definitions are still in the input of
+``typeCheckResultAction``. If your don't take care to filter the typechecked
+input, the behavior of your tool might be inconsistent.
+
+Interface files
+^^^^^^^^^^^^^^^
+
+Sometimes when you are writing a tool, knowing the source code is not enough,
+you also have to know details about the modules that you import. In this case we
+suggest using the ``interfaceLoadAction``. This will be called each time when
+the code of an already compiled module is loaded. It will be invoked for modules
+from installed packages and even modules that are installed with GHC. It will
+NOT be invoked with your own modules.
+
+::
+
+ interfaceLoad :: forall lcl . [CommandLineOption] -> ModIface
+ -> IfM lcl ModIface
+
+In the ``ModIface`` datatype you can find lots of useful information, including
+the exported definitions and type class instances.
+
+
+Source plugin example
+^^^^^^^^^^^^^^^^^^^^^
+
+In this example, we inspect all available details of the compiled source code.
+We don't change any of the representation, but write out the details to the
+standard output. The pretty printed representation of the parsed, renamed and
+type checked syntax tree will be in the output as well as the evaluated splices
+and quasi quotes. The name of the interfaces that are loaded will also be
+displayed.
+
+::
+
+ module SourcePlugin where
+
+ import Control.Monad.IO.Class
+ import Plugins
+ import HscTypes
+ import TcRnTypes
+ import HsExtension
+ import HsExpr
+ import Outputable
+ import HsDoc
+
+ plugin :: Plugin
+ plugin = defaultPlugin { parsedResultAction = parsedPlugin
+ , renamedResultAction = Just renamedAction
+ , typeCheckResultAction = typecheckPlugin
+ , spliceRunAction = metaPlugin
+ , interfaceLoadAction = interfaceLoadPlugin
+ }
+
+ parsedPlugin :: [CommandLineOption] -> ModSummary -> HsParsedModule -> Hsc HsParsedModule
+ parsedPlugin _ _ pm
+ = do liftIO $ putStrLn $ "parsePlugin: \n" ++ (showSDocUnsafe $ ppr $ hpm_module pm)
+ return pm
+
+ renamedAction :: [CommandLineOption] -> ModSummary
+ -> ( HsGroup GhcRn, [LImportDecl GhcRn]
+ , Maybe [(LIE GhcRn, Avails)], Maybe LHsDocString )
+ -> Hsc ()
+ renamedAction _ _ ( gr, _, _, _ )
+ = liftIO $ putStrLn "typeCheckPlugin (rn): " ++ (showSDocUnsafe $ ppr gr)
+
+ typecheckPlugin :: [CommandLineOption] -> ModSummary -> TcGblEnv -> Hsc TcGblEnv
+ typecheckPlugin _ _ tc
+ = do liftIO $ putStrLn $ "typeCheckPlugin (rn): \n" ++ (showSDocUnsafe $ ppr $ tcg_rn_decls tc)
+ liftIO $ putStrLn $ "typeCheckPlugin (tc): \n" ++ (showSDocUnsafe $ ppr $ tcg_binds tc)
+ return tc
+
+ metaPlugin :: [CommandLineOption] -> LHsExpr GhcTc -> TcM (LHsExpr GhcTc)
+ metaPlugin _ meta
+ = do liftIO $ putStrLn $ "meta: " ++ (showSDocUnsafe $ ppr meta)
+ return meta
+
+ interfaceLoadPlugin :: [CommandLineOption] -> ModIface -> IfM lcl ModIface
+ interfaceLoadPlugin _ iface
+ = do liftIO $ putStrLn $ "interface loaded: " ++ (showSDocUnsafe $ ppr $ mi_module iface)
+ return iface
+
+When you compile a simple module that contains Template Haskell splice
+
+::
+
+ {-# LANGUAGE TemplateHaskell #-}
+ module A where
+
+ a = ()
+
+ $(return [])
+
+with the compiler flags ``-fplugin SourcePlugin`` it will give the following
+output:
+
+.. code-block:: none
+
+ parsePlugin:
+ module A where
+ a = ()
+ $(return [])
+ interface loaded: Prelude
+ interface loaded: GHC.Float
+ interface loaded: GHC.Base
+ interface loaded: Language.Haskell.TH.Lib.Internal
+ interface loaded: Language.Haskell.TH.Syntax
+ interface loaded: GHC.Types
+ meta: return []
+ interface loaded: GHC.Integer.Type
+ typeCheckPlugin (rn):
+ Just a = ()
+ typeCheckPlugin (tc):
+ {$trModule = Module (TrNameS "main"#) (TrNameS "A"#), a = ()}
+
+
.. _plugin_recompilation:
Controlling Recompilation