Commit | Line | Data |
---|---|---|
5400d4bf | 1 | import System.IO (hFlush, stdout) |
87cb47ec | 2 | import Control.Monad ((<=<)) |
53db2d63 | 3 | import Control.Monad.Except (runExceptT) |
87cb47ec | 4 | import Control.Monad.Trans (liftIO) |
b76aa73b | 5 | import qualified Data.Map as Map |
b76aa73b | 6 | |
219f15b7 | 7 | import Readline (addHistory, readline, load_history) |
b76aa73b JM |
8 | import Types |
9 | import Reader (read_str) | |
10 | import Printer (_pr_str) | |
11 | ||
12 | -- read | |
6116c2d5 | 13 | |
5400d4bf | 14 | mal_read :: String -> IOThrows MalVal |
6116c2d5 | 15 | mal_read = read_str |
b76aa73b JM |
16 | |
17 | -- eval | |
b76aa73b | 18 | |
6116c2d5 NB |
19 | -- eval_ast is replaced with pattern matching. |
20 | ||
21 | apply_ast :: [MalVal] -> IOThrows MalVal | |
22 | ||
23 | apply_ast [] = return $ toList [] | |
24 | ||
25 | apply_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 | |
31 | eval :: MalVal -> IOThrows MalVal | |
32 | eval (MalSymbol sym) = do | |
33 | case Map.lookup sym repl_env of | |
34 | Nothing -> throwStr $ "'" ++ sym ++ "' not found" | |
35 | Just val -> return val | |
36 | eval (MalSeq _ (Vect False) xs) = apply_ast xs | |
37 | eval (MalSeq m (Vect True) xs) = MalSeq m (Vect True) <$> mapM eval xs | |
38 | eval (MalHashMap m xs) = MalHashMap m <$> mapM eval xs | |
39 | eval ast = return ast | |
b76aa73b JM |
40 | |
41 | ||
6116c2d5 | 42 | |
87cb47ec NB |
43 | mal_print :: MalVal -> IOThrows String |
44 | mal_print = liftIO. Printer._pr_str True | |
b76aa73b JM |
45 | |
46 | -- repl | |
6116c2d5 NB |
47 | |
48 | add :: Fn | |
c150ec41 | 49 | add [MalNumber a, MalNumber b] = return $ MalNumber $ a + b |
5400d4bf | 50 | add _ = throwStr $ "illegal arguments to +" |
6116c2d5 NB |
51 | |
52 | sub :: Fn | |
c150ec41 | 53 | sub [MalNumber a, MalNumber b] = return $ MalNumber $ a - b |
5400d4bf | 54 | sub _ = throwStr $ "illegal arguments to -" |
6116c2d5 NB |
55 | |
56 | mult :: Fn | |
c150ec41 | 57 | mult [MalNumber a, MalNumber b] = return $ MalNumber $ a * b |
5400d4bf | 58 | mult _ = throwStr $ "illegal arguments to *" |
6116c2d5 NB |
59 | |
60 | divd :: Fn | |
c150ec41 | 61 | divd [MalNumber a, MalNumber b] = return $ MalNumber $ a `div` b |
5400d4bf | 62 | divd _ = throwStr $ "illegal arguments to /" |
b76aa73b JM |
63 | |
64 | repl_env :: Map.Map String MalVal | |
fa9a9758 JM |
65 | repl_env = Map.fromList [("+", _func add), |
66 | ("-", _func sub), | |
67 | ("*", _func mult), | |
68 | ("/", _func divd)] | |
b76aa73b | 69 | |
5400d4bf | 70 | rep :: String -> IOThrows String |
87cb47ec | 71 | rep = mal_print <=< eval <=< mal_read |
b76aa73b JM |
72 | |
73 | repl_loop :: IO () | |
74 | repl_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 | ||
92 | main :: IO () | |
fa9a9758 JM |
93 | main = do |
94 | load_history | |
6116c2d5 | 95 | |
fa9a9758 | 96 | repl_loop |