3 import java
.io
.IOException
;
5 import java
.io
.StringWriter
;
6 import java
.io
.PrintWriter
;
9 import java
.util
.HashMap
;
10 import java
.util
.Iterator
;
18 public class step9_try
{
20 public static MalVal
READ(String str
) throws MalThrowable
{
21 return reader
.read_str(str
);
25 public static Boolean
is_pair(MalVal x
) {
26 return x
instanceof MalList
&& ((MalList
)x
).size() > 0;
29 public static MalVal
quasiquote(MalVal ast
) {
31 return new MalList(new MalSymbol("quote"), ast
);
33 MalVal a0
= ((MalList
)ast
).nth(0);
34 if ((a0
instanceof MalSymbol
) &&
35 (((MalSymbol
)a0
).getName().equals("unquote"))) {
36 return ((MalList
)ast
).nth(1);
37 } else if (is_pair(a0
)) {
38 MalVal a00
= ((MalList
)a0
).nth(0);
39 if ((a00
instanceof MalSymbol
) &&
40 (((MalSymbol
)a00
).getName().equals("splice-unquote"))) {
41 return new MalList(new MalSymbol("concat"),
43 quasiquote(((MalList
)ast
).rest()));
46 return new MalList(new MalSymbol("cons"),
48 quasiquote(((MalList
)ast
).rest()));
52 public static Boolean
is_macro_call(MalVal ast
, Env env
)
54 if (ast
instanceof MalList
) {
55 MalVal a0
= ((MalList
)ast
).nth(0);
56 if (a0
instanceof MalSymbol
&&
57 env
.find(((MalSymbol
)a0
)) != null) {
58 MalVal mac
= env
.get(((MalSymbol
)a0
));
59 if (mac
instanceof MalFunction
&&
60 ((MalFunction
)mac
).isMacro()) {
68 public static MalVal
macroexpand(MalVal ast
, Env env
)
70 while (is_macro_call(ast
, env
)) {
71 MalSymbol a0
= (MalSymbol
)((MalList
)ast
).nth(0);
72 MalFunction mac
= (MalFunction
) env
.get(a0
);
73 ast
= mac
.apply(((MalList
)ast
).rest());
78 public static MalVal
eval_ast(MalVal ast
, Env env
) throws MalThrowable
{
79 if (ast
instanceof MalSymbol
) {
80 return env
.get((MalSymbol
)ast
);
81 } else if (ast
instanceof MalList
) {
82 MalList old_lst
= (MalList
)ast
;
83 MalList new_lst
= ast
.list_Q() ?
new MalList()
84 : (MalList
)new MalVector();
85 for (MalVal mv
: (List
<MalVal
>)old_lst
.value
) {
86 new_lst
.conj_BANG(EVAL(mv
, env
));
89 } else if (ast
instanceof MalHashMap
) {
90 MalHashMap new_hm
= new MalHashMap();
91 Iterator it
= ((MalHashMap
)ast
).value
.entrySet().iterator();
92 while (it
.hasNext()) {
93 Map
.Entry entry
= (Map
.Entry
)it
.next();
94 new_hm
.value
.put(entry
.getKey(), EVAL((MalVal
)entry
.getValue(), env
));
102 public static MalVal
EVAL(MalVal orig_ast
, Env env
) throws MalThrowable
{
103 MalVal a0
, a1
,a2
, a3
, res
;
108 //System.out.println("EVAL: " + printer._pr_str(orig_ast, true));
109 if (!orig_ast
.list_Q()) {
110 return eval_ast(orig_ast
, env
);
112 if (((MalList
)orig_ast
).size() == 0) { return orig_ast
; }
115 MalVal expanded
= macroexpand(orig_ast
, env
);
116 if (!expanded
.list_Q()) {
117 return eval_ast(expanded
, env
);
119 MalList ast
= (MalList
) expanded
;
120 if (ast
.size() == 0) { return ast
; }
122 String a0sym
= a0
instanceof MalSymbol ?
((MalSymbol
)a0
).getName()
129 env
.set(((MalSymbol
)a1
), res
);
136 Env let_env
= new Env(env
);
137 for(int i
=0; i
<((MalList
)a1
).size(); i
+=2) {
138 key
= (MalSymbol
)((MalList
)a1
).nth(i
);
139 val
= ((MalList
)a1
).nth(i
+1);
140 let_env
.set(key
, EVAL(val
, let_env
));
148 orig_ast
= quasiquote(ast
.nth(1));
154 ((MalFunction
)res
).setMacro();
155 env
.set((MalSymbol
)a1
, res
);
159 return macroexpand(a1
, env
);
162 return EVAL(ast
.nth(1), env
);
163 } catch (Throwable t
) {
164 if (ast
.size() > 2) {
167 MalVal a20
= ((MalList
)a2
).nth(0);
168 if (((MalSymbol
)a20
).getName().equals("catch*")) {
169 if (t
instanceof MalException
) {
170 exc
= ((MalException
)t
).getValue();
172 StringWriter sw
= new StringWriter();
173 t
.printStackTrace(new PrintWriter(sw
));
174 String tstr
= sw
.toString();
175 exc
= new MalString(t
.getMessage() + ": " + tstr
);
177 return EVAL(((MalList
)a2
).nth(2),
178 new Env(env
, ((MalList
)a2
).slice(1,2),
185 eval_ast(ast
.slice(1, ast
.size()-1), env
);
186 orig_ast
= ast
.nth(ast
.size()-1);
190 MalVal cond
= EVAL(a1
, env
);
191 if (cond
== types
.Nil
|| cond
== types
.False
) {
192 // eval false slot form
193 if (ast
.size() > 3) {
194 orig_ast
= ast
.nth(3);
199 // eval true slot form
200 orig_ast
= ast
.nth(2);
204 final MalList a1f
= (MalList
)ast
.nth(1);
205 final MalVal a2f
= ast
.nth(2);
206 final Env cur_env
= env
;
207 return new MalFunction (a2f
, (mal
.env
.Env
)env
, a1f
) {
208 public MalVal
apply(MalList args
) throws MalThrowable
{
209 return EVAL(a2f
, new Env(cur_env
, a1f
, args
));
213 el
= (MalList
)eval_ast(ast
, env
);
214 MalFunction f
= (MalFunction
)el
.nth(0);
215 MalVal fnast
= f
.getAst();
218 env
= f
.genEnv(el
.slice(1));
220 return f
.apply(el
.rest());
228 public static String
PRINT(MalVal exp
) {
229 return printer
._pr_str(exp
, true);
233 public static MalVal
RE(Env env
, String str
) throws MalThrowable
{
234 return EVAL(READ(str
), env
);
237 public static void main(String
[] args
) throws MalThrowable
{
238 String prompt
= "user> ";
240 final Env repl_env
= new Env(null);
242 // core.java: defined using Java
243 for (String key
: core
.ns
.keySet()) {
244 repl_env
.set(new MalSymbol(key
), core
.ns
.get(key
));
246 repl_env
.set(new MalSymbol("eval"), new MalFunction() {
247 public MalVal
apply(MalList args
) throws MalThrowable
{
248 return EVAL(args
.nth(0), repl_env
);
251 MalList _argv
= new MalList();
252 for (Integer i
=1; i
< args
.length
; i
++) {
253 _argv
.conj_BANG(new MalString(args
[i
]));
255 repl_env
.set(new MalSymbol("*ARGV*"), _argv
);
258 // core.mal: defined using the language itself
259 RE(repl_env
, "(def! not (fn* (a) (if a false true)))");
260 RE(repl_env
, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))");
261 RE(repl_env
, "(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)))))))");
264 if (args
.length
> 0 && args
[0].equals("--raw")) {
265 readline
.mode
= readline
.Mode
.JAVA
;
268 if (args
.length
> fileIdx
) {
269 RE(repl_env
, "(load-file \"" + args
[fileIdx
] + "\")");
277 line
= readline
.readline(prompt
);
278 if (line
== null) { continue; }
279 } catch (readline
.EOFException e
) {
281 } catch (IOException e
) {
282 System
.out
.println("IOException: " + e
.getMessage());
286 System
.out
.println(PRINT(RE(repl_env
, line
)));
287 } catch (MalContinue e
) {
289 } catch (MalException e
) {
290 System
.out
.println("Error: " + printer
._pr_str(e
.getValue(), false));
292 } catch (MalThrowable t
) {
293 System
.out
.println("Error: " + t
.getMessage());
295 } catch (Throwable t
) {
296 System
.out
.println("Uncaught " + t
+ ": " + t
.getMessage());