b84a07925ac88b197ac62db7522bad88898f0ccf
[jackhill/mal.git] / rust / src / bin / stepA_mal.rs
1 #![feature(exit_status)]
2
3 extern crate mal;
4
5 use std::collections::HashMap;
6 use std::env as stdenv;
7
8 use mal::types::{MalVal, MalRet, MalError, err_str};
9 use mal::types::{symbol, _nil, string, list, vector, hash_map, malfunc, malfuncd};
10 use mal::types::MalType::{Nil, False, Sym, List, Vector, Hash_Map, Func, MalFunc};
11 use mal::types::MalError::{ErrString, ErrMalVal};
12 use mal::{readline, reader, core};
13 use mal::env::{env_set, env_get, env_new, env_bind, env_find, env_root, Env};
14
15 // read
16 fn read(str: String) -> MalRet {
17 reader::read_str(str)
18 }
19
20 // eval
21 fn is_pair(x: MalVal) -> bool {
22 match *x {
23 List(ref lst,_) | Vector(ref lst,_) => lst.len() > 0,
24 _ => false,
25 }
26 }
27
28 fn quasiquote(ast: MalVal) -> MalVal {
29 if !is_pair(ast.clone()) {
30 return list(vec![symbol("quote"), ast])
31 }
32
33 match *ast.clone() {
34 List(ref args,_) | Vector(ref args,_) => {
35 let ref a0 = args[0];
36 match **a0 {
37 Sym(ref s) if *s == "unquote" => return args[1].clone(),
38 _ => (),
39 }
40 if is_pair(a0.clone()) {
41 match **a0 {
42 List(ref a0args,_) | Vector(ref a0args,_) => {
43 match *a0args[0] {
44 Sym(ref s) if *s == "splice-unquote" => {
45 return list(vec![symbol("concat"),
46 a0args[1].clone(),
47 quasiquote(list(args[1..].to_vec()))])
48 },
49 _ => (),
50 }
51 },
52 _ => (),
53 }
54 }
55 let rest = list(args[1..].to_vec());
56 return list(vec![symbol("cons"),
57 quasiquote(a0.clone()),
58 quasiquote(rest)])
59 },
60 _ => _nil(), // should never reach
61 }
62 }
63
64 fn is_macro_call(ast: MalVal, env: Env) -> bool {
65 let lst = match *ast {
66 List(ref lst,_) => &lst[0],
67 _ => return false
68 };
69 match **lst {
70 Sym(_) => {},
71 _ => return false
72 }
73 if env_find(&env, lst).is_none() {
74 return false
75 }
76 let f = match env_get(&env, lst) {
77 Ok(f) => f,
78 _ => return false
79 };
80 match *f {
81 MalFunc(ref mfd,_) => mfd.is_macro,
82 _ => false,
83 }
84 }
85
86 fn macroexpand(mut ast: MalVal, env: Env) -> MalRet {
87 while is_macro_call(ast.clone(), env.clone()) {
88 let ast2 = ast.clone();
89 let args = match *ast2 {
90 List(ref args,_) => args,
91 _ => break,
92 };
93 let ref a0 = args[0];
94 let mf = match **a0 {
95 Sym(_) => try!(env_get(&env, &a0)),
96 _ => break,
97 };
98 match *mf {
99 MalFunc(_,_) => ast = try!(mf.apply(args[1..].to_vec())),
100 _ => break,
101 }
102 }
103 Ok(ast)
104 }
105
106 fn eval_ast(ast: MalVal, env: Env) -> MalRet {
107 match *ast {
108 Sym(_) => env_get(&env, &ast),
109 List(ref a,_) | Vector(ref a,_) => {
110 let mut ast_vec : Vec<MalVal> = vec![];
111 for mv in a.iter() {
112 let mv2 = mv.clone();
113 ast_vec.push(try!(eval(mv2, env.clone())));
114 }
115 Ok(match *ast { List(_,_) => list(ast_vec),
116 _ => vector(ast_vec) })
117 }
118 Hash_Map(ref hm,_) => {
119 let mut new_hm: HashMap<String,MalVal> = HashMap::new();
120 for (key, value) in hm.iter() {
121 new_hm.insert(key.to_string(),
122 try!(eval(value.clone(), env.clone())));
123 }
124 Ok(hash_map(new_hm))
125 }
126 _ => Ok(ast.clone()),
127 }
128 }
129
130 fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
131 'tco: loop {
132
133 //println!("eval: {}, {}", ast, env.borrow());
134 //println!("eval: {}", ast);
135 match *ast {
136 List(_,_) => (), // continue
137 _ => return eval_ast(ast, env),
138 }
139
140 // apply list
141 ast = try!(macroexpand(ast, env.clone()));
142 match *ast {
143 List(_,_) => (), // continue
144 _ => return Ok(ast),
145 }
146
147 let tmp = ast;
148 let (args, a0sym) = match *tmp {
149 List(ref args,_) => {
150 if args.len() == 0 {
151 return Ok(tmp.clone());
152 }
153 let ref a0 = *args[0];
154 match *a0 {
155 Sym(ref a0sym) => (args, &a0sym[..]),
156 _ => (args, "__<fn*>__"),
157 }
158 },
159 _ => return err_str("Expected list"),
160 };
161
162 match a0sym {
163 "def!" => {
164 let a1 = (*args)[1].clone();
165 let a2 = (*args)[2].clone();
166 let r = try!(eval(a2, env.clone()));
167 match *a1 {
168 Sym(_) => {
169 env_set(&env.clone(), a1, r.clone());
170 return Ok(r);
171 },
172 _ => return err_str("def! of non-symbol"),
173 }
174 },
175 "let*" => {
176 let let_env = env_new(Some(env.clone()));
177 let a1 = (*args)[1].clone();
178 let a2 = (*args)[2].clone();
179 match *a1 {
180 List(ref binds,_) | Vector(ref binds,_) => {
181 let mut it = binds.iter();
182 while it.len() >= 2 {
183 let b = it.next().unwrap();
184 let exp = it.next().unwrap();
185 match **b {
186 Sym(_) => {
187 let r = try!(eval(exp.clone(), let_env.clone()));
188 env_set(&let_env, b.clone(), r);
189 },
190 _ => return err_str("let* with non-symbol binding"),
191 }
192 }
193 },
194 _ => return err_str("let* with non-list bindings"),
195 }
196 ast = a2;
197 env = let_env.clone();
198 continue 'tco;
199 },
200 "quote" => return Ok((*args)[1].clone()),
201 "quasiquote" => {
202 let a1 = (*args)[1].clone();
203 ast = quasiquote(a1);
204 continue 'tco;
205 },
206 "defmacro!" => {
207 let a1 = (*args)[1].clone();
208 let a2 = (*args)[2].clone();
209 let r = try!(eval(a2, env.clone()));
210 match *r {
211 MalFunc(ref mfd,_) => {
212 match *a1 {
213 Sym(_) => {
214 let mut new_mfd = mfd.clone();
215 new_mfd.is_macro = true;
216 let mf = malfuncd(new_mfd,_nil());
217 env_set(&env.clone(), a1.clone(), mf.clone());
218 return Ok(mf);
219 },
220 _ => return err_str("def! of non-symbol"),
221 }
222 },
223 _ => return err_str("def! of non-symbol"),
224 }
225 },
226 "macroexpand" => {
227 let a1 = (*args)[1].clone();
228 return macroexpand(a1, env.clone())
229 },
230 "try*" => {
231 let a1 = (*args)[1].clone();
232 match eval(a1, env.clone()) {
233 Ok(res) => return Ok(res),
234 Err(err) => {
235 if args.len() < 3 { return Err(err); }
236 let a2 = (*args)[2].clone();
237 let cat = match *a2 {
238 List(ref cat,_) => cat,
239 _ => return err_str("invalid catch* clause"),
240 };
241 if cat.len() != 3 {
242 return err_str("wrong arity to catch* clause");
243 }
244 let c1 = (*cat)[1].clone();
245 match *c1 {
246 Sym(_) => {},
247 _ => return err_str("invalid catch* binding"),
248 };
249 let exc = match err {
250 ErrMalVal(mv) => mv,
251 ErrString(s) => string(s),
252 };
253 let bind_env = env_new(Some(env.clone()));
254 env_set(&bind_env, c1.clone(), exc);
255 let c2 = (*cat)[2].clone();
256 return eval(c2, bind_env);
257 },
258 };
259 }
260 "do" => {
261 let el = list(args[1..args.len()-1].to_vec());
262 try!(eval_ast(el, env.clone()));
263 ast = args[args.len() - 1].clone();
264 continue 'tco;
265 },
266 "if" => {
267 let a1 = (*args)[1].clone();
268 let c = try!(eval(a1, env.clone()));
269 match *c {
270 False | Nil => {
271 if args.len() >= 4 {
272 ast = args[3].clone();
273 continue 'tco;
274 } else {
275 return Ok(_nil());
276 }
277 },
278 _ => {
279 ast = args[2].clone();
280 continue 'tco;
281 },
282 }
283 },
284 "fn*" => {
285 let a1 = args[1].clone();
286 let a2 = args[2].clone();
287 return Ok(malfunc(eval, a2, env, a1, _nil()));
288 },
289 "eval" => {
290 let a1 = (*args)[1].clone();
291 ast = try!(eval(a1, env.clone()));
292 env = env_root(&env);
293 continue 'tco;
294 },
295 _ => { // function call
296 let el = try!(eval_ast(tmp.clone(), env.clone()));
297 let args = match *el {
298 List(ref args,_) => args,
299 _ => return err_str("Invalid apply"),
300 };
301 return match *args.clone()[0] {
302 Func(f,_) => f(args[1..].to_vec()),
303 MalFunc(ref mf,_) => {
304 let mfc = mf.clone();
305 let alst = list(args[1..].to_vec());
306 let new_env = env_new(Some(mfc.env.clone()));
307 match env_bind(&new_env, mfc.params, alst) {
308 Ok(_) => {
309 ast = mfc.exp;
310 env = new_env;
311 continue 'tco;
312 },
313 Err(e) => err_str(&e),
314 }
315 },
316 _ => err_str("attempt to call non-function"),
317 }
318 },
319 }
320
321 }
322 }
323
324 // print
325 fn print(exp: MalVal) -> String {
326 exp.pr_str(true)
327 }
328
329 fn rep(str: &str, env: Env) -> Result<String,MalError> {
330 let ast = try!(read(str.to_string()));
331 //println!("read: {}", ast);
332 let exp = try!(eval(ast, env));
333 Ok(print(exp))
334 }
335
336 fn main() {
337 // core.rs: defined using rust
338 let repl_env = env_new(None);
339 for (k, v) in core::ns().into_iter() {
340 env_set(&repl_env, symbol(&k), v);
341 }
342 // see eval() for definition of "eval"
343 env_set(&repl_env, symbol("*ARGV*"), list(vec![]));
344
345 // core.mal: defined using the language itself
346 let _ = rep("(def! *host-language* \"rust\")", repl_env.clone());
347 let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone());
348 let _ = rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", repl_env.clone());
349 let _ = 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)))))))", repl_env.clone());
350 let _ = rep("(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))))))))", repl_env.clone());
351
352 // Invoked with command line arguments
353 let args = stdenv::args();
354 if args.len() > 1 {
355 let mv_args = args.skip(2)
356 .map(|a| string(a))
357 .collect::<Vec<MalVal>>();
358 env_set(&repl_env, symbol("*ARGV*"), list(mv_args));
359 let lf = format!("(load-file \"{}\")",
360 stdenv::args().skip(1).next().unwrap());
361 return match rep(&lf, repl_env.clone()) {
362 Ok(_) => stdenv::set_exit_status(0),
363 Err(str) => {
364 println!("Error: {:?}", str);
365 stdenv::set_exit_status(1);
366 }
367 };
368 }
369
370 // repl loop
371 let _ = rep("(println (str \"Mal [\" *host-language* \"]\"))", repl_env.clone());
372 loop {
373 let line = readline::mal_readline("user> ");
374 match line { None => break, _ => () }
375 match rep(&line.unwrap(), repl_env.clone()) {
376 Ok(str) => println!("{}", str),
377 Err(ErrMalVal(_)) => (), // Blank line
378 Err(ErrString(s)) => println!("Error: {}", s),
379 }
380 }
381 }