| | 58 | |
| | 59 | SPJ believes that external core would not protect against versioning in GHCs core representation as it will change with core itself and so we should use core directly for simplicity. This also allows reuse of GHCs substantial internal utility library for manipulating core representations by the plugin authors. |
| | 60 | |
| | 61 | Concretely, the plugin writer would implement an interface that looked something like this: |
| | 62 | |
| | 63 | {{{ |
| | 64 | |
| | 65 | -- The pragma supplied options must be of type dynamic because they are instantiated by GHC. The plugin author |
| | 66 | -- will want to check that the data the user supplied is something they are prepared to accept as a pragma |
| | 67 | -- Command line options will be supplied as a simple string list of those things supplied to GHC with a -p prefix |
| | 68 | -- Note that this design means that the type of command line plugin option are limited to: |
| | 69 | -- * -pfoo |
| | 70 | -- * -pfoo-arg (NOT -pfoo arg) |
| | 71 | -- * -pfoo=n |
| | 72 | -- * -pfoo; |
| | 73 | -- Furthermore we cannot warn about unrecognized -p args unless we have plugins report back unrecognized args. Reporting the error at that |
| | 74 | -- late stage will also be problematic, so we probably shouldn't bother. |
| | 75 | -- We should provide a library that is able to parse these for plugin writers so they don't reinvent the wheel (maybe just using |
| | 76 | -- GHCs CmdLineParser) |
| | 77 | -- An alternative design for functionPragmaOptions would be to attach the pragma data structures to Notes in the Core syntax tree. |
| | 78 | -- However, SPJ feels that would interact too much with other compiler stages, that have a habit of moving Notes around.. |
| | 79 | newtype PluginOptions = PluginOptions { ambientPragmaOptions :: [Dynamic], functionPragmaOptions :: Map Id [Dynamic], commandLineOptions :: [String] } |
| | 80 | initialize :: PluginOptions -> IO GHCPluginInstance |
| | 81 | |
| | 82 | data GHCPluginInstance = GHCPluginInstance { |
| | 83 | -- We could either have them change the pipeline explicitly, by providing a CoreDoPluginPass constructor in CoreToDo: |
| | 84 | installCorePasses :: [CoreToDo] -> [CoreToDo] |
| | 85 | -- Or (possibly less fragile and operational, but more complicated) just something like: |
| | 86 | providedCorePasses :: [(CorePassPlacementSpec, PluginCorePassName, PluginCorePass)] |
| | 87 | -- For details see note [Declarative Core Pass Placement] |
| | 88 | |
| | 89 | -- TODO: work out the best way to allow plugins to specify link artifacts |
| | 90 | } |
| | 91 | |
| | 92 | |
| | 93 | type PluginCorePass = DynFlags -> UniqSupply -> [CoreBind] -> IO [CoreBind] |
| | 94 | |
| | 95 | -- Note: [Declarative Core Pass Placement] |
| | 96 | -- If we went the declarative route for core pass placement we would have something like this: |
| | 97 | type CorePassPlacementSpec = [CorePassPlacement] |
| | 98 | data CorePassPlacement |
| | 99 | = CertainlyBefore CorePassName |
| | 100 | | CertainlyAfter CorePassName |
| | 101 | | IdeallyBefore CorePassName |
| | 102 | | IdeallyAfter CorePassName |
| | 103 | | InPhase Int -- Phase 0, 1 or 2 as they currently exist in GHC |
| | 104 | | WhenOptimizationLevelAtLeast Int -- Level 0, 1 or 2 as they currently exist in GHC |
| | 105 | |
| | 106 | type CorePassName = String |
| | 107 | type PluginCorePassName = CorePassName |
| | 108 | -- Alternatively we could expose a CoreToDo style of thing as the core |
| | 109 | -- pass names, e.g: |
| | 110 | type PluginCorePassName = String |
| | 111 | data CorePassName |
| | 112 | = SimplifyCorePass |
| | 113 | | FloatInwardsCorePass |
| | 114 | | CSECorePass |
| | 115 | | ... |
| | 116 | | PluginCorePass PluginCorePassName |
| | 117 | deriving (Eq) |
| | 118 | -- This would let us recover some compile time safety while still allowing plugins to refer |
| | 119 | -- to passes installed by other plugins, which may be desirable. |
| | 120 | -- End Note: [Declarative Core Pass Placement] |
| | 121 | |
| | 122 | |
| | 123 | -- |
| | 124 | |
| | 125 | }}} |
| | 126 | |
| | 127 | Alternative design that would let the plugin authors reuse GHCs parsing infrastructure and also let us warn about unrecognized command line flags in command line parsing as usual: |
| | 128 | |
| | 129 | {{{ |
| | 130 | -- The actions encapsulated within the OptKind will be run by |
| | 131 | -- the GHC command line parser: you can use the action to accumulate flags that will |
| | 132 | -- be output by the runCommandLineM thing and eventually fed back to the initialize function |
| | 133 | runCommandLineM :: CommandLineM a -> (a, CommandLineOptions) |
| | 134 | dynamicFlags :: [(String, OptKind CommandLineM)] |
| | 135 | |
| | 136 | -- These will be defined by the particular plugin author: clearly this makes it hard for GHC to |
| | 137 | -- type check the plugin, but we'll ignore the type safety of dynamic linking here! |
| | 138 | newtype CommandLineM = ... |
| | 139 | newtype CommandLineOptions = ... |
| | 140 | }}} |