DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / haskell / step2_eval.hs
CommitLineData
5400d4bf 1import System.IO (hFlush, stdout)
87cb47ec 2import Control.Monad ((<=<))
53db2d63 3import Control.Monad.Except (runExceptT)
87cb47ec 4import Control.Monad.Trans (liftIO)
b76aa73b 5import qualified Data.Map as Map
b76aa73b 6
219f15b7 7import Readline (addHistory, readline, load_history)
b76aa73b
JM
8import Types
9import Reader (read_str)
10import Printer (_pr_str)
11
12-- read
6116c2d5 13
5400d4bf 14mal_read :: String -> IOThrows MalVal
6116c2d5 15mal_read = read_str
b76aa73b
JM
16
17-- eval
b76aa73b 18
6116c2d5
NB
19-- eval_ast is replaced with pattern matching.
20
21apply_ast :: [MalVal] -> IOThrows MalVal
22
23apply_ast [] = return $ toList []
24
25apply_ast ast = do
26 evd <- mapM eval ast
27 case evd of
28 MalFunction {fn=f} : args -> f args
87cb47ec 29 _ -> throwStr . (++) "invalid apply: " =<< liftIO (Printer._pr_str True (toList ast))
6116c2d5
NB
30
31eval :: MalVal -> IOThrows MalVal
32eval (MalSymbol sym) = do
33 case Map.lookup sym repl_env of
34 Nothing -> throwStr $ "'" ++ sym ++ "' not found"
35 Just val -> return val
36eval (MalSeq _ (Vect False) xs) = apply_ast xs
37eval (MalSeq m (Vect True) xs) = MalSeq m (Vect True) <$> mapM eval xs
38eval (MalHashMap m xs) = MalHashMap m <$> mapM eval xs
39eval ast = return ast
b76aa73b
JM
40
41-- print
6116c2d5 42
87cb47ec
NB
43mal_print :: MalVal -> IOThrows String
44mal_print = liftIO. Printer._pr_str True
b76aa73b
JM
45
46-- repl
6116c2d5
NB
47
48add :: Fn
c150ec41 49add [MalNumber a, MalNumber b] = return $ MalNumber $ a + b
5400d4bf 50add _ = throwStr $ "illegal arguments to +"
6116c2d5
NB
51
52sub :: Fn
c150ec41 53sub [MalNumber a, MalNumber b] = return $ MalNumber $ a - b
5400d4bf 54sub _ = throwStr $ "illegal arguments to -"
6116c2d5
NB
55
56mult :: Fn
c150ec41 57mult [MalNumber a, MalNumber b] = return $ MalNumber $ a * b
5400d4bf 58mult _ = throwStr $ "illegal arguments to *"
6116c2d5
NB
59
60divd :: Fn
c150ec41 61divd [MalNumber a, MalNumber b] = return $ MalNumber $ a `div` b
5400d4bf 62divd _ = throwStr $ "illegal arguments to /"
b76aa73b
JM
63
64repl_env :: Map.Map String MalVal
fa9a9758
JM
65repl_env = Map.fromList [("+", _func add),
66 ("-", _func sub),
67 ("*", _func mult),
68 ("/", _func divd)]
b76aa73b 69
5400d4bf 70rep :: String -> IOThrows String
87cb47ec 71rep = mal_print <=< eval <=< mal_read
b76aa73b
JM
72
73repl_loop :: IO ()
74repl_loop = do
fa9a9758
JM
75 line <- readline "user> "
76 case line of
77 Nothing -> return ()
78 Just "" -> repl_loop
79 Just str -> do
219f15b7 80 addHistory str
53db2d63 81 res <- runExceptT $ rep str
5400d4bf 82 out <- case res of
87cb47ec 83 Left mv -> (++) "Error: " <$> liftIO (Printer._pr_str True mv)
5400d4bf 84 Right val -> return val
fa9a9758 85 putStrLn out
5400d4bf 86 hFlush stdout
fa9a9758 87 repl_loop
b76aa73b 88
6116c2d5
NB
89_func :: Fn -> MalVal
90_func f = MalFunction {fn=f, f_ast=Nil, f_params=[], macro=False, meta=Nil}
91
92main :: IO ()
fa9a9758
JM
93main = do
94 load_history
6116c2d5 95
fa9a9758 96 repl_loop