4 import types
.MalException
16 macro_Q
= { ast
, env
->
17 if (types
.list_Q(ast
) &&
19 ast
[0].class == MalSymbol
&&
21 def obj
= env
.get(ast
[0])
22 if (obj
instanceof MalFunc
&& obj
.ismacro
) {
28 macroexpand
= { ast
, env
->
29 while (macro_Q(ast
, env
)) {
30 def mac
= env
.get(ast
[0])
31 ast
= mac(ast
.drop(1))
36 pair_Q
= { ast
-> types
.sequential_Q(ast
) && ast
.size() > 0}
39 [new MalSymbol("quote"), ast
]
40 } else if (ast
[0] != null &&
41 ast
[0].class == MalSymbol
&&
42 ast
[0].value
== "unquote") {
44 } else if (pair_Q(ast
[0]) && ast
[0][0].class == MalSymbol
&&
45 ast
[0][0].value
== "splice-unquote") {
46 [new MalSymbol("concat"), ast
[0][1], quasiquote(ast
.drop(1))]
48 [new MalSymbol("cons"), quasiquote(ast
[0]), quasiquote(ast
.drop(1))]
52 eval_ast
= { ast
, env
->
54 case MalSymbol
: return env
.get(ast
);
55 case List
: return types
.vector_Q(ast
) ?
56 types
.vector(ast
.collect
{ EVAL(it
,env
) }) :
57 ast
.collect
{ EVAL(it
,env
) }
58 case Map
: def new_hm
= [:]
60 new_hm
[EVAL(k
, env
)] = EVAL(v
, env
)
69 //println("EVAL: ${printer.pr_str(ast,true)}")
70 if (! types
.list_Q(ast
)) return eval_ast(ast
, env
)
72 ast
= macroexpand(ast
, env
)
73 if (! types
.list_Q(ast
)) return eval_ast(ast
, env
)
74 if (ast
.size() == 0) return ast
77 case { it
instanceof MalSymbol
&& it
.value
== "def!" }:
78 return env
.set(ast
[1], EVAL(ast
[2], env
))
79 case { it
instanceof MalSymbol
&& it
.value
== "let*" }:
80 def let_env
= new Env(env
)
81 for (int i
=0; i
< ast
[1].size(); i
+= 2) {
82 let_env
.set(ast
[1][i
], EVAL(ast
[1][i
+1], let_env
))
87 case { it
instanceof MalSymbol
&& it
.value
== "quote" }:
89 case { it
instanceof MalSymbol
&& it
.value
== "quasiquote" }:
90 ast
= quasiquote(ast
[1])
92 case { it
instanceof MalSymbol
&& it
.value
== "defmacro!" }:
93 def f
= EVAL(ast
[2], env
)
95 return env
.set(ast
[1], f
)
96 case { it
instanceof MalSymbol
&& it
.value
== "macroexpand" }:
97 return macroexpand(ast
[1], env
)
98 case { it
instanceof MalSymbol
&& it
.value
== "do" }:
99 ast
.size() > 2 ?
eval_ast(ast
[1..-2], env
) : null
102 case { it
instanceof MalSymbol
&& it
.value
== "if" }:
103 def cond
= EVAL(ast
[1], env
)
104 if (cond
== false || cond
== null) {
115 case { it
instanceof MalSymbol
&& it
.value
== "fn*" }:
116 return new MalFunc(EVAL
, ast
[2], env
, ast
[1])
118 def el
= eval_ast(ast
, env
)
119 def (f
, args
) = [el
[0], el
.drop(1)]
120 if (f
instanceof MalFunc
) {
121 env
= new Env(f
.env
, f
.params
, args
)
133 printer
.pr_str exp
, true
137 repl_env
= new Env();
139 PRINT(EVAL(READ(str
), repl_env
))
142 // core.EXT: defined using Groovy
143 core
.ns
.each
{ k
,v
->
144 repl_env
.set(new MalSymbol(k
), v
)
146 repl_env
.set(new MalSymbol("eval"), { a
-> EVAL(a
[0], repl_env
)})
147 repl_env
.set(new MalSymbol("*ARGV*"), this.args as List
)
149 // core.mal: defined using mal itself
150 REP("(def! not (fn* (a) (if a false true)))")
151 REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))")
152 REP("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))");
155 if (this.args
.size() > 0) {
156 repl_env
.set(new MalSymbol("*ARGV*"), this.args
.drop(1) as List
)
157 REP("(load-file \"${this.args[0]}\")")
162 line
= System
.console().readLine
'user> '
168 } catch(MalException ex
) {
169 println
"Error: ${printer.pr_str(ex.obj, true)}"
170 } catch(StackOverflowError ex
) {
171 println
"Error: ${ex}"