{-# LANGUAGE TemplateHaskell #-}
module Control.Super.Monad.Plugin
( plugin ) where
import Plugins ( Plugin )
import Outputable ( SDoc, hang, text, ($$) )
import Module ( Module )
import Control.Super.Plugin.Prototype ( pluginPrototype )
import Control.Super.Plugin.Utils ( errIndent )
import Control.Super.Plugin.ClassDict ( ClassDict )
import Control.Super.Plugin.Detect
( ModuleQuery(..)
, ClassQuery(..)
, InstanceImplication
, clsDictInstImp, clsDictInstEquiv
, defaultFindEitherModuleErrMsg )
import Control.Super.Plugin.Names
( PluginClassName, PluginModuleName
, supermonadModuleName, supermonadCtModuleName
, legacySupermonadModuleName, legacySupermonadCtModuleName
, supermonadPreludeModuleName, supermonadCtPreludeModuleName
, legacySupermonadPreludeModuleName, legacySupermonadCtPreludeModuleName
, bindClassName, returnClassName, applicativeClassName )
plugin :: Plugin
plugin = pluginPrototype [ supermonadClassQuery, monadPlusClassQuery, alternativeClassQuery ]
solvingGroups
supermonadInstanceImplications
alternativeEmptyClassName, alternativeAltClassName :: PluginClassName
alternativeEmptyClassName = "AlternativeEmpty"
alternativeAltClassName = "AlternativeAlt"
alternativeModuleName, alternativeCtModuleName :: PluginModuleName
alternativeModuleName = "Control.Super.Monad.Alternative"
alternativeCtModuleName = "Control.Super.Monad.Constrained.Alternative"
monadPlusZeroClassName, monadPlusAddClassName :: PluginClassName
monadPlusZeroClassName = "MonadPlusZero"
monadPlusAddClassName = "MonadPlusAdd"
monadPlusModuleName, monadPlusCtModuleName :: PluginModuleName
monadPlusModuleName = "Control.Super.Monad.MonadPlus"
monadPlusCtModuleName = "Control.Super.Monad.Constrained.MonadPlus"
solvingGroups :: [[PluginClassName]]
solvingGroups =
[ [ bindClassName, returnClassName, applicativeClassName
, monadPlusZeroClassName, monadPlusAddClassName
, alternativeEmptyClassName, alternativeAltClassName ]
]
supermonadModuleQuery :: ModuleQuery
supermonadModuleQuery = EitherModule
[ AnyModule [ ThisModule supermonadModuleName Nothing
, ThisModule supermonadPreludeModuleName Nothing
, ThisModule legacySupermonadModuleName Nothing
, ThisModule legacySupermonadPreludeModuleName Nothing
]
, AnyModule [ ThisModule supermonadCtModuleName Nothing
, ThisModule supermonadCtPreludeModuleName Nothing
, ThisModule legacySupermonadCtModuleName Nothing
, ThisModule legacySupermonadCtPreludeModuleName Nothing
]
] $ Just findSupermonadModulesErrMsg
alternativeModuleQuery :: ModuleQuery
alternativeModuleQuery = EitherModule
[ ThisModule alternativeModuleName Nothing
, ThisModule alternativeCtModuleName Nothing
] $ Just findAlternativeModulesErrMsg
monadPlusModuleQuery :: ModuleQuery
monadPlusModuleQuery = EitherModule
[ ThisModule monadPlusModuleName Nothing
, ThisModule monadPlusCtModuleName Nothing
] $ Just findMonadPlusModulesErrMsg
supermonadClassQuery :: ClassQuery
supermonadClassQuery = ClassQuery False supermonadModuleQuery
[ (bindClassName , 3)
, (returnClassName , 1)
, (applicativeClassName, 3)
]
alternativeClassQuery :: ClassQuery
alternativeClassQuery = ClassQuery True alternativeModuleQuery
[ (alternativeAltClassName , 3)
, (alternativeEmptyClassName, 1)
]
monadPlusClassQuery :: ClassQuery
monadPlusClassQuery = ClassQuery True monadPlusModuleQuery
[ (monadPlusZeroClassName, 1)
, (monadPlusAddClassName , 3)
]
supermonadInstanceImplications :: ClassDict -> [InstanceImplication]
supermonadInstanceImplications clsDict =
(applicativeClassName ==> returnClassName ) ++
(bindClassName ==> returnClassName ) ++
(alternativeEmptyClassName <=> alternativeAltClassName) ++
(monadPlusZeroClassName <=> monadPlusAddClassName )
where
(==>) = clsDictInstImp clsDict
(<=>) = clsDictInstEquiv clsDict
findSupermonadModulesErrMsg :: [Either SDoc Module] -> SDoc
findSupermonadModulesErrMsg [Left errA, Left errB] =
hang (text "Could not find supermonad or constrained supermonad modules!") errIndent (errA $$ errB)
findSupermonadModulesErrMsg [Right _mdlA, Right _mdlB] =
text "Found unconstrained and constrained supermonad modules!"
findSupermonadModulesErrMsg mdls = defaultFindEitherModuleErrMsg mdls
findAlternativeModulesErrMsg :: [Either SDoc Module] -> SDoc
findAlternativeModulesErrMsg [Left errA, Left errB] =
hang (text "Could not find alternative or constrained alternative modules!") errIndent (errA $$ errB)
findAlternativeModulesErrMsg [Right _mdlA, Right _mdlB] =
text "Found unconstrained and constrained alternative modules!"
findAlternativeModulesErrMsg mdls = defaultFindEitherModuleErrMsg mdls
findMonadPlusModulesErrMsg :: [Either SDoc Module] -> SDoc
findMonadPlusModulesErrMsg [Left errA, Left errB] =
hang (text "Could not find monad plus or constrained monad plus modules!") errIndent (errA $$ errB)
findMonadPlusModulesErrMsg [Right _mdlA, Right _mdlB] =
text "Found unconstrained and constrained monad plus modules!"
findMonadPlusModulesErrMsg mdls = defaultFindEitherModuleErrMsg mdls