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