optimusprime-0.0.1.20091114: Optimus/Util.hs
module Optimus.Util where
import Flite.Fresh
import Flite.Syntax
import Flite.Traversals hiding (freshen)
import Optimus.Uniplate
import Flite.Let
import Flite.Matching
import Data.Char
import Data.List
import Control.Monad
import Data.Generics.Uniplate
import qualified Data.Map as Map
import Data.Maybe
primitives = ["(+)", "(-)", "(==)", "(/=)", "(<=)", "emit", "emitInt"]
freshen :: Exp -> Id -> Fresh Exp
freshen e v = fresh >>= return . fix e . Var
where
fix (Case x as) w = Case x [ if (Var v `elem` universe p) then (subst w v p, subst w v y) else (p, y) | (p, y) <- as]
fix (Let bs x) w@(Var w_) | v `elem` map fst bs = Let [ (if v == v_ then w_ else v_, subst w v y) | (v_, y) <- bs ] (subst w v x)
| otherwise = Let bs x
fix _ _ = error "Not designed to freshen this."
freshenMany :: Exp -> [Id] -> Fresh Exp
freshenMany = foldM freshen
freshenDescend :: Exp -> Id -> Fresh Exp
freshenDescend e@(Case _ _) v = freshen e v >>= descendM (flip freshenDescend v)
freshenDescend e@(Let _ _) v = freshen e v >>= descendM (flip freshenDescend v)
freshenDescend e v = descendM (flip freshenDescend v) e
freshenMD :: Exp -> [Id] -> Fresh Exp
freshenMD = foldM freshenDescend
autoFresh :: Fresh a -> a
autoFresh x = snd $ runFresh x "v" 0
freshProg :: (Prog -> Fresh Prog) -> Prog -> Prog
freshProg f x = snd $ runFresh (f x) "v" $ (+) 1 $ maximum $ -1 : [ read rest | 'v':rest <- allNames x, (not . null) rest, all isDigit rest ]
allNames :: Prog -> [Id]
allNames p = nub $ concat [ [f] ++ concatMap patVars a ++ allnames r | Func f a r <- p ]
where
allnames (Var v) = [v]
allnames (Fun f) = [f]
allnames e@(Case _ as) = concatMap (patVars . fst) as ++ extract allnames e
allnames e@(Let bs _) = map fst bs ++ extract allnames e
allnames e = extract allnames e
-- allNames p = concat [ [f] ++ (concatMap patVars a) ++ [ v | Var v <- universe r ] ++ (concat [ patVars p | Case _ as <- universe r, (p, _) <- as ]) | Func f a r <- p ]
alphaExp :: Exp -> Fresh Exp
alphaExp e = (alpha . Func "NOVAR" []) e >>= return . funcRhs
autoAlphaExp :: Exp -> Exp
autoAlphaExp e = snd $ runFresh (alphaExp e) "v" $ (+) 1 $ maximum $ -1 : [ read rest | 'v':rest <- freeVars e, (not . null) rest, all isDigit rest ]
insertMany :: Ord k => Map.Map k a -> [(k, a)] -> Map.Map k a
insertMany = foldr (uncurry Map.insert)
alpha :: Decl -> Fresh Decl
alpha (Func i a r) = alphaM
where
alphaM = do
l <- assocFresh ([ v | Var v <- concatMap universe a ] ++ [i]) >>= return . Map.fromList
r' <- freshSubst l r
a' <- mapM (freshSubst l) a
return $ Func (fromJust $ Map.lookup i l) a' r'
assocFresh :: [Id] -> Fresh [(Id, Id)]
assocFresh = mapM (\v -> fresh >>= \v' -> return (v, v'))
freshSubst :: Map.Map Id Id -> Exp -> Fresh Exp
freshSubst l (Var v) | isJust v' = return . Var . fromJust $ v'
| otherwise = return . Var $ v
where
v' = Map.lookup v l
freshSubst l (Let bs x) = let (vs, ys) = unzip bs in do
m <- assocFresh vs
descendM (freshSubst $ insertMany l m) (Let (zip (map snd m) ys) x)
freshSubst l (Case x as) = do
x' <- freshSubst l x
as' <- sequence [ assocFresh [v | Var v <- universe p] >>= \m -> let fS' = freshSubst $ insertMany l m in liftM2 (,) (fS' p) (fS' y) | (p, y) <- as]
return (Case x' as')
freshSubst l e = descendM (freshSubst l) e
desugar :: Prog -> Fresh Prog
desugar p = return p >>= desugarCase >>= desugarEqn >>= inlineLinearLet >>= inlineSimpleLet
funcReuse :: Prog -> Prog
funcReuse p = if null reused then p else error $ "Reused the name of a function as a local variable. " ++ show reused
where
reused = funcs p `intersect` (nub . concatMap (\d -> (concatMap patVars . funcArgs) d ++ (boundVars . funcRhs) d) $ p)
byFuncName :: Prog -> Map.Map Id Decl
byFuncName [] = Map.empty
byFuncName (d@(Func f _ _):ds) = Map.insert f d (byFuncName ds)
boundVars :: Exp -> [Id]
boundVars = nub . bv
where
bv e@(Case _ as) = concatMap (patVars . fst) as ++ extract bv e
bv e@(Let bs _) = map fst bs ++ extract bv e
bv e = extract bv e