<div dir="ltr">Sorry for the earlier mishap, here&#39;s the full email.<div><br></div><div><span style="font-family:arial,sans-serif;font-size:13px">Hi all,</span><br style="font-family:arial,sans-serif;font-size:13px"><br style="font-family:arial,sans-serif;font-size:13px">
<span style="font-family:arial,sans-serif;font-size:13px">The plugin mechanism gives access to the program in Core; this suffices for many but not quite all purposes. Tools that need access to the original AST can call typecheckModule directly, but of course this requires using the GHC API directly. Moreover, even when using the GHC API directly anyway (as in my case), it means that tools cannot take advantage of ghc&#39;s infrastructure for dependency tracking, recompiling only changed modules, etc.</span><br style="font-family:arial,sans-serif;font-size:13px">
<br style="font-family:arial,sans-serif;font-size:13px"><span style="font-family:arial,sans-serif;font-size:13px">Hence it would be useful to have &quot;source plugins&quot;, which can be used both externally and when using ghc API (in the latter case I guess &quot;hooks&quot; would be the more appropriate terminology). Currently &quot;core plugins&quot; are recorded as part of DynFlags as</span><br style="font-family:arial,sans-serif;font-size:13px">
<br style="font-family:arial,sans-serif;font-size:13px"><font face="courier new, monospace" style="font-size:13px">    pluginModNames        :: [ModuleName],<br>    pluginModNameOpts     :: [(ModuleName,String)],<br></font><br style="font-family:arial,sans-serif;font-size:13px">
<div style="font-family:arial,sans-serif;font-size:13px">This makes sense when thinking of plugins only as an external mechanism, but is less convenient when using them as internal hooks, too. In my draft patch I introduce a new type &quot;HscPlugin&quot; (described shortly) and added</div>
<div style="font-family:arial,sans-serif;font-size:13px"><br></div><div style="font-family:arial,sans-serif;font-size:13px"><div><font face="courier new, monospace">    sourcePlugins         :: [HscPlugin],</font></div><div>
<br></div></div><div style="font-family:arial,sans-serif;font-size:13px">to DynFlags. HscPlugin is a record of a pair of functions; having the actual record here rather than  a module name means that these functions can have a non-empty closure, which is obviously convenient when using this as a hook rather than an external plugin.</div>
<div style="font-family:arial,sans-serif;font-size:13px"><br></div><div style="font-family:arial,sans-serif;font-size:13px">In my current version HscPlugin looks like</div><div style="font-family:arial,sans-serif;font-size:13px">
<br></div><div style="font-family:arial,sans-serif;font-size:13px"><div><font face="courier new, monospace">    data HscPlugin = HscPlugin {</font></div><div><font face="courier new, monospace">        runHscPlugin :: forall m. MonadIO m </font></div>
<div><font face="courier new, monospace">                     =&gt; DynFlags</font></div><div><font face="courier new, monospace">                     -&gt; TcGblEnv</font></div><div><font face="courier new, monospace">                     -&gt; m TcGblEnv</font></div>
<div><font face="courier new, monospace">    </font></div><div><font face="courier new, monospace">      , runHscQQ     :: forall m. MonadIO m </font></div><div><font face="courier new, monospace">                     =&gt; Env TcGblEnv TcLclEnv</font></div>
<div><font face="courier new, monospace">                     -&gt; HsQuasiQuote Name</font></div><div><font face="courier new, monospace">                     -&gt; m (HsQuasiQuote Name)</font></div><div><font face="courier new, monospace">      }</font></div>
<div><br></div></div><div style="font-family:arial,sans-serif;font-size:13px">runHscPlugin is the main function; it gets passed the TcGblEnv (which contains the type checked AST as its tcd_binds field) and gets a change to return it modified (we don&#39;t currently take advantage of that; I did that only to be in line with &quot;core plugins&quot;).</div>
<div style="font-family:arial,sans-serif;font-size:13px"><br></div><div style="font-family:arial,sans-serif;font-size:13px">Unfortunately, the typechecked AST is only a subset of the renamed AST (see <a href="http://www.haskell.org/pipermail/ghc-devs/2013-February/000540.html">http://www.haskell.org/pipermail/ghc-devs/2013-February/000540.html</a>). The TcGblEnv contains a  tcg_rn_decls field, which is a reference to the full renamed (as opposed to typechecked) AST, but by default this is not initialized: the typechecker only optionally retains the renamed AST, and this is hardcoded to by False. In my current patch I have changed this so that it&#39;s hard coded to be True; ideally this should become an option in DynFlags (more ideal still would be if the type checked AST would not lose any information).</div>
</div><div style="font-family:arial,sans-serif;font-size:13px"><br></div><div style="font-family:arial,sans-serif;font-size:13px">Unfortunately, even the renamer loses information: quasi-quotes get expanded during renaming and all evidence of that there was ever a quasi-quote there has disappeared when the renamer returns. For this reason, the HscPlugin type that I&#39;m using at the moment also has a hook for quasi-quotes.</div>
<div style="font-family:arial,sans-serif;font-size:13px"><br></div><div style="font-family:arial,sans-serif;font-size:13px">So what I have currently done is:</div><div><ol style><li style><font face="arial, sans-serif">Introduced the above HscPlugin type and added a corresponding field to DynFlags</font></li>
<li style><font face="arial, sans-serif">Call runHscQQ in the renamer whenever a quasi-quote gets expanded.</font></li><li style><font face="arial, sans-serif">Make sure that the typechecker passes the result of the renamer through.</font></li>
<li style><font face="arial, sans-serif">Call runHscPlugin on the result of the typechecker.</font></li></ol><div style><font face="arial, sans-serif">In my client code I then combine the information obtained from these three sources (2, 3, 4). </font></div>
</div><div style><font face="arial, sans-serif"><br></font></div><div style="font-family:arial,sans-serif;font-size:13px">The path of least resistance for me currently to submit this as a patch for ghc therefore be to submit a patch that does precisely what I described above, mutatis mutandis based on your feedback, except that I would add an option to add to DynFlags that would tell the type checker whether or not to pass the result of the renamer through, rather than hardcoding it.</div>
<div style="font-family:arial,sans-serif;font-size:13px"><br></div><div style="font-family:arial,sans-serif;font-size:13px">It is a little bit messy mostly because parts of the AST get lost along the way: quasi-quotes in the renamer, data type declarations and other things during type checking. A more ideal way, but also more time consuming, would be to change this so that the renamer leaves evidence of the quasi-quotes in the tree, and the type checker returns the entire tree type checked, rather than just a subset. I think that ultimately this is the better approach, at least for our purposes -- I&#39;m not sure about other tools, but since this would be a larger change that affects larger parts of the ghc pipeline I&#39;m not sure that I&#39;ll be able to do it.</div>
<div style="font-family:arial,sans-serif;font-size:13px"><br></div><div style="font-family:arial,sans-serif;font-size:13px">Any and all feedback on the above would be appreciated!</div><div style="font-family:arial,sans-serif;font-size:13px">
<br></div><div style="font-family:arial,sans-serif;font-size:13px">Edsko</div></div>