1 import System
.IO (hFlush, stdout)
2 import Control
.Monad
((<=<))
3 import Control
.Monad
.Except
(runExceptT
)
4 import Control
.Monad
.Trans
(liftIO
)
6 import Readline
(addHistory
, readline
, load_history
)
8 import Reader
(read_str
)
9 import Printer
(_pr_str
)
10 import Env
(env_new
, env_get
, env_set
)
14 mal_read
:: String -> IOThrows MalVal
19 -- eval_ast is replaced with pattern matching.
21 let_bind
:: Env
-> [MalVal
] -> IOThrows
()
22 let_bind _
[] = return ()
23 let_bind env
(MalSymbol b
: e
: xs
) = do
24 liftIO
. env_set env b
=<< eval env e
26 let_bind _ _
= throwStr
"invalid let*"
28 apply_ast
:: [MalVal
] -> Env
-> IOThrows MalVal
30 apply_ast
[] _
= return $ toList
[]
32 apply_ast
[MalSymbol
"def!", MalSymbol a1
, a2
] env
= do
34 liftIO
$ env_set env a1 evd
36 apply_ast
(MalSymbol
"def!" : _
) _
= throwStr
"invalid def!"
38 apply_ast
[MalSymbol
"let*", MalSeq _ _ params
, a2
] env
= do
39 let_env
<- liftIO
$ env_new env
40 let_bind let_env params
42 apply_ast
(MalSymbol
"let*" : _
) _
= throwStr
"invalid let*"
44 apply_ast ast env
= do
45 evd
<- mapM (eval env
) ast
47 MalFunction
{fn
=f
} : args
-> f args
48 _
-> throwStr
. (++) "invalid apply: " =<< liftIO
(Printer
._pr_str
True (toList ast
))
50 eval
:: Env
-> MalVal
-> IOThrows MalVal
51 eval env
(MalSymbol sym
) = do
52 maybeVal
<- liftIO
$ env_get env sym
54 Nothing
-> throwStr
$ "'" ++ sym
++ "' not found"
55 Just val
-> return val
56 eval env
(MalSeq _
(Vect
False) xs
) = apply_ast xs env
57 eval env
(MalSeq m
(Vect
True) xs
) = MalSeq m
(Vect
True) <$> mapM (eval env
) xs
58 eval env
(MalHashMap m xs
) = MalHashMap m
<$> mapM (eval env
) xs
59 eval _ ast
= return ast
63 mal_print
:: MalVal
-> IOThrows
String
64 mal_print
= liftIO
. Printer
._pr_str
True
69 add
[MalNumber a
, MalNumber b
] = return $ MalNumber
$ a
+ b
70 add _
= throwStr
$ "illegal arguments to +"
73 sub
[MalNumber a
, MalNumber b
] = return $ MalNumber
$ a
- b
74 sub _
= throwStr
$ "illegal arguments to -"
77 mult
[MalNumber a
, MalNumber b
] = return $ MalNumber
$ a
* b
78 mult _
= throwStr
$ "illegal arguments to *"
81 divd
[MalNumber a
, MalNumber b
] = return $ MalNumber
$ a `
div` b
82 divd _
= throwStr
$ "illegal arguments to /"
84 rep
:: Env
-> String -> IOThrows
String
85 rep env
= mal_print
<=< eval env
<=< mal_read
87 repl_loop
:: Env
-> IO ()
89 line
<- readline
"user> "
92 Just
"" -> repl_loop env
95 res
<- runExceptT
$ rep env str
97 Left mv
-> (++) "Error: " <$> liftIO
(Printer
._pr_str
True mv
)
98 Right val
-> return val
103 defBuiltIn
:: Env
-> String -> Fn
-> IO ()
104 defBuiltIn env sym f
=
105 env_set env sym
$ MalFunction
{fn
=f
, f_ast
=Nil
, f_params
=[], macro
=False, meta
=Nil
}
111 repl_env
<- env_new
[]
113 defBuiltIn repl_env
"+" add
114 defBuiltIn repl_env
"-" sub
115 defBuiltIn repl_env
"*" mult
116 defBuiltIn repl_env
"/" divd