a80892605d068375d0764cafb2aaf9211455bafd
[jackhill/mal.git] / rust / src / bin / step8_macros.rs
1 #![feature(exit_status)]
2
3 extern crate mal;
4
5 use std::collections::HashMap;
6 use std::env as stdenv;
7
8 use mal::types::{MalVal, MalRet, MalError, err_str};
9 use mal::types::{symbol, _nil, string, list, vector, hash_map, malfunc, malfuncd};
10 use mal::types::MalType::{Nil, False, Sym, List, Vector, Hash_Map, Func, MalFunc};
11 use mal::types::MalError::{ErrString, ErrMalVal};
12 use mal::{readline, reader, core};
13 use mal::env::{env_set, env_get, env_new, env_bind, env_find, env_root, Env};
14
15 // read
16 fn read(str: String) -> MalRet {
17 reader::read_str(str)
18 }
19
20 // eval
21 fn is_pair(x: MalVal) -> bool {
22 match *x {
23 List(ref lst,_) | Vector(ref lst,_) => lst.len() > 0,
24 _ => false,
25 }
26 }
27
28 fn quasiquote(ast: MalVal) -> MalVal {
29 if !is_pair(ast.clone()) {
30 return list(vec![symbol("quote"), ast])
31 }
32
33 match *ast.clone() {
34 List(ref args,_) | Vector(ref args,_) => {
35 let ref a0 = args[0];
36 match **a0 {
37 Sym(ref s) => {
38 if s.to_string() == "unquote".to_string() {
39 let ref a1 = args[1];
40 return a1.clone();
41 }
42 },
43 _ => (),
44 }
45 if is_pair(a0.clone()) {
46 match **a0 {
47 List(ref a0args,_) | Vector(ref a0args,_) => {
48 let a00 = a0args[0].clone();
49 match *a00 {
50 Sym(ref s) => {
51 if s.to_string() == "splice-unquote".to_string() {
52 return list(vec![symbol("concat"),
53 a0args[1].clone(),
54 quasiquote(list(args[1..].to_vec()))])
55 }
56 },
57 _ => (),
58 }
59 },
60 _ => (),
61 }
62 }
63 let rest = list(args[1..].to_vec());
64 return list(vec![symbol("cons"),
65 quasiquote(a0.clone()),
66 quasiquote(rest)])
67 },
68 _ => _nil(), // should never reach
69 }
70 }
71
72 fn is_macro_call(ast: MalVal, env: Env) -> bool {
73 match *ast {
74 List(ref lst,_) => {
75 match *lst[0] {
76 Sym(_) => {
77 if env_find(&env, &lst[0]).is_some() {
78 match env_get(&env, &lst[0]) {
79 Ok(f) => {
80 match *f {
81 MalFunc(ref mfd,_) => {
82 mfd.is_macro
83 },
84 _ => false,
85 }
86 },
87 _ => false,
88 }
89 } else {
90 false
91 }
92 },
93 _ => false,
94 }
95 },
96 _ => false,
97 }
98 }
99
100 fn macroexpand(mut ast: MalVal, env: Env) -> MalRet {
101 while is_macro_call(ast.clone(), env.clone()) {
102 let ast2 = ast.clone();
103 let args = match *ast2 {
104 List(ref args,_) => args,
105 _ => break,
106 };
107 let ref a0 = args[0];
108 let mf = match **a0 {
109 Sym(_) => try!(env_get(&env, &a0)),
110 _ => break,
111 };
112 match *mf {
113 MalFunc(_,_) => ast = try!(mf.apply(args[1..].to_vec())),
114 _ => break,
115 }
116 }
117 Ok(ast)
118 }
119
120 fn eval_ast(ast: MalVal, env: Env) -> MalRet {
121 let ast2 = ast.clone();
122 match *ast2 {
123 //match *ast {
124 Sym(_) => env_get(&env, &ast),
125 List(ref a,_) | Vector(ref a,_) => {
126 let mut ast_vec : Vec<MalVal> = vec![];
127 for mv in a.iter() {
128 let mv2 = mv.clone();
129 match eval(mv2, env.clone()) {
130 Ok(mv) => { ast_vec.push(mv); },
131 Err(e) => { return Err(e); },
132 }
133 }
134 Ok(match *ast { List(_,_) => list(ast_vec),
135 _ => vector(ast_vec) })
136 },
137 Hash_Map(ref hm,_) => {
138 let mut new_hm: HashMap<String,MalVal> = HashMap::new();
139 for (key, value) in hm.iter() {
140 match eval(value.clone(), env.clone()) {
141 Ok(mv) => { new_hm.insert(key.to_string(), mv); },
142 Err(e) => return Err(e),
143 }
144 }
145 Ok(hash_map(new_hm))
146 },
147 _ => {
148 Ok(ast)
149 }
150 }
151 }
152
153 fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
154 'tco: loop {
155
156 //println!("eval: {}, {}", ast, env.borrow());
157 //println!("eval: {}", ast);
158 let mut ast2 = ast.clone();
159 match *ast2 {
160 List(_,_) => (), // continue
161 _ => return eval_ast(ast2, env),
162 }
163
164 // apply list
165 match macroexpand(ast2, env.clone()) {
166 Ok(a) => {
167 ast2 = a;
168 },
169 Err(e) => return Err(e),
170 }
171 match *ast2 {
172 List(_,_) => (), // continue
173 _ => return Ok(ast2),
174 }
175 let ast3 = ast2.clone();
176
177 let (args, a0sym) = match *ast2 {
178 List(ref args,_) => {
179 if args.len() == 0 {
180 return Ok(ast3);
181 }
182 let ref a0 = *args[0];
183 match *a0 {
184 Sym(ref a0sym) => (args, &a0sym[..]),
185 _ => (args, "__<fn*>__"),
186 }
187 },
188 _ => return err_str("Expected list"),
189 };
190
191 match a0sym {
192 "def!" => {
193 let a1 = (*args)[1].clone();
194 let a2 = (*args)[2].clone();
195 let res = eval(a2, env.clone());
196 match res {
197 Ok(r) => {
198 match *a1 {
199 Sym(_) => {
200 env_set(&env.clone(), a1.clone(), r.clone());
201 return Ok(r);
202 },
203 _ => {
204 return err_str("def! of non-symbol")
205 }
206 }
207 },
208 Err(e) => return Err(e),
209 }
210 },
211 "let*" => {
212 let let_env = env_new(Some(env.clone()));
213 let a1 = (*args)[1].clone();
214 let a2 = (*args)[2].clone();
215 match *a1 {
216 List(ref binds,_) | Vector(ref binds,_) => {
217 let mut it = binds.iter();
218 while it.len() >= 2 {
219 let b = it.next().unwrap();
220 let exp = it.next().unwrap();
221 match **b {
222 Sym(_) => {
223 match eval(exp.clone(), let_env.clone()) {
224 Ok(r) => {
225 env_set(&let_env, b.clone(), r);
226 },
227 Err(e) => {
228 return Err(e);
229 },
230 }
231 },
232 _ => {
233 return err_str("let* with non-symbol binding");
234 },
235 }
236 }
237 },
238 _ => return err_str("let* with non-list bindings"),
239 }
240 ast = a2;
241 env = let_env.clone();
242 continue 'tco;
243 },
244 "quote" => {
245 return Ok((*args)[1].clone());
246 },
247 "quasiquote" => {
248 let a1 = (*args)[1].clone();
249 ast = quasiquote(a1);
250 continue 'tco;
251 },
252 "defmacro!" => {
253 let a1 = (*args)[1].clone();
254 let a2 = (*args)[2].clone();
255 match eval(a2, env.clone()) {
256 Ok(r) => {
257 match *r {
258 MalFunc(ref mfd,_) => {
259 match *a1 {
260 Sym(_) => {
261 let mut new_mfd = mfd.clone();
262 new_mfd.is_macro = true;
263 let mf = malfuncd(new_mfd,_nil());
264 env_set(&env.clone(), a1.clone(), mf.clone());
265 return Ok(mf);
266 },
267 _ => return err_str("def! of non-symbol"),
268 }
269 },
270 _ => return err_str("def! of non-symbol"),
271 }
272 },
273 Err(e) => return Err(e),
274 }
275 },
276 "macroexpand" => {
277 let a1 = (*args)[1].clone();
278 return macroexpand(a1, env.clone())
279 },
280 "do" => {
281 let el = list(args[1..args.len()-1].to_vec());
282 match eval_ast(el, env.clone()) {
283 Err(e) => return Err(e),
284 Ok(_) => {
285 let ref last = args[args.len()-1];
286 ast = last.clone();
287 continue 'tco;
288 },
289 }
290 },
291 "if" => {
292 let a1 = (*args)[1].clone();
293 let cond = eval(a1, env.clone());
294 match cond {
295 Err(e) => return Err(e),
296 Ok(c) => match *c {
297 False | Nil => {
298 if args.len() >= 4 {
299 let a3 = (*args)[3].clone();
300 ast = a3;
301 env = env.clone();
302 continue 'tco;
303 } else {
304 return Ok(_nil());
305 }
306 },
307 _ => {
308 let a2 = (*args)[2].clone();
309 ast = a2;
310 env = env.clone();
311 continue 'tco;
312 },
313 }
314 }
315 },
316 "fn*" => {
317 let a1 = (*args)[1].clone();
318 let a2 = (*args)[2].clone();
319 return Ok(malfunc(eval, a2, env.clone(), a1, _nil()));
320 },
321 "eval" => {
322 let a1 = (*args)[1].clone();
323 match eval(a1, env.clone()) {
324 Ok(exp) => {
325 ast = exp;
326 env = env_root(&env);
327 continue 'tco;
328 },
329 Err(e) => return Err(e),
330 }
331 },
332 _ => { // function call
333 return match eval_ast(ast3, env.clone()) {
334 Err(e) => Err(e),
335 Ok(el) => {
336 let args = match *el {
337 List(ref args,_) => args,
338 _ => return err_str("Invalid apply"),
339 };
340 match *args.clone()[0] {
341 Func(f,_) => f(args[1..].to_vec()),
342 MalFunc(ref mf,_) => {
343 let mfc = mf.clone();
344 let alst = list(args[1..].to_vec());
345 let new_env = env_new(Some(mfc.env.clone()));
346 match env_bind(&new_env, mfc.params, alst) {
347 Ok(_) => {
348 ast = mfc.exp;
349 env = new_env;
350 continue 'tco;
351 },
352 Err(e) => err_str(&e),
353 }
354 },
355 _ => err_str("attempt to call non-function"),
356 }
357 }
358 }
359 },
360 }
361
362 }
363 }
364
365 // print
366 fn print(exp: MalVal) -> String {
367 exp.pr_str(true)
368 }
369
370 fn rep(str: &str, env: Env) -> Result<String,MalError> {
371 match read(str.to_string()) {
372 Err(e) => Err(e),
373 Ok(ast) => {
374 //println!("read: {}", ast);
375 match eval(ast, env) {
376 Err(e) => Err(e),
377 Ok(exp) => Ok(print(exp)),
378 }
379 }
380 }
381 }
382
383 fn main() {
384 // core.rs: defined using rust
385 let repl_env = env_new(None);
386 for (k, v) in core::ns().into_iter() {
387 env_set(&repl_env, symbol(&k), v);
388 }
389 // see eval() for definition of "eval"
390 env_set(&repl_env, symbol("*ARGV*"), list(vec![]));
391
392 // core.mal: defined using the language itself
393 let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone());
394 let _ = rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", repl_env.clone());
395 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.clone());
396 let _ = rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))", repl_env.clone());
397
398 // Invoked with command line arguments
399 let args = stdenv::args();
400 if args.len() > 1 {
401 let mv_args = args.skip(2)
402 .map(|a| string(a))
403 .collect::<Vec<MalVal>>();
404 env_set(&repl_env, symbol("*ARGV*"), list(mv_args));
405 let lf = format!("(load-file \"{}\")",
406 stdenv::args().skip(1).next().unwrap());
407 return match rep(&lf, repl_env.clone()) {
408 Ok(_) => stdenv::set_exit_status(0),
409 Err(str) => {
410 println!("Error: {:?}", str);
411 stdenv::set_exit_status(1);
412 }
413 };
414 }
415
416 // repl loop
417 loop {
418 let line = readline::mal_readline("user> ");
419 match line { None => break, _ => () }
420 match rep(&line.unwrap(), repl_env.clone()) {
421 Ok(str) => println!("{}", str),
422 Err(ErrMalVal(_)) => (), // Blank line
423 Err(ErrString(s)) => println!("Error: {}", s),
424 }
425 }
426 }