summaryrefslogtreecommitdiff
path: root/docs/users_guide/extending_ghc.rst
diff options
context:
space:
mode:
authorBoldizsar Nemeth <nboldi@elte.hu>2018-06-02 19:08:40 -0400
committerBen Gamari <ben@smart-cactus.org>2018-06-02 23:20:47 -0400
commitc2783ccf545faabd21a234a4dfc569cd856082b9 (patch)
tree506fa03c577a381a4bb9c74e9f9749723b3928a3 /docs/users_guide/extending_ghc.rst
parent727256680c8547282bda09dffefba01f9db98d1e (diff)
downloadhaskell-c2783ccf545faabd21a234a4dfc569cd856082b9.tar.gz
Extended the plugin system to run plugins on more representations
Extend GHC plugins to access parsed, type checked representation, interfaces that are loaded. And splices that are evaluated. The goal is to enable development tools to access the GHC representation in the pre-existing build environment. See the full proposal here: https://ghc.haskell.org/trac/ghc/wiki/ExtendedPluginsProposal Reviewers: goldfire, bgamari, ezyang, angerman, mpickering Reviewed By: mpickering Subscribers: ezyang, angerman, mpickering, ulysses4ever, rwbarton, thomie, carter GHC Trac Issues: #14709 Differential Revision: https://phabricator.haskell.org/D4342
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