2 //use std::collections::HashMap;
4 use itertools::Itertools;
7 extern crate lazy_static;
9 extern crate itertools;
12 extern crate rustyline;
13 use rustyline::error::ReadlineError;
14 use rustyline::Editor;
19 use types::{MalVal,MalArgs,MalRet,MalErr,error,format_error,func};
20 use types::MalVal::{Nil,Int,Sym,List,Vector,Hash};
24 use env::{Env,env_new,env_get,env_set,env_sets};
27 fn read(str: &str) -> MalRet {
28 reader::read_str(str.to_string())
32 fn eval_ast(ast: &MalVal, env: &Env) -> MalRet {
34 Sym(_) => Ok(env_get(&env, &ast)?),
36 let mut lst: MalArgs = vec![];
37 for a in v.iter() { lst.push(eval(a.clone(), env.clone())?) }
41 let mut lst: MalArgs = vec![];
42 for a in v.iter() { lst.push(eval(a.clone(), env.clone())?) }
46 let mut new_hm: FnvHashMap<String,MalVal> = FnvHashMap::default();
47 for (k,v) in hm.iter() {
48 new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
50 Ok(Hash(Rc::new(new_hm),Rc::new(Nil)))
56 fn eval(ast: MalVal, env: Env) -> MalRet {
59 if l.len() == 0 { return Ok(ast); }
62 Sym(ref a0sym) if a0sym == "def!" => {
63 env_set(&env, l[1].clone(), eval(l[2].clone(), env.clone())?)
65 Sym(ref a0sym) if a0sym == "let*" => {
66 let let_env = env_new(Some(env.clone()));
67 let (a1, a2) = (l[1].clone(), l[2].clone());
69 List(ref binds,_) | Vector(ref binds,_) => {
70 for (b, e) in binds.iter().tuples() {
73 let _ = env_set(&let_env, b.clone(),
74 eval(e.clone(), let_env.clone())?);
77 return error("let* with non-Sym binding");
83 return error("let* with non-List bindings");
89 match eval_ast(&ast, &env)? {
91 let ref f = el[0].clone();
92 f.apply(el[1..].to_vec())
95 error("expected a list")
101 _ => eval_ast(&ast, &env),
106 fn print(ast: &MalVal) -> String {
110 fn rep(str: &str, env: &Env) -> Result<String,MalErr> {
111 let ast = read(str)?;
112 let exp = eval(ast, env.clone())?;
116 fn int_op(op: fn(i64, i64) -> i64, a:MalArgs) -> MalRet {
117 match (a[0].clone(), a[1].clone()) {
118 (Int(a0), Int(a1)) => Ok(Int(op(a0,a1))),
119 _ => error("invalid int_op args"),
124 // `()` can be used when no completer is required
125 let mut rl = Editor::<()>::new();
126 if rl.load_history(".mal-history").is_err() {
127 println!("No previous history.");
130 let repl_env = env_new(None);
131 env_sets(&repl_env, "+", func(|a:MalArgs|{int_op(|i,j|{i+j},a)}));
132 env_sets(&repl_env, "-", func(|a:MalArgs|{int_op(|i,j|{i-j},a)}));
133 env_sets(&repl_env, "*", func(|a:MalArgs|{int_op(|i,j|{i*j},a)}));
134 env_sets(&repl_env, "/", func(|a:MalArgs|{int_op(|i,j|{i/j},a)}));
137 let readline = rl.readline("user> ");
140 rl.add_history_entry(&line);
141 rl.save_history(".mal-history").unwrap();
143 match rep(&line, &repl_env) {
144 Ok(out) => println!("{}", out),
145 Err(e) => println!("Error: {}", format_error(e)),
149 Err(ReadlineError::Interrupted) => continue,
150 Err(ReadlineError::Eof) => break,
152 println!("Error: {:?}", err);
159 // vim: ts=2:sw=2:expandtab