ddc-core-flow-0.3.2.1: DDC/Core/Flow/Transform/Extract/Intersperse.hs
module DDC.Core.Flow.Transform.Extract.Intersperse
(intersperseStmts)
where
import DDC.Core.Flow.Compounds
import DDC.Core.Flow.Prim
import DDC.Core.Flow.Exp
import DDC.Core.Collect
import DDC.Core.Transform.Annotate
import DDC.Type.Env
import Data.List (partition, (\\))
import qualified Data.Set as Set
-- | Given two lists of lets, order them so that any variables are bound before use.
intersperseStmts :: [LetsF] -> [LetsF] -> [LetsF]
intersperseStmts ls rs
= let bls = nubbish $ map takeSubstBoundsOfBinds $ map valwitBindsOfLets ls
brs = nubbish $ map takeSubstBoundsOfBinds $ map valwitBindsOfLets rs
in intersperse' (ls `zip` bls ++ rs `zip` brs)
-- Because a name might be bound a couple of times
-- (see extractStmtEnd:EndVecSlice)
nubbish :: [[Bound Name]] -> [[Bound Name]]
nubbish bs' = go bs' []
where go [] _ = []
go (b:bs) accs = (b \\ accs) : go bs (accs ++ b)
intersperse'
:: [(Lets () Name, [Bound Name])]
-> [Lets () Name]
intersperse' [] = []
intersperse' ((x,b):bxs)
-- Check if any of the free variables in x are bound later on.
-- If so, defer this binding...
| f <- freeXLets x
, (r:rs,os) <- partition (any (flip Set.member f) . snd) bxs
, (x', _) <- r
= x' : intersperse' (rs ++ (x, b) : os)
-- Otherwise it's a valid binding
| otherwise
= x : intersperse' bxs
freeXLets :: LetsF -> Set.Set (Bound Name)
freeXLets ll
= freeX empty $ annotate () (XLet ll (XCon (dcBool True)))