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_bind
, env_get
, env_set
)
16 mal_read
:: String -> IOThrows MalVal
17 mal_read str
= read_str str
20 eval_ast
:: MalVal
-> Env
-> IOThrows MalVal
21 eval_ast sym
@(MalSymbol _
) env
= env_get env sym
22 eval_ast ast
@(MalList lst m
) env
= do
23 new_lst
<- mapM (\x
-> (eval x env
)) lst
24 return $ MalList new_lst m
25 eval_ast ast
@(MalVector lst m
) env
= do
26 new_lst
<- mapM (\x
-> (eval x env
)) lst
27 return $ MalVector new_lst m
28 eval_ast ast
@(MalHashMap lst m
) env
= do
29 new_hm
<- DT
.mapM (\x
-> (eval x env
)) lst
30 return $ MalHashMap new_hm m
31 eval_ast ast env
= return ast
33 let_bind
:: Env
-> [MalVal
] -> IOThrows Env
34 let_bind env
[] = return env
35 let_bind env
(b
:e
:xs
) = do
37 x
<- liftIO
$ env_set env b evaled
40 apply_ast
:: MalVal
-> Env
-> IOThrows MalVal
41 apply_ast ast
@(MalList
(MalSymbol
"def!" : args
) _
) env
= do
43 (a1
@(MalSymbol _
): a2
: []) -> do
45 liftIO
$ env_set env a1 evaled
46 _
-> throwStr
"invalid def!"
47 apply_ast ast
@(MalList
(MalSymbol
"let*" : args
) _
) env
= do
50 params
<- (_to_list a1
)
51 let_env
<- liftIO
$ env_new
$ Just env
52 let_bind let_env params
54 _
-> throwStr
"invalid let*"
55 apply_ast ast
@(MalList
(MalSymbol
"do" : args
) _
) env
= do
59 el
<- eval_ast
(MalList args Nil
) env
61 (MalList lst _
) -> return $ last lst
63 apply_ast ast
@(MalList
(MalSymbol
"if" : args
) _
) env
= do
65 (a1
: a2
: a3
: []) -> do
67 if cond
== MalFalse || cond
== Nil
72 if cond
== MalFalse || cond
== Nil
75 _
-> throwStr
"invalid if"
76 apply_ast ast
@(MalList
(MalSymbol
"fn*" : args
) _
) env
= do
79 params
<- (_to_list a1
)
80 return $ (_malfunc a2 env
(MalList params Nil
)
82 fn_env1
<- liftIO
$ env_new
$ Just env
83 fn_env2
<- liftIO
$ env_bind fn_env1 params args
85 _
-> throwStr
"invalid fn*"
86 apply_ast ast
@(MalList _ _
) env
= do
87 el
<- eval_ast ast env
89 (MalList
((Func
(Fn f
) _
) : rest
) _
) ->
91 (MalList
((MalFunc
{ast
=ast
, env
=fn_env
, params
=(MalList params Nil
)}) : rest
) _
) -> do
92 fn_env1
<- liftIO
$ env_new
$ Just fn_env
93 fn_env2
<- liftIO
$ env_bind fn_env1 params rest
96 throwStr
$ "invalid apply: " ++ (show el
)
98 eval
:: MalVal
-> Env
-> IOThrows MalVal
101 (MalList _ _
) -> apply_ast ast env
102 _
-> eval_ast ast env
106 mal_print
:: MalVal
-> String
107 mal_print
exp = show exp
111 rep
:: Env
-> String -> IOThrows
String
115 return $ mal_print
exp
117 repl_loop
:: Env
-> IO ()
119 line
<- readline
"user> "
122 Just
"" -> repl_loop env
124 res
<- runErrorT
$ rep env str
126 Left
(StringError str
) -> return $ "Error: " ++ str
127 Left
(MalValError mv
) -> return $ "Error: " ++ (show mv
)
128 Right val
-> return val
136 repl_env
<- env_new Nothing
138 -- core.hs: defined using Haskell
139 (mapM (\(k
,v
) -> (env_set repl_env
(MalSymbol k
) v
)) Core
.ns
)
141 -- core.mal: defined using the language itself
142 runErrorT
$ rep repl_env
"(def! not (fn* (a) (if a false true)))"