3 import java
.io
.IOException
;
4 import java
.io
.FileNotFoundException
;
6 import java
.util
.Scanner
;
8 import java
.io
.StringWriter
;
9 import java
.io
.PrintWriter
;
10 import java
.util
.List
;
12 import java
.util
.HashMap
;
13 import java
.util
.Iterator
;
21 public class stepA_more
{
23 public static MalVal
READ(String str
) throws MalThrowable
{
24 return reader
.read_str(str
);
28 public static Boolean
is_pair(MalVal x
) {
29 return x
instanceof MalList
&& ((MalList
)x
).size() > 0;
32 public static MalVal
quasiquote(MalVal ast
) {
34 return new MalList(new MalSymbol("quote"), ast
);
36 MalVal a0
= ((MalList
)ast
).nth(0);
37 if ((a0
instanceof MalSymbol
) &&
38 (((MalSymbol
)a0
).getName() == "unquote")) {
39 return ((MalList
)ast
).nth(1);
40 } else if (is_pair(a0
)) {
41 MalVal a00
= ((MalList
)a0
).nth(0);
42 if ((a00
instanceof MalSymbol
) &&
43 (((MalSymbol
)a00
).getName() == "splice-unquote")) {
44 return new MalList(new MalSymbol("concat"),
46 quasiquote(((MalList
)ast
).rest()));
49 return new MalList(new MalSymbol("cons"),
51 quasiquote(((MalList
)ast
).rest()));
55 public static Boolean
is_macro_call(MalVal ast
, Env env
)
57 if (ast
instanceof MalList
) {
58 MalVal a0
= ((MalList
)ast
).nth(0);
59 if (a0
instanceof MalSymbol
&&
60 env
.find(((MalSymbol
)a0
).getName()) != null) {
61 MalVal mac
= env
.get(((MalSymbol
)a0
).getName());
62 if (mac
instanceof MalFunction
&&
63 ((MalFunction
)mac
).isMacro()) {
71 public static MalVal
macroexpand(MalVal ast
, Env env
)
73 while (is_macro_call(ast
, env
)) {
74 MalSymbol a0
= (MalSymbol
)((MalList
)ast
).nth(0);
75 MalFunction mac
= (MalFunction
) env
.get(a0
.getName());
76 ast
= mac
.apply(((MalList
)ast
).rest());
81 public static MalVal
eval_ast(MalVal ast
, Env env
) throws MalThrowable
{
82 if (ast
instanceof MalSymbol
) {
83 MalSymbol sym
= (MalSymbol
)ast
;
84 return env
.get(sym
.getName());
85 } else if (ast
instanceof MalList
) {
86 MalList old_lst
= (MalList
)ast
;
87 MalList new_lst
= ast
.list_Q() ?
new MalList()
88 : (MalList
)new MalVector();
89 for (MalVal mv
: (List
<MalVal
>)old_lst
.value
) {
90 new_lst
.conj_BANG(EVAL(mv
, env
));
93 } else if (ast
instanceof MalHashMap
) {
94 MalHashMap new_hm
= new MalHashMap();
95 Iterator it
= ((MalHashMap
)ast
).value
.entrySet().iterator();
96 while (it
.hasNext()) {
97 Map
.Entry entry
= (Map
.Entry
)it
.next();
98 new_hm
.value
.put(entry
.getKey(), EVAL((MalVal
)entry
.getValue(), env
));
106 public static MalVal
EVAL(MalVal orig_ast
, Env env
) throws MalThrowable
{
107 MalVal a0
, a1
,a2
, a3
, res
;
112 //System.out.println("EVAL: " + printer._pr_str(orig_ast, true));
113 if (!orig_ast
.list_Q()) {
114 return eval_ast(orig_ast
, env
);
118 MalVal expanded
= macroexpand(orig_ast
, env
);
119 if (!expanded
.list_Q()) { return expanded
; }
120 MalList ast
= (MalList
) expanded
;
121 if (ast
.size() == 0) { return ast
; }
123 String a0sym
= a0
instanceof MalSymbol ?
((MalSymbol
)a0
).getName()
130 env
.set(((MalSymbol
)a1
).getName(), res
);
137 Env let_env
= new Env(env
);
138 for(int i
=0; i
<((MalList
)a1
).size(); i
+=2) {
139 key
= (MalSymbol
)((MalList
)a1
).nth(i
);
140 val
= ((MalList
)a1
).nth(i
+1);
141 let_env
.set(key
.getName(), EVAL(val
, let_env
));
143 return EVAL(a2
, let_env
);
147 return EVAL(quasiquote(ast
.nth(1)), env
);
152 ((MalFunction
)res
).setMacro();
153 env
.set(((MalSymbol
)a1
).getName(), res
);
157 return macroexpand(a1
, env
);
160 return EVAL(ast
.nth(1), env
);
161 } catch (Throwable t
) {
162 if (ast
.size() > 2) {
165 MalVal a20
= ((MalList
)a2
).nth(0);
166 if (((MalSymbol
)a20
).getName().equals("catch*")) {
167 if (t
instanceof MalException
) {
168 exc
= ((MalException
)t
).getValue();
170 StringWriter sw
= new StringWriter();
171 t
.printStackTrace(new PrintWriter(sw
));
172 String tstr
= sw
.toString();
173 exc
= new MalString(t
.getMessage() + ": " + tstr
);
175 return EVAL(((MalList
)a2
).nth(2),
176 new Env(env
, ((MalList
)a2
).slice(1,2),
183 eval_ast(ast
.slice(1, ast
.size()-1), env
);
184 orig_ast
= ast
.nth(ast
.size()-1);
188 MalVal cond
= EVAL(a1
, env
);
189 if (cond
== types
.Nil
|| cond
== types
.False
) {
190 // eval false slot form
191 if (ast
.size() > 3) {
192 orig_ast
= ast
.nth(3);
197 // eval true slot form
198 orig_ast
= ast
.nth(2);
202 final MalList a1f
= (MalList
)ast
.nth(1);
203 final MalVal a2f
= ast
.nth(2);
204 final Env cur_env
= env
;
205 return new MalFunction (a2f
, (mal
.env
.Env
)env
, a1f
) {
206 public MalVal
apply(MalList args
) throws MalThrowable
{
207 return EVAL(a2f
, new Env(cur_env
, a1f
, args
));
211 el
= (MalList
)eval_ast(ast
, env
);
212 MalFunction f
= (MalFunction
)el
.nth(0);
213 MalVal fnast
= f
.getAst();
216 env
= f
.genEnv(el
.slice(1));
218 return f
.apply(el
.rest());
226 public static String
PRINT(MalVal exp
) {
227 return printer
._pr_str(exp
, true);
231 public static MalVal
RE(Env env
, String str
) throws MalThrowable
{
232 return EVAL(READ(str
), env
);
234 public static Env
_ref(Env env
, String name
, MalVal mv
) {
235 return env
.set(name
, mv
);
237 public static String
slurp(String fname
) throws MalThrowable
{
239 return new Scanner(new File(fname
))
240 .useDelimiter("\\Z").next();
241 } catch (FileNotFoundException e
) {
242 throw new MalError(e
.getMessage());
246 public static void main(String
[] args
) throws MalThrowable
{
247 String prompt
= "user> ";
249 final Env repl_env
= new Env(null);
250 for (String key
: core
.ns
.keySet()) {
251 _ref(repl_env
, key
, core
.ns
.get(key
));
253 _ref(repl_env
, "readline", new MalFunction() {
254 public MalVal
apply(MalList args
) throws MalThrowable
{
255 String prompt
= ((MalString
)args
.nth(0)).getValue();
257 return new MalString(readline
.readline(prompt
));
258 } catch (IOException e
) {
259 throw new MalException(new MalString(e
.getMessage()));
260 } catch (readline
.EOFException e
) {
261 throw new MalException(new MalString(e
.getMessage()));
265 _ref(repl_env
, "read-string", new MalFunction() {
266 public MalVal
apply(MalList args
) throws MalThrowable
{
268 return reader
.read_str(((MalString
)args
.nth(0)).getValue());
269 } catch (MalContinue c
) {
274 _ref(repl_env
, "eval", new MalFunction() {
275 public MalVal
apply(MalList args
) throws MalThrowable
{
276 return EVAL(args
.nth(0), repl_env
);
279 _ref(repl_env
, "slurp", new MalFunction() {
280 public MalVal
apply(MalList args
) throws MalThrowable
{
281 String fname
= ((MalString
)args
.nth(0)).getValue();
282 return new MalString(slurp(fname
));
286 RE(repl_env
, "(def! not (fn* (a) (if a false true)))");
287 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)))))))");
288 RE(repl_env
, "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))");
289 RE(repl_env
, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
292 if (args
.length
> 0 && args
[0].equals("--raw")) {
293 readline
.mode
= readline
.Mode
.JAVA
;
296 if (args
.length
> fileIdx
) {
297 for(Integer i
=fileIdx
; i
<args
.length
; i
++) {
298 RE(repl_env
, "(load-file \"" + args
[i
] + "\")");
305 line
= readline
.readline(prompt
);
306 if (line
== null) { continue; }
307 } catch (readline
.EOFException e
) {
309 } catch (IOException e
) {
310 System
.out
.println("IOException: " + e
.getMessage());
314 System
.out
.println(PRINT(RE(repl_env
, line
)));
315 } catch (MalContinue e
) {
317 } catch (reader
.ParseError e
) {
318 System
.out
.println(e
.getMessage());
320 } catch (MalException e
) {
321 System
.out
.println("Error: " + printer
._pr_str(e
.getValue(), false));
323 } catch (MalThrowable t
) {
324 System
.out
.println("Error: " + t
.getMessage());