1 #![feature(exit_status)]
5 use std::collections::HashMap;
6 use std::env as stdenv;
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};
16 fn read(str: String) -> MalRet {
21 fn is_pair(x: MalVal) -> bool {
23 List(ref lst,_) | Vector(ref lst,_) => lst.len() > 0,
28 fn quasiquote(ast: MalVal) -> MalVal {
29 if !is_pair(ast.clone()) {
30 return list(vec![symbol("quote"), ast])
34 List(ref args,_) | Vector(ref args,_) => {
38 if s.to_string() == "unquote".to_string() {
45 if is_pair(a0.clone()) {
47 List(ref a0args,_) | Vector(ref a0args,_) => {
48 let a00 = a0args[0].clone();
51 if s.to_string() == "splice-unquote".to_string() {
52 return list(vec![symbol("concat"),
54 quasiquote(list(args[1..].to_vec()))])
63 let rest = list(args[1..].to_vec());
64 return list(vec![symbol("cons"),
65 quasiquote(a0.clone()),
68 _ => _nil(), // should never reach
72 fn is_macro_call(ast: MalVal, env: Env) -> bool {
77 if env_find(&env, &lst[0]).is_some() {
78 match env_get(&env, &lst[0]) {
81 MalFunc(ref mfd,_) => {
100 fn macroexpand(mut ast: MalVal, env: Env) -> MalRet {
101 while is_macro_call(ast.clone(), env.clone()) {
102 let ast2 = ast.clone();
103 let args = match *ast2 {
104 List(ref args,_) => args,
107 let ref a0 = args[0];
108 let mf = match **a0 {
109 Sym(_) => try!(env_get(&env, &a0)),
113 MalFunc(_,_) => ast = try!(mf.apply(args[1..].to_vec())),
120 fn eval_ast(ast: MalVal, env: Env) -> MalRet {
121 let ast2 = ast.clone();
124 Sym(_) => env_get(&env, &ast),
125 List(ref a,_) | Vector(ref a,_) => {
126 let mut ast_vec : Vec<MalVal> = vec![];
128 let mv2 = mv.clone();
129 match eval(mv2, env.clone()) {
130 Ok(mv) => { ast_vec.push(mv); },
131 Err(e) => { return Err(e); },
134 Ok(match *ast { List(_,_) => list(ast_vec),
135 _ => vector(ast_vec) })
137 Hash_Map(ref hm,_) => {
138 let mut new_hm: HashMap<String,MalVal> = HashMap::new();
139 for (key, value) in hm.iter() {
140 match eval(value.clone(), env.clone()) {
141 Ok(mv) => { new_hm.insert(key.to_string(), mv); },
142 Err(e) => return Err(e),
153 fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
156 //println!("eval: {}, {}", ast, env.borrow());
157 //println!("eval: {}", ast);
158 let mut ast2 = ast.clone();
160 List(_,_) => (), // continue
161 _ => return eval_ast(ast2, env),
165 match macroexpand(ast2, env.clone()) {
169 Err(e) => return Err(e),
172 List(_,_) => (), // continue
173 _ => return Ok(ast2),
175 let ast3 = ast2.clone();
177 let (args, a0sym) = match *ast2 {
178 List(ref args,_) => {
182 let ref a0 = *args[0];
184 Sym(ref a0sym) => (args, &a0sym[..]),
185 _ => (args, "__<fn*>__"),
188 _ => return err_str("Expected list"),
193 let a1 = (*args)[1].clone();
194 let a2 = (*args)[2].clone();
195 let res = eval(a2, env.clone());
200 env_set(&env.clone(), a1.clone(), r.clone());
204 return err_str("def! of non-symbol")
208 Err(e) => return Err(e),
212 let let_env = env_new(Some(env.clone()));
213 let a1 = (*args)[1].clone();
214 let a2 = (*args)[2].clone();
216 List(ref binds,_) | Vector(ref binds,_) => {
217 let mut it = binds.iter();
218 while it.len() >= 2 {
219 let b = it.next().unwrap();
220 let exp = it.next().unwrap();
223 match eval(exp.clone(), let_env.clone()) {
225 env_set(&let_env, b.clone(), r);
233 return err_str("let* with non-symbol binding");
238 _ => return err_str("let* with non-list bindings"),
241 env = let_env.clone();
245 return Ok((*args)[1].clone());
248 let a1 = (*args)[1].clone();
249 ast = quasiquote(a1);
253 let a1 = (*args)[1].clone();
254 let a2 = (*args)[2].clone();
255 match eval(a2, env.clone()) {
258 MalFunc(ref mfd,_) => {
261 let mut new_mfd = mfd.clone();
262 new_mfd.is_macro = true;
263 let mf = malfuncd(new_mfd,_nil());
264 env_set(&env.clone(), a1.clone(), mf.clone());
267 _ => return err_str("def! of non-symbol"),
270 _ => return err_str("def! of non-symbol"),
273 Err(e) => return Err(e),
277 let a1 = (*args)[1].clone();
278 return macroexpand(a1, env.clone())
281 let el = list(args[1..args.len()-1].to_vec());
282 match eval_ast(el, env.clone()) {
283 Err(e) => return Err(e),
285 let ref last = args[args.len()-1];
292 let a1 = (*args)[1].clone();
293 let cond = eval(a1, env.clone());
295 Err(e) => return Err(e),
299 let a3 = (*args)[3].clone();
308 let a2 = (*args)[2].clone();
317 let a1 = (*args)[1].clone();
318 let a2 = (*args)[2].clone();
319 return Ok(malfunc(eval, a2, env.clone(), a1, _nil()));
322 let a1 = (*args)[1].clone();
323 match eval(a1, env.clone()) {
326 env = env_root(&env);
329 Err(e) => return Err(e),
332 _ => { // function call
333 return match eval_ast(ast3, env.clone()) {
336 let args = match *el {
337 List(ref args,_) => args,
338 _ => return err_str("Invalid apply"),
340 match *args.clone()[0] {
341 Func(f,_) => f(args[1..].to_vec()),
342 MalFunc(ref mf,_) => {
343 let mfc = mf.clone();
344 let alst = list(args[1..].to_vec());
345 let new_env = env_new(Some(mfc.env.clone()));
346 match env_bind(&new_env, mfc.params, alst) {
352 Err(e) => err_str(&e),
355 _ => err_str("attempt to call non-function"),
366 fn print(exp: MalVal) -> String {
370 fn rep(str: &str, env: Env) -> Result<String,MalError> {
371 match read(str.to_string()) {
374 //println!("read: {}", ast);
375 match eval(ast, env) {
377 Ok(exp) => Ok(print(exp)),
384 // core.rs: defined using rust
385 let repl_env = env_new(None);
386 for (k, v) in core::ns().into_iter() {
387 env_set(&repl_env, symbol(&k), v);
389 // see eval() for definition of "eval"
390 env_set(&repl_env, symbol("*ARGV*"), list(vec![]));
392 // core.mal: defined using the language itself
393 let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone());
394 let _ = rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", repl_env.clone());
395 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());
396 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());
398 // Invoked with command line arguments
399 let args = stdenv::args();
401 let mv_args = args.skip(2)
403 .collect::<Vec<MalVal>>();
404 env_set(&repl_env, symbol("*ARGV*"), list(mv_args));
405 let lf = format!("(load-file \"{}\")",
406 stdenv::args().skip(1).next().unwrap());
407 return match rep(&lf, repl_env.clone()) {
408 Ok(_) => stdenv::set_exit_status(0),
410 println!("Error: {:?}", str);
411 stdenv::set_exit_status(1);
418 let line = readline::mal_readline("user> ");
419 match line { None => break, _ => () }
420 match rep(&line.unwrap(), repl_env.clone()) {
421 Ok(str) => println!("{}", str),
422 Err(ErrMalVal(_)) => (), // Blank line
423 Err(ErrString(s)) => println!("Error: {}", s),