packages feed

apple-0.1.0.0: src/R/Dfn.hs

{-# LANGUAGE OverloadedStrings #-}

module R.Dfn ( dedfn ) where

import           A
import           Control.Monad.State.Strict (get, modify)
import qualified Data.Text                  as T
import           Nm
import           R.M
import           U

dummyName :: T.Text -> RM (a -> Nm a)
dummyName n = do
    st <- get
    Nm n (U$st+1) <$ modify (+1)

dedfn :: Int -> E a -> (E a, Int)
dedfn i = runR i . dedfnM

-- bottom-up
dedfnM :: E a -> RM (E a)
dedfnM e@ILit{} = pure e
dedfnM e@FLit{} = pure e
dedfnM e@BLit{} = pure e
dedfnM e@Var{} = pure e
dedfnM e@Builtin{} = pure e
dedfnM e@ResVar{} = pure e
dedfnM (Ann l e t) = Ann l <$> dedfnM e <*> pure t
dedfnM (ALit l es) = ALit l <$> traverse dedfnM es
dedfnM (Tup l es) = Tup l <$> traverse dedfnM es
dedfnM (EApp l e e') = EApp l <$> dedfnM e <*> dedfnM e'
dedfnM (Cond l e e' e'') = Cond l <$> dedfnM e <*> dedfnM e' <*> dedfnM e''
dedfnM (Lam l n e) = Lam l n <$> dedfnM e
dedfnM (Let l (n, e) eBody) = do
    e' <- dedfnM e
    Let l (n, e') <$> dedfnM eBody
dedfnM (Def l (n, e) eBody) = do
    e' <- dedfnM e
    Def l (n, e') <$> dedfnM eBody
dedfnM (LLet l (n, e) eBody) = do
    e' <- dedfnM e
    LLet l (n, e') <$> dedfnM eBody
dedfnM (Dfn l e) = do
    e' <- dedfnM e
    x <- dummyName "x" -- TODO: do we need uniques? could rename it later
    y <- dummyName "y"
    let (eDone, hasY) = replaceXY x y e'
    pure $ if hasY
        then Lam l (x l) (Lam l (y l) eDone)
        else Lam l (x l) eDone
dedfnM (Parens _ e) = dedfnM e

-- this approach is criminally inefficient
replaceXY :: (a -> Nm a) -- ^ x
          -> (a -> Nm a) -- ^ y
          -> E a -> (E a, Bool) -- True if it has 'y'
replaceXY _ y (ResVar l Y) = (Var l (y l), True)
replaceXY x _ (ResVar l X) = (Var l (x l), False)
replaceXY _ _ e@FLit{} = (e, False)
replaceXY _ _ e@ILit{} = (e, False)
replaceXY _ _ e@BLit{} = (e, False)
replaceXY _ _ e@Var{} = (e, False)
replaceXY _ _ e@Builtin{} = (e, False)
replaceXY x y (Ann l e t) =
    let (e', b) = replaceXY x y e
        in (Ann l e' t, b)
replaceXY x y (Lam l n e) =
    let (e', b) = replaceXY x y e
        in (Lam l n e', b)
replaceXY x y (EApp l e e') =
    let (eR, b) = replaceXY x y e
        (eR', b') = replaceXY x y e'
        in (EApp l eR eR', b || b')
replaceXY x y (Cond l p e e') =
    let (pR, b0) = replaceXY x y p
        (eR, b1) = replaceXY x y e
        (eR', b2) = replaceXY x y e'
    in (Cond l pR eR eR', b0 || b1 || b2)
replaceXY x y (Let l (n, e) e') =
    let (eR, b) = replaceXY x y e
        (eR', b') = replaceXY x y e'
        in (Let l (n, eR) eR', b || b')
replaceXY x y (LLet l (n, e) e') =
    let (eR, b) = replaceXY x y e
        (eR', b') = replaceXY x y e'
        in (LLet l (n, eR) eR', b || b')
replaceXY x y (Def l (n, e) e') =
    let (eR, b) = replaceXY x y e
        (eR', b') = replaceXY x y e'
        in (Def l (n, eR) eR', b || b')
replaceXY x y (ALit l es) =
    let (esR, bs) = unzip (fmap (replaceXY x y) es)
    in (ALit l esR, or bs)
replaceXY x y (Tup l es) =
    let (esR, bs) = unzip (fmap (replaceXY x y) es)
    in (Tup l esR, or bs)