cli, cps interpreter, stack vm, closure-conversion, fixes, tests, LOL
build / build (push) Successful in 7m49s

This commit is contained in:
2026-08-20 01:05:16 -06:00
parent 94b1a5fb45
commit c5f9bf1850
23 changed files with 587 additions and 99 deletions
+3 -1
View File
@@ -4,4 +4,6 @@
(haskell-mode-buffer-apply-command "cabal-fmt")) (haskell-mode-buffer-apply-command "cabal-fmt"))
(add-hook 'before-save-hook #'apply-cabal-fmt-h nil t) (add-hook 'before-save-hook #'apply-cabal-fmt-h nil t)
(add-to-list 'haskell-font-lock-quasi-quote-modes (add-to-list 'haskell-font-lock-quasi-quote-modes
'("cps" . scheme-mode))))))) '("cps" . scheme-mode))
(add-to-list 'haskell-font-lock-quasi-quote-modes
'("scm" . scheme-mode)))))))
+51
View File
@@ -2,8 +2,59 @@
the closure-conversion phase makes closed-over variables explicit by addition of the primitive ~make-closure~, taking a code pointer (in the CPS language, bare lambda) and the environment. the closure-conversion phase makes closed-over variables explicit by addition of the primitive ~make-closure~, taking a code pointer (in the CPS language, bare lambda) and the environment.
nice testable properties of closure-converted code:
- code pointers only appear in function position
- no function has free variables
multiple ~env-ref~ calls could probably be replaced with a primitive that loads the entire environment at once, returning multiple variables.
* scratchpad * scratchpad
** example
#+caption: scheme source
#+begin_src scheme
(letrec ((curried-add (λ (n)
(λ (m)
(+ n m)))))
((curried-add 3) 4))
#+end_src
#+caption: cps
#+begin_src scheme
(letrec ((curried-add
(λ (n ktail0)
(letrec ((curried-add-in
(λ (m ktail1)
(prim (+ n m)
(κ (x0) (continue ktail1 x0))))))
(continue ktail0 curried-add-in)))))
(letrec ((k0 (κ (adder) (adder 4 halt))))
(curried-add 3 k0)))
#+end_src
#+caption: closure-converted
#+begin_src scheme
(letrec ((curried-add
(λ (n ktail0)
(letrec ((curried-add-in-code
(λ (env m ktail1)
(prim (env-ref 0 env)
(κ (n)
(prim (+ n m)
(κ (x0) (continue ktail1 x0))))))))
(prim (make-closure curried-add-in-code n)
(κ (curried-add-in)
(continue ktail0 curried-add-in)))))))
(letrec ((k0 (κ (adder-closure)
(prim (closure-code adder-closure)
(κ (adder)
(adder adder-closure 4 halt))))))
(curried-add 3 k0)))
#+end_src
** wasm
#+begin_src scheme #+begin_src scheme
(letrec ((make-adder (letrec ((make-adder
(lambda (n) (lambda (n)
+2
View File
@@ -0,0 +1,2 @@
ret > ExitSuccess
out > 9
+2
View File
@@ -0,0 +1,2 @@
ret > ExitSuccess
out > 456
+2
View File
@@ -0,0 +1,2 @@
ret > ExitSuccess
out > 16
+2
View File
@@ -0,0 +1,2 @@
ret > ExitSuccess
out > 16
+2
View File
@@ -0,0 +1,2 @@
(letrec ((square (λ (x) (* x x))))
(square 4))
+4
View File
@@ -54,6 +54,7 @@ library
exposed-modules: exposed-modules:
Gyehoek.CPS.Close Gyehoek.CPS.Close
Gyehoek.CPS.Convert Gyehoek.CPS.Convert
Gyehoek.CPS.Eval
Gyehoek.CPS.Lower Gyehoek.CPS.Lower
Gyehoek.CPS.Stackify Gyehoek.CPS.Stackify
Gyehoek.CPS.Syntax Gyehoek.CPS.Syntax
@@ -83,6 +84,7 @@ library
, megaparsec , megaparsec
, mtl , mtl
, optparse-applicative , optparse-applicative
, ordered-containers
, pretty-simple , pretty-simple
, prettyprinter , prettyprinter
, process , process
@@ -105,9 +107,11 @@ test-suite test
hs-source-dirs: test hs-source-dirs: test
main-is: Main.hs main-is: Main.hs
other-modules: other-modules:
Gyehoek.Test.CPS.Eval
Gyehoek.Test.CPS.Stackify Gyehoek.Test.CPS.Stackify
Gyehoek.Test.CPS.Syntax Gyehoek.Test.CPS.Syntax
Gyehoek.Test.Golden Gyehoek.Test.Golden
Gyehoek.Test.Scheme.Syntax
Gyehoek.Test.Sexp Gyehoek.Test.Sexp
Gyehoek.Test.Stack.VM Gyehoek.Test.Stack.VM
+79 -9
View File
@@ -1,3 +1,4 @@
{-# LANGUAGE OverloadedLists #-}
module Gyehoek.CPS.Close module Gyehoek.CPS.Close
( closeProgram ( closeProgram
) where ) where
@@ -9,6 +10,12 @@ import Control.Monad ((>=>))
import Control.Lens import Control.Lens
import Data.List.NonEmpty (NonEmpty) import Data.List.NonEmpty (NonEmpty)
import qualified Data.HashSet as HS import qualified Data.HashSet as HS
import qualified Data.Set.Ordered as O
import Data.Set.Ordered (OSet)
import Gyehoek.GenSym
import Data.String.Interpolate (i)
import Debug.Pretty.Simple
import Data.HashSet (HashSet)
cataM cataM
@@ -16,14 +23,77 @@ cataM
=> (Base t a -> m a) -> t -> m a => (Base t a -> m a) -> t -> m a
cataM f = cata (sequenceA >=> f) cataM f = cata (sequenceA >=> f)
close :: Exp -> Exp close :: GenSym :> es => Exp -> Eff es Exp
close = cata \case
ExpLetRecF {bindersF,bodyF} -> ExpLetRec binders bodyF
where
binders = bindersF & (each . _2 . _AbsLambda' . _3) %~ \e -> _
e -> embed e
-- let frees = freeWithBound' (HS.fromList $ ktail : bs) e' close = transformM \case
closeProgram :: Program -> Eff es Program ExpLetRec [(f, AbsLambda lam@(MkLambda bs kb m))] e -> do
closeProgram (MkProgram e) = pure . MkProgram . close $ e f_code <- gensym' @Name $ f ^. _Wrapped'. to (<> "-code")
-- it would probably be most sane to generate a symbol for `env`,
-- but we're reusing the lambda binding for the sake of recursive
-- reverences.
-- env <- gensym' @Name "env"
let frees = freeWithBound' [f] lam
let m' = ifoldr
(\n x q -> [cps|(prim (env-ref #{f} #{n})
(κ (#{x}) #{q}))|])
m frees
pure [cps|
(letrec ((#{f_code} (λ (#{f} ##{bs} #{kb})
#{m'})))
(prim (make-closure ($ #{f_code}) ##{frees})
(κ (#{f}) #{e})))
|]
ExpApply f xs ktail -> do
code <- gensym' @Name "code"
pure [cps|
(prim (env-code #{f})
(κ (#{code})
(#{code} #{f} ##{xs} #{ktail})))
|]
e -> pure e
e -> error [i|unimplemented case: #{e}|]
-- lam@(ExpLambdaF bs m) -> do
-- env <- gensym' @Name "env"
-- let upvalBinds = free' (embed lam)
-- & itraversed %@~ \i x -> (x, [cps|(env-ref #{env} #{i})|])
-- let upvals = upvalBinds ^.. each . _1
-- pure [cps|
-- (make-closure (λ (#{env} ##{bs})
-- (let #{upvalBinds}
-- #{m}))
-- ##{upvals})
-- |]
-- ExpApplyF f xs ->
-- pure [scm|
-- (apply-closure #{f} ##{xs})
-- |]
closeProgram :: GenSym :> es => Program -> Eff es Program
closeProgram = traverseOf #body close
curriedadd :: Program
curriedadd = [cps|
(letrec ((curried-add
(λ (n ktail1)
(letrec ((curried-add-in
(λ (m ktail2)
(prim (+ n m)
(κ (x0) (continue ktail2 x0))))))
(continue ktail1 curried-add-in)))))
(letrec ((k0 (κ (adder) (adder 4 halt))))
(curried-add 5 k0)))
|]
square :: Program
square = [cps|
(letrec ((lambda-body0 (λ (x lambda-tail1)
(prim (* x x) (κ (r2) (continue lambda-tail1 r2))))))
(letrec
((r3 (κ (x4) (continue halt x4))))
(lambda-body0 5 r3)))
|]
+3 -2
View File
@@ -18,6 +18,7 @@ import Data.String.Interpolate (i)
import Data.Functor (unzip) import Data.Functor (unzip)
import Data.List (List) import Data.List (List)
import Prelude hiding (unzip) import Prelude hiding (unzip)
import Debug.Pretty.Simple (pTraceShowMForceColor)
-- 뻘짓이어라 -- 뻘짓이어라
@@ -64,7 +65,7 @@ convert (Scm.ExpPrim p) k =
ExpPrim p' . MkKappa [r] <$> k (ValVar r) ExpPrim p' . MkKappa [r] <$> k (ValVar r)
convert (Scm.ExpLambda xs e) k = do convert (Scm.ExpLambda xs e) k = do
f <- gensym' "λ-body" f <- gensym' "lambda-body"
lam <- convertLambda xs e lam <- convertLambda xs e
ke <- k $ ValVar f ke <- k $ ValVar f
pure [cps| pure [cps|
@@ -92,7 +93,7 @@ convert (Scm.ExpLet bs e) k =
let rhss = bs ^.. each . _2 let rhss = bs ^.. each . _2
in telescope (convert @es) rhss \rhss' -> do in telescope (convert @es) rhss \rhss' -> do
e' <- convert e k e' <- convert e k
kbody <- gensym' @Name "letrec-body" kbody <- gensym' @Name "let-body"
let bs' = bs ^.. each . _1 let bs' = bs ^.. each . _1
pure [cps| pure [cps|
(letrec ((#{kbody} (κ #{bs'} #{e'}))) (letrec ((#{kbody} (κ #{bs'} #{e'})))
+107
View File
@@ -0,0 +1,107 @@
{-# LANGUAGE ViewPatterns #-}
module Gyehoek.CPS.Eval
( evalProgram
, module Gyehoek.CPS.Syntax
) where
import Gyehoek.CPS.Syntax
import Data.String.Interpolate (i)
import Data.HashMap.Strict (HashMap)
import Control.Lens
import Data.Maybe (fromMaybe)
import Data.Generics.Labels ()
import GHC.Generics (Generic)
import Data.List (List)
import Text.Show.Functions ()
import qualified Data.HashMap.Strict as H
import Debug.Pretty.Simple (pTraceShowId)
import qualified Data.Text as T
data Code
= CodeKap (List Obj -> List Obj)
| CodeLam (List Obj -> Name -> List Obj)
deriving (Show, Generic)
data Env = MkEnv
{ vars :: HashMap Name Obj
, labels :: HashMap Name (Env, Abs)
}
deriving (Show, Generic)
eval :: Env -> Exp -> List Obj
eval g (Halt xs) = evalVal g <$> xs
eval g (ExpContinue k xs) =
case g ^. #labels . at k of
Just (h, AbsKappa' bs m) -> eval h' m
where h' = h & #vars <>~ envOfBinds bs (evalVal g <$> xs)
_ -> error [i|not a kappa: #{k}|]
eval g (ExpApply ((^?! #ValVar) -> f) xs ktail) =
case g ^?! #labels . at f of
Just (h,AbsLambda' bs kb m) -> eval h' m
where h' = h & #vars <>~ envOfBinds bs (evalVal g <$> xs)
& #labels . at kb .~ (g ^. #labels . at ktail)
Nothing -> error [i|undefined label: #{f}|]
eval g (ExpLetRec [(b, ab)] e) = eval g' e
where g' = g & #labels . at b ?~ (g,ab)
eval g (ExpPrim p (MkKappa bs e)) = case evalVal g <$> p of
PrimAdd x y -> arithBinop (+) x y
PrimMul x y -> arithBinop (*) x y
PrimSub x y -> arithBinop (-) x y
PrimDiv x y -> arithBinop div x y
_ -> error [i|unhandled prim: #{p}|]
where
ret rs = eval
(g & #vars <>~ envOfBinds bs rs)
e
arithBinop f (ObjImm (ImmInt x)) (ObjImm (ImmInt y)) =
ret [ObjImm . ImmInt $ f x y]
arithBinop _ x y = error [i|bad arith: #{x}, #{y}|]
eval _ e = error [i|unimplemented case: #{e}|]
envOfBinds bs xs = foldMap (uncurry H.singleton) (zip bs xs)
evalVal :: Env -> Val -> Obj
evalVal g = \case
ValVar x -> fromMaybe (error [i|unbound: #{x}|]) $ g ^?! #vars . at x
ValImm x -> ObjImm x
ValLit l -> ObjImm $ case l of
LitInt n -> ImmInt n
LitBool b -> ImmBool b
emptyEnv :: Env
emptyEnv = MkEnv
{ vars = mempty
, labels = H.singleton "halt" $
( emptyEnv
, AbsKappa' ["h0"] $ Halt [ValVar "h0"]
)
}
evalProgram :: Program -> List Obj
evalProgram (MkProgram e) = eval emptyEnv e
curriedadd :: Program
curriedadd = [cps|
(letrec ((curried-add
(λ (n ktail1)
(letrec ((curried-add-in
(λ (m ktail2)
(prim (+ n m)
(κ (x0) (continue ktail2 x0))))))
(continue ktail1 curried-add-in)))))
(letrec ((k0 (κ (adder) (adder 4 halt))))
(curried-add 5 k0)))
|]
idfn = [cps|
(letrec ((id (λ (x ktail)
(continue ktail x))))
(id 456 halt))
|] :: Program
+20 -15
View File
@@ -8,6 +8,7 @@ module Gyehoek.CPS.Stackify
import Gyehoek.CPS.Syntax import Gyehoek.CPS.Syntax
import Gyehoek.Stack.Syntax qualified as Stk import Gyehoek.Stack.Syntax qualified as Stk
import Data.Sequence (Seq) import Data.Sequence (Seq)
import Data.Sequence qualified as Seq
import Effectful import Effectful
import Gyehoek.GenSym import Gyehoek.GenSym
import Effectful.Writer.Static.Shared import Effectful.Writer.Static.Shared
@@ -18,7 +19,7 @@ import GHC.Generics (Generic)
import Data.Foldable import Data.Foldable
import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as H import qualified Data.HashMap.Strict as H
import Data.List (List) import Data.List (List, elemIndex)
import GHC.Exts (IsList(fromList)) import GHC.Exts (IsList(fromList))
@@ -48,12 +49,10 @@ stackify g (ExpLetRec [(f, kap@(AbsKappa' xs m))] e) = do
stackify g (ExpLetRec [(f, AbsLambda' xs k m)] e) = do stackify g (ExpLetRec [(f, AbsLambda' xs k m)] e) = do
let vs = (k:xs) <&> \x -> (x, Stk.ValReg x) let vs = (k:xs) <&> \x -> (x, Stk.ValReg x)
lam_body <- gensym' "lambda-body"
m' <- stackify (g & #bound .~ H.fromList vs m' <- stackify (g & #bound .~ H.fromList vs
& #bound . at f ?~ Stk.ValLabel lam_body
& #contStack %~ (k:)) m & #contStack %~ (k:)) m
tell [Stk.MkBlock lam_body xs . toList $ m'] tell [Stk.MkBlock f xs . toList $ m']
stackify (g & #bound . at f ?~ Stk.ValLabel lam_body) e stackify g e
stackify g (ExpIf c t f) = do stackify g (ExpIf c t f) = do
t' <- stackify g t t' <- stackify g t
@@ -70,16 +69,21 @@ stackify g (ExpApply f xs ktail) = do
ls = fold $ (k ^? #ValImm . #ImmLabel) ls = fold $ (k ^? #ValImm . #ImmLabel)
>>= \klbl -> g ^. #liveness . at klbl >>= \klbl -> g ^. #liveness . at klbl
-- this probably won't work for call/cc, for cps-converted code it'll stackify g (ExpContinue k xs) =
-- be fine i think. notice how, instead of calling `var g k`, we just -- return continuations require popping the stack. how do we know
-- assume it's the return continuation on top of the stack. -- when a continuation is a return continuation? is this a correct
stackify g (ExpContinue k xs) = do -- test?
ktail <- gensym' $ k ^. _Wrapped' case elemIndex k g.contStack of
pure $ Nothing -> pure [ Stk.Call (Stk.ValLabel k) xs' ]
fromList [ Stk.PopCont "_" | _ <- takeWhile (/= k) g.contStack ] Just j -> do
<> [ Stk.PopCont ktail ktail <- gensym' $ k ^. _Wrapped'
, Stk.Call (Stk.ValReg ktail) (stackifyVal g <$> xs) pure $
] Seq.replicate j (Stk.PopCont "_")
<> [ Stk.PopCont ktail
, Stk.Call (Stk.ValReg ktail) (stackifyVal g <$> 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
@@ -91,6 +95,7 @@ stackifyVal :: Env -> Val -> Stk.Val
stackifyVal g = \case stackifyVal g = \case
ValLit (LitInt n) -> Stk.ValImm (ImmInt n) ValLit (LitInt n) -> Stk.ValImm (ImmInt n)
ValLit (LitBool b) -> Stk.ValImm (ImmBool b) ValLit (LitBool b) -> Stk.ValImm (ImmBool b)
ValImm imm -> Stk.ValImm imm
ValVar v -> var g v ValVar v -> var g v
v -> error [i|unimplemented val: #{v}|] v -> error [i|unimplemented val: #{v}|]
+78 -8
View File
@@ -4,6 +4,7 @@
{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE DeriveAnyClass #-}
module Gyehoek.CPS.Syntax module Gyehoek.CPS.Syntax
( Val(..) ( Val(..)
, Kappa(..) , Kappa(..)
@@ -14,6 +15,9 @@ module Gyehoek.CPS.Syntax
, Prim(..) , Prim(..)
, Program(..) , Program(..)
, Lit(..) , Lit(..)
, Imm(..)
, Obj(..)
, Hob(..)
, pattern Void , pattern Void
, pattern Halt , pattern Halt
, pattern Halt1 , pattern Halt1
@@ -34,6 +38,8 @@ module Gyehoek.CPS.Syntax
, Free(..) , Free(..)
, Vars(..) , Vars(..)
, Subst(..) , Subst(..)
, pattern ValLabel
, labelName -- don't like that this is part of the api
) )
where where
@@ -61,14 +67,41 @@ import Data.Monoid (Endo)
import Data.Containers.ListUtils (nubOrd) import Data.Containers.ListUtils (nubOrd)
import Data.Functor.Foldable.TH import Data.Functor.Foldable.TH
import Data.Functor.Foldable (Recursive(..), Corecursive (..)) import Data.Functor.Foldable (Recursive(..), Corecursive (..))
import Control.DeepSeq (NFData)
import qualified Gyehoek.Sexp as GS
import qualified Language.Sexp.Located as SL
import Data.Data.Lens (uniplate)
-- Data types -- Data types
data Val data Val
= ValVar Name = ValImm Imm
| ValLit Lit | ValLit Lit
| ValVar Name
deriving (Show, Generic, Data, Eq) deriving (Show, Generic, Data, Eq)
pattern ValLabel :: Name -> Val
pattern ValLabel x = ValImm (ImmLabel x)
data Imm
= ImmInt Int
| ImmBool Bool
| ImmLabel Name
deriving stock (Show, Generic, Data, Eq)
deriving anyclass (NFData)
data Obj
= ObjImm Imm
| ObjHob Hob
deriving stock (Show, Generic, Data, Eq)
deriving anyclass (NFData)
-- | a heap object.
data Hob
= HobClosure { label :: Name, env :: List Obj }
deriving stock (Show, Generic, Data, Eq)
deriving anyclass (NFData)
data Kappa = MkKappa { binders :: List Name, body :: Exp } data Kappa = MkKappa { binders :: List Name, body :: Exp }
deriving (Show, Generic, Data, Eq) deriving (Show, Generic, Data, Eq)
@@ -88,7 +121,7 @@ pattern AbsLambda' xs e ktail = AbsLambda (MkLambda xs e ktail)
data Exp data Exp
= ExpPrim (Prim Val) Kappa = ExpPrim (Prim Val) Kappa
| ExpLetRec { binders :: NonEmpty (Name, Abs), body :: Exp } | ExpLetRec { binders :: List (Name, Abs), body :: Exp }
| ExpContinue Name (List Val) | ExpContinue Name (List Val)
| ExpIf Val Exp Exp | ExpIf Val Exp Exp
| ExpApply | ExpApply
@@ -139,15 +172,57 @@ _AbsLambda' = prism'
(\case AbsLambda' bs ktail e -> Just (bs,ktail,e) (\case AbsLambda' bs ktail e -> Just (bs,ktail,e)
_ -> Nothing) _ -> Nothing)
instance Plated Exp where
plate = uniplate
-- plate k = \case
-- ExpPrim p kap -> ExpPrim p <$> body k kap
-- ExpLetRec bs e -> ExpLetRec <$> (each . _2 . body) k bs <*> k e
-- ExpContinue c xs -> pure $ ExpContinue c xs
-- ExpIf c t f -> ExpIf c <$> k t <*> k f
-- ExpApply f xs ktail -> pure $ ExpApply f xs ktail
-- SexpIso instances -- SexpIso instances
instance S.SexpIso Val where instance S.SexpIso Val where
sexpIso = match sexpIso = match
$ With (\var -> var . S.sexpIso)
$ With (\lit -> lit . S.sexpIso) $ With (\lit -> lit . S.sexpIso)
$ With (\imm -> imm . S.sexpIso)
$ With (\var -> var . S.sexpIso)
$ End $ End
instance S.SexpIso Obj where
sexpIso = match
$ With (\imm -> imm . S.sexpIso)
$ With (\hob -> hob . S.sexpIso)
$ End
instance S.SexpIso Imm where
sexpIso = match
$ With (. S.int)
$ With (. GS.schemeBool)
$ With (. labelName)
$ End
labelName :: S.SexpGrammar Name
labelName = S.coproduct
[ S.sexpIso @Name >>> Gyehoek.Sexp.prismIso
(S.expected "label")
(prefixed @Name "$")
, S.list $ S.el (S.sym "$") >>> S.el (S.sexpIso @Name)
]
instance S.SexpIso Hob where
sexpIso = match
$ With (. closure)
$ End
where
-- closures can be printed, but not parsed.
closure :: S.Grammar S.Position (Sexp :- t) (List Obj :- Name :- t)
closure = IG.Flip $ IG.PartialIso
(\(env:-code:-t) -> SL.Modified SL.Hash [GS.sx|(#{code} ##{env})|] :- t)
(const . Left $ mempty)
instance S.SexpIso Lambda where instance S.SexpIso Lambda where
sexpIso = match sexpIso = match
$ With (. lambda) $ With (. lambda)
@@ -359,8 +434,3 @@ instance Scoped Exp where
class Subst a where class Subst a where
substWith :: (Name -> Maybe Val) -> a -> a substWith :: (Name -> Maybe Val) -> a -> a
instance Subst Exp where
substWith f = go HS.empty where
go bound e = case scope e of
Use xs ss -> _
+42 -19
View File
@@ -19,7 +19,7 @@ import System.IO (Handle)
import System.IO qualified as IO import System.IO qualified as IO
import Gyehoek.CPS.Convert import Gyehoek.CPS.Convert
import Gyehoek.CPS.Lower import Gyehoek.CPS.Lower
import Gyehoek.CPS.Syntax qualified as Cps import Gyehoek.CPS.Eval qualified as CPS
import Control.Monad import Control.Monad
import Text.Pretty.Simple (pShowNoColor) import Text.Pretty.Simple (pShowNoColor)
import System.Process.Typed import System.Process.Typed
@@ -33,8 +33,11 @@ import Text.Pretty.Simple (pShow)
import Gyehoek.Stack.VM (eval, writeObj, Obj) import Gyehoek.Stack.VM (eval, writeObj, Obj)
import qualified Data.Text as T import qualified Data.Text as T
import Data.List (List) import Data.List (List)
import Gyehoek.Stack.Syntax (encodeProgram) import Gyehoek.Stack.Syntax qualified as Stk
import Effectful.Exception import Effectful.Exception
import Gyehoek.CPS.Close (closeProgram)
import Control.Lens.Extras (is)
import Control.Arrow ((>>>))
main :: IO () main :: IO ()
@@ -98,6 +101,18 @@ inspectWasm wat = do
IO.hFlush (getStdin pager) IO.hFlush (getStdin pager)
IO.hClose (getStdin pager) IO.hClose (getStdin pager)
dumpOrRun
:: Monad m
=> Bool -> Bool
-> m a
-> (a -> m ()) -> (a -> m ())
-> m ()
dumpOrRun dump run acquire do_dump do_run =
when (dump || run) do
x <- acquire
when dump (do_dump x)
when run (do_run x)
driver driver
:: (GenSym :> es, FileSystem :> es, IOE :> es) :: (GenSym :> es, FileSystem :> es, IOE :> es)
=> Options -> Eff es () => Options -> Eff es ()
@@ -108,32 +123,40 @@ driver opts = do
cps <- convertProgram scm cps <- convertProgram scm
when opts.dumpCPS do when opts.dumpCPS do
hPutStrLn FS.stdout $ Sexp.encodePretty cps ^?! _Right hPutStrLn FS.stdout $ Sexp.encodePretty cps ^?! _Right
stk <- stackifyProgram cps closedCps <- closeProgram cps
if opts.dumpStackified then do when opts.dumpClosed do
hPutStrLn FS.stdout . encodeProgram $ stk hPutStrLn FS.stdout $ Sexp.encodePretty closedCps ^?! _Right
else if opts.stackify then do let rt_is p = is (_Just . p) opts.runtime
eval stk & fmap writeObj dumpOrRun opts.dumpStackified (rt_is #Stackify)
& T.unwords (stackifyProgram closedCps)
& hPutStrLn FS.stdout (hPutStrLn FS.stdout . Stk.encodeProgram)
else do (eval >>> fmap writeObj
wat <- lowerProgram cps >>> T.unwords
withFile opts.output FS.WriteMode \h -> >>> hPutStrLn FS.stdout)
hPutStrLn h wat dumpOrRun False (rt_is #CPS)
when opts.inspectWasm do (pure closedCps)
inspectWasm wat (const $ pure ())
(CPS.evalProgram >>> fmap writeObj
>>> T.unwords
>>> hPutStrLn FS.stdout)
dumpOrRun opts.inspectWasm (rt_is #Wasm)
(lowerProgram cps)
inspectWasm
(\wat -> withFile opts.output FS.WriteMode \h -> hPutStrLn h wat)
parse_e2e :: FilePath -> IO Scm.Program parse_e2e :: FilePath -> IO Scm.Program
parse_e2e = runEff . runFileSystem . readScm parse_e2e = runEff . runFileSystem . readScm
convert_e2e :: FilePath -> IO Cps.Program convert_e2e :: FilePath -> IO CPS.Program
convert_e2e = runEff . runFileSystem . runGenSym . (convertProgram <=< readScm) convert_e2e = runEff . runFileSystem . runGenSym
. (closeProgram <=< convertProgram <=< readScm)
lower_e2e :: FilePath -> IO Text lower_e2e :: FilePath -> IO Text
lower_e2e = lower_e2e =
runEff . runFileSystem . runGenSym runEff . runFileSystem . runGenSym
. (lowerProgram <=< convertProgram <=< readScm) . (lowerProgram <=< closeProgram <=< convertProgram <=< readScm)
eval_e2e :: FilePath -> IO (List Obj) eval_e2e :: FilePath -> IO (List Obj)
eval_e2e fp = runEff . runFileSystem . runGenSym $ do eval_e2e fp = runEff . runFileSystem . runGenSym $ do
stk <- stackifyProgram <=< convertProgram <=< readScm $ fp stk <- stackifyProgram <=< closeProgram <=< convertProgram <=< readScm $ fp
pure . eval $ stk pure . eval $ stk
+25 -5
View File
@@ -1,6 +1,7 @@
{-# LANGUAGE NoFieldSelectors #-} {-# LANGUAGE NoFieldSelectors #-}
module Gyehoek.Options module Gyehoek.Options
( Options(..) ( Options(..)
, Runtime(..)
, parser , parser
) )
where where
@@ -12,13 +13,18 @@ import System.FilePath
import qualified Data.HashSet as HS import qualified Data.HashSet as HS
import Control.Lens hiding (argument) import Control.Lens hiding (argument)
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Data.Foldable
data Runtime = Stackify | Wasm | CPS
deriving (Show, Generic)
data Options = MkOptions data Options = MkOptions
{ dumpCPS :: Bool { dumpClosed :: Bool
, dumpCPS :: Bool
, dumpParsed :: Bool , dumpParsed :: Bool
, dumpStackified :: Bool , dumpStackified :: Bool
, stackify :: Bool , runtime :: Maybe Runtime
, inspectWasm :: Bool , inspectWasm :: Bool
, output :: FilePath , output :: FilePath
, sourceFile :: FilePath , sourceFile :: FilePath
@@ -48,18 +54,32 @@ parseOutput = strOption
<> value "-" <> value "-"
) )
parseRuntime = option rdr . fold $
[ long "runtime"
, short 'R'
, value Nothing
]
where
rdr = maybeReader \case
"stackify" -> Just (Just Stackify)
"wasm" -> Just (Just Wasm)
"cps" -> Just (Just CPS)
"none" -> Just Nothing
_ -> Nothing
parseDumpClosed = switch (long "dump-closed")
parseDumpCPS = switch (long "dump-cps") parseDumpCPS = switch (long "dump-cps")
parseDumpStackified = switch (long "dump-stackified") parseDumpStackified = switch (long "dump-stackified")
parseStackify = switch (long "stackify")
parseDumpParsed = switch (long "dump-parsed") parseDumpParsed = switch (long "dump-parsed")
parseInspectWasm = switch $ long "inspect-wasm" <> short 'p' parseInspectWasm = switch $ long "inspect-wasm" <> short 'p'
parser :: Parser Options parser :: Parser Options
parser = MkOptions parser = MkOptions
<$> parseDumpCPS <$> parseDumpClosed
<*> parseDumpCPS
<*> parseDumpParsed <*> parseDumpParsed
<*> parseDumpStackified <*> parseDumpStackified
<*> parseStackify <*> parseRuntime
<*> parseInspectWasm <*> parseInspectWasm
<*> parseOutput <*> parseOutput
<*> argument str (metavar "FILE") <*> argument str (metavar "FILE")
+52 -4
View File
@@ -1,4 +1,5 @@
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
@@ -15,6 +16,7 @@ module Gyehoek.Scheme.Syntax
, Lit(..) , Lit(..)
, Def(..) , Def(..)
, Exp(..) , Exp(..)
, ExpF(..)
, Sexp(..) , Sexp(..)
, Program(..) , Program(..)
, CommandOrDef(..) , CommandOrDef(..)
@@ -26,11 +28,15 @@ module Gyehoek.Scheme.Syntax
, scm , scm
, readExp , readExp
, readProgram , readProgram
, free'
, freeWithBound'
, freeO
, encodeProgram
) )
where where
import Data.Text (Text) import Data.Text (Text)
import Data.List (List) import Data.List (List, intersperse)
import Language.SexpGrammar import Language.SexpGrammar
( SexpIso(..), list, el, rest, sym, symbol ) ( SexpIso(..), list, el, rest, sym, symbol )
import Language.SexpGrammar qualified as Sexp import Language.SexpGrammar qualified as Sexp
@@ -51,13 +57,15 @@ import Data.Functor.Foldable.TH (makeBaseFunctor)
import Data.Functor.Foldable hiding (fold) import Data.Functor.Foldable hiding (fold)
import Data.HashSet (HashSet) import Data.HashSet (HashSet)
import qualified Data.HashSet as HS import qualified Data.HashSet as HS
import Data.Foldable (fold) import Data.Foldable (fold, toList)
import Language.Haskell.TH.Quote (QuasiQuoter) import Language.Haskell.TH.Quote (QuasiQuoter)
import Effectful.FileSystem (runFileSystem) import Effectful.FileSystem (runFileSystem)
import qualified Effectful.FileSystem.IO as FS import qualified Effectful.FileSystem.IO as FS
import qualified Data.Text.Encoding as T import qualified Data.Text.Encoding as T
import qualified Effectful.FileSystem.IO.ByteString as FB import qualified Effectful.FileSystem.IO.ByteString as FB
import Control.DeepSeq (NFData) import Control.DeepSeq (NFData)
import qualified Data.Set.Ordered as O
import Data.Sequence (Seq)
newtype Name = MkName { inner :: Text } newtype Name = MkName { inner :: Text }
@@ -87,6 +95,7 @@ data Prim e
| PrimNewline | PrimNewline
| PrimMakeClosure { code :: e, env :: List e } | PrimMakeClosure { code :: e, env :: List e }
| PrimEnvRef e Int | PrimEnvRef e Int
| PrimEnvCode e
| PrimCallCC e | PrimCallCC e
deriving stock (Show, Generic, Functor, Foldable, Traversable, Data, Eq) deriving stock (Show, Generic, Functor, Foldable, Traversable, Data, Eq)
deriving anyclass (NFData) deriving anyclass (NFData)
@@ -112,8 +121,8 @@ data Def
deriving anyclass (NFData) deriving anyclass (NFData)
data Exp data Exp
= ExpLet (NonEmpty (Name, Exp)) Exp = ExpLet (List (Name, Exp)) Exp
| ExpLetRec (NonEmpty (Name, Exp)) Exp | ExpLetRec (List (Name, Exp)) Exp
| ExpPrim (Prim Exp) | ExpPrim (Prim Exp)
| ExpBegin (List Exp) | ExpBegin (List Exp)
| ExpIf Exp Exp Exp | ExpIf Exp Exp Exp
@@ -180,6 +189,7 @@ primSexpIso namefn a = match
$ With (. nullop "newline") $ With (. nullop "newline")
$ With (. ht1' "make-closure") $ With (. ht1' "make-closure")
$ With (. GS.headTagged2 (namefn "env-ref") a Sexp.int) $ With (. GS.headTagged2 (namefn "env-ref") a Sexp.int)
$ With (. ht1 "env-code")
$ With (. ht1 "call/cc") $ With (. ht1 "call/cc")
$ End $ End
where where
@@ -253,6 +263,35 @@ instance SexpIso CommandOrDef where
scm :: QuasiQuoter scm :: QuasiQuoter
scm = GS.makeSx [|| GS.fromSexp @Exp ||] scm = GS.makeSx [|| GS.fromSexp @Exp ||]
freeWithBound' :: Foldable f => f Name -> Exp -> List Name
freeWithBound' bound = filter (`elem` bound) . free'
freeO :: Exp -> O.OSet Name
freeO = O.unbiased . cata \case
ExpVarF x -> O.Bias @O.L $ O.singleton x
ExpLetF bs e ->
foldOf (each . _2) bs
<> (e & coerced %~ deleteFromO (bs ^.. each . _1))
ExpLetRecF bs e ->
(foldOf (each . _2) bs & coerced %~ deleteFromO binds)
<> (e & coerced %~ deleteFromO binds)
where binds = bs ^.. each . _1
ExpLambdaF bs e -> e & coerced %~ deleteFromO bs
e -> fold e
free' :: Exp -> List Name
free' = toList @O.OSet . O.unbiased . cata \case
ExpVarF x -> O.Bias @O.L $ O.singleton x
ExpLetF bs e ->
foldOf (each . _2) bs
<> (e & coerced %~ deleteFromO (bs ^.. each . _1))
ExpLetRecF bs e ->
(foldOf (each . _2) bs & coerced %~ deleteFromO binds)
<> (e & coerced %~ deleteFromO binds)
where binds = bs ^.. each . _1
ExpLambdaF bs e -> e & coerced %~ deleteFromO bs
e -> fold e
free :: Exp -> HashSet Name free :: Exp -> HashSet Name
free = cata \case free = cata \case
ExpVarF x -> HS.singleton x ExpVarF x -> HS.singleton x
@@ -260,6 +299,9 @@ free = cata \case
ExpLambdaF binders vs -> deleteFrom binders vs ExpLambdaF binders vs -> deleteFrom binders vs
e -> fold e e -> fold e
deleteFromO :: (Foldable f, Ord a) => f a -> O.OSet a -> O.OSet a
deleteFromO = flip $ foldr O.delete
deleteFrom :: (Foldable f, Hashable a) => f a -> HashSet a -> HashSet a deleteFrom :: (Foldable f, Hashable a) => f a -> HashSet a -> HashSet a
deleteFrom = flip $ foldr HS.delete deleteFrom = flip $ foldr HS.delete
@@ -292,3 +334,9 @@ readProgram fp = runFileSystem $
readExp :: IOE :> es => FilePath -> Eff es Exp readExp :: IOE :> es => FilePath -> Eff es Exp
readExp fp = readProgram fp <&> (^?! #commandsAndDefs . _head . #Command) readExp fp = readProgram fp <&> (^?! #commandsAndDefs . _head . #Command)
encodeProgram :: Program -> Text
encodeProgram p = p.commandsAndDefs
& fmap ((^?! _Right) . GS.encodePretty)
& intersperse "\n\n"
& mconcat
+3 -6
View File
@@ -170,12 +170,12 @@ let_
:: Text :: Text
-> (forall t. Grammar Position (Sexp :- t) (a :- t)) -> (forall t. Grammar Position (Sexp :- t) (a :- t))
-> (forall t. Grammar Position (Sexp :- t) (b :- t)) -> (forall t. Grammar Position (Sexp :- t) (b :- t))
-> Grammar Position (Sexp :- (NonEmpty (a, b) :- t1)) t2 -> Grammar Position (Sexp :- (List (a, b) :- t1)) t2
-> Grammar Position (Sexp :- t1) t2 -> Grammar Position (Sexp :- t1) t2
let_ kw name rhs e = list (el (sym kw) >>> el bindings >>> el e) let_ kw name rhs e = list (el (sym kw) >>> el bindings >>> el e)
where where
-- bindings :: Grammar Position (Sexp :- _) (List (_, _) :- _) -- bindings :: Grammar Position (Sexp :- _) (List (_, _) :- _)
bindings = nonempty binding bindings = list $ rest binding
binding :: Grammar Position (Sexp :- t) ((_, _) :- t) binding :: Grammar Position (Sexp :- t) ((_, _) :- t)
binding = list (el name >>> el rhs) >>> pair binding = list (el name >>> el rhs) >>> pair
@@ -304,6 +304,7 @@ instance Each Sexp Sexp Sexp Sexp where
each k (SL.ParenList xs) = SL.ParenList <$> traverse k xs each k (SL.ParenList xs) = SL.ParenList <$> traverse k xs
each k (SL.BracketList xs) = SL.BracketList <$> traverse k xs each k (SL.BracketList xs) = SL.BracketList <$> traverse k xs
each k (SL.BraceList xs) = SL.BraceList <$> traverse k xs each k (SL.BraceList xs) = SL.BraceList <$> traverse k xs
-- each k (SL.Modified m e) = SL.Modified m <$> each k e
each _ e@(SL.Atom _; SL.Modified _ _) = pure e each _ e@(SL.Atom _; SL.Modified _ _) = pure e
stripLocation :: Sexp -> Sexp stripLocation :: Sexp -> Sexp
@@ -348,10 +349,6 @@ unquoteSplicingRecursive xs = [| mconcat $(spans) |]
_ (UnquoteSplicing _) -> False _ (UnquoteSplicing _) -> False
_ _ -> True _ _ -> True
& fmap \case & fmap \case
-- [e@(Unquote _)] ->
-- case unquote e of
-- Just x -> [| [$(x)] |]
-- Nothing -> error "unreachable"
[UnquoteSplicing x] -> [UnquoteSplicing x] ->
[| spliceSexp $(varE (mkName (T.unpack x))) |] [| spliceSexp $(varE (mkName (T.unpack x))) |]
es -> listE $ unquoteRecursive <$> es es -> listE $ unquoteRecursive <$> es
+2 -24
View File
@@ -10,6 +10,7 @@ module Gyehoek.Stack.Syntax
, Lit(..) , Lit(..)
, Obj(..) , Obj(..)
, Imm(..) , Imm(..)
, Hob(..)
, Prim(..) , Prim(..)
, Name , Name
, pattern ValLabel , pattern ValLabel
@@ -34,6 +35,7 @@ import Gyehoek.Scheme.Syntax (Name(..), Lit(..), Prim(..))
import GHC.Exts (IsList(..)) import GHC.Exts (IsList(..))
import Data.List (intersperse) import Data.List (intersperse)
import Control.DeepSeq (NFData) import Control.DeepSeq (NFData)
import Gyehoek.CPS.Syntax (Imm(..), Obj(..), Hob(..), labelName)
newtype Program = MkProgram newtype Program = MkProgram
@@ -79,18 +81,6 @@ data Val
pattern ValLabel :: Name -> Val pattern ValLabel :: Name -> Val
pattern ValLabel x = ValImm (ImmLabel x) pattern ValLabel x = ValImm (ImmLabel x)
data Imm
= ImmInt Int
| ImmBool Bool
| ImmLabel Name
deriving stock (Show, Generic, Data, Eq)
deriving anyclass (NFData)
data Obj
= ObjImm Imm
deriving stock (Show, Generic, Data, Eq)
deriving anyclass (NFData)
--- sexp work --- sexp work
@@ -118,13 +108,6 @@ instance SexpIso Val where
$ With (S.sexpIso >>>) $ With (S.sexpIso >>>)
$ End $ End
instance SexpIso Imm where
sexpIso = match
$ With (S.sexpIso @Int >>>)
$ With (Gyehoek.Sexp.schemeBool >>>)
$ With (labelName >>>)
$ End
instance SexpIso Block where instance SexpIso Block where
sexpIso = with (block >>>) sexpIso = with (block >>>)
where where
@@ -143,8 +126,3 @@ regName :: S.SexpGrammar Name
regName = S.sexpIso @Name >>> Gyehoek.Sexp.prismIso regName = S.sexpIso @Name >>> Gyehoek.Sexp.prismIso
(S.expected "register") (S.expected "register")
(prefixed @Name "%") (prefixed @Name "%")
labelName :: S.SexpGrammar Name
labelName = S.sexpIso @Name >>> Gyehoek.Sexp.prismIso
(S.expected "label")
(prefixed @Name "$")
+16 -2
View File
@@ -57,6 +57,18 @@ stepI e vm (Prim r p) = case evalVal e vm <$> p of
PrimMul x y -> arith_binop (*) x y PrimMul x y -> arith_binop (*) x y
PrimSub x y -> arith_binop (-) x y PrimSub x y -> arith_binop (-) x y
PrimDiv x y -> arith_binop div x y PrimDiv x y -> arith_binop div x y
PrimMakeClosure f env ->
case f of
ObjImm (ImmLabel l) -> ret . ObjHob $ HobClosure l env
_ -> error [i|expected label, got #{f}|]
PrimEnvCode env ->
case env of
ObjHob (HobClosure l _) -> ret . ObjImm . ImmLabel $ l
_ -> error [i|expected closure, got #{env}|]
PrimEnvRef env n ->
case env of
ObjHob (HobClosure _ xs) -> ret $ xs ^?! ix n
_ -> error [i|expected closure, got #{env}|]
x -> error [i|unimplemented prim: #{p}|] x -> error [i|unimplemented prim: #{p}|]
where where
ret v = vm & #registers . at r ?~ v ret v = vm & #registers . at r ?~ v
@@ -69,8 +81,8 @@ 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 (PopCont r) = case vm ^. #kstack of stepI e vm ins@(PopCont r) = case vm ^. #kstack of
[] -> error "empty stack" [] -> error [i|empty cont stack: #{ins}|]
(x:xs) -> vm & #registers . at r ?~ ObjImm (ImmLabel x) (x:xs) -> vm & #registers . at r ?~ ObjImm (ImmLabel x)
& #kstack .~ xs & #kstack .~ xs
@@ -141,3 +153,5 @@ writeObj (ObjImm im) = case im of
ImmBool True -> "#t" ImmBool True -> "#t"
ImmBool False -> "#f" ImmBool False -> "#f"
ImmLabel l -> "#<procedure>" ImmLabel l -> "#<procedure>"
writeObj (ObjHob h) = case h of
HobClosure code env -> "#<procedure>"
+56
View File
@@ -0,0 +1,56 @@
module Gyehoek.Test.CPS.Eval (root) where
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit
import Language.SexpGrammar ()
import Gyehoek.CPS.Syntax (cps, Obj(..), Hob(..), Imm(..))
import Gyehoek.CPS.Eval qualified as Sut
import Data.List (List)
root :: IO TestTree
root = pure . testGroup "cps interpreter" $
[ prim
, testCase "halt with constant" do
evalsTo [ObjImm (ImmInt 123)] [cps|
(continue halt 123)
|]
, testCase "identity cont" do
evalsTo [ObjImm (ImmInt 154)] [cps|
(letrec ((id (κ (x)
(continue halt x))))
(continue id 154))
|]
, testCase "identity function" do
evalsTo [ObjImm (ImmInt 456)] [cps|
(letrec ((id (λ (x ktail)
(continue ktail x))))
(id 456 halt))
|]
, testCase "square" do
evalsTo [ObjImm (ImmInt 81)] [cps|
(letrec ((square (λ (x ktail)
(prim (* x x)
(κ (r) (continue ktail r))))))
(square 9 halt))
|]
]
evalsTo :: HasCallStack => List Obj -> Sut.Program -> Assertion
evalsTo rs p = Sut.evalProgram p @?= rs
prim = testGroup "primitives"
[ testGroup "arith"
[ testCase "basic 1" do
evalsTo [ObjImm (ImmInt 20)] [cps|
(prim (* 4 5)
(κ (x) (continue halt x)))
|]
, testCase "basic 2" do
evalsTo [ObjImm (ImmInt 35)] [cps|
(prim (* 2 16)
(κ (x) (prim (+ x 3)
(κ (r) (continue halt r)))))
|]
]
]
+5 -4
View File
@@ -25,10 +25,11 @@ brokenWasmTests =
brokenStackifyTests :: List String brokenStackifyTests :: List String
brokenStackifyTests = brokenStackifyTests =
[ "adder" []
, "let-fn" -- [ "adder"
, "callcc-nested1" -- requires closure-conversion -- , "let-fn"
] -- , "callcc-nested1" -- requires closure-conversion
-- ]
root :: IO TestTree root :: IO TestTree
root = do root = do
+27
View File
@@ -0,0 +1,27 @@
module Gyehoek.Test.Scheme.Syntax (root) where
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit
import Language.SexpGrammar ()
import Gyehoek.Scheme.Syntax (scm)
import Gyehoek.Scheme.Syntax qualified as Sut
root :: IO TestTree
root = pure . testGroup "scheme syntax" $
[ freeTree
]
freeTree :: TestTree
freeTree = testGroup "free"
[ testCase "lambda" do
Sut.free' [scm|
(lambda (x y z k) (f x b a))
|] @=? ["f","b","a"]
, testCase "exp" do
Sut.free' [scm|
(letrec ((x (lambda (r) (f a y)))
(y (lambda (r b) (f b x))))
(g x y z))
|] @=? ["f","a","g","z"]
]
+4
View File
@@ -5,8 +5,10 @@ import Test.Tasty.Silver.Interactive (defaultMain)
import qualified Gyehoek.Test.Golden import qualified Gyehoek.Test.Golden
import qualified Gyehoek.Test.Sexp import qualified Gyehoek.Test.Sexp
import qualified Gyehoek.Test.CPS.Syntax import qualified Gyehoek.Test.CPS.Syntax
import qualified Gyehoek.Test.Scheme.Syntax
import qualified Gyehoek.Test.Stack.VM import qualified Gyehoek.Test.Stack.VM
import qualified Gyehoek.Test.CPS.Stackify import qualified Gyehoek.Test.CPS.Stackify
import qualified Gyehoek.Test.CPS.Eval
main :: IO () main :: IO ()
@@ -17,7 +19,9 @@ root = testGroup "test" <$> sequenceA
[ Gyehoek.Test.Golden.root [ Gyehoek.Test.Golden.root
, Gyehoek.Test.Sexp.root , Gyehoek.Test.Sexp.root
, Gyehoek.Test.CPS.Syntax.root , Gyehoek.Test.CPS.Syntax.root
, Gyehoek.Test.Scheme.Syntax.root
, Gyehoek.Test.Stack.VM.root , Gyehoek.Test.Stack.VM.root
, Gyehoek.Test.CPS.Stackify.root , Gyehoek.Test.CPS.Stackify.root
, Gyehoek.Test.CPS.Eval.root
] ]