{---------------------------------------------------------------------------- What is the Meaning of These Constant Interruptions? Graham Hutton and Joel Wright University of Nottingham March 2007 Instructions: 1) Download QuickCheck.hs from the web 2) Load the present file into Hugs 3) Enter "quickCheck correct" 4) See that 100 tests are passed! ----------------------------------------------------------------------------} import List import QuickCheck ----------------------------------------------------------------------------- -- Type declarations ----------------------------------------------------------------------------- data Expr = Val Int | Throw | Add Expr Expr | Seqn Expr Expr | Catch Expr Expr | Block Expr | Unblock Expr deriving (Show, Eq, Ord) data Status = B | U deriving (Show, Eq, Ord) type Stack = [Item] data Item = VAL Int | HAN Code | INT Status deriving (Show, Eq, Ord) type Code = [Op] data Op = PUSH Int | THROW | ADD | POP | MARK Code | UNMARK | SET Status | RESET deriving (Show, Eq, Ord) ----------------------------------------------------------------------------- -- Auxiliary functions on trees ----------------------------------------------------------------------------- data Tree a = Node a [Tree a] deriving (Show, Eq, Ord) leaves :: Tree a -> [a] leaves (Node x []) = [x] leaves (Node _ ts) = concat (map leaves ts) unfold :: (a -> [a]) -> a -> Tree a unfold f x = Node x [unfold f x' | x' <- f x] ----------------------------------------------------------------------------- -- Expression generator for quickcheck ----------------------------------------------------------------------------- instance Arbitrary Expr where arbitrary = sized arbExpr arbExpr :: Int -> Gen Expr arbExpr 0 = frequency [(6, do n <- arbitrary return (Val n)), (1, return Throw)] arbExpr n = frequency [(6, arbExpr 0), (3, do x <- arbExpr' y <- arbExpr' return (Add x y)), (3, do x <- arbExpr' y <- arbExpr' return (Seqn x y)), (3, do x <- arbExpr' y <- arbExpr' return (Catch x y)), (3, do x <- arbExpr (n-1) return (Block x)), (3, do x <- arbExpr (n-1) return (Unblock x))] where arbExpr' = arbExpr (n `div` 2) ----------------------------------------------------------------------------- -- Evaluation semantics ----------------------------------------------------------------------------- semantics :: Expr -> [Expr] semantics e = bigstep e U bigstep :: Expr -> Status -> [Expr] bigstep e B = eval e B bigstep e U = eval e U ++ [Throw] eval :: Expr -> Status -> [Expr] eval (Val n) i = [Val n] eval (Throw) i = [Throw] eval (Block x) i = bigstep x B eval (Unblock x) i = bigstep x U eval (Add x y) i = [Val (n+m) | Val n <- bigstep x i, Val m <- bigstep y i] ++ [Throw | Throw <- bigstep x i] ++ [Throw | Val n <- bigstep x i, Throw <- bigstep y i] eval (Seqn x y) i = [v | Val n <- bigstep x i, v <- bigstep y i] ++ [Throw | Throw <- bigstep x i] eval (Catch x y) i = [Val n | Val n <- bigstep x i] ++ [v | Throw <- bigstep x i, v <- bigstep y i] ----------------------------------------------------------------------------- -- Virtual machine ----------------------------------------------------------------------------- data State = TRIP Code Status Stack | PAIR Status Stack deriving (Show, Eq, Ord) machine :: State -> [State] machine s = leaves (unfold smallstep s) smallstep :: State -> [State] smallstep (TRIP ops i s) | null ops = [] | i == U = [trans (TRIP ops i s), PAIR U s] | otherwise = [trans (TRIP ops i s)] smallstep (PAIR i s) | null s = [] | otherwise = [trans (PAIR i s)] trans :: State -> State trans (TRIP (PUSH n : ops) i s) = TRIP ops i (VAL n : s) trans (TRIP (THROW : ops) i s) = PAIR i s trans (TRIP (ADD : ops) i (VAL m : VAL n : s)) = TRIP ops i (VAL (n+m) : s) trans (TRIP (POP : ops) i (VAL _ : s)) = TRIP ops i s trans (TRIP (MARK ops' : ops) i s) = TRIP ops i (HAN ops' : s) trans (TRIP (UNMARK : ops) i (x : HAN _ : s)) = TRIP ops i (x:s) trans (TRIP (SET i' : ops) i s) = TRIP ops i' (INT i : s) trans (TRIP (RESET : ops) _ (x : INT i' : s)) = TRIP ops i' (x : s) trans (PAIR i (VAL _ : s)) = PAIR i s trans (PAIR _ (INT i' : s)) = PAIR i' s trans (PAIR i (HAN ops : s)) = TRIP ops i s ----------------------------------------------------------------------------- -- Compiler ----------------------------------------------------------------------------- comp :: Expr -> Code -> Code comp (Val n) ops = PUSH n : ops comp (Throw) ops = THROW : ops comp (Add x y) ops = comp x (comp y (ADD : ops)) comp (Seqn x y) ops = comp x (POP : comp y ops) comp (Catch x y) ops = MARK (comp y ops) : comp x (UNMARK : ops) comp (Block x) ops = SET B : comp x (RESET : ops) comp (Unblock x) ops = SET U : comp x (RESET : ops) ----------------------------------------------------------------------------- -- Compiler correctness ----------------------------------------------------------------------------- correct :: Expr -> Bool correct e = equiv (semantics e) (machine s) where s = TRIP (comp e []) U [] equiv :: [Expr] -> [State] -> Bool equiv es sts = sort (nub es) == sort (nub (map unload sts)) unload :: State -> Expr unload (TRIP [] _ [VAL n]) = Val n unload (PAIR _ []) = Throw -----------------------------------------------------------------------------