module Transform.SortDefinitions (sortDefs) where
import Control.Monad.State
import Control.Applicative ((<$>),(<*>))
import qualified Data.Graph as Graph
import qualified Data.Map as Map
import qualified Data.Maybe as Maybe
import qualified Data.Set as Set
import AST.Annotation
import AST.Expression.General (Expr'(..), PortImpl(..))
import qualified AST.Expression.Canonical as Canonical
import qualified AST.Pattern as P
import qualified AST.Variable as V
ctors :: P.CanonicalPattern -> [String]
ctors pattern =
case pattern of
P.Var _ -> []
P.Alias _ p -> ctors p
P.Record _ -> []
P.Anything -> []
P.Literal _ -> []
P.Data (V.Canonical home name) ps ->
case home of
V.Local -> name : rest
V.BuiltIn -> rest
V.Module _ -> rest
where
rest = concatMap ctors ps
free :: String -> State (Set.Set String) ()
free x =
modify (Set.insert x)
freeIfLocal :: V.Canonical -> State (Set.Set String) ()
freeIfLocal (V.Canonical home name) =
case home of
V.Local -> free name
V.BuiltIn -> return ()
V.Module _ -> return ()
bound :: Set.Set String -> State (Set.Set String) ()
bound boundVars =
modify (\freeVars -> Set.difference freeVars boundVars)
sortDefs :: Canonical.Expr -> Canonical.Expr
sortDefs expression =
evalState (reorder expression) Set.empty
reorder :: Canonical.Expr -> State (Set.Set String) Canonical.Expr
reorder (A ann expression) =
A ann <$>
case expression of
Var var ->
do freeIfLocal var
return expression
Lambda pattern body ->
uncurry Lambda <$> bindingReorder (pattern,body)
Binop op leftExpr rightExpr ->
do freeIfLocal op
Binop op <$> reorder leftExpr <*> reorder rightExpr
Case expr cases ->
Case <$> reorder expr <*> mapM bindingReorder cases
Data name exprs ->
do free name
Data name <$> mapM reorder exprs
Literal _ ->
return expression
Range lowExpr highExpr ->
Range <$> reorder lowExpr <*> reorder highExpr
ExplicitList es ->
ExplicitList <$> mapM reorder es
App func arg ->
App <$> reorder func <*> reorder arg
MultiIf branches ->
MultiIf <$> mapM (\(cond,branch) -> (,) <$> reorder cond <*> reorder branch) branches
Access record field ->
Access <$> reorder record <*> return field
Remove record field ->
Remove <$> reorder record <*> return field
Insert record field expr ->
Insert <$> reorder record <*> return field <*> reorder expr
Modify record fields ->
Modify
<$> reorder record
<*> mapM (\(field,expr) -> (,) field <$> reorder expr) fields
Record fields ->
Record
<$> mapM (\(field,expr) -> (,) field <$> reorder expr) fields
GLShader _ _ _ ->
return expression
Port impl ->
Port <$>
case impl of
In _ _ ->
return impl
Out name expr tipe ->
(\e -> Out name e tipe) <$> reorder expr
Task name expr tipe ->
(\e -> Task name e tipe) <$> reorder expr
Let defs body ->
do body' <- reorder body
sccs <- Graph.stronglyConnComp <$> buildDefDict defs
let defss = map Graph.flattenSCC sccs
forM_ defs $ \(Canonical.Definition pattern _ _) -> do
bound (P.boundVars pattern)
mapM free (ctors pattern)
let A _ let' =
foldr (\ds bod -> A ann (Let ds bod)) body' defss
return let'
bindingReorder
:: (P.CanonicalPattern, Canonical.Expr)
-> State (Set.Set String) (P.CanonicalPattern, Canonical.Expr)
bindingReorder (pattern,expr) =
do expr' <- reorder expr
bound (P.boundVars pattern)
mapM_ free (ctors pattern)
return (pattern, expr')
reorderAndGetDependencies
:: Canonical.Def
-> State (Set.Set String) (Canonical.Def, [String])
reorderAndGetDependencies (Canonical.Definition pattern expr mType) =
do globalFrees <- get
put Set.empty
expr' <- reorder expr
localFrees <- get
modify (Set.union globalFrees)
return (Canonical.Definition pattern expr' mType, Set.toList localFrees)
buildDefDict
:: [Canonical.Def]
-> State (Set.Set String) [(Canonical.Def, Int, [Int])]
buildDefDict defs =
do pdefsDeps <- mapM reorderAndGetDependencies defs
return $ realDeps (addKey pdefsDeps)
where
addKey :: [(Canonical.Def, [String])] -> [(Canonical.Def, Int, [String])]
addKey =
zipWith (\n (pdef,deps) -> (pdef,n,deps)) [0..]
variableToKey :: (Canonical.Def, Int, [String]) -> [(String, Int)]
variableToKey (Canonical.Definition pattern _ _, key, _) =
[ (var, key) | var <- Set.toList (P.boundVars pattern) ]
variableToKeyMap :: [(Canonical.Def, Int, [String])] -> Map.Map String Int
variableToKeyMap pdefsDeps =
Map.fromList (concatMap variableToKey pdefsDeps)
realDeps :: [(Canonical.Def, Int, [String])] -> [(Canonical.Def, Int, [Int])]
realDeps pdefsDeps =
map convert pdefsDeps
where
varDict = variableToKeyMap pdefsDeps
convert (pdef, key, deps) =
(pdef, key, Maybe.mapMaybe (flip Map.lookup varDict) deps)