2 //use std::collections::HashMap;
6 extern crate lazy_static;
8 extern crate itertools;
11 extern crate rustyline;
12 use rustyline::error::ReadlineError;
13 use rustyline::Editor;
18 use crate::types::MalErr::ErrString;
19 use crate::types::MalVal::{Hash, Int, List, Nil, Sym, Vector};
20 use crate::types::{error, format_error, func, MalArgs, MalErr, MalRet, MalVal};
23 // TODO: figure out a way to avoid including env
27 pub type Env = FnvHashMap<String, MalVal>;
30 fn read(str: &str) -> MalRet {
31 reader::read_str(str.to_string())
35 fn eval_ast(ast: &MalVal, env: &Env) -> MalRet {
39 .ok_or(ErrString(format!("'{}' not found", sym)))?
42 let mut lst: MalArgs = vec![];
44 lst.push(eval(a.clone(), env.clone())?)
49 let mut lst: MalArgs = vec![];
51 lst.push(eval(a.clone(), env.clone())?)
56 let mut new_hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
57 for (k, v) in hm.iter() {
58 new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
60 Ok(Hash(Rc::new(new_hm), Rc::new(Nil)))
66 fn eval(ast: MalVal, env: Env) -> MalRet {
72 match eval_ast(&ast, &env)? {
74 let ref f = el[0].clone();
75 f.apply(el[1..].to_vec())
77 _ => error("expected a list"),
80 _ => eval_ast(&ast, &env),
85 fn print(ast: &MalVal) -> String {
89 fn rep(str: &str, env: &Env) -> Result<String, MalErr> {
91 let exp = eval(ast, env.clone())?;
95 fn int_op(op: fn(i64, i64) -> i64, a: MalArgs) -> MalRet {
96 match (a[0].clone(), a[1].clone()) {
97 (Int(a0), Int(a1)) => Ok(Int(op(a0, a1))),
98 _ => error("invalid int_op args"),
103 // `()` can be used when no completer is required
104 let mut rl = Editor::<()>::new();
105 if rl.load_history(".mal-history").is_err() {
106 eprintln!("No previous history.");
109 let mut repl_env = Env::default();
110 repl_env.insert("+".to_string(), func(|a: MalArgs| int_op(|i, j| i + j, a)));
111 repl_env.insert("-".to_string(), func(|a: MalArgs| int_op(|i, j| i - j, a)));
112 repl_env.insert("*".to_string(), func(|a: MalArgs| int_op(|i, j| i * j, a)));
113 repl_env.insert("/".to_string(), func(|a: MalArgs| int_op(|i, j| i / j, a)));
116 let readline = rl.readline("user> ");
119 rl.add_history_entry(&line);
120 rl.save_history(".mal-history").unwrap();
122 match rep(&line, &repl_env) {
123 Ok(out) => println!("{}", out),
124 Err(e) => println!("Error: {}", format_error(e)),
128 Err(ReadlineError::Interrupted) => continue,
129 Err(ReadlineError::Eof) => break,
131 println!("Error: {:?}", err);