module AbsCF where
import Data.Map (empty, unions, fromList, toList, (!))
import Control.Monad.State
import Control.Applicative ((<$>))
import Data.Set (Set)
import qualified Data.Set as S
import CPSScheme
import Common
type Closure c = (Lambda, BEnv c)
class (Show c, Eq c, Ord c) => Contour c where
initial :: c
nb :: c -> Label -> c
newtype CFA0 = CFA0 ()
deriving (Show, Eq, Ord)
instance Contour CFA0 where
initial = CFA0 ()
nb _ _ = CFA0 ()
newtype CFA1 = CFA1 Label
deriving (Show, Eq, Ord)
instance Contour CFA1 where
initial = CFA1 (1)
nb _ l = CFA1 l
type BEnv c = Label :⇀ c
type VEnv c = Var :× c :⇀ D c
data Proc c = PC (Closure c)
| PP Prim
| Stop
deriving (Show, Eq, Ord)
type D c = [Proc c]
type CCtxt c = Label :× BEnv c
type CCache c = CCtxt c :⇀ D c
type Ans c = CCache c
type FState c = (Proc c, [D c], VEnv c, c)
type CState c = (Call, BEnv c, VEnv c, c)
type Memo c = Set (Either (FState c) (CState c))
evalCPS :: Contour c => Prog -> Ans c
evalCPS lam = evalState (evalF (f, [[Stop]], ve, initial)) S.empty
where ve = empty
β = empty
[f] = evalV (L lam) β ve
evalCPS_CFA0 :: Prog -> Ans CFA0
evalCPS_CFA0 = evalCPS
evalCPS_CFA1 :: Prog -> Ans CFA1
evalCPS_CFA1 = evalCPS
evalV :: Contour c => Val -> BEnv c -> VEnv c -> D c
evalV (C _ int) β ve = []
evalV (P prim) β ve = [PP prim]
evalV (R _ var) β ve = ve ! (var, β ! binder var)
evalV (L lam) β ve = [PC (lam, β)]
evalF :: Contour c => FState c -> State (Memo c) (Ans c)
evalF args = do
seen <- gets (S.member (Left args))
if seen then return empty else do
modify (S.insert (Left args))
case args of
(PC (Lambda lab vs c, β), as, ve, b)
-> if (length as /= length vs)
then error $ "Wrong number of arguments to lambda expression " ++ show lab
else evalC (c,β',ve',b)
where β' = β `upd` [lab ↦ b]
ve' = ve `upd` zipWith (\v a -> (v,b) ↦ a) vs as
(PP (Plus c), [_, _, conts], ve, b)
-> unionsM [ evalF (cont,[[]],ve,b') | cont <- conts ] `upd'` [ (c, β) ↦ conts ]
where b' = nb b c
β = empty `upd` [ c ↦ b ]
(PP (If ct cf), [_, contt, contf], ve, b)
-> unionsM (
[ evalF (cont,[],ve,bt') | cont <- contt ] ++
[ evalF (cont,[],ve,bf') | cont <- contf ] )
`upd'` [ (ct, βt) ↦ contt, (cf, βf) ↦ contf ]
where bt' = nb b ct
bf' = nb b cf
βt = empty `upd` [ ct ↦ b ]
βf = empty `upd` [ cf ↦ b ]
(Stop,[_],_,_) -> return empty
(Stop,_,_,_) -> error $ "Stop called with wrong number or types of arguments"
(PP prim,_,_,_) -> error $ "Primop " ++ show prim ++ " called with wrong arguments"
evalC :: Contour c => CState c -> State (Memo c) (Ans c)
evalC args = do
seen <- gets (S.member (Right args))
if seen then return empty else do
modify (S.insert (Right args))
case args of
(App lab f vs, β, ve, b)
-> unionsM [evalF (f',as,ve,b') | f' <- fs ] `upd'` [ (lab,β) ↦ fs ]
where fs = evalV f β ve
as = map (\v -> evalV v β ve) vs
b' = nb b lab
(Let lab ls c', β, ve, b)
-> evalC (c',β',ve',b')
where b' = nb b lab
β' = β `upd` [lab ↦ b']
ve' = ve `upd` [(v,b') ↦ evalV (L l) β' ve | (v,l) <- ls]
graphToEdgelist :: Show c => Ans c -> [Label :× Label]
graphToEdgelist = concat . map go . toList
where go ((l,_),ds) = concat $ map go' ds
where go' Stop = []
go' (PP (Plus l')) = [(l,l')]
go' (PP (If l' _)) = [(l,l')]
go' (PC (Lambda l' _ _ , _)) = [(l,l')]