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;
18 use types::{MalVal,MalArgs,MalRet,MalErr,error,format_error};
19 use types::MalVal::{Nil,Bool,Str,Sym,List,Vector,Hash,Func,MalFunc};
23 use env::{Env,env_new,env_bind,env_get,env_set,env_sets};
28 fn read(str: &str) -> MalRet {
29 reader::read_str(str.to_string())
33 fn eval_ast(ast: &MalVal, env: &Env) -> MalRet {
35 Sym(_) => Ok(env_get(&env, &ast)?),
37 let mut lst: MalArgs = vec![];
38 for a in v.iter() { lst.push(eval(a.clone(), env.clone())?) }
42 let mut lst: MalArgs = vec![];
43 for a in v.iter() { lst.push(eval(a.clone(), env.clone())?) }
47 let mut new_hm: FnvHashMap<String,MalVal> = FnvHashMap::default();
48 for (k,v) in hm.iter() {
49 new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
51 Ok(Hash(Rc::new(new_hm),Rc::new(Nil)))
57 fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
62 ret = match ast.clone() {
64 if l.len() == 0 { return Ok(ast); }
67 Sym(ref a0sym) if a0sym == "def!" => {
68 env_set(&env, l[1].clone(), eval(l[2].clone(), env.clone())?)
70 Sym(ref a0sym) if a0sym == "let*" => {
71 env = env_new(Some(env.clone()));
72 let (a1, a2) = (l[1].clone(), l[2].clone());
74 List(ref binds,_) | Vector(ref binds,_) => {
75 for (b, e) in binds.iter().tuples() {
78 let _ = env_set(&env, b.clone(),
79 eval(e.clone(), env.clone())?);
82 return error("let* with non-Sym binding");
88 return error("let* with non-List bindings");
94 Sym(ref a0sym) if a0sym == "do" => {
95 match eval_ast(&list!(l[1..l.len()-1].to_vec()), &env)? {
97 ast = l.last().unwrap_or(&Nil).clone();
100 _ => error("invalid do form"),
103 Sym(ref a0sym) if a0sym == "if" => {
104 let cond = eval(l[1].clone(), env.clone())?;
106 Bool(false) | Nil if l.len() >= 4 => {
110 Bool(false) | Nil => Ok(Nil),
111 _ if l.len() >= 3 => {
118 Sym(ref a0sym) if a0sym == "fn*" => {
119 let (a1, a2) = (l[1].clone(), l[2].clone());
120 Ok(MalFunc{eval: eval, ast: Rc::new(a2), env: env,
121 params: Rc::new(a1), is_macro: false,
124 Sym(ref a0sym) if a0sym == "eval" => {
125 ast = eval(l[1].clone(), env.clone())?;
126 while let Some(ref e) = env.clone().outer {
132 match eval_ast(&ast, &env)? {
134 let ref f = el[0].clone();
135 let args = el[1..].to_vec();
137 Func(_,_) => f.apply(args),
138 MalFunc{ast: mast, env: menv, params, ..} => {
141 env = env_bind(Some(menv.clone()), p.clone(), args)?;
145 _ => error("attempt to call non-function"),
149 error("expected a list")
155 _ => eval_ast(&ast, &env),
166 fn print(ast: &MalVal) -> String {
170 fn rep(str: &str, env: &Env) -> Result<String,MalErr> {
171 let ast = read(str)?;
172 let exp = eval(ast, env.clone())?;
177 let mut args = std::env::args();
178 let arg1 = args.nth(1);
180 // `()` can be used when no completer is required
181 let mut rl = Editor::<()>::new();
182 if rl.load_history(".mal-history").is_err() {
183 eprintln!("No previous history.");
186 // core.rs: defined using rust
187 let repl_env = env_new(None);
188 for (k, v) in core::ns() {
189 env_sets(&repl_env, k, v);
191 env_sets(&repl_env, "*ARGV*", list!(args.map(Str).collect()));
193 // core.mal: defined using the language itself
194 let _ = rep("(def! not (fn* (a) (if a false true)))", &repl_env);
195 let _ = rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", &repl_env);
197 // Invoked with arguments
198 if let Some(f) = arg1 {
199 match rep(&format!("(load-file \"{}\")",f), &repl_env) {
200 Ok(_) => std::process::exit(0),
202 println!("Error: {}", format_error(e));
203 std::process::exit(1);
210 let readline = rl.readline("user> ");
213 rl.add_history_entry(&line);
214 rl.save_history(".mal-history").unwrap();
216 match rep(&line, &repl_env) {
217 Ok(out) => println!("{}", out),
218 Err(e) => println!("Error: {}", format_error(e)),
222 Err(ReadlineError::Interrupted) => continue,
223 Err(ReadlineError::Eof) => break,
225 println!("Error: {:?}", err);
232 // vim: ts=2:sw=2:expandtab