module Main where
import Control.Monad.Trans
import Control.Monad.State
import Control.Exception
import System.Environment
import System.Console.Haskeline
import Text.ParserCombinators.Parsec hiding (try)
import Format
import Interpreter
-- | A filename is a string containing the directory path and
-- the real name of the file.
type Filename = String
-- Lambda interpreter
-- The actions of the interpreter are written here. It allows to execute normal
-- actions (bindings and evaluation), and interpreter specific actions, as
-- "quit" or "load".
-- | Runs the interpreter with default settings and an empty context.
main :: IO ()
main = do
args <- getArgs
case args of
[] -> runInputT defaultSettings ( outputStrLn initialText
>> interpreterLoop defaultOptions emptyContext
)
[filename] -> executeFile filename
_ -> putStrLn "Wrong number of arguments"
-- | Interpreter awaiting for an instruction.
interpreterLoop :: InterpreterOptions -> Context -> InputT IO ()
interpreterLoop options context = do
minput <- getInputLine promptText
let interpreteraction =
case minput of
Nothing -> Quit
Just "" -> EmptyLine
Just input -> case parse interpreteractionParser "" input of
Left _ -> Error
Right a -> a
case interpreteraction of
EmptyLine -> interpreterLoop options context
Quit -> return ()
Error -> do
outputStr formatFormula
outputStrLn "Unknown command"
outputStr end
interpreterLoop options context
SetVerbose -> do
outputStrLn $
formatFormula ++
"verbose mode: " ++ if getVerbose options then "off" else "on" ++
end
interpreterLoop (changeVerbose options) context
SetColors -> interpreterLoop (changeColor options) context
Help -> outputStr helpText >> interpreterLoop options context
Load filename -> do
maybeloadfile <- lift $ loadFile filename
case maybeloadfile of
Nothing -> do
outputStrLn "Error loading file"
interpreterLoop options context
Just actions -> case runState (multipleAct actions) context of
(output, ccontext) -> do
outputActions options output
interpreterLoop options ccontext
Interpret action -> case runState (act action) context of
(output, ccontext) -> do
outputActions options output
interpreterLoop options ccontext
-- | Outputs results from actions. Given a list of options and outputs,
-- formats and prints them in console.
outputActions :: InterpreterOptions -> [String] -> InputT IO ()
outputActions options output = do
outputStr formatFormula
mapM_ (outputStr . format) output
outputStr end
where
format :: String -> String
format "" = ""
format s
| not (getVerbose options) = (++"\n") . last . lines $ s
| otherwise = s
-- Loading and reading files
-- | Loads the given filename and returns the complete list of actions.
-- Returns Nothing if there is an error reading or parsing the file.
loadFile :: String -> IO (Maybe [Action])
loadFile filename = do
putStrLn filename
input <- try $ (readFile filename) :: IO (Either IOException String)
case input of
Left _ -> return Nothing
Right inputs -> do
let parsing = map (parse actionParser "") $ filter (/="") $ lines inputs
let actions = map (\x -> case x of
Left _ -> Nothing
Right a -> Just a) parsing
return $ sequence actions
-- | Executes the commands inside a file. A .mkr file can contain a sequence of
-- expressions and variable bindings, and it is interpreted sequentially.
executeFile :: Filename -> IO ()
executeFile filename = do
maybeloadfile <- loadFile filename
case maybeloadfile of
Nothing -> putStrLn "Error loading file"
Just actions -> case runState (multipleAct actions) emptyContext of
(outputs, _) -> mapM_ (putStr . format) outputs
where
format :: String -> String
format "" = ""
format s = (++"\n") . last . lines $ s