{- | Module : Main Description : Evaluate a BrainFuck program Copyright : (c) Sebastian Galkin, 2014 License : MIT Maintainer : paraseba@gmail.com Stability : experimental Usage: > brainfuck path/to/program.bf It will parse the program and evaluate it by doing I/O to the console. In case of parsing or execution errors it reports them to stderr -} module Main(main) where import HaskBF.Eval ( evalBS, EvalResult ( EvalSuccess, EvalExecError, EvalParseError ) , defaultIOMachine, BFExError, Tape ( Tape ), BFTape, errMsg, errTape, rTape ) import System.Exit ( ExitCode (..), exitWith ) import System.Environment ( getArgs, getProgName ) import qualified Data.ByteString.Lazy as BS main :: IO ExitCode main = getProgram >>= BS.readFile >>= evalBS defaultIOMachine >>= reportResults >>= exitWith {- | Read command line and obtain the path to the program. Display error message - if missing argument -} getProgram :: IO FilePath getProgram = do args <- getArgs if length args /= 1 then do exe <- getProgName error $ "Usage: " ++ exe ++ " filepath" else return $ head args -- | Report result of program parsing and evaluation reportResults :: EvalResult -> IO ExitCode reportResults (EvalSuccess _) = return ExitSuccess reportResults (EvalParseError parseError) = do putStrLn "Error parsing program:" print parseError return $ ExitFailure 1 reportResults (EvalExecError err) = do putStrLn $ "Error evaluating program: " ++ errMsg err putStrLn $ "Current tape value: " ++ (show . rTape . errTape) err putStrLn $ "Consumed tape: " ++ (showConsumed . errTape) err return $ ExitFailure 2 {- | Use heuristic to display tape state. It estimates consumed right tape by - calling 'consumed' -} showConsumed :: BFTape -> String showConsumed (Tape _ _ r) = "[" ++ concatMap ( (++ ",") . show ) (consumed r ++ [0, 0, 0]) ++ "..." -- | Return consumed tape by assuming that it is unused after 10 zeros. consumed :: (Eq a, Num a) => [a] -> [a] consumed (0 : 0 : 0 : 0 : 0 : 0 : 0 : 0 : 0 : 0 : _) = [] consumed (x : xs) = x : consumed xs