aboutsummaryrefslogtreecommitdiff
path: root/app/Main.hs
blob: 01cf1e1d4b07f3f9ccfd10401bf8d321f23426a5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
module Main where

import Control.Concurrent (threadDelay)
import Data.Maybe (fromMaybe)
import Data.Monoid
import System.IO (hFlush, stdout, isEOF)

import Turing.Machine
import Turing.Examples

data Cmd = Exit | Run | Print | Help | Wait (Maybe Int) | Step Int
data SimResult = Ok String | Error String deriving Show
data SimState  = SimState { stMConf :: Config
                          , stStopped :: Maybe SimResult
                          , stWait :: Int }

mkSimState :: Config -> SimState
mkSimState conf = SimState conf Nothing 0

stFailed, stUserStopped :: SimState -> SimState
stFailed st = st { stStopped = Just (Error "Failed to do transition") }
stUserStopped st = st { stStopped = Just (Ok "Stopped by user") }

sim :: Machine -> Maybe Config -> IO SimResult
sim m conf = prompt $ mkSimState (fromMaybe (mkConfig [SymSpace]) conf)
    where
      prompt st = do
        putStr "> "
        hFlush stdout
        eof <- isEOF
        if eof then return (Ok "Stopped by user")
        else do
          line <- getLine
          case parseCmd (words line) of
            Just cmd -> do st' <- execCmd st cmd
                           case stStopped st' of
                             Just how -> return how
                             Nothing  -> prompt st'
            Nothing  -> putStrLn "Unknown command (type 'h' for help)" >>
                        prompt st

      doSteps :: SimState -> Maybe Int -> IO SimState
      doSteps st stop = if state (stMConf st) `elem` finals m || stop == Just 0
                        then return st
                        else case step (stMConf st) (delta m) of
                               Nothing -> return $ stFailed st
                               Just c' -> do print c'
                                             threadDelay (stWait st)
                                             let st' = st { stMConf = c' }
                                             doSteps st' (fmap pred stop)

      execCmd :: SimState -> Cmd -> IO SimState
      execCmd st cmd =
          case cmd of
            Exit -> return (stUserStopped st)
            Run -> doSteps st Nothing
            Print -> print (stMConf st) >> return st
            Help -> printHelp >> return st
            Wait Nothing  -> putStrLn ("t = " ++ show (stWait st) ++ " µs") >>
                             return st
            Wait (Just t) -> let t' = 1000 * t in
                             putStrLn ("t = " ++ show t' ++ " µs") >>
                             return (st { stWait = t' })
            Step n -> doSteps st (Just n)

      parseCmd          :: [String] -> Maybe Cmd
      parseCmd []       = Just (Step 1)
      parseCmd ["q"]    = Just Exit
      parseCmd ["r"]    = Just Run
      parseCmd ["p"]    = Just Print
      parseCmd ["h"]    = Just Help
      parseCmd ["?"]    = Just Help
      parseCmd ["t"]    = Just (Wait Nothing)
      parseCmd ["t", n] = Just (Wait (Just (read n)))
      parseCmd ["s", n] = Just (Step (read n))
      parseCmd _        = Nothing

      printHelp :: IO ()
      printHelp = mapM_ (putStrLn . showCmd) cmds
          where showCmd (cmd, desc) =
                    cmd ++ replicate (gap - length cmd) ' ' ++ " - " ++ desc
                cmds = [("q","exit the simulation")
                       ,("r","run the simulation until it finishes")
                       ,("p","print the machine")
                       ,("h","print this help")
                       ,("t [<n>]","print/set the current time interval")
                       ,("s <n>","steps <n> times without prompting")]
                gap = maximum (map (length . fst) cmds)

main :: IO ()
main = do
  let example = mconcat [mWriteStr "_aaaaaa_aaa", mInit, mSub, mDecr]
  print example
  print =<< sim example Nothing