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 crate::types::MalErr::{ErrMalVal, ErrString};
19 use crate::types::MalVal::{Bool, Func, Hash, List, MalFunc, Nil, Str, Sym, Vector};
20 use crate::types::{error, format_error, MalArgs, MalErr, MalRet, MalVal};
24 use crate::env::{env_bind, env_find, env_get, env_new, env_set, env_sets, Env};
29 fn read(str: &str) -> MalRet {
30 reader::read_str(str.to_string())
35 fn qq_iter(elts: &MalArgs) -> MalVal {
36 let mut acc = list![];
37 for elt in elts.iter().rev() {
38 if let List(v, _) = elt {
40 if let Sym(ref s) = v[0] {
41 if s == "splice-unquote" {
42 acc = list![Sym("concat".to_string()), v[1].clone(), acc];
48 acc = list![Sym("cons".to_string()), quasiquote(&elt), acc];
53 fn quasiquote(ast: &MalVal) -> MalVal {
57 if let Sym(ref s) = v[0] {
65 Vector(v, _) => return list![Sym("vec".to_string()), qq_iter(&v)],
66 Hash(_, _) | Sym(_)=> return list![Sym("quote".to_string()), ast.clone()],
71 fn is_macro_call(ast: &MalVal, env: &Env) -> Option<(MalVal, MalArgs)> {
73 List(v, _) => match v[0] {
74 Sym(ref s) => match env_find(env, s) {
75 Some(e) => match env_get(&e, &v[0]) {
76 Ok(f @ MalFunc { is_macro: true, .. }) => Some((f, v[1..].to_vec())),
87 fn macroexpand(mut ast: MalVal, env: &Env) -> (bool, MalRet) {
88 let mut was_expanded = false;
89 while let Some((mf, args)) = is_macro_call(&ast, env) {
90 //println!("macroexpand 1: {:?}", ast);
91 ast = match mf.apply(args) {
92 Err(e) => return (false, Err(e)),
95 //println!("macroexpand 2: {:?}", ast);
98 ((was_expanded, Ok(ast)))
101 fn eval_ast(ast: &MalVal, env: &Env) -> MalRet {
103 Sym(_) => Ok(env_get(&env, &ast)?),
105 let mut lst: MalArgs = vec![];
107 lst.push(eval(a.clone(), env.clone())?)
112 let mut lst: MalArgs = vec![];
114 lst.push(eval(a.clone(), env.clone())?)
119 let mut new_hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
120 for (k, v) in hm.iter() {
121 new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
123 Ok(Hash(Rc::new(new_hm), Rc::new(Nil)))
125 _ => Ok(ast.clone()),
129 fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
133 ret = match ast.clone() {
138 match macroexpand(ast.clone(), &env) {
139 (true, Ok(new_ast)) => {
143 (_, Err(e)) => return Err(e),
152 Sym(ref a0sym) if a0sym == "def!" => {
153 env_set(&env, l[1].clone(), eval(l[2].clone(), env.clone())?)
155 Sym(ref a0sym) if a0sym == "let*" => {
156 env = env_new(Some(env.clone()));
157 let (a1, a2) = (l[1].clone(), l[2].clone());
159 List(ref binds, _) | Vector(ref binds, _) => {
160 for (b, e) in binds.iter().tuples() {
166 eval(e.clone(), env.clone())?,
170 return error("let* with non-Sym binding");
176 return error("let* with non-List bindings");
182 Sym(ref a0sym) if a0sym == "quote" => Ok(l[1].clone()),
183 Sym(ref a0sym) if a0sym == "quasiquoteexpand" => Ok(quasiquote(&l[1])),
184 Sym(ref a0sym) if a0sym == "quasiquote" => {
185 ast = quasiquote(&l[1]);
188 Sym(ref a0sym) if a0sym == "defmacro!" => {
189 let (a1, a2) = (l[1].clone(), l[2].clone());
190 let r = eval(a2, env.clone())?;
205 params: params.clone(),
210 _ => error("set_macro on non-function"),
213 Sym(ref a0sym) if a0sym == "macroexpand" => {
214 match macroexpand(l[1].clone(), &env) {
215 (_, Ok(new_ast)) => Ok(new_ast),
219 Sym(ref a0sym) if a0sym == "try*" => match eval(l[1].clone(), env.clone()) {
220 Err(ref e) if l.len() >= 3 => {
222 ErrMalVal(mv) => mv.clone(),
223 ErrString(s) => Str(s.to_string()),
227 let catch_env = env_bind(
229 list!(vec![c[1].clone()]),
232 eval(c[2].clone(), catch_env)
234 _ => error("invalid catch block"),
239 Sym(ref a0sym) if a0sym == "do" => {
240 match eval_ast(&list!(l[1..l.len() - 1].to_vec()), &env)? {
242 ast = l.last().unwrap_or(&Nil).clone();
245 _ => error("invalid do form"),
248 Sym(ref a0sym) if a0sym == "if" => {
249 let cond = eval(l[1].clone(), env.clone())?;
251 Bool(false) | Nil if l.len() >= 4 => {
255 Bool(false) | Nil => Ok(Nil),
256 _ if l.len() >= 3 => {
263 Sym(ref a0sym) if a0sym == "fn*" => {
264 let (a1, a2) = (l[1].clone(), l[2].clone());
274 Sym(ref a0sym) if a0sym == "eval" => {
275 ast = eval(l[1].clone(), env.clone())?;
276 while let Some(ref e) = env.clone().outer {
281 _ => match eval_ast(&ast, &env)? {
283 let ref f = el[0].clone();
284 let args = el[1..].to_vec();
286 Func(_, _) => f.apply(args),
295 env = env_bind(Some(menv.clone()), p.clone(), args)?;
299 _ => error("attempt to call non-function"),
302 _ => error("expected a list"),
306 _ => eval_ast(&ast, &env),
316 fn print(ast: &MalVal) -> String {
320 fn rep(str: &str, env: &Env) -> Result<String, MalErr> {
321 let ast = read(str)?;
322 let exp = eval(ast, env.clone())?;
327 let mut args = std::env::args();
328 let arg1 = args.nth(1);
330 // `()` can be used when no completer is required
331 let mut rl = Editor::<()>::new();
332 if rl.load_history(".mal-history").is_err() {
333 eprintln!("No previous history.");
336 // core.rs: defined using rust
337 let repl_env = env_new(None);
338 for (k, v) in core::ns() {
339 env_sets(&repl_env, k, v);
341 env_sets(&repl_env, "*ARGV*", list!(args.map(Str).collect()));
343 // core.mal: defined using the language itself
344 let _ = rep("(def! not (fn* (a) (if a false true)))", &repl_env);
346 "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))",
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);
351 // Invoked with arguments
352 if let Some(f) = arg1 {
353 match rep(&format!("(load-file \"{}\")", f), &repl_env) {
354 Ok(_) => std::process::exit(0),
356 println!("Error: {}", format_error(e));
357 std::process::exit(1);
364 let readline = rl.readline("user> ");
367 rl.add_history_entry(&line);
368 rl.save_history(".mal-history").unwrap();
370 match rep(&line, &repl_env) {
371 Ok(out) => println!("{}", out),
372 Err(e) => println!("Error: {}", format_error(e)),
376 Err(ReadlineError::Interrupted) => continue,
377 Err(ReadlineError::Eof) => break,
379 println!("Error: {:?}", err);