module UHC.Light.Compiler.Module.Merge
( ModDbBindLetInfo''
, ModDbBindArray'
, ModPuller (..)
, modMergeByPullingInM
, modMergeByPullingIn )
where
import UHC.Light.Compiler.Base.Common
import Data.List
import Data.Maybe
import qualified Data.Set as Set
import qualified Data.Map as Map
import UHC.Util.Utils
import Control.Monad.Identity
import Control.Monad.State
import Data.Array
import qualified UHC.Util.FastSeq as Seq
type ModDbBindLetInfo'' f cat bind = (cat,f bind)
type ModDbBindLetInfo'2 cat bind = ModDbBindLetInfo'' [] cat bind
type ModDbBindArray' cat bind = Array Int (ModDbBindLetInfo'' (Array Int) cat bind)
class ModPuller modFr modsDb modsRem modTo expr cat bind
| modFr -> expr cat bind modsRem modsDb modTo
, expr -> modFr
, cat -> modFr
, bind -> modFr
, modsRem -> modFr
, modsDb -> modFr
, modTo -> modFr
where
mpullSplit :: modFr -> [modFr] -> (expr, Maybe (cat,[(bind,HsNameS)]), modsDb, modsRem)
mpullUsedBindings :: Monad m => HsName -> modsDb -> m (Maybe (cat, [bind], HsNameS))
mpullRelevantExprs :: bind -> [expr]
mpullFreeVars :: expr -> HsNameS
mpullBindingsAddToMod :: modsRem -> expr -> [(cat,[bind])] -> modTo -> modTo
data PullState cat bind
= PullState
{ pullstBinds :: Seq.Seq (ModDbBindLetInfo'2 cat bind)
, pullstPulledNmS :: !HsNameS
, pullstToDo :: ![HsName]
}
emptyPullState :: PullState cat bind
emptyPullState = PullState Seq.empty Set.empty []
type ModMergeT cat bind m a = StateT (PullState cat bind) m a
modMergeByPullingInM
:: ( ModPuller modFr modsDb modsRem modTo expr cat bind
, Monad m
)
=> (modFr, [modFr])
-> ModMergeT cat bind m
( (modTo -> modTo)
, HsNameS
)
modMergeByPullingInM (modMain,modImpL) = do
let (rootExpr,mbExports,modDb,modRem) = mpullSplit modMain modImpL
put $ emptyPullState {pullstToDo = Set.toList $ Set.unions $ mpullFreeVars rootExpr : (maybe [] (map snd . snd) mbExports)}
pull modDb
when (isJust mbExports) $
let (Just (exportCateg,rootExports)) = mbExports
in modify $ \st -> st {pullstBinds = pullstBinds st `Seq.union` Seq.fromList [ (exportCateg,[b]) | (b,_) <- rootExports ]}
final <- get
return
( mpullBindingsAddToMod modRem rootExpr (Seq.toList $ pullstBinds final)
, Set.map (panicJust "modMergeByPullingInM" . hsnQualifier) $ pullstPulledNmS final
)
where
pull modDb = do
s <- get
case pullstToDo s of
(nm:nmRest)
| nm `Set.notMember` pullstPulledNmS s -> do
mbPull@(~(Just (cat,binds,pulled))) <- lift $ mpullUsedBindings nm modDb
if isJust mbPull
then do
let pulledNms = pullstPulledNmS s `Set.union` pulled
newNms
= (Set.unions $ map (Set.unions . map mpullFreeVars . mpullRelevantExprs) binds)
`Set.difference` pulledNms
put $
s { pullstToDo = Set.toList newNms ++ nmRest
, pullstBinds = Seq.singleton (cat,binds) `Seq.union` pullstBinds s
, pullstPulledNmS = pulledNms
}
pull modDb
else
dfltContinue
| otherwise -> dfltContinue
where
dfltContinue = do
put $ s { pullstToDo = nmRest }
pull modDb
_ -> return ()
modMergeByPullingIn
:: ModPuller modFr modsDb modsRem modTo expr cat bind
=> (modFr, [modFr])
-> ( (modTo -> modTo)
, HsNameS
)
modMergeByPullingIn mods = flip evalState emptyPullState $ modMergeByPullingInM mods