Implement basic mima-run functionality
Bugs fixed: - Print correct file name when load/save error occurs - Correctly identify invalid file formats
This commit is contained in:
parent
362025c8df
commit
6b81fd67b4
5 changed files with 52 additions and 16 deletions
|
|
@ -1,10 +1,31 @@
|
||||||
module Main where
|
module Main where
|
||||||
|
|
||||||
import Options.Applicative
|
import Control.Monad.IO.Class
|
||||||
|
import qualified Data.Text.IO as T
|
||||||
|
import Options.Applicative
|
||||||
|
|
||||||
import Mima.MimaRun.Options
|
import Mima.Format
|
||||||
|
import Mima.MimaRun.Options
|
||||||
|
import Mima.Run
|
||||||
|
import Mima.Vm.State
|
||||||
|
import Mima.Vm.Storage
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = runOrExit 2 $ do
|
||||||
opts <- execParser parserInfo
|
opts <- liftIO $ execParser parserInfo
|
||||||
putStrLn $ "The options are: " ++ show opts
|
initialState <- loadMimaState $ inputFile opts
|
||||||
|
finalState <- liftIO $ case steps opts of
|
||||||
|
Nothing -> do
|
||||||
|
let (finalState, abortReason, stepsMade) = execute initialState
|
||||||
|
putStrLn $ "Stopped after " ++ show stepsMade ++ " steps, reason:"
|
||||||
|
T.putStrLn $ toText abortReason
|
||||||
|
pure finalState
|
||||||
|
Just n -> do
|
||||||
|
let (finalState, mAbortReason, stepsMade) = executeN n initialState
|
||||||
|
putStrLn $ "Stopped after " ++ show stepsMade ++ " steps, reason:"
|
||||||
|
case mAbortReason of
|
||||||
|
Nothing -> putStrLn "Ran out of steps"
|
||||||
|
Just abortReason -> T.putStrLn $ toText abortReason
|
||||||
|
pure finalState
|
||||||
|
liftIO $ putStrLn ""
|
||||||
|
liftIO $ print finalState
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,16 @@ module Mima.MimaRun.Options
|
||||||
, parserInfo
|
, parserInfo
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Options.Applicative
|
import Options.Applicative
|
||||||
|
|
||||||
data Options = Options
|
data Options = Options
|
||||||
{ inputFile :: FilePath
|
{ inputFile :: FilePath
|
||||||
, steps :: Maybe Integer
|
, steps :: Maybe Integer
|
||||||
} deriving (Show)
|
} deriving (Show)
|
||||||
|
|
||||||
parser :: Parser Options
|
parser :: Parser Options
|
||||||
parser = Options
|
parser = Options
|
||||||
<$> strOption
|
<$> strArgument
|
||||||
( help "The .mima file to use"
|
( help "The .mima file to use"
|
||||||
<> metavar "INPUTFILE"
|
<> metavar "INPUTFILE"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ module Mima.Run
|
||||||
-- * The 'Run' monad
|
-- * The 'Run' monad
|
||||||
Run
|
Run
|
||||||
, run
|
, run
|
||||||
|
, runOrExit
|
||||||
, throw
|
, throw
|
||||||
, catch
|
, catch
|
||||||
, handle
|
, handle
|
||||||
|
|
@ -18,8 +19,10 @@ module Mima.Run
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
import Control.Monad.Trans.Except
|
import Control.Monad.Trans.Except
|
||||||
import qualified Data.ByteString.Lazy as BS
|
import qualified Data.ByteString.Lazy as BS
|
||||||
|
import Data.Maybe
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.IO as T
|
import qualified Data.Text.IO as T
|
||||||
|
import System.Exit
|
||||||
import System.IO.Error
|
import System.IO.Error
|
||||||
|
|
||||||
newtype Run a = Run (ExceptT T.Text IO a)
|
newtype Run a = Run (ExceptT T.Text IO a)
|
||||||
|
|
@ -28,6 +31,16 @@ newtype Run a = Run (ExceptT T.Text IO a)
|
||||||
run :: Run a -> IO (Either T.Text a)
|
run :: Run a -> IO (Either T.Text a)
|
||||||
run (Run e) = runExceptT e
|
run (Run e) = runExceptT e
|
||||||
|
|
||||||
|
runOrExit :: Int -> Run () -> IO ()
|
||||||
|
runOrExit exitCode r = do
|
||||||
|
result <- run r
|
||||||
|
case result of
|
||||||
|
Right () -> pure ()
|
||||||
|
Left e -> do
|
||||||
|
putStrLn "Encountered an exception:"
|
||||||
|
T.putStrLn e
|
||||||
|
exitWith $ ExitFailure exitCode
|
||||||
|
|
||||||
throw :: T.Text -> Run a
|
throw :: T.Text -> Run a
|
||||||
throw = Run . throwE
|
throw = Run . throwE
|
||||||
|
|
||||||
|
|
@ -43,8 +56,10 @@ isRelevantError e = isAlreadyInUseError e || isDoesNotExistError e || isPermissi
|
||||||
formatRelevantError :: IOError -> Maybe T.Text
|
formatRelevantError :: IOError -> Maybe T.Text
|
||||||
formatRelevantError e
|
formatRelevantError e
|
||||||
| isRelevantError e = Just $ T.pack $
|
| isRelevantError e = Just $ T.pack $
|
||||||
"Can't open file " <> ioeGetLocation e <> ": " <> ioeGetErrorString e
|
"Can't open file " <> fileName <> ": " <> ioeGetErrorString e
|
||||||
| otherwise = Nothing
|
| otherwise = Nothing
|
||||||
|
where
|
||||||
|
fileName = fromMaybe "<unknown>" $ ioeGetFileName e
|
||||||
|
|
||||||
protect :: IO a -> Run a
|
protect :: IO a -> Run a
|
||||||
protect m = do
|
protect m = do
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ module Mima.Vm.State
|
||||||
, basicState
|
, basicState
|
||||||
, AbortReason(..)
|
, AbortReason(..)
|
||||||
, step
|
, step
|
||||||
, run
|
, execute
|
||||||
, runN
|
, executeN
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
|
|
@ -157,16 +157,16 @@ step ms = do
|
||||||
(SmallInstruction so lv) -> doSmallOpcode so lv ms'
|
(SmallInstruction so lv) -> doSmallOpcode so lv ms'
|
||||||
(LargeInstruction lo sv) -> doLargeOpcode lo sv ms'
|
(LargeInstruction lo sv) -> doLargeOpcode lo sv ms'
|
||||||
|
|
||||||
run :: MimaState -> (MimaState, AbortReason, Integer)
|
execute :: MimaState -> (MimaState, AbortReason, Integer)
|
||||||
run = helper 0
|
execute = helper 0
|
||||||
where
|
where
|
||||||
helper completed s =
|
helper completed s =
|
||||||
case step s of
|
case step s of
|
||||||
Left e -> (s, e, completed)
|
Left e -> (s, e, completed)
|
||||||
Right s' -> helper (completed + 1) s'
|
Right s' -> helper (completed + 1) s'
|
||||||
|
|
||||||
runN :: Integer -> MimaState -> (MimaState, Maybe AbortReason, Integer)
|
executeN :: Integer -> MimaState -> (MimaState, Maybe AbortReason, Integer)
|
||||||
runN n = helper 0
|
executeN n = helper 0
|
||||||
where
|
where
|
||||||
helper completed s =
|
helper completed s =
|
||||||
if completed >= n
|
if completed >= n
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ loadMimaState :: FilePath -> Run MimaState
|
||||||
loadMimaState path = do
|
loadMimaState path = do
|
||||||
bs <- readFileBS path
|
bs <- readFileBS path
|
||||||
case B.decodeOrFail bs of
|
case B.decodeOrFail bs of
|
||||||
Right ("", 0, a) -> pure a
|
Right ("", _, a) -> pure a
|
||||||
Right _ -> throw "invalid file format"
|
Right _ -> throw "invalid file format"
|
||||||
Left (_, _, e) -> throw $ T.pack e
|
Left (_, _, e) -> throw $ T.pack e
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue