1 import System
.IO (hFlush, stdout)
2 import Control
.Monad
(mapM)
3 import Control
.Monad
.Error
(runErrorT
)
4 import Control
.Monad
.Trans
(liftIO
)
5 import qualified Data
.Map
as Map
6 import qualified Data
.Traversable
as DT
8 import Readline
(readline
, load_history
)
10 import Reader
(read_str
)
11 import Printer
(_pr_str
)
12 import Env
(Env
, env_new
, env_get
, env_set
)
15 mal_read
:: String -> IOThrows MalVal
16 mal_read str
= read_str str
19 eval_ast
:: MalVal
-> Env
-> IOThrows MalVal
20 eval_ast sym
@(MalSymbol _
) env
= env_get env sym
21 eval_ast ast
@(MalList lst m
) env
= do
22 new_lst
<- mapM (\x
-> (eval x env
)) lst
23 return $ MalList new_lst m
24 eval_ast ast
@(MalVector lst m
) env
= do
25 new_lst
<- mapM (\x
-> (eval x env
)) lst
26 return $ MalVector new_lst m
27 eval_ast ast
@(MalHashMap lst m
) env
= do
28 new_hm
<- DT
.mapM (\x
-> (eval x env
)) lst
29 return $ MalHashMap new_hm m
30 eval_ast ast env
= return ast
32 let_bind
:: Env
-> [MalVal
] -> IOThrows Env
33 let_bind env
[] = return env
34 let_bind env
(b
:e
:xs
) = do
36 x
<- liftIO
$ env_set env b evaled
39 apply_ast
:: MalVal
-> Env
-> IOThrows MalVal
40 apply_ast ast
@(MalList
(MalSymbol
"def!" : args
) _
) env
= do
42 (a1
@(MalSymbol _
): a2
: []) -> do
44 liftIO
$ env_set env a1 evaled
45 _
-> throwStr
"invalid def!"
46 apply_ast ast
@(MalList
(MalSymbol
"let*" : args
) _
) env
= do
49 params
<- (_to_list a1
)
50 let_env
<- liftIO
$ env_new
$ Just env
51 let_bind let_env params
53 _
-> throwStr
"invalid let*"
54 apply_ast ast
@(MalList _ _
) env
= do
55 el
<- eval_ast ast env
57 (MalList
((Func
(Fn f
) _
) : rest
) _
) ->
60 throwStr
$ "invalid apply: " ++ (show el
)
62 eval
:: MalVal
-> Env
-> IOThrows MalVal
65 (MalList _ _
) -> apply_ast ast env
70 mal_print
:: MalVal
-> String
71 mal_print
exp = show exp
74 add
[MalNumber a
, MalNumber b
] = return $ MalNumber
$ a
+ b
75 add _
= throwStr
$ "illegal arguments to +"
76 sub
[MalNumber a
, MalNumber b
] = return $ MalNumber
$ a
- b
77 sub _
= throwStr
$ "illegal arguments to -"
78 mult
[MalNumber a
, MalNumber b
] = return $ MalNumber
$ a
* b
79 mult _
= throwStr
$ "illegal arguments to *"
80 divd
[MalNumber a
, MalNumber b
] = return $ MalNumber
$ a `
div` b
81 divd _
= throwStr
$ "illegal arguments to /"
83 rep
:: Env
-> String -> IOThrows
String
87 return $ mal_print
exp
89 repl_loop
:: Env
-> IO ()
91 line
<- readline
"user> "
94 Just
"" -> repl_loop env
96 res
<- runErrorT
$ rep env str
98 Left
(StringError str
) -> return $ "Error: " ++ str
99 Left
(MalValError mv
) -> return $ "Error: " ++ (show mv
)
100 Right val
-> return val
108 repl_env
<- env_new Nothing
109 env_set repl_env
(MalSymbol
"+") $ _func add
110 env_set repl_env
(MalSymbol
"-") $ _func sub
111 env_set repl_env
(MalSymbol
"*") $ _func mult
112 env_set repl_env
(MalSymbol
"/") $ _func divd