{-# LANGUAGE FlexibleContexts, TypeOperators #-}
module Test.IOSpec.Teletype
(
Teletype
, getChar
, putChar
, putStr
, putStrLn
, getLine
)
where
import Prelude hiding (getChar, putChar, putStr, putStrLn, getLine)
import Control.Monad (forM_)
import Test.IOSpec.Types
import Test.IOSpec.VirtualMachine
data Teletype a =
GetChar (Char -> a)
| PutChar Char a
instance Functor Teletype where
fmap f (GetChar tt) = GetChar (f . tt)
fmap f (PutChar c tt) = PutChar c (f tt)
getChar :: (:<:) Teletype f => IOSpec f Char
getChar = inject (GetChar return)
putChar :: (Teletype :<: f) => Char -> IOSpec f ()
putChar c = inject (PutChar c (return ()))
instance Executable Teletype where
step (GetChar f) = do
c <- readChar
return (Step (f c))
step (PutChar c a) = do
printChar c
return (Step a)
putStr :: (Teletype :<: f) => String -> IOSpec f ()
putStr str = forM_ str putChar
putStrLn :: (Teletype :<: f) => String -> IOSpec f ()
putStrLn str = putStr str >> putChar '\n'
getLine :: (Teletype :<: f) => IOSpec f String
getLine = do
c <- getChar
if c == '\n'
then return []
else getLine >>= \line -> return (c : line)