4 import types
.MalException
16 macro_Q
= { ast
, env
->
17 if (types
.list_Q(ast
) &&
18 ast
[0].class == MalSymbol
&&
20 def obj
= env
.get(ast
[0])
21 if (obj
instanceof MalFunc
&& obj
.ismacro
) {
27 macroexpand
= { ast
, env
->
28 while (macro_Q(ast
, env
)) {
29 def mac
= env
.get(ast
[0])
30 ast
= mac(ast
.drop(1))
35 pair_Q
= { ast
-> types
.sequential_Q(ast
) && ast
.size() > 0}
38 [new MalSymbol("quote"), ast
]
39 } else if (ast
[0] != null &&
40 ast
[0].class == MalSymbol
&&
41 ast
[0].value
== "unquote") {
43 } else if (pair_Q(ast
[0]) && ast
[0][0].class == MalSymbol
&&
44 ast
[0][0].value
== "splice-unquote") {
45 [new MalSymbol("concat"), ast
[0][1], quasiquote(ast
.drop(1))]
47 [new MalSymbol("cons"), quasiquote(ast
[0]), quasiquote(ast
.drop(1))]
51 eval_ast
= { ast
, env
->
53 case MalSymbol
: return env
.get(ast
);
54 case List
: return types
.vector_Q(ast
) ?
55 types
.vector(ast
.collect
{ EVAL(it
,env
) }) :
56 ast
.collect
{ EVAL(it
,env
) }
57 case Map
: def new_hm
= [:]
59 new_hm
[EVAL(k
, env
)] = EVAL(v
, env
)
68 //println("EVAL: ${printer.pr_str(ast,true)}")
69 if (! types
.list_Q(ast
)) return eval_ast(ast
, env
)
71 ast
= macroexpand(ast
, env
)
72 if (! types
.list_Q(ast
)) return ast
75 case { it
instanceof MalSymbol
&& it
.value
== "def!" }:
76 return env
.set(ast
[1], EVAL(ast
[2], env
))
77 case { it
instanceof MalSymbol
&& it
.value
== "let*" }:
78 def let_env
= new Env(env
)
79 for (int i
=0; i
< ast
[1].size(); i
+= 2) {
80 let_env
.set(ast
[1][i
], EVAL(ast
[1][i
+1], let_env
))
85 case { it
instanceof MalSymbol
&& it
.value
== "quote" }:
87 case { it
instanceof MalSymbol
&& it
.value
== "quasiquote" }:
88 ast
= quasiquote(ast
[1])
90 case { it
instanceof MalSymbol
&& it
.value
== "defmacro!" }:
91 def f
= EVAL(ast
[2], env
)
93 return env
.set(ast
[1], f
)
94 case { it
instanceof MalSymbol
&& it
.value
== "macroexpand" }:
95 return macroexpand(ast
[1], env
)
96 case { it
instanceof MalSymbol
&& it
.value
== "try*" }:
98 return EVAL(ast
[1], env
)
100 if (ast
.size() > 2 &&
101 ast
[2][0] instanceof MalSymbol
&&
102 ast
[2][0].value
== "catch*") {
104 if (exc
instanceof MalException
) {
109 return EVAL(ast
[2][2], new Env(env
, [ast
[2][1]], [e
]))
114 case { it
instanceof MalSymbol
&& it
.value
== "do" }:
115 ast
.size() > 2 ?
eval_ast(ast
[1..-2], env
) : null
118 case { it
instanceof MalSymbol
&& it
.value
== "if" }:
119 def cond
= EVAL(ast
[1], env
)
120 if (cond
== false || cond
== null) {
131 case { it
instanceof MalSymbol
&& it
.value
== "fn*" }:
132 return new MalFunc(EVAL
, ast
[2], env
, ast
[1])
134 def el
= eval_ast(ast
, env
)
135 def (f
, args
) = [el
[0], el
.drop(1)]
136 if (f
instanceof MalFunc
) {
137 env
= new Env(f
.env
, f
.params
, args
)
149 printer
.pr_str exp
, true
153 repl_env
= new Env();
155 PRINT(EVAL(READ(str
), repl_env
))
158 // core.EXT: defined using Groovy
159 core
.ns
.each
{ k
,v
->
160 repl_env
.set(new MalSymbol(k
), v
)
162 repl_env
.set(new MalSymbol("eval"), { a
-> EVAL(a
[0], repl_env
)})
163 repl_env
.set(new MalSymbol("*ARGV*"), this.args as List
)
165 // core.mal: defined using mal itself
166 REP("(def! *host-language* \"groovy\")")
167 REP("(def! not (fn* (a) (if a false true)))")
168 REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
169 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)))))))");
170 REP("(def! *gensym-counter* (atom 0))");
171 REP("(def! gensym (fn* [] (symbol (str \"G__\" (swap! *gensym-counter* (fn* [x] (+ 1 x)))))))");
172 REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) (let* (condvar (gensym)) `(let* (~condvar ~(first xs)) (if ~condvar ~condvar (or ~@(rest xs)))))))))");
175 if (this.args
.size() > 0) {
176 repl_env
.set(new MalSymbol("*ARGV*"), this.args
.drop(1) as List
)
177 REP("(load-file \"${this.args[0]}\")")
181 REP("(println (str \"Mal [\" *host-language* \"]\"))")
183 line
= System
.console().readLine
'user> '
189 } catch(MalException ex
) {
190 println
"Error: ${ex.message}"
191 } catch(StackOverflowError ex
) {
192 println
"Error: ${ex}"