114 lines
2.9 KiB
Haskell
114 lines
2.9 KiB
Haskell
{-# LANGUAGE OverloadedLists #-}
|
|
module Gyehoek.Test.Stack.VM where
|
|
|
|
import Test.Tasty (TestTree, testGroup)
|
|
import Test.Tasty.HUnit
|
|
import Gyehoek.Stack.Syntax
|
|
import Gyehoek.Stack.VM qualified as Sut
|
|
import Data.List (List)
|
|
import Gyehoek.Jalmot
|
|
import Gyehoek.Prelude (i)
|
|
|
|
|
|
evalsTo :: List Obj -> Program -> Assertion
|
|
evalsTo rs p = runJalmotUnsafe (Sut.eval p) @?= rs
|
|
|
|
test_root = testGroup "stack machine"
|
|
[ testCase "immediate halt" do
|
|
evalsTo [] [stkP|
|
|
(define $start
|
|
(return 0))
|
|
|]
|
|
, testCase "lit int" do
|
|
evalsTo [ObjImm (ImmInt 3)] [stkP|
|
|
(define $start
|
|
(push! 3)
|
|
(return 1))
|
|
|]
|
|
, testCase "non-tail identity function" do
|
|
evalsTo [ObjImm (ImmInt 123)] [stkP|
|
|
(define $id
|
|
(return 1))
|
|
(define $c
|
|
(return 1))
|
|
(define $start
|
|
(push! $c)
|
|
(push! $id)
|
|
(push! 123)
|
|
(call 1))
|
|
|]
|
|
, testCase "tail identity function" do
|
|
evalsTo [ObjImm (ImmInt 123)] [stkP|
|
|
(define $id
|
|
(return 1))
|
|
(define $start
|
|
(push! $id)
|
|
(push! 123)
|
|
(tail-call 1))
|
|
|]
|
|
, testCase "return constant" do
|
|
evalsTo [ObjImm (ImmInt 123)] [stkP|
|
|
(define $start
|
|
(push! $silly)
|
|
(tail-call 1))
|
|
(define $silly
|
|
(push! 123)
|
|
(return 1))
|
|
|]
|
|
, testCase "return multiple" do
|
|
evalsTo [ObjImm (ImmInt n) | n <- [1,2,3]] [stkP|
|
|
(define $start
|
|
(push! 3)
|
|
(push! 2)
|
|
(push! 1)
|
|
(return 3))
|
|
|]
|
|
, testCase "return none" do
|
|
evalsTo [] [stkP|
|
|
(define $start
|
|
(return 0))
|
|
|]
|
|
, testCase "square" do
|
|
evalsTo [ObjImm (ImmInt 16)] [stkP|
|
|
(define $start
|
|
(push! $square)
|
|
(push! 4)
|
|
(tail-call 1))
|
|
(define $square
|
|
(pop! %x)
|
|
(prim %x2 (* %x %x))
|
|
(push! %x2)
|
|
(return 1))
|
|
|]
|
|
, testGroup "factorial"
|
|
let
|
|
hsfac (n :: Int) = foldr @List (*) (1) [1..n]
|
|
fac (n :: Int) = [stkP|
|
|
(define $start
|
|
(push! $fac)
|
|
(push! #{n})
|
|
(tail-call 1))
|
|
(define $fac
|
|
(load %n 0)
|
|
(prim %x0 (zero? %n))
|
|
(if %x0
|
|
(then (push! 1)
|
|
(return 1))
|
|
(else (prim %x1 (- %n 1))
|
|
(push! $fac-c0)
|
|
(push! $fac)
|
|
(push! %x1)
|
|
(call 1))))
|
|
(define $fac-c0
|
|
(pop! %x2)
|
|
(pop! %n)
|
|
(prim %x3 (* %n %x2))
|
|
(push! %x3)
|
|
(return 1))
|
|
|]
|
|
mkcase n = testCase [i|#{n}|] do
|
|
evalsTo [ObjImm . ImmInt $ hsfac n] $ fac n
|
|
-- 20 is the greatest `n` for which n! ≤ maxBount @Int
|
|
in [ mkcase n | n <- [0,1,6,20] ]
|
|
]
|