diff --git a/app/Main.hs b/app/Main.hs index 6ab71ef..f2f154e 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -7,9 +7,12 @@ import LispParser import Evaluator import LispEnv import Expressions +import System.Environment (getArgs) +import System.Exit (exitSuccess, exitFailure, exitWith, ExitCode (ExitFailure)) +import Control.Exception (IOException, catch) -main :: IO () -main = runInputT defaultSettings (loop defaultEnv) +runRepl :: LispEnv -> IO () +runRepl env = runInputT defaultSettings (loop env) where loop :: LispEnv -> InputT IO () loop env = do @@ -30,3 +33,42 @@ main = runInputT defaultSettings (loop defaultEnv) (Left err) -> outputStrLn err >> return env (_, lo) -> outputStrLn ("**Error: Invalid syntax near: " ++ lo ++ "**") >> return env + +evalFiles :: [String] -> LispEnv -> Either String (Atom, LispEnv) +evalFiles [x] env = evalFile x env +evalFiles (x:xs) env = do + (ret, nEnv) <- evalFile x env + evalFiles xs nEnv +evalFiles [] env = undefined + +evalFile :: String -> LispEnv -> Either String (Atom, LispEnv) +evalFile file env = + case parse pLisp file of + (Just statements, []) -> evalStatements statements env + (_, lo) -> Left $ "**Parse error near " ++ lo ++ "**" + +evalStatements :: [Statement] -> LispEnv -> Either String (Atom, LispEnv) +evalStatements [x] env = eval x env +evalStatements (x:xs) env = do + (ret, nEnv) <- eval x env + evalStatements xs nEnv +evalStatements [] env = Right (ANothing, env) + + +main :: IO () +main = do + (args, repl) <- parseArgs <$> getArgs + files <- catch (sequence $ readFile <$> args) handler + case evalFiles files defaultEnv of + Right (ret, env) -> if repl then runRepl env else print ret + Left err -> putStrLn err >> exitWith (ExitFailure 84) + where + handler :: IOException -> IO [String] + handler e = putStrLn ("Error: " ++ show e) >> exitWith (ExitFailure 84) + + parseArgs :: [String] -> ([String], Bool) + parseArgs ("-i":xs) = let (files, _) = parseArgs xs + in (files, True) + parseArgs (x:xs) = let (files, repl) = parseArgs xs + in (x:files, repl) + parseArgs [] = ([], False) \ No newline at end of file diff --git a/example/fact.lisp b/example/fact.lisp new file mode 100644 index 0000000..781a302 --- /dev/null +++ b/example/fact.lisp @@ -0,0 +1,3 @@ +(define (fact x) + (cond ((eq? x 1) 1) + (#t (* x (fact (- x 1)))))) diff --git a/src/LispParser.hs b/src/LispParser.hs index dddcbac..0e73b1a 100644 --- a/src/LispParser.hs +++ b/src/LispParser.hs @@ -3,7 +3,7 @@ module LispParser where import BasicParser ( Parser, pCharIf, pUntil, pInt, pFloat, tokenify, pToken, pString ) import Expressions ( SExpr(..), Atom(..), Statement(..) ) -import Control.Applicative ( Alternative(some, (<|>)) ) +import Control.Applicative ( Alternative(some, many, (<|>)) ) _pAtom :: Parser Atom _pAtom = AInt <$> pInt @@ -64,4 +64,4 @@ pStatement = pCharIf (== '(') <|> Atom <$> pAtom pLisp :: Parser [Statement] -pLisp = some $ tokenify pStatement +pLisp = many $ tokenify pStatement diff --git a/src/Maths.hs b/src/Maths.hs index cd962ab..0c2eb5c 100644 --- a/src/Maths.hs +++ b/src/Maths.hs @@ -51,7 +51,7 @@ evalMult [] env = Right (AInt 1, env) evalDiv :: [Statement] -> LispEnv -> Either String (Atom, LispEnv) evalDiv [_, Atom (AInt 0)] env = Left "**Error: Division by 0 is undefined.**" evalDiv [_, Atom (AFloat 0)] env = Left "**Error: Division by 0 is undefined.**" -evalDiv [Atom (AInt f), Atom (AInt s)] env = Right (AInt (f `div` s), env) +evalDiv [Atom (AInt f), Atom (AInt s)] env = Right (AInt (f `quot` s), env) evalDiv [Atom (AFloat f), Atom (AFloat s)] env = Right (AFloat (f / s), env) evalDiv [Atom (AFloat f), Atom (AInt s)] env = Right (AFloat (f / fromIntegral s), env) evalDiv [Atom (AInt f), Atom (AFloat s)] env = Right (AFloat (fromIntegral f / s), env)