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::MalVal::{Bool, Func, Hash, List, MalFunc, Nil, Str, Sym, Vector};
19 use crate::types::{error, format_error, MalArgs, MalErr, MalRet, MalVal};
23 use crate::env::{env_bind, env_find, env_get, env_new, env_set, env_sets, Env};
28 fn read(str: &str) -> MalRet {
29 reader::read_str(str.to_string())
33 fn quasiquote(ast: &MalVal) -> MalVal {
35 List(ref v, _) | Vector(ref v, _) if v.len() > 0 => {
38 Sym(ref s) if s == "unquote" => v[1].clone(),
40 List(ref v0, _) | Vector(ref v0, _) if v0.len() > 0 => match v0[0] {
41 Sym(ref s) if s == "splice-unquote" => list![
42 Sym("concat".to_string()),
44 quasiquote(&list!(v[1..].to_vec()))
47 Sym("cons".to_string()),
49 quasiquote(&list!(v[1..].to_vec()))
53 Sym("cons".to_string()),
55 quasiquote(&list!(v[1..].to_vec()))
60 _ => list![Sym("quote".to_string()), ast.clone()],
64 fn is_macro_call(ast: &MalVal, env: &Env) -> Option<(MalVal, MalArgs)> {
66 List(v, _) => match v[0] {
67 Sym(ref s) => match env_find(env, s) {
68 Some(e) => match env_get(&e, &v[0]) {
69 Ok(f @ MalFunc { is_macro: true, .. }) => Some((f, v[1..].to_vec())),
80 fn macroexpand(mut ast: MalVal, env: &Env) -> (bool, MalRet) {
81 let mut was_expanded = false;
82 while let Some((mf, args)) = is_macro_call(&ast, env) {
83 //println!("macroexpand 1: {:?}", ast);
84 ast = match mf.apply(args) {
85 Err(e) => return (false, Err(e)),
88 //println!("macroexpand 2: {:?}", ast);
91 ((was_expanded, Ok(ast)))
94 fn eval_ast(ast: &MalVal, env: &Env) -> MalRet {
96 Sym(_) => Ok(env_get(&env, &ast)?),
98 let mut lst: MalArgs = vec![];
100 lst.push(eval(a.clone(), env.clone())?)
105 let mut lst: MalArgs = vec![];
107 lst.push(eval(a.clone(), env.clone())?)
112 let mut new_hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
113 for (k, v) in hm.iter() {
114 new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
116 Ok(Hash(Rc::new(new_hm), Rc::new(Nil)))
118 _ => Ok(ast.clone()),
122 fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
126 ret = match ast.clone() {
131 match macroexpand(ast.clone(), &env) {
132 (true, Ok(new_ast)) => {
136 (_, Err(e)) => return Err(e),
145 Sym(ref a0sym) if a0sym == "def!" => {
146 env_set(&env, l[1].clone(), eval(l[2].clone(), env.clone())?)
148 Sym(ref a0sym) if a0sym == "let*" => {
149 env = env_new(Some(env.clone()));
150 let (a1, a2) = (l[1].clone(), l[2].clone());
152 List(ref binds, _) | Vector(ref binds, _) => {
153 for (b, e) in binds.iter().tuples() {
159 eval(e.clone(), env.clone())?,
163 return error("let* with non-Sym binding");
169 return error("let* with non-List bindings");
175 Sym(ref a0sym) if a0sym == "quote" => Ok(l[1].clone()),
176 Sym(ref a0sym) if a0sym == "quasiquote" => {
177 ast = quasiquote(&l[1]);
180 Sym(ref a0sym) if a0sym == "defmacro!" => {
181 let (a1, a2) = (l[1].clone(), l[2].clone());
182 let r = eval(a2, env.clone())?;
197 params: params.clone(),
202 _ => error("set_macro on non-function"),
205 Sym(ref a0sym) if a0sym == "macroexpand" => {
206 match macroexpand(l[1].clone(), &env) {
207 (_, Ok(new_ast)) => Ok(new_ast),
211 Sym(ref a0sym) if a0sym == "do" => {
212 match eval_ast(&list!(l[1..l.len() - 1].to_vec()), &env)? {
214 ast = l.last().unwrap_or(&Nil).clone();
217 _ => error("invalid do form"),
220 Sym(ref a0sym) if a0sym == "if" => {
221 let cond = eval(l[1].clone(), env.clone())?;
223 Bool(false) | Nil if l.len() >= 4 => {
227 Bool(false) | Nil => Ok(Nil),
228 _ if l.len() >= 3 => {
235 Sym(ref a0sym) if a0sym == "fn*" => {
236 let (a1, a2) = (l[1].clone(), l[2].clone());
246 Sym(ref a0sym) if a0sym == "eval" => {
247 ast = eval(l[1].clone(), env.clone())?;
248 while let Some(ref e) = env.clone().outer {
253 _ => match eval_ast(&ast, &env)? {
255 let ref f = el[0].clone();
256 let args = el[1..].to_vec();
258 Func(_, _) => f.apply(args),
267 env = env_bind(Some(menv.clone()), p.clone(), args)?;
271 _ => error("attempt to call non-function"),
274 _ => error("expected a list"),
278 _ => eval_ast(&ast, &env),
288 fn print(ast: &MalVal) -> String {
292 fn rep(str: &str, env: &Env) -> Result<String, MalErr> {
293 let ast = read(str)?;
294 let exp = eval(ast, env.clone())?;
299 let mut args = std::env::args();
300 let arg1 = args.nth(1);
302 // `()` can be used when no completer is required
303 let mut rl = Editor::<()>::new();
304 if rl.load_history(".mal-history").is_err() {
305 eprintln!("No previous history.");
308 // core.rs: defined using rust
309 let repl_env = env_new(None);
310 for (k, v) in core::ns() {
311 env_sets(&repl_env, k, v);
313 env_sets(&repl_env, "*ARGV*", list!(args.map(Str).collect()));
315 // core.mal: defined using the language itself
316 let _ = rep("(def! not (fn* (a) (if a false true)))", &repl_env);
318 "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))",
321 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);
323 // Invoked with arguments
324 if let Some(f) = arg1 {
325 match rep(&format!("(load-file \"{}\")", f), &repl_env) {
326 Ok(_) => std::process::exit(0),
328 println!("Error: {}", format_error(e));
329 std::process::exit(1);
336 let readline = rl.readline("user> ");
339 rl.add_history_entry(&line);
340 rl.save_history(".mal-history").unwrap();
342 match rep(&line, &repl_env) {
343 Ok(out) => println!("{}", out),
344 Err(e) => println!("Error: {}", format_error(e)),
348 Err(ReadlineError::Interrupted) => continue,
349 Err(ReadlineError::Eof) => break,
351 println!("Error: {:?}", err);