This commit is contained in:
@@ -38,4 +38,4 @@ close = transformM \case
|
|||||||
e -> pure e
|
e -> pure e
|
||||||
|
|
||||||
closeProgram :: GenSym :> es => Program -> Eff es Program
|
closeProgram :: GenSym :> es => Program -> Eff es Program
|
||||||
closeProgram = traverseOf #body close
|
closeProgram = traverseOf (#body . #body) close
|
||||||
|
|||||||
@@ -109,8 +109,11 @@ convertLambda bs m = do
|
|||||||
pure [cps|(λ (##{bs} #{ktail}) #{m'})|]
|
pure [cps|(λ (##{bs} #{ktail}) #{m'})|]
|
||||||
|
|
||||||
convertProgram :: forall es. (GenSym :> es) => Scm.Program -> Eff es Program
|
convertProgram :: forall es. (GenSym :> es) => Scm.Program -> Eff es Program
|
||||||
convertProgram p =
|
convertProgram p = do
|
||||||
MkProgram <$> telescope (convert @es) (p ^.. each . _Left) (pure . Halt)
|
ktail <- gensym' "start-ktail"
|
||||||
|
m <- telescope (convert @es) (p ^.. each . _Left)
|
||||||
|
(pure . ExpContinue (ValVar ktail))
|
||||||
|
pure . MkProgram $ MkLambda [] ktail m
|
||||||
|
|
||||||
convertExp :: forall es. (GenSym :> es) => Scm.Exp -> Eff es Exp
|
convertExp :: forall es. (GenSym :> es) => Scm.Exp -> Eff es Exp
|
||||||
convertExp e = convert e (pure . Halt1)
|
convertExp e = convert e (pure . Halt1)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
module Gyehoek.CPS.Eval
|
module Gyehoek.CPS.Eval
|
||||||
( evalProgram
|
( evalProgram
|
||||||
, module Gyehoek.CPS.Syntax
|
, module Gyehoek.CPS.Syntax
|
||||||
|
, evalExp
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Gyehoek.CPS.Syntax
|
import Gyehoek.CPS.Syntax
|
||||||
@@ -22,7 +23,7 @@ eval :: Env -> Exp -> List Obj
|
|||||||
|
|
||||||
eval g (Halt xs) = evalVal g <$> xs
|
eval g (Halt xs) = evalVal g <$> xs
|
||||||
|
|
||||||
eval g (ExpContinue k xs) =
|
eval g (ExpContinue ((^?! #ValVar) -> k) xs) =
|
||||||
case g ^. #labels . at k of
|
case g ^. #labels . at k of
|
||||||
Just (h, AbsKappa' bs m) -> eval h' m
|
Just (h, AbsKappa' bs m) -> eval h' m
|
||||||
where h' = h & #vars <>~ envOfBinds bs (evalVal g <$> xs)
|
where h' = h & #vars <>~ envOfBinds bs (evalVal g <$> xs)
|
||||||
@@ -75,5 +76,11 @@ emptyEnv = MkEnv
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evalExp :: Exp -> List Obj
|
||||||
|
evalExp = eval emptyEnv
|
||||||
|
|
||||||
evalProgram :: Program -> List Obj
|
evalProgram :: Program -> List Obj
|
||||||
evalProgram (MkProgram e) = eval emptyEnv e
|
evalProgram (MkProgram lam) = eval emptyEnv [cps|
|
||||||
|
(letrec ((start #{lam}))
|
||||||
|
(apply start halt))
|
||||||
|
|]
|
||||||
|
|||||||
+53
-56
@@ -1,7 +1,6 @@
|
|||||||
{-# LANGUAGE OverloadedLists #-}
|
{-# LANGUAGE OverloadedLists #-}
|
||||||
module Gyehoek.CPS.Stackify
|
module Gyehoek.CPS.Stackify
|
||||||
( stackifyExp
|
( stackifyProgram
|
||||||
, stackifyProgram
|
|
||||||
, module Gyehoek.CPS.Syntax
|
, module Gyehoek.CPS.Syntax
|
||||||
) where
|
) where
|
||||||
|
|
||||||
@@ -13,8 +12,11 @@ import Gyehoek.GenSym
|
|||||||
import Effectful.Writer.Static.Shared
|
import Effectful.Writer.Static.Shared
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
import qualified Data.HashMap.Strict as H
|
import qualified Data.HashMap.Strict as H
|
||||||
import Data.List (elemIndex)
|
import Data.List (elemIndex, nub)
|
||||||
|
import Data.Text qualified as T
|
||||||
import Gyehoek.Prelude
|
import Gyehoek.Prelude
|
||||||
|
import Debug.Pretty.Simple
|
||||||
|
import qualified Gyehoek.Sexp as S
|
||||||
|
|
||||||
|
|
||||||
type Stackify = Writer Stk.Program
|
type Stackify = Writer Stk.Program
|
||||||
@@ -23,9 +25,10 @@ runStackify :: Eff (Stackify : es) a -> Eff es (a, Stk.Program)
|
|||||||
runStackify = runWriter
|
runStackify = runWriter
|
||||||
|
|
||||||
live :: Free a => Env -> a -> List Name
|
live :: Free a => Env -> a -> List Name
|
||||||
live g e = free' e & filter \x ->
|
-- TODO: free' should return an OSet lol
|
||||||
|
live g e = nub (free' e) & filter \x ->
|
||||||
x `H.member` g.bound
|
x `H.member` g.bound
|
||||||
&& not (x `elem` g.contStack)
|
-- && not (x `elem` g.contStack)
|
||||||
|
|
||||||
data BlockBuilder
|
data BlockBuilder
|
||||||
= Code (List Stk.Instr) BlockBuilder
|
= Code (List Stk.Instr) BlockBuilder
|
||||||
@@ -47,20 +50,18 @@ stackify
|
|||||||
stackify g (ExpLetRec [(f, kap@(AbsKappa' xs m))] e) = do
|
stackify g (ExpLetRec [(f, kap@(AbsKappa' xs m))] e) = do
|
||||||
let vs = (f, Stk.ValLabel f) : (bindReg <$> xs)
|
let vs = (f, Stk.ValLabel f) : (bindReg <$> xs)
|
||||||
let ls = live g kap
|
let ls = live g kap
|
||||||
m' <- stackify (g & #bound .~ H.fromList (vs ++ (bindReg <$> ls))) m
|
m' <- stackify (g & #bound <>~ H.fromList (vs ++ (bindReg <$> ls))) m
|
||||||
emitRoutine $
|
emitRoutine $
|
||||||
Stk.MkRoutine f xs . buildBlock $
|
Stk.MkRoutine f xs . buildBlock $
|
||||||
Code [Stk.Pop x | x <- ls] m'
|
-- pop in the opposite order we push
|
||||||
|
Code [Stk.Pop x | x <- reverse ls] m'
|
||||||
let g' = g & #bound . at f ?~ Stk.ValLabel f
|
let g' = g & #bound . at f ?~ Stk.ValLabel f
|
||||||
& #liveness . at f ?~ ls
|
& #liveness . at f ?~ ls
|
||||||
stackify g' e
|
stackify g' e
|
||||||
|
|
||||||
stackify g (ExpLetRec [(f, AbsLambda' xs k m)] e) = do
|
stackify g (ExpLetRec [(f, AbsLambda lam)] e) = do
|
||||||
let vs = (k:xs) <&> \x -> (x, Stk.ValReg x)
|
emitRoutine =<< stackifyLambda g f lam
|
||||||
m' <- stackify (g & #bound .~ H.fromList vs
|
stackify (g & #bound . at f ?~ Stk.ValLabel f) e
|
||||||
& #contStack %~ (k:)) m
|
|
||||||
emitRoutine $ Stk.MkRoutine f xs (buildBlock m')
|
|
||||||
stackify g e
|
|
||||||
|
|
||||||
stackify g (ExpIf c t f) = do
|
stackify g (ExpIf c t f) = do
|
||||||
let c' = stackifyVal g c
|
let c' = stackifyVal g c
|
||||||
@@ -69,36 +70,41 @@ stackify g (ExpIf c t f) = do
|
|||||||
pure . Tail $ Stk.If c' t' f'
|
pure . Tail $ Stk.If c' t' f'
|
||||||
|
|
||||||
stackify g (ExpApply f xs ktail) = pure $
|
stackify g (ExpApply f xs ktail) = pure $
|
||||||
Code [ Stk.PushCont k ] $
|
|
||||||
Code [ Stk.Push (Stk.ValReg l) | l <- ls ] $
|
Code [ Stk.Push (Stk.ValReg l) | l <- ls ] $
|
||||||
Tail (Stk.TailCall (stackifyVal g f) (stackifyVal g <$> xs))
|
Tail (Stk.TailCall (stackifyVal g f) (k : (stackifyVal g <$> xs)))
|
||||||
where
|
where
|
||||||
k = var g ktail
|
k = var g ktail
|
||||||
ls = fold $ (k ^? #ValImm . #ImmLabel)
|
ls = fold $ (k ^? #ValImm . #ImmLabel)
|
||||||
>>= \klbl -> g ^. #liveness . at klbl
|
>>= \klbl -> g ^. #liveness . at klbl
|
||||||
|
|
||||||
stackify g (ExpContinue k xs) =
|
stackify g e@(ExpContinue k xs) = do
|
||||||
-- return continuations require popping the stack. how do we know
|
pure $
|
||||||
-- when a continuation is a return continuation? is this a correct
|
Code [ Stk.Push (Stk.ValReg l) | l <- ls ] $
|
||||||
-- test?
|
Tail (Stk.TailCall k' (stackifyVal g <$> xs))
|
||||||
case elemIndex k g.contStack of
|
where
|
||||||
Nothing -> pure . Tail $ Stk.TailCall (Stk.ValLabel k) xs'
|
k' = stackifyVal g k
|
||||||
Just j -> do
|
ls = fold $ (k' ^? #ValImm . #ImmLabel)
|
||||||
ktail <- gensym' @Name $ k ^. _Wrapped'
|
>>= \klbl -> g ^. #liveness . at klbl
|
||||||
pure $
|
|
||||||
Code (replicate j $ Stk.PopCont "_") $
|
|
||||||
Code [Stk.PopCont ktail] $
|
|
||||||
Tail (Stk.TailCall (Stk.ValReg ktail) xs')
|
|
||||||
where xs' = stackifyVal g <$> xs
|
|
||||||
|
|
||||||
stackify g (ExpPrim p (MkKappa [x] e)) = do
|
stackify g (ExpPrim p (MkKappa [x] e)) = do
|
||||||
e' <- stackify (g & #bound . at x ?~ Stk.ValReg x) e
|
e' <- stackify (g & #bound . at x ?~ Stk.ValReg x) e
|
||||||
pure $
|
pure $
|
||||||
Code [ Stk.Prim x (stackifyVal g <$> p) ] $
|
Code [ Stk.Prim x (stackifyVal g <$> p) ] e'
|
||||||
e'
|
|
||||||
|
|
||||||
stackify _ e = error [i|unimplemented exp: #{e}|]
|
stackify _ e = error [i|unimplemented exp: #{e}|]
|
||||||
|
|
||||||
|
-- affine
|
||||||
|
_ValName :: Traversal' Val Name
|
||||||
|
_ValName = failing #ValVar (#ValImm . #ImmLabel)
|
||||||
|
|
||||||
|
stackifyLambda
|
||||||
|
:: (Stackify :> es, GenSym :> es)
|
||||||
|
=> Env -> Name -> Lambda -> Eff es Stk.Routine
|
||||||
|
stackifyLambda g name (MkLambda xs k m) = do
|
||||||
|
let vs = [ (x, Stk.ValReg x) | x <- k:xs ]
|
||||||
|
m' <- stackify (g & #bound <>~ H.fromList vs) m
|
||||||
|
pure $ Stk.MkRoutine name (k:xs) (buildBlock m')
|
||||||
|
|
||||||
stackifyVal :: Env -> Val -> Stk.Val
|
stackifyVal :: Env -> Val -> Stk.Val
|
||||||
stackifyVal g = \case
|
stackifyVal g = \case
|
||||||
ValImm imm -> Stk.ValImm imm
|
ValImm imm -> Stk.ValImm imm
|
||||||
@@ -121,39 +127,30 @@ data Env = MkEnv
|
|||||||
-- entry @(k,ls)@ where @ls@ is the sequence of registers @k@
|
-- entry @(k,ls)@ where @ls@ is the sequence of registers @k@
|
||||||
-- expects to find saved on the stack.
|
-- expects to find saved on the stack.
|
||||||
, liveness :: HashMap Name (List Name)
|
, liveness :: HashMap Name (List Name)
|
||||||
, contStack :: List Name
|
|
||||||
}
|
}
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic)
|
||||||
|
|
||||||
emptyEnv :: Env
|
emptyEnv :: Env
|
||||||
emptyEnv = MkEnv mempty mempty ["halt"]
|
emptyEnv = MkEnv mempty mempty
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
stackifyExp :: GenSym :> es => Name -> Exp -> Eff es Stk.Program
|
|
||||||
stackifyExp lbl e = do
|
|
||||||
(code,p) <- runStackify $ stackify emptyEnv e
|
|
||||||
pure $ p <> [ Stk.MkRoutine lbl [] (buildBlock code) ]
|
|
||||||
|
|
||||||
stackifyProgram :: GenSym :> es => Program -> Eff es Stk.Program
|
stackifyProgram :: GenSym :> es => Program -> Eff es Stk.Program
|
||||||
stackifyProgram (MkProgram e) = stackifyExp "main" e
|
stackifyProgram (MkProgram lam) = do
|
||||||
|
let g = emptyEnv
|
||||||
|
(start,p) <- runStackify $ stackifyLambda g "start" lam
|
||||||
|
pure $ p <> [ start ]
|
||||||
|
|
||||||
|
letfn :: Program
|
||||||
|
letfn = [cps|
|
||||||
fac :: Program
|
(λ (start-ktail0)
|
||||||
fac = [cps|
|
(letrec ((lambda-body1
|
||||||
(letrec ((fac (λ (n ktail)
|
(λ (x lambda-tail2)
|
||||||
(prim (zero? n)
|
(prim (* x x) (κ (r3) (continue lambda-tail2 r3))))))
|
||||||
(κ (x0)
|
(letrec ((let-body6
|
||||||
(if x0
|
(κ (square)
|
||||||
(continue ktail 1)
|
(letrec ((r4 (κ (x5) (continue start-ktail0 x5))))
|
||||||
(prim (- n 1)
|
(square 4 r4)))))
|
||||||
(κ (x1)
|
(continue let-body6 lambda-body1))))
|
||||||
(letrec ((fac-k0
|
|
||||||
(κ (x2)
|
|
||||||
(prim (* n x2)
|
|
||||||
(κ (x3)
|
|
||||||
(continue ktail x3))))))
|
|
||||||
(fac x1 fac-k0))))))))))
|
|
||||||
(fac 6 halt))
|
|
||||||
|]
|
|]
|
||||||
|
|
||||||
|
|||||||
+13
-18
@@ -121,7 +121,7 @@ data Def = DefConstant Name Exp
|
|||||||
deriving (Show, Generic, Data)
|
deriving (Show, Generic, Data)
|
||||||
|
|
||||||
data Program = MkProgram
|
data Program = MkProgram
|
||||||
{ body :: Exp
|
{ body :: Lambda
|
||||||
}
|
}
|
||||||
deriving (Show, Generic, Data)
|
deriving (Show, Generic, Data)
|
||||||
|
|
||||||
@@ -190,28 +190,23 @@ instance S.DatumIso Hob where
|
|||||||
(const . Left $ mempty)
|
(const . Left $ mempty)
|
||||||
|
|
||||||
instance S.DatumIso Lambda where
|
instance S.DatumIso Lambda where
|
||||||
datumIso = S.match
|
datumIso = S.with (lam >>>)
|
||||||
$ S.With (. lambda)
|
|
||||||
$ S.End
|
|
||||||
where
|
where
|
||||||
lambda = S.list $
|
lam :: forall t. G (Datum :- t) (Exp :- Name :- List Name :- t)
|
||||||
S.el S.lambdaKeyword
|
lam = S.lambdaLike
|
||||||
>>> S.el binders
|
S.lambdaKeyword
|
||||||
>>> S.el S.datumIso
|
binders
|
||||||
|
(S.el $ S.datumIso @Exp)
|
||||||
binders :: forall t. G (Datum :- t) (Name :- List Name :- t)
|
binders :: forall t. G (Datum :- t) (Name :- List Name :- t)
|
||||||
binders = S.list $
|
binders =
|
||||||
S.rest (S.datumIso @Name)
|
S.list (S.rest $ S.datumIso @Name)
|
||||||
>>> S.onTail (S.flipped $ IG.PartialIso
|
>>> S.flipped S.snoced
|
||||||
(\(ktail:-args:-t) -> (args ++ [ktail]) :- t)
|
>>> S.swap
|
||||||
(\(args:-t) -> case args ^? _Snoc of
|
|
||||||
Just (args',ktail) -> Right $ ktail :- args' :- t
|
|
||||||
Nothing -> Left $ S.expected "cont param")
|
|
||||||
)
|
|
||||||
|
|
||||||
instance S.DatumIso Kappa where
|
instance S.DatumIso Kappa where
|
||||||
datumIso = S.with \g ->
|
datumIso = S.with \g ->
|
||||||
S.lambdaLike S.kappaKeyword
|
S.lambdaLike S.kappaKeyword
|
||||||
(S.list $ S.rest (S.datumIso @Name))
|
(S.datumIso @(List Name))
|
||||||
(S.el $ S.datumIso @Exp)
|
(S.el $ S.datumIso @Exp)
|
||||||
>>> g
|
>>> g
|
||||||
|
|
||||||
@@ -260,7 +255,7 @@ instance S.DatumIso Exp where
|
|||||||
>>> S.el S.datumIso
|
>>> S.el S.datumIso
|
||||||
|
|
||||||
instance S.DatumIso Program where
|
instance S.DatumIso Program where
|
||||||
datumIso = S.with \prog -> S.datumIso @Exp >>> prog
|
datumIso = S.with \prog -> S.datumIso @Lambda >>> prog
|
||||||
|
|
||||||
|
|
||||||
-- quasiquoters
|
-- quasiquoters
|
||||||
|
|||||||
@@ -365,9 +365,9 @@ letLike kw name rhs e = listWithIndentation (NSpecial 1) $
|
|||||||
|
|
||||||
lambdaLike
|
lambdaLike
|
||||||
:: (forall t. G (Datum :- t) t)
|
:: (forall t. G (Datum :- t) t)
|
||||||
-> DatumGrammar a
|
-> G (Datum :- t1) (a :- t2)
|
||||||
-> G (ListContext :- a :- t) (ListContext :- t')
|
-> G (ListContext :- a :- t2) (ListContext :- t3)
|
||||||
-> G (Datum :- t) t'
|
-> G (Datum :- t1) t3
|
||||||
lambdaLike kw formals body = listWithIndentation (NSpecial 1) $
|
lambdaLike kw formals body = listWithIndentation (NSpecial 1) $
|
||||||
el (decorate SynBuiltin >>> kw)
|
el (decorate SynBuiltin >>> kw)
|
||||||
>>> el formals
|
>>> el formals
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ lowerBlock = _
|
|||||||
|
|
||||||
lowerInstr :: Instr -> Wasm.Expr
|
lowerInstr :: Instr -> Wasm.Expr
|
||||||
lowerInstr = \case
|
lowerInstr = \case
|
||||||
PopCont ktail -> [wat|
|
-- PopCont ktail -> [wat|
|
||||||
|
|
||||||
|]
|
-- |]
|
||||||
|
|
||||||
lowerProgram :: Program -> Eff es Wasm.Module
|
lowerProgram :: Program -> Eff es Wasm.Module
|
||||||
lowerProgram p = pure [watM|
|
lowerProgram p = pure [watM|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ data Block = MkBlock
|
|||||||
|
|
||||||
data Tail
|
data Tail
|
||||||
= TailCall Val (List Val)
|
= TailCall Val (List Val)
|
||||||
|
| PushCall Val Val (List Val)
|
||||||
| If Val Block Block
|
| If Val Block Block
|
||||||
deriving stock (Show, Generic, Data)
|
deriving stock (Show, Generic, Data)
|
||||||
deriving anyclass (NFData)
|
deriving anyclass (NFData)
|
||||||
@@ -67,8 +68,6 @@ data Tail
|
|||||||
data Instr
|
data Instr
|
||||||
= Pop Name
|
= Pop Name
|
||||||
| Push Val
|
| Push Val
|
||||||
| PopCont Name
|
|
||||||
| PushCont Val
|
|
||||||
| Prim Name (Prim Val)
|
| Prim Name (Prim Val)
|
||||||
deriving stock (Show, Generic, Data)
|
deriving stock (Show, Generic, Data)
|
||||||
deriving anyclass (NFData)
|
deriving anyclass (NFData)
|
||||||
@@ -91,8 +90,6 @@ instance S.DatumIso Instr where
|
|||||||
datumIso = S.match
|
datumIso = S.match
|
||||||
$ S.With (S.headTagged1 "pop!" regName >>>)
|
$ S.With (S.headTagged1 "pop!" regName >>>)
|
||||||
$ S.With (S.headTagged1 "push!" S.datumIso >>>)
|
$ S.With (S.headTagged1 "push!" S.datumIso >>>)
|
||||||
$ S.With (S.headTagged1 "pop-cont!" regName >>>)
|
|
||||||
$ S.With (S.headTagged1 "push-cont!" S.datumIso >>>)
|
|
||||||
$ S.With (S.headTagged2 "prim" regName S.datumIso >>>)
|
$ S.With (S.headTagged2 "prim" regName S.datumIso >>>)
|
||||||
$ S.End
|
$ S.End
|
||||||
where
|
where
|
||||||
@@ -108,6 +105,7 @@ instance S.DataIso Block where
|
|||||||
instance S.DatumIso Tail where
|
instance S.DatumIso Tail where
|
||||||
datumIso = S.match
|
datumIso = S.match
|
||||||
$ S.With (S.headTagged1' "tail-call" S.datumIso S.datumIso >>>)
|
$ S.With (S.headTagged1' "tail-call" S.datumIso S.datumIso >>>)
|
||||||
|
$ S.With (S.headTagged2' "push-call" S.datumIso S.datumIso S.datumIso >>>)
|
||||||
$ S.With (if_ >>>)
|
$ S.With (if_ >>>)
|
||||||
$ S.End
|
$ S.End
|
||||||
where
|
where
|
||||||
|
|||||||
+24
-10
@@ -17,7 +17,6 @@ import Gyehoek.Prelude
|
|||||||
|
|
||||||
data VM = MkVM
|
data VM = MkVM
|
||||||
{ stack :: List Obj
|
{ stack :: List Obj
|
||||||
, kstack :: List Name
|
|
||||||
, code :: List Instr
|
, code :: List Instr
|
||||||
, tail :: Tail
|
, tail :: Tail
|
||||||
, registers :: HashMap Name Obj
|
, registers :: HashMap Name Obj
|
||||||
@@ -40,8 +39,6 @@ stepI :: Env -> VM -> Instr -> VM
|
|||||||
|
|
||||||
stepI e vm (Push v) = vm & #stack %~ (evalVal e vm v :)
|
stepI e vm (Push v) = vm & #stack %~ (evalVal e vm v :)
|
||||||
|
|
||||||
stepI e vm (PushCont k) = vm & #kstack %~ (evalToLabel e vm k :)
|
|
||||||
|
|
||||||
stepI e vm (Prim r p) = case evalVal e vm <$> p of
|
stepI e vm (Prim r p) = case evalVal e vm <$> p of
|
||||||
PrimZeroP x -> case x of
|
PrimZeroP x -> case x of
|
||||||
ObjImm (ImmInt n) -> ret . ObjImm . ImmBool $ n == 0
|
ObjImm (ImmInt n) -> ret . ObjImm . ImmBool $ n == 0
|
||||||
@@ -74,11 +71,6 @@ stepI e vm (Pop r) = case vm ^. #stack of
|
|||||||
(x:xs) -> vm & #registers . at r ?~ x
|
(x:xs) -> vm & #registers . at r ?~ x
|
||||||
& #stack .~ xs
|
& #stack .~ xs
|
||||||
|
|
||||||
stepI e vm ins@(PopCont r) = case vm ^. #kstack of
|
|
||||||
[] -> error [i|empty cont stack: #{ins}|]
|
|
||||||
(x:xs) -> vm & #registers . at r ?~ ObjImm (ImmLabel x)
|
|
||||||
& #kstack .~ xs
|
|
||||||
|
|
||||||
stepI e vm ins = error [i|unimplemented instruction: #{ins}|]
|
stepI e vm ins = error [i|unimplemented instruction: #{ins}|]
|
||||||
|
|
||||||
stepT :: Env -> VM -> Tail -> VM
|
stepT :: Env -> VM -> Tail -> VM
|
||||||
@@ -95,6 +87,9 @@ stepT g vm (TailCall f xs) =
|
|||||||
Nothing -> error [i|undefined label: #{l}|]
|
Nothing -> error [i|undefined label: #{l}|]
|
||||||
Just x -> x
|
Just x -> x
|
||||||
|
|
||||||
|
stepT g vm (PushCall k f xs) =
|
||||||
|
_
|
||||||
|
|
||||||
stepT g vm (If c t f) = vm & #code .~ branch.code & #tail .~ branch.tail
|
stepT g vm (If c t f) = vm & #code .~ branch.code & #tail .~ branch.tail
|
||||||
where
|
where
|
||||||
branch = case evalVal g vm c of
|
branch = case evalVal g vm c of
|
||||||
@@ -116,9 +111,8 @@ evalVal e vm = \case
|
|||||||
initialVM :: VM
|
initialVM :: VM
|
||||||
initialVM = MkVM
|
initialVM = MkVM
|
||||||
{ stack = []
|
{ stack = []
|
||||||
, kstack = ["halt"]
|
|
||||||
, code = []
|
, code = []
|
||||||
, tail = TailCall (ValLabel "main") []
|
, tail = TailCall (ValLabel "start") [ValLabel "halt"]
|
||||||
, registers = mempty
|
, registers = mempty
|
||||||
, stdout = ""
|
, stdout = ""
|
||||||
, result = Nothing
|
, result = Nothing
|
||||||
@@ -154,3 +148,23 @@ writeObj (ObjImm im) = case im of
|
|||||||
ImmLabel l -> "#<procedure>"
|
ImmLabel l -> "#<procedure>"
|
||||||
writeObj (ObjHob h) = case h of
|
writeObj (ObjHob h) = case h of
|
||||||
HobClosure code env -> "#<procedure>"
|
HobClosure code env -> "#<procedure>"
|
||||||
|
|
||||||
|
blah = [stkP|
|
||||||
|
(define ($lambda-body0-code7 %lambda-tail1 %lambda-body0 %x)
|
||||||
|
(prim %r2 (* %x %x))
|
||||||
|
(tail-call %lambda-tail1 %r2))
|
||||||
|
|
||||||
|
(define ($r3 %x4)
|
||||||
|
(pop! %main-ktail)
|
||||||
|
(tail-call %main-ktail %x4))
|
||||||
|
|
||||||
|
(define ($main %main-ktail)
|
||||||
|
(prim %lambda-body0 (make-closure $lambda-body0-code7))
|
||||||
|
(tail-call $let-body5 %lambda-body0))
|
||||||
|
|
||||||
|
(define ($let-body5 %square)
|
||||||
|
(pop! %main-ktail)
|
||||||
|
(prim %code6 (env-code %square))
|
||||||
|
(push! %main-ktail)
|
||||||
|
(tail-call %code6 $r3 %square 4))
|
||||||
|
|]
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ test_cpsInterpreter = testGroup "cps interpreter" $
|
|||||||
|]
|
|]
|
||||||
]
|
]
|
||||||
|
|
||||||
evalsTo :: HasCallStack => List Obj -> Sut.Program -> Assertion
|
evalsTo :: HasCallStack => List Obj -> Sut.Exp -> Assertion
|
||||||
evalsTo rs p = Sut.evalProgram p @?= rs
|
evalsTo rs e = Sut.evalExp e @?= rs
|
||||||
|
|
||||||
primitives = testGroup "primitives"
|
primitives = testGroup "primitives"
|
||||||
[ testGroup "arith"
|
[ testGroup "arith"
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import Test.Tasty (TestTree, testGroup)
|
|||||||
import Test.Tasty.HUnit
|
import Test.Tasty.HUnit
|
||||||
import qualified Gyehoek.CPS.Stackify as Sut
|
import qualified Gyehoek.CPS.Stackify as Sut
|
||||||
import Gyehoek.Stack.VM as Stk
|
import Gyehoek.Stack.VM as Stk
|
||||||
import Data.List (List)
|
|
||||||
import Gyehoek.CPS.Syntax (cps)
|
import Gyehoek.CPS.Syntax (cps)
|
||||||
|
import Gyehoek.CPS.Syntax qualified as CPS
|
||||||
import Gyehoek.GenSym (runGenSym)
|
import Gyehoek.GenSym (runGenSym)
|
||||||
import Effectful
|
import Effectful
|
||||||
|
import Gyehoek.Prelude
|
||||||
|
|
||||||
|
|
||||||
test_stackify =
|
test_stackify =
|
||||||
@@ -19,9 +20,11 @@ test_stackify =
|
|||||||
]
|
]
|
||||||
|
|
||||||
evalsTo :: List Obj -> Sut.Exp -> Assertion
|
evalsTo :: List Obj -> Sut.Exp -> Assertion
|
||||||
evalsTo rs e =
|
evalsTo rs e = Stk.eval e' @?= rs
|
||||||
Stk.eval e' @?= rs
|
where
|
||||||
where e' = runPureEff . runGenSym $ Sut.stackifyExp "main" e
|
e' = e & CPS.MkLambda [] "_ktail"
|
||||||
|
& CPS.MkProgram
|
||||||
|
& Sut.stackifyProgram & runGenSym & runPureEff
|
||||||
|
|
||||||
trivialReturn = testGroup "trivial return"
|
trivialReturn = testGroup "trivial return"
|
||||||
[ testCase "return int" do
|
[ testCase "return int" do
|
||||||
|
|||||||
@@ -28,15 +28,20 @@ free = testGroup "free"
|
|||||||
qq :: TestTree
|
qq :: TestTree
|
||||||
qq = testGroup "parser"
|
qq = testGroup "parser"
|
||||||
[ testCase "lambda" do
|
[ testCase "lambda" do
|
||||||
assertEqual "" (Sut.MkLambda ["x","y"] "ktail"
|
assertEqual ""
|
||||||
(Sut.ExpContinue (Sut.ValLabel "ktail") [Sut.ValVar "x"]))
|
(Sut.MkLambda ["x","y"] "ktail"
|
||||||
|
(Sut.ExpContinue (Sut.ValVar "ktail") [Sut.ValVar "x"]))
|
||||||
[cps|(λ (x y ktail) (continue ktail x))|]
|
[cps|(λ (x y ktail) (continue ktail x))|]
|
||||||
assertEqual "" (Sut.MkLambda [] "ktail"
|
assertEqual ""
|
||||||
(Sut.ExpContinue (Sut.ValLabel "ktail") [Sut.ValVar "x"]))
|
(Sut.MkLambda [] "ktail"
|
||||||
|
(Sut.ExpContinue (Sut.ValVar "ktail") [Sut.ValVar "x"]))
|
||||||
[cps|(λ (ktail) (continue ktail x))|]
|
[cps|(λ (ktail) (continue ktail x))|]
|
||||||
, testCase "kappa" do
|
, testCase "kappa" do
|
||||||
assertEqual "" (Sut.MkKappa ["x","y"]
|
assertEqual ""
|
||||||
(Sut.ExpContinue (Sut.ValLabel "k123") [Sut.ValVar "x", Sut.ValVar "y"]))
|
(Sut.MkKappa ["x","y"]
|
||||||
|
(Sut.ExpContinue
|
||||||
|
(Sut.ValVar "k123")
|
||||||
|
[Sut.ValVar "x", Sut.ValVar "y"]))
|
||||||
[cps|(κ (x y) (continue k123 x y))|]
|
[cps|(κ (x y) (continue k123 x y))|]
|
||||||
, testCase "application" do
|
, testCase "application" do
|
||||||
assertEqual "" (Sut.ExpApply (Sut.ValVar "f")
|
assertEqual "" (Sut.ExpApply (Sut.ValVar "f")
|
||||||
|
|||||||
@@ -14,58 +14,58 @@ evalsTo rs p = Sut.eval p @?= rs
|
|||||||
test_root = testGroup "stack machine"
|
test_root = testGroup "stack machine"
|
||||||
[ testCase "lit int" do
|
[ testCase "lit int" do
|
||||||
evalsTo [ObjImm (ImmInt 3)] [stkP|
|
evalsTo [ObjImm (ImmInt 3)] [stkP|
|
||||||
(define ($main)
|
(define ($start %ktail)
|
||||||
(pop-cont! %ktail)
|
|
||||||
(tail-call %ktail 3))
|
(tail-call %ktail 3))
|
||||||
|]
|
|]
|
||||||
, testCase "return constant" do
|
, testCase "return constant" do
|
||||||
evalsTo [ObjImm (ImmInt 123)] [stkP|
|
evalsTo [ObjImm (ImmInt 123)] [stkP|
|
||||||
(define ($main)
|
(define ($start %ktail)
|
||||||
(tail-call $silly))
|
(tail-call $silly %ktail))
|
||||||
(define ($silly)
|
(define ($silly %ktail)
|
||||||
(pop-cont! %ktail)
|
|
||||||
(tail-call %ktail 123))
|
(tail-call %ktail 123))
|
||||||
|]
|
|]
|
||||||
|
, testCase "identity continuation" do
|
||||||
|
evalsTo [ObjImm (ImmInt 45)] [stkP|
|
||||||
|
(define ($start %ktail)
|
||||||
|
(push! %ktail)
|
||||||
|
(tail-call $id 45))
|
||||||
|
(define ($id %x)
|
||||||
|
(pop! %ktail)
|
||||||
|
(tail-call %ktail %x))
|
||||||
|
|]
|
||||||
, testCase "identity function" do
|
, testCase "identity function" do
|
||||||
evalsTo [ObjImm (ImmInt 45)] [stkP|
|
evalsTo [ObjImm (ImmInt 45)] [stkP|
|
||||||
(define ($main)
|
(define ($start %ktail)
|
||||||
(tail-call $id 45))
|
(tail-call $id 45 %ktail))
|
||||||
(define ($id %x)
|
(define ($id %x %ktail)
|
||||||
(pop-cont! %ktail)
|
|
||||||
(tail-call %ktail %x))
|
(tail-call %ktail %x))
|
||||||
|]
|
|]
|
||||||
-- , testCase "square" do
|
|
||||||
-- evalsTo [ObjImm (ImmInt 16)] [stkP|
|
|
||||||
-- (define ($main))
|
|
||||||
-- |]
|
|
||||||
, testCase "square" do
|
, testCase "square" do
|
||||||
evalsTo [ObjImm (ImmInt 16)] [stkP|
|
evalsTo [ObjImm (ImmInt 16)] [stkP|
|
||||||
(define ($main)
|
(define ($start %ktail)
|
||||||
(tail-call $square 4))
|
(tail-call $square 4 %ktail))
|
||||||
(define ($square %x)
|
(define ($square %x %ktail)
|
||||||
(prim %x2 (* %x %x))
|
(prim %x2 (* %x %x))
|
||||||
(pop-cont! %ktail)
|
|
||||||
(tail-call %ktail %x2))
|
(tail-call %ktail %x2))
|
||||||
|]
|
|]
|
||||||
, testCase "factorial" do
|
, testCase "factorial" do
|
||||||
let hsfac (n :: Int) = foldr (*) (1) [1..n]
|
let hsfac (n :: Int) = foldr (*) (1) [1..n]
|
||||||
let fac (n :: Int) = [stkP|
|
let fac (n :: Int) = [stkP|
|
||||||
(define ($fac %n)
|
(define ($fac %n %ktail)
|
||||||
(prim %x0 (zero? %n))
|
(prim %x0 (zero? %n))
|
||||||
(if %x0
|
(if %x0
|
||||||
(then (pop-cont! %ktail)
|
(then (tail-call %ktail 1))
|
||||||
(tail-call %ktail 1))
|
|
||||||
(else (push! %n)
|
(else (push! %n)
|
||||||
|
(push! %ktail)
|
||||||
(prim %x1 (- %n 1))
|
(prim %x1 (- %n 1))
|
||||||
(push-cont! $fac-k0)
|
(tail-call $fac %x1 $fac-k0))))
|
||||||
(tail-call $fac %x1))))
|
|
||||||
(define ($fac-k0 %x2)
|
(define ($fac-k0 %x2)
|
||||||
|
(pop! %ktail)
|
||||||
(pop! %n)
|
(pop! %n)
|
||||||
(prim %x3 (* %x2 %n))
|
(prim %x3 (* %x2 %n))
|
||||||
(pop-cont! %ktail)
|
|
||||||
(tail-call %ktail %x3))
|
(tail-call %ktail %x3))
|
||||||
(define ($main)
|
(define ($start %ktail)
|
||||||
(tail-call $fac #{n}))
|
(tail-call $fac #{n} %ktail))
|
||||||
|]
|
|]
|
||||||
evalsTo [ObjImm (ImmInt 1)] $ fac 0
|
evalsTo [ObjImm (ImmInt 1)] $ fac 0
|
||||||
evalsTo [ObjImm (ImmInt 1)] $ fac 1
|
evalsTo [ObjImm (ImmInt 1)] $ fac 1
|
||||||
|
|||||||
Reference in New Issue
Block a user