module Lib.LiftLambda import Prelude import Lib.Common import Lib.CompileExp import Lib.Types import Lib.TopContext import Lib.Ref2 import Data.SortedMap import Data.SnocList import Data.IORef import Monad.State ExpMap : U ExpMap = SortedMap QName CExp liftLambdaTm : QName → SnocList (Quant × Name) → CExp → State ExpMap CExp -- CBnd liftLambdaTm name env (CFun nms t) = CFun nms <$> liftLambdaTm name (env <>< nms) t liftLambdaTm name env (CApp t u) = CApp <$> liftLambdaTm name env t <*> liftLambdaTm name env u liftLambdaTm name env (CLet nm v sc) = do v <- liftLambdaTm name env v sc <- liftLambdaTm name (env :< (Many, nm)) sc pure $ CLet nm v sc liftLambdaTm name env (CLetRec nm v sc) = do -- references should be removed by liftWhere v <- liftLambdaTm name (env :< (Zero, nm)) v sc <- liftLambdaTm name (env :< (Zero, nm)) sc pure $ CLetRec nm v sc liftLambdaTm name env tm@(CCase t alts) = do t <- liftLambdaTm name env t alts' <- traverse liftLambdaAlt alts pure $ CCase t alts' where -- This is where I wish I had put indexes on things liftLambdaAlt : CAlt → State ExpMap CAlt liftLambdaAlt (CDefAlt tm) = CDefAlt <$> liftLambdaTm name env tm liftLambdaAlt (CLitAlt l tm) = CLitAlt l <$> liftLambdaTm name env tm liftLambdaAlt (CConAlt ix nm info args tm) = CConAlt ix nm info args <$> liftLambdaTm name (env <>< map (_,_ Many) args) tm liftLambdaTm name@(QN ns nm) env tm@(CLam nm t) = do let (nms, t) = splitLam tm Lin t' <- liftLambdaTm name (env <>< nms) t let env' = env <>> nms -- TODO - maybe a better name here? qn <- getName name "lifted" modify $ updateMap qn (CFun env' t') pure $ CAppRef qn (makeApp (snoclen env)) (map fst env') where getName : QName → String → State ExpMap QName getName qn@(QN ns nm) ext = do top <- get let qn' = QN ns (nm ++ "." ++ ext) let (Just _) = lookupMap qn' top | _ => pure qn' getName qn (ext ++ "'") splitLam : CExp → SnocList (Quant × Name) → List (Quant × Name) × CExp splitLam (CLam nm t) acc = splitLam t (acc :< (Many, nm)) splitLam t acc = (acc <>> Nil, t) wrapLam : Nat → CExp → CExp wrapLam Z t = t wrapLam (S k) t = CLam "_" $ wrapLam k t makeApp : Nat → List CExp makeApp Z = Nil makeApp (S k) = CBnd (cast k) :: makeApp k liftLambdaTm name env tm = pure tm liftLambdaFn : QName × CExp → State ExpMap Unit liftLambdaFn (name, tm) = do tm' <- liftLambdaTm name Lin tm modify $ updateMap name tm' liftLambdaFn _ = pure MkUnit liftLambda : ExpMap → M ExpMap liftLambda defs = do pure $ snd $ (traverse liftLambdaFn $ toList defs).runState defs