packages feed

apple-0.1.0.0: src/I.hs

module I ( inline
         , β
         ) where

import           A
import           Control.Monad.State.Strict (State, gets, modify, runState)
import           Data.Bifunctor             (second)
import qualified Data.IntMap                as IM
import           Nm
import           Nm.IntMap
import           R
import           Ty
import           U

data ISt a = ISt { renames :: !Rs
                 , binds   :: IM.IntMap (E a)
                 }

instance HasRs (ISt a) where
    rename f s = fmap (\x -> s { renames = x }) (f (renames s))

type M a = State (ISt a)

bind :: Nm a -> E a -> ISt a -> ISt a
bind n e (ISt r bs) = ISt r (insert n e bs)

runI i = second (max_.renames) . flip runState (ISt (Rs i mempty) mempty)

inline :: Int -> E (T ()) -> (E (T ()), Int)
inline i = runI i.iM

β :: Int -> E (T ()) -> (E (T ()), Int)
β i = runI i.bM

hRi :: Idiom -> Bool
hRi (AShLit _ es) = any hR es

hR :: E a -> Bool
hR (EApp _ (EApp _ (Builtin _ R) _) _) = True
hR Builtin{}                           = False
hR FLit{}                              = False
hR ILit{}                              = False
hR BLit{}                              = False
hR (ALit _ es)                         = any hR es
hR (Tup _ es)                          = any hR es
hR (Cond _ p e e')                     = hR p||hR e||hR e'
hR (EApp _ e e')                       = hR e||hR e'
hR (Lam _ _ e)                         = hR e
hR (Let _ (_, e') e)                   = hR e'||hR e
hR (Def _ (_, e') e)                   = hR e'||hR e
hR (LLet _ (_, e') e)                  = hR e'||hR e
hR Var{}                               = False
hR (Id _ i)                            = hRi i

-- assumes globally renamed already
-- | Inlining is easy because we don't have recursion
iM :: E (T ()) -> M (T ()) (E (T ()))
iM e@Builtin{} = pure e
iM e@FLit{} = pure e
iM e@ILit{} = pure e
iM e@BLit{} = pure e
iM (ALit l es) = ALit l <$> traverse iM es
iM (Tup l es) = Tup l <$> traverse iM es
iM (Cond l p e0 e1) = Cond l <$> iM p <*> iM e0 <*> iM e1
iM (EApp l e0 e1) = EApp l <$> iM e0 <*> iM e1
iM (Lam l n e) = Lam l n <$> iM e
iM (LLet l (n, e') e) = do
    e'I <- iM e'
    eI <- iM e
    pure $ LLet l (n, e'I) eI
iM (Let l (n, e') e) | not(hR e')= do
    eI <- iM e'
    modify (bind n eI) *> iM e
                     | otherwise = iM(LLet l (n,e') e)
iM (Def _ (n, e') e) = do
    eI <- iM e'
    modify (bind n eI) *> iM e
iM e@(Var t (Nm _ (U i) _)) = do
    st <- gets binds
    case IM.lookup i st of
        Just e' -> do {er <- rE e'; pure $ fmap (rwArr.aT (match (eAnn er) t)) er}
        Nothing -> pure e

-- beta reduction
bM :: E (T ()) -> M (T ()) (E (T ()))
bM e@Builtin{} = pure e
bM e@FLit{} = pure e
bM e@ILit{} = pure e
bM e@BLit{} = pure e
bM (ALit l es) = ALit l <$> traverse bM es
bM (Tup l es) = Tup l <$> traverse bM es
bM (Cond l p e0 e1) = Cond l <$> bM p <*> bM e0 <*> bM e1
bM (EApp l (Lam _ n e') e) | not(hR e) = do
    eI <- bM e
    modify (bind n eI) *> bM e'
                           | otherwise = do
    eI <- bM e
    LLet l (n, eI) <$> bM e'
bM (EApp l e0 e1) = do
    e0' <- bM e0
    e1' <- bM e1
    case e0' of
        Lam{} -> bM (EApp l e0' e1')
        _     -> pure $ EApp l e0' e1'
bM (Lam l n e) = Lam l n <$> bM e
bM e@(Var _ (Nm _ (U i) _)) = do
    st <- gets binds
    case IM.lookup i st of
        -- TODO: track if looked up once before (avoid spurious clones?)
        Just e' -> rE e' -- rE vs. match ... t?
        Nothing -> pure e
bM (LLet l (n, e') e) = do
    e'B <- bM e'
    eB <- bM e
    pure $ LLet l (n, e'B) eB
bM (Id l idm) = Id l <$> bid idm

bid :: Idiom -> M (T ()) Idiom
bid (FoldSOfZip seed op es) = FoldSOfZip <$> bM seed <*> bM op <*> traverse bM es
bid (FoldOfZip zop op es)   = FoldOfZip <$> bM zop <*> bM op <*> traverse bM es
bid (AShLit ds es)          = AShLit ds <$> traverse bM es
bid (FoldGen seed f g n)    = FoldGen <$> bM seed <*> bM f <*> bM g <*> bM n