3 using System
.Collections
;
4 using System
.Collections
.Generic
;
6 using MalVal
= Mal
.types
.MalVal
;
7 using MalString
= Mal
.types
.MalString
;
8 using MalSymbol
= Mal
.types
.MalSymbol
;
9 using MalInt
= Mal
.types
.MalInt
;
10 using MalList
= Mal
.types
.MalList
;
11 using MalVector
= Mal
.types
.MalVector
;
12 using MalHashMap
= Mal
.types
.MalHashMap
;
13 using MalFunc
= Mal
.types
.MalFunc
;
14 using Env
= Mal
.env
.Env
;
19 static MalVal
READ(string str
) {
20 return reader
.read_str(str
);
24 public static bool is_pair(MalVal x
) {
25 return x
is MalList
&& ((MalList
)x
).size() > 0;
28 public static MalVal
quasiquote(MalVal ast
) {
30 return new MalList(new MalSymbol("quote"), ast
);
32 MalVal a0
= ((MalList
)ast
)[0];
33 if ((a0
is MalSymbol
) &&
34 (((MalSymbol
)a0
).getName() == "unquote")) {
35 return ((MalList
)ast
)[1];
36 } else if (is_pair(a0
)) {
37 MalVal a00
= ((MalList
)a0
)[0];
38 if ((a00
is MalSymbol
) &&
39 (((MalSymbol
)a00
).getName() == "splice-unquote")) {
40 return new MalList(new MalSymbol("concat"),
42 quasiquote(((MalList
)ast
).rest()));
45 return new MalList(new MalSymbol("cons"),
47 quasiquote(((MalList
)ast
).rest()));
51 public static bool is_macro_call(MalVal ast
, Env env
) {
53 MalVal a0
= ((MalList
)ast
)[0];
54 if (a0
is MalSymbol
&&
55 env
.find(((MalSymbol
)a0
).getName()) != null) {
56 MalVal mac
= env
.get(((MalSymbol
)a0
).getName());
58 ((MalFunc
)mac
).isMacro()) {
66 public static MalVal
macroexpand(MalVal ast
, Env env
) {
67 while (is_macro_call(ast
, env
)) {
68 MalSymbol a0
= (MalSymbol
)((MalList
)ast
)[0];
69 MalFunc mac
= (MalFunc
) env
.get(a0
.getName());
70 ast
= mac
.apply(((MalList
)ast
).rest());
75 static MalVal
eval_ast(MalVal ast
, Env env
) {
76 if (ast
is MalSymbol
) {
77 MalSymbol sym
= (MalSymbol
)ast
;
78 return env
.get(sym
.getName());
79 } else if (ast
is MalList
) {
80 MalList old_lst
= (MalList
)ast
;
81 MalList new_lst
= ast
.list_Q() ? new MalList()
82 : (MalList
)new MalVector();
83 foreach (MalVal mv
in old_lst
.getValue()) {
84 new_lst
.conj_BANG(EVAL(mv
, env
));
87 } else if (ast
is MalHashMap
) {
88 var new_dict
= new Dictionary
<string, MalVal
>();
89 foreach (var entry
in ((MalHashMap
)ast
).getValue()) {
90 new_dict
.Add(entry
.Key
, EVAL((MalVal
)entry
.Value
, env
));
92 return new MalHashMap(new_dict
);
99 static MalVal
EVAL(MalVal orig_ast
, Env env
) {
100 MalVal a0
, a1
, a2
, res
;
105 //System.out.println("EVAL: " + printer._pr_str(orig_ast, true));
106 if (!orig_ast
.list_Q()) {
107 return eval_ast(orig_ast
, env
);
111 MalVal expanded
= macroexpand(orig_ast
, env
);
112 if (!expanded
.list_Q()) { return expanded; }
113 MalList ast
= (MalList
) expanded
;
115 if (ast
.size() == 0) { return ast; }
118 String a0sym
= a0
is MalSymbol
? ((MalSymbol
)a0
).getName()
126 env
.set(((MalSymbol
)a1
).getName(), res
);
133 Env let_env
= new Env(env
);
134 for(int i
=0; i
<((MalList
)a1
).size(); i
+=2) {
135 key
= (MalSymbol
)((MalList
)a1
)[i
];
136 val
= ((MalList
)a1
)[i
+1];
137 let_env
.set(key
.getName(), EVAL(val
, let_env
));
145 orig_ast
= quasiquote(ast
[1]);
151 ((MalFunc
)res
).setMacro();
152 env
.set(((MalSymbol
)a1
).getName(), res
);
156 return macroexpand(a1
, env
);
159 return EVAL(ast
[1], env
);
160 } catch (Exception e
) {
161 if (ast
.size() > 2) {
164 MalVal a20
= ((MalList
)a2
)[0];
165 if (((MalSymbol
)a20
).getName() == "catch*") {
166 if (e
is Mal
.types
.MalException
) {
167 exc
= ((Mal
.types
.MalException
)e
).getValue();
169 exc
= new MalString(e
.StackTrace
);
171 return EVAL(((MalList
)a2
)[2],
172 new Env(env
, ((MalList
)a2
).slice(1,2),
179 eval_ast(ast
.slice(1, ast
.size()-1), env
);
180 orig_ast
= ast
[ast
.size()-1];
184 MalVal cond
= EVAL(a1
, env
);
185 if (cond
== Mal
.types
.Nil
|| cond
== Mal
.types
.False
) {
186 // eval false slot form
187 if (ast
.size() > 3) {
190 return Mal
.types
.Nil
;
193 // eval true slot form
198 MalList a1f
= (MalList
)ast
[1];
201 return new MalFunc(a2f
, env
, a1f
,
202 args
=> EVAL(a2f
, new Env(cur_env
, a1f
, args
)) );
204 el
= (MalList
)eval_ast(ast
, env
);
205 var f
= (MalFunc
)el
[0];
206 MalVal fnast
= f
.getAst();
209 env
= f
.genEnv(el
.rest());
211 return f
.apply(el
.rest());
220 static string PRINT(MalVal exp
) {
221 return printer
._pr_str(exp
, true);
225 static void Main(string[] args
) {
226 var repl_env
= new Mal
.env
.Env(null);
227 Func
<string, MalVal
> RE
= (string str
) => EVAL(READ(str
), repl_env
);
229 // core.cs: defined using C#
230 foreach (var entry
in core
.ns
) {
231 repl_env
.set(entry
.Key
, entry
.Value
);
233 repl_env
.set("eval", new MalFunc(a
=> EVAL(a
[0], repl_env
)));
235 if (args
.Length
> 0 && args
[0] == "--raw") {
236 Mal
.readline
.mode
= Mal
.readline
.Mode
.Raw
;
239 MalList _argv
= new MalList();
240 for (int i
=fileIdx
; i
< args
.Length
; i
++) {
241 _argv
.conj_BANG(new MalString(args
[i
]));
243 repl_env
.set("*ARGV*", _argv
);
245 // core.mal: defined using the language itself
246 RE("(def! *host-language* \"c#\")");
247 RE("(def! not (fn* (a) (if a false true)))");
248 RE("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
249 RE("(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)))))))");
250 RE("(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))))))))");
252 if (args
.Length
> fileIdx
) {
253 RE("(load-file \"" + args
[fileIdx
] + "\")");
258 RE("(println (str \"Mal [\" *host-language* \"]\"))");
262 line
= Mal
.readline
.Readline("user> ");
263 if (line
== null) { break; }
264 if (line
== "") { continue; }
265 } catch (IOException e
) {
266 Console
.WriteLine("IOException: " + e
.Message
);
270 Console
.WriteLine(PRINT(RE(line
)));
271 } catch (Mal
.types
.MalContinue
) {
273 } catch (Mal
.types
.MalException e
) {
274 Console
.WriteLine("Error: " +
275 printer
._pr_str(e
.getValue(), false));
277 } catch (Exception e
) {
278 Console
.WriteLine("Error: " + e
.Message
);
279 Console
.WriteLine(e
.StackTrace
);