{-# LANGUAGE ConstraintKinds #-} -- | Facilities for changing the lore of some fragment, with no -- context. We call this "rephrasing", for no deep reason. module Futhark.Analysis.Rephrase ( rephraseProg, rephraseFunDef, rephraseExp, rephraseBody, rephraseStm, rephraseLambda, rephrasePattern, rephrasePatElem, Rephraser (..), ) where import Futhark.IR -- | A collection of functions that together allow us to rephrase some -- IR fragment, in some monad @m@. If we let @m@ be the 'Maybe' -- monad, we can conveniently do rephrasing that might fail. This is -- useful if you want to see if some IR in e.g. the @Kernels@ lore -- actually uses any @Kernels@-specific operations. data Rephraser m from to = Rephraser { rephraseExpLore :: ExpDec from -> m (ExpDec to), rephraseLetBoundLore :: LetDec from -> m (LetDec to), rephraseFParamLore :: FParamInfo from -> m (FParamInfo to), rephraseLParamLore :: LParamInfo from -> m (LParamInfo to), rephraseBodyLore :: BodyDec from -> m (BodyDec to), rephraseRetType :: RetType from -> m (RetType to), rephraseBranchType :: BranchType from -> m (BranchType to), rephraseOp :: Op from -> m (Op to) } -- | Rephrase an entire program. rephraseProg :: Monad m => Rephraser m from to -> Prog from -> m (Prog to) rephraseProg rephraser (Prog consts funs) = Prog <$> mapM (rephraseStm rephraser) consts <*> mapM (rephraseFunDef rephraser) funs -- | Rephrase a function definition. rephraseFunDef :: Monad m => Rephraser m from to -> FunDef from -> m (FunDef to) rephraseFunDef rephraser fundec = do body' <- rephraseBody rephraser $ funDefBody fundec params' <- mapM (rephraseParam $ rephraseFParamLore rephraser) $ funDefParams fundec rettype' <- mapM (rephraseRetType rephraser) $ funDefRetType fundec return fundec {funDefBody = body', funDefParams = params', funDefRetType = rettype'} -- | Rephrase an expression. rephraseExp :: Monad m => Rephraser m from to -> Exp from -> m (Exp to) rephraseExp = mapExpM . mapper -- | Rephrase a statement. rephraseStm :: Monad m => Rephraser m from to -> Stm from -> m (Stm to) rephraseStm rephraser (Let pat (StmAux cs attrs dec) e) = Let <$> rephrasePattern (rephraseLetBoundLore rephraser) pat <*> (StmAux cs attrs <$> rephraseExpLore rephraser dec) <*> rephraseExp rephraser e -- | Rephrase a pattern. rephrasePattern :: Monad m => (from -> m to) -> PatternT from -> m (PatternT to) rephrasePattern = traverse -- | Rephrase a pattern element. rephrasePatElem :: Monad m => (from -> m to) -> PatElemT from -> m (PatElemT to) rephrasePatElem rephraser (PatElem ident from) = PatElem ident <$> rephraser from -- | Rephrase a parameter. rephraseParam :: Monad m => (from -> m to) -> Param from -> m (Param to) rephraseParam rephraser (Param name from) = Param name <$> rephraser from -- | Rephrase a body. rephraseBody :: Monad m => Rephraser m from to -> Body from -> m (Body to) rephraseBody rephraser (Body lore bnds res) = Body <$> rephraseBodyLore rephraser lore <*> (stmsFromList <$> mapM (rephraseStm rephraser) (stmsToList bnds)) <*> pure res -- | Rephrase a lambda. rephraseLambda :: Monad m => Rephraser m from to -> Lambda from -> m (Lambda to) rephraseLambda rephraser lam = do body' <- rephraseBody rephraser $ lambdaBody lam params' <- mapM (rephraseParam $ rephraseLParamLore rephraser) $ lambdaParams lam return lam {lambdaBody = body', lambdaParams = params'} mapper :: Monad m => Rephraser m from to -> Mapper from to m mapper rephraser = identityMapper { mapOnBody = const $ rephraseBody rephraser, mapOnRetType = rephraseRetType rephraser, mapOnBranchType = rephraseBranchType rephraser, mapOnFParam = rephraseParam (rephraseFParamLore rephraser), mapOnLParam = rephraseParam (rephraseLParamLore rephraser), mapOnOp = rephraseOp rephraser }