packages feed

apple-0.1.0.0: src/R.hs

{-# LANGUAGE RankNTypes #-}

module R ( Rs (..), HasRs (..)
         , maxLens
         , rG, rE
         ) where

import           A
import           Control.Monad.State.Strict (StateT, runState)
import           Data.Bifunctor             (second)
import           Data.Functor               (($>))
import qualified Data.IntMap                as IM
import           Lens.Micro                 (Lens')
import           Lens.Micro.Mtl             (modifying, use, (.=))
import           Nm
import           Ty.Clone
import           U

data Rs = Rs { max_ :: Int, bound :: IM.IntMap Int }

class HasRs a where
    rename :: Lens' a Rs

instance HasRs Rs where rename = id

maxLens :: Lens' Rs Int
maxLens f s = fmap (\x -> s { max_ = x }) (f (max_ s))

boundLens :: Lens' Rs (IM.IntMap Int)
boundLens f s = fmap (\x -> s { bound = x }) (f (bound s))

-- Make sure you don't have cycles in the renames map!
replaceUnique :: (Monad m, HasRs s) => U -> StateT s m U
replaceUnique u@(U i) = do
    rSt <- use (rename.boundLens)
    case IM.lookup i rSt of
        Nothing -> pure u
        Just j  -> replaceUnique (U j)

replaceVar :: (Monad m, HasRs s) => Nm a -> StateT s m (Nm a)
replaceVar (Nm n u l) = do
    u' <- replaceUnique u
    pure $ Nm n u' l

doLocal :: (HasRs s, Monad m) => StateT s m a -> StateT s m a
doLocal act = do
    preB <- use (rename.boundLens)
    act <* ((rename.boundLens) .= preB)

freshen :: (HasRs s, Monad m) => Nm a -> StateT s m (Nm a)
freshen (Nm t (U i) l) = do
    m <- use (rename.maxLens)
    let nU=m+1
    rename.maxLens .= nU
    modifying (rename.boundLens) (IM.insert i nU) $> Nm t (U nU) l

-- globally unique
rG :: Int -> E a -> (E a, Int)
rG i = second max_ . flip runState (Rs i IM.empty) . rE

{-# INLINABLE liftR #-}
liftR :: (HasRs s, Monad m) => T a -> StateT s m (T a)
liftR t = do
    i <- use (rename.maxLens)
    let (u,t',_) = cloneT i t
    (rename.maxLens .= u) $> t'

{-# INLINABLE rE #-}
rE :: (HasRs s, Monad m) => E a -> StateT s m (E a)
rE (Lam l n e) = doLocal $ do
    n' <- freshen n
    Lam l n' <$> rE e
rE (Let l (n, eϵ) e) = do
    eϵ' <- rE eϵ
    n' <- freshen n
    Let l (n', eϵ') <$> rE e
rE (Def l (n, eϵ) e) = do
    eϵ' <- rE eϵ
    n' <- freshen n
    Def l (n', eϵ') <$> rE e
rE (LLet l (n, eϵ) e) = do
    eϵ' <- rE eϵ
    n' <- freshen n
    LLet l (n', eϵ') <$> rE e
rE e@Builtin{} = pure e
rE e@FLit{} = pure e
rE e@ILit{} = pure e
rE e@BLit{} = pure e
rE (ALit l es) = ALit l <$> traverse rE es
rE (Tup l es) = Tup l <$> traverse rE es
rE (EApp l e e') = EApp l <$> rE e <*> rE e'
rE (Cond l e e' e'') = Cond l <$> rE e <*> rE e' <*> rE e''
rE (Var l n) = Var l <$> replaceVar n
rE (Ann l e t) = Ann l <$> rE e <*> liftR t
rE (Id l (AShLit is es)) = Id l . AShLit is <$> traverse rE es