DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / rust / step5_tco.rs
CommitLineData
4ef4b17c
JM
1use std::rc::Rc;
2//use std::collections::HashMap;
3use fnv::FnvHashMap;
4use itertools::Itertools;
5
6#[macro_use]
7extern crate lazy_static;
4ef4b17c 8extern crate fnv;
4a649b37
RF
9extern crate itertools;
10extern crate regex;
4ef4b17c
JM
11
12extern crate rustyline;
13use rustyline::error::ReadlineError;
14use rustyline::Editor;
15
16#[macro_use]
17mod types;
c9b18677
GL
18use crate::types::MalVal::{Bool, Func, Hash, List, MalFunc, Nil, Sym, Vector};
19use crate::types::{error, format_error, MalArgs, MalErr, MalRet, MalVal};
4ef4b17c 20mod env;
4a649b37
RF
21mod printer;
22mod reader;
c9b18677 23use crate::env::{env_bind, env_get, env_new, env_set, env_sets, Env};
4ef4b17c
JM
24#[macro_use]
25mod core;
26
27// read
28fn read(str: &str) -> MalRet {
4a649b37 29 reader::read_str(str.to_string())
4ef4b17c
JM
30}
31
32// eval
33fn eval_ast(ast: &MalVal, env: &Env) -> MalRet {
4a649b37
RF
34 match ast {
35 Sym(_) => Ok(env_get(&env, &ast)?),
36 List(v, _) => {
37 let mut lst: MalArgs = vec![];
38 for a in v.iter() {
39 lst.push(eval(a.clone(), env.clone())?)
40 }
41 Ok(list!(lst))
42 }
43 Vector(v, _) => {
44 let mut lst: MalArgs = vec![];
45 for a in v.iter() {
46 lst.push(eval(a.clone(), env.clone())?)
47 }
48 Ok(vector!(lst))
49 }
50 Hash(hm, _) => {
51 let mut new_hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
52 for (k, v) in hm.iter() {
53 new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
54 }
55 Ok(Hash(Rc::new(new_hm), Rc::new(Nil)))
56 }
57 _ => Ok(ast.clone()),
58 }
4ef4b17c
JM
59}
60
61fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
4a649b37 62 let ret: MalRet;
4ef4b17c 63
4a649b37
RF
64 'tco: loop {
65 ret = match ast.clone() {
66 List(l, _) => {
67 if l.len() == 0 {
68 return Ok(ast);
69 }
70 let a0 = &l[0];
71 match a0 {
72 Sym(ref a0sym) if a0sym == "def!" => {
73 env_set(&env, l[1].clone(), eval(l[2].clone(), env.clone())?)
74 }
75 Sym(ref a0sym) if a0sym == "let*" => {
76 env = env_new(Some(env.clone()));
77 let (a1, a2) = (l[1].clone(), l[2].clone());
78 match a1 {
79 List(ref binds, _) | Vector(ref binds, _) => {
80 for (b, e) in binds.iter().tuples() {
81 match b {
82 Sym(_) => {
83 let _ = env_set(
84 &env,
85 b.clone(),
86 eval(e.clone(), env.clone())?,
87 );
88 }
89 _ => {
90 return error("let* with non-Sym binding");
91 }
92 }
93 }
94 }
95 _ => {
96 return error("let* with non-List bindings");
97 }
98 };
99 ast = a2;
100 continue 'tco;
101 }
102 Sym(ref a0sym) if a0sym == "do" => {
103 match eval_ast(&list!(l[1..l.len() - 1].to_vec()), &env)? {
104 List(_, _) => {
105 ast = l.last().unwrap_or(&Nil).clone();
106 continue 'tco;
107 }
108 _ => error("invalid do form"),
109 }
110 }
111 Sym(ref a0sym) if a0sym == "if" => {
112 let cond = eval(l[1].clone(), env.clone())?;
113 match cond {
114 Bool(false) | Nil if l.len() >= 4 => {
115 ast = l[3].clone();
116 continue 'tco;
117 }
118 Bool(false) | Nil => Ok(Nil),
119 _ if l.len() >= 3 => {
120 ast = l[2].clone();
121 continue 'tco;
122 }
123 _ => Ok(Nil),
124 }
125 }
126 Sym(ref a0sym) if a0sym == "fn*" => {
127 let (a1, a2) = (l[1].clone(), l[2].clone());
128 Ok(MalFunc {
129 eval: eval,
130 ast: Rc::new(a2),
131 env: env,
132 params: Rc::new(a1),
133 is_macro: false,
134 meta: Rc::new(Nil),
135 })
136 }
137 _ => match eval_ast(&ast, &env)? {
138 List(ref el, _) => {
139 let ref f = el[0].clone();
140 let args = el[1..].to_vec();
141 match f {
142 Func(_, _) => f.apply(args),
143 MalFunc {
144 ast: mast,
145 env: menv,
146 params,
147 ..
148 } => {
149 let a = &**mast;
150 let p = &**params;
151 env = env_bind(Some(menv.clone()), p.clone(), args)?;
152 ast = a.clone();
153 continue 'tco;
154 }
155 _ => error("attempt to call non-function"),
156 }
157 }
158 _ => error("expected a list"),
159 },
4ef4b17c 160 }
4ef4b17c 161 }
4a649b37
RF
162 _ => eval_ast(&ast, &env),
163 };
4ef4b17c 164
4a649b37
RF
165 break;
166 } // end 'tco loop
4ef4b17c 167
4a649b37 168 ret
4ef4b17c
JM
169}
170
171// print
172fn print(ast: &MalVal) -> String {
4a649b37 173 ast.pr_str(true)
4ef4b17c
JM
174}
175
4a649b37
RF
176fn rep(str: &str, env: &Env) -> Result<String, MalErr> {
177 let ast = read(str)?;
178 let exp = eval(ast, env.clone())?;
179 Ok(print(&exp))
4ef4b17c
JM
180}
181
182fn main() {
4a649b37
RF
183 // `()` can be used when no completer is required
184 let mut rl = Editor::<()>::new();
185 if rl.load_history(".mal-history").is_err() {
186 eprintln!("No previous history.");
187 }
4ef4b17c 188
4a649b37
RF
189 // core.rs: defined using rust
190 let repl_env = env_new(None);
191 for (k, v) in core::ns() {
192 env_sets(&repl_env, k, v);
193 }
4ef4b17c 194
4a649b37
RF
195 // core.mal: defined using the language itself
196 let _ = rep("(def! not (fn* (a) (if a false true)))", &repl_env);
197
198 // main repl loop
199 loop {
200 let readline = rl.readline("user> ");
201 match readline {
202 Ok(line) => {
203 rl.add_history_entry(&line);
204 rl.save_history(".mal-history").unwrap();
205 if line.len() > 0 {
206 match rep(&line, &repl_env) {
207 Ok(out) => println!("{}", out),
208 Err(e) => println!("Error: {}", format_error(e)),
209 }
210 }
211 }
212 Err(ReadlineError::Interrupted) => continue,
213 Err(ReadlineError::Eof) => break,
214 Err(err) => {
215 println!("Error: {:?}", err);
216 break;
217 }
4ef4b17c 218 }
4ef4b17c 219 }
4ef4b17c 220}