183 lines
5.7 KiB
Haskell
183 lines
5.7 KiB
Haskell
{-# LANGUAGE LambdaCase, BlockArguments #-}
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
module TI
|
|
where
|
|
----------------------------------------------------------------------------------
|
|
import Data.Map (Map, (!?), (!))
|
|
import Data.Map qualified as M
|
|
import Data.Set (Set)
|
|
import Data.Set qualified as S
|
|
import Data.Maybe (fromJust, fromMaybe)
|
|
import Data.List (mapAccumL)
|
|
import Control.Monad (guard)
|
|
import Data.Foldable (traverse_)
|
|
import Data.Function ((&))
|
|
import Data.Pretty
|
|
import Data.Heap
|
|
import Control.DFA
|
|
import Core
|
|
----------------------------------------------------------------------------------
|
|
|
|
data TiState = TiState [Addr] Dump TiHeap [(Name, Addr)] Stats
|
|
deriving Show
|
|
|
|
type TiHeap = Heap Node
|
|
|
|
data Node = NAp Addr Addr
|
|
| NSupercomb Name [Name] Expr
|
|
| NNum Int
|
|
deriving Show
|
|
|
|
data Dump = DumpTempDummy
|
|
deriving Show
|
|
|
|
type Stats = Int
|
|
|
|
----------------------------------------------------------------------------------
|
|
|
|
tiStatIncSteps :: Stats -> Stats
|
|
tiStatIncSteps = (+1)
|
|
|
|
tiStatGetSteps :: Stats -> Int
|
|
tiStatGetSteps = id
|
|
|
|
----------------------------------------------------------------------------------
|
|
|
|
compile :: Program -> Maybe TiState
|
|
compile prog = Just $ TiState s d h g stats
|
|
where
|
|
s = [mainAddr]
|
|
d = DumpTempDummy
|
|
(h,g) = buildInitialHeap defs
|
|
defs = prog <> corePrelude
|
|
stats = 0
|
|
|
|
mainAddr = fromJust $ lookup "main" g
|
|
|
|
buildInitialHeap :: Program -> (TiHeap, [(Name, Addr)])
|
|
buildInitialHeap (Program scdefs) = mapAccumL allocateSc mempty scdefs
|
|
where
|
|
allocateSc :: TiHeap -> ScDef -> (TiHeap, (Name, Addr))
|
|
allocateSc h (ScDef n a b) = (h', (n, addr))
|
|
where
|
|
(h', addr) = alloc h (NSupercomb n a b)
|
|
|
|
getArgs :: TiHeap -> [Addr] -> [Addr]
|
|
getArgs h (sc:s) = fmap f s
|
|
where
|
|
f addr = case hLookup addr h of
|
|
Just (NAp _ arg) -> arg
|
|
_ -> error "glados yuri"
|
|
|
|
instantiate :: Expr -> TiHeap -> [(Name, Addr)] -> (TiHeap, Addr)
|
|
instantiate (App f x) h g = alloc h'' (NAp f' x')
|
|
where
|
|
(h', f') = instantiate f h g
|
|
(h'', x') = instantiate x h' g
|
|
instantiate (Var k) h g =
|
|
(h, fromMaybe (error $ "variable `" <> k <> "' not in scope") v)
|
|
where v = lookup k g
|
|
instantiate (Case _ _) _ _ = error "cannot instantiate case expressions"
|
|
|
|
instantiate (Let NonRec bs e) h g = instantiate e h' (g' ++ g)
|
|
where
|
|
-- :t mapAccumL @[] @TiHeap @(Name, Expr) @(Name,Addr)
|
|
-- :: (TiHeap -> (Name, Expr) -> (TiHeap, (Name, Addr)))
|
|
-- -> TiHeap -> [(Name, Expr)] -> (TiHeap, [(Name, Addr)])
|
|
(h', g') = mapAccumL instBinder h bs
|
|
instBinder :: TiHeap -> Binding -> (TiHeap, (Name, Addr))
|
|
instBinder h (k := v) =
|
|
let (h',a) = instantiate v h g
|
|
in (h',(k,a))
|
|
|
|
instantiate (Let Rec bs e) h g = instantiate e h' env
|
|
where
|
|
env = g' ++ g
|
|
(h', g') = mapAccumL instBinder h bs
|
|
instBinder :: TiHeap -> Binding -> (TiHeap, (Name, Addr))
|
|
instBinder h (k := v) =
|
|
let (h',a) = instantiate v h env
|
|
in (h',(k,a))
|
|
|
|
instantiate (Prim (IntP n)) h _ = alloc h (NNum n)
|
|
|
|
instantiate _ _ _ = error "unimplemented"
|
|
|
|
----------------------------------------------------------------------------------
|
|
|
|
eval :: TiState -> [TiState]
|
|
eval st = st : sts
|
|
where
|
|
sts | isFinal st = []
|
|
| otherwise = eval next
|
|
next = doAdmin (step st)
|
|
|
|
step :: TiState -> TiState
|
|
step st =
|
|
let TiState (top:_) _ h _ _ = st
|
|
in case fromMaybe (error "segfault!") (hLookup top h) of
|
|
NNum n -> numStep n st
|
|
NAp f x -> apStep f x st
|
|
NSupercomb n as b -> ncStep n as b st
|
|
|
|
where
|
|
numStep :: Int -> TiState -> TiState
|
|
numStep _ _ = error "number applied as function..."
|
|
|
|
apStep :: Addr -> Addr -> TiState -> TiState
|
|
apStep f _ (TiState s d h g sts) =
|
|
TiState (f:s) d h g sts
|
|
|
|
ncStep :: Name -> [Name] -> Expr -> TiState -> TiState
|
|
ncStep n as b (TiState s d h g sts) =
|
|
TiState s' d h' g sts
|
|
where
|
|
s' = resAddr : drop (length as + 1) s
|
|
(h', resAddr) = instantiate b h env
|
|
env = argBinds ++ g
|
|
argBinds = as `zip` getArgs h s
|
|
|
|
isFinal :: TiState -> Bool
|
|
isFinal (TiState [addr] _ h _ _) =
|
|
case hLookup addr h of
|
|
Just a -> isDataNode a
|
|
_ -> error "isFinal: segfault!"
|
|
isFinal (TiState [] _ _ _ _) = error "empty stack..."
|
|
isFinal _ = False
|
|
|
|
isDataNode :: Node -> Bool
|
|
isDataNode (NNum _) = True
|
|
isDataNode _ = False
|
|
|
|
doAdmin :: TiState -> TiState
|
|
doAdmin (TiState s d h g sts) = TiState s d h g (sts+1)
|
|
|
|
dbgProg :: Program -> IO ()
|
|
dbgProg p = prettyPrint `traverse_` eval (fromJust $ compile p)
|
|
|
|
letrecExample :: Program
|
|
letrecExample = Program
|
|
-- [ ScDef "main" [] $ Prim IntAddP :$ Prim (IntP 2) :$ Prim (IntP 3)
|
|
[ ScDef "pair" ["x","y","f"] $ "f" :$ "x" :$ "y"
|
|
, ScDef "fst" ["p"] $ "p" :$ "K"
|
|
, ScDef "snd" ["p"] $ "p" :$ "K1"
|
|
, ScDef "f" ["x","y"] $
|
|
Let Rec
|
|
[ "a" := "pair" :$ "x" :$ "b"
|
|
, "b" := "pair" :$ "y" :$ "a"
|
|
]
|
|
("fst" :$ ("snd" :$ ("snd" :$ ("snd" :$ "a"))))
|
|
, ScDef "main" [] $ "f" :$ Prim (IntP 3) :$ Prim (IntP 4)
|
|
]
|
|
|
|
instance Pretty TiState where
|
|
prettyPrec (TiState s d h g sts) _ =
|
|
"==== TiState Stack ====" <> IBreak
|
|
<> mconcat (fmap ((<>IBreak) . showAddr) s)
|
|
where
|
|
showAddr a = IStr (show a) <> ": " <> precPretty 0 (hLookup a h)
|
|
|
|
instance Pretty Node where
|
|
prettyPrec a _ = IStr $ show a
|
|
|