1 // support precompiled regexes in reader.rs
4 extern crate regex_macros;
7 use std::collections::HashMap;
10 use types::{MalVal,MalRet,MalFunc,Nil,False,Sym,List,Vector,Hash_Map,Func,
11 _nil,symbol,string,list,vector,hash_map,malfunc,malfuncd};
12 use env::{Env,env_new,env_bind,env_root,env_find,env_set,env_get};
21 fn read(str: String) -> MalRet {
26 fn is_pair(x: MalVal) -> bool {
28 List(ref lst) => lst.len() > 0,
33 fn quasiquote(ast: MalVal) -> MalVal {
34 if !is_pair(ast.clone()) {
35 return list(vec![symbol("quote"), ast])
43 if s.to_string() == "unquote".to_string() {
50 if is_pair(a0.clone()) {
53 let a00 = a0args[0].clone();
56 if s.to_string() == "splice-unquote".to_string() {
57 return list(vec![symbol("concat"),
59 quasiquote(list(args.slice(1,args.len()).to_vec()))])
68 let rest = list(args.slice(1,args.len()).to_vec());
69 return list(vec![symbol("cons"),
70 quasiquote(a0.clone()),
73 _ => _nil(), // should never reach
77 fn is_macro_call(ast: MalVal, env: Env) -> bool {
83 if env_find(env.clone(), a0sym.to_string()).is_some() {
84 match env_get(env, a0sym.to_string()) {
106 fn macroexpand(mut ast: MalVal, env: Env) -> MalRet {
107 while is_macro_call(ast.clone(), env.clone()) {
110 let ref a0 = args[0];
113 match env_get(env.clone(), s.to_string()) {
117 match mf.apply(args.slice(1,args.len()).to_vec()) {
119 Err(e) => return Err(e),
125 Err(e) => return Err(e),
137 fn eval_ast(ast: MalVal, env: Env) -> MalRet {
138 let ast2 = ast.clone();
142 env_get(env.clone(), sym.clone())
144 List(ref a) | Vector(ref a) => {
145 let mut ast_vec : Vec<MalVal> = vec![];
147 let mv2 = mv.clone();
148 match eval(mv2, env.clone()) {
149 Ok(mv) => { ast_vec.push(mv); },
150 Err(e) => { return Err(e); },
153 Ok(match *ast { List(_) => list(ast_vec),
154 _ => vector(ast_vec) })
156 Hash_Map(ref hm) => {
157 let mut new_hm: HashMap<String,MalVal> = HashMap::new();
158 for (key, value) in hm.iter() {
159 match eval(value.clone(), env.clone()) {
160 Ok(mv) => { new_hm.insert(key.to_string(), mv); },
161 Err(e) => return Err(e),
172 fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
175 //println!("eval: {}, {}", ast, env.borrow());
176 //println!("eval: {}", ast);
177 let mut ast2 = ast.clone();
179 List(_) => (), // continue
180 _ => return eval_ast(ast2, env),
184 match macroexpand(ast2, env.clone()) {
188 Err(e) => return Err(e),
191 List(_) => (), // continue
192 _ => return Ok(ast2),
194 let ast3 = ast2.clone();
201 let ref a0 = *args[0];
204 match a0sym.as_slice() {
206 let a1 = (*args)[1].clone();
207 let a2 = (*args)[2].clone();
208 let res = eval(a2, env.clone());
213 env_set(&env.clone(), s.clone(), r.clone());
217 return Err("def! of non-symbol".to_string())
221 Err(e) => return Err(e),
225 let let_env = env_new(Some(env.clone()));
226 let a1 = (*args)[1].clone();
227 let a2 = (*args)[2].clone();
229 List(ref binds) | Vector(ref binds) => {
230 let mut it = binds.iter();
231 while it.len() >= 2 {
232 let b = it.next().unwrap();
233 let exp = it.next().unwrap();
236 match eval(exp.clone(), let_env.clone()) {
238 env_set(&let_env, bstr.clone(), r);
246 return Err("let* with non-symbol binding".to_string());
251 _ => return Err("let* with non-list bindings".to_string()),
254 env = let_env.clone();
258 return Ok((*args)[1].clone());
261 let a1 = (*args)[1].clone();
262 ast = quasiquote(a1);
266 let a1 = (*args)[1].clone();
267 let a2 = (*args)[2].clone();
268 match eval(a2, env.clone()) {
271 MalFunc(ref mfd) => {
274 let mut new_mfd = mfd.clone();
275 new_mfd.is_macro = true;
276 let mf = malfuncd(new_mfd);
277 env_set(&env.clone(), s.clone(), mf.clone());
280 _ => return Err("def! of non-symbol".to_string()),
283 _ => return Err("def! of non-symbol".to_string()),
286 Err(e) => return Err(e),
290 let a1 = (*args)[1].clone();
291 return macroexpand(a1, env.clone())
294 let el = list(args.slice(1,args.len()-1).to_vec());
295 match eval_ast(el, env.clone()) {
296 Err(e) => return Err(e),
298 let ref last = args[args.len()-1];
305 let a1 = (*args)[1].clone();
306 let cond = eval(a1, env.clone());
307 if cond.is_err() { return cond; }
308 match *cond.unwrap() {
311 let a3 = (*args)[3].clone();
320 let a2 = (*args)[2].clone();
328 let a1 = (*args)[1].clone();
329 let a2 = (*args)[2].clone();
330 return Ok(malfunc(eval, a2, env.clone(), a1));
333 let a1 = (*args)[1].clone();
334 match eval(a1, env.clone()) {
337 env = env_root(&env);
340 Err(e) => return Err(e),
350 if is_macro_call(ast3.clone(), env.clone()) {
351 println!("macro call");
354 return match eval_ast(ast3, env.clone()) {
359 let args2 = args.clone();
361 Func(f) => f(args.slice(1,args.len()).to_vec()),
363 let mfc = mf.clone();
364 let alst = list(args.slice(1,args.len()).to_vec());
365 let new_env = env_new(Some(mfc.env.clone()));
366 match env_bind(&new_env, mfc.params, alst) {
375 _ => Err("attempt to call non-function".to_string()),
378 _ => Err("Invalid apply".to_string()),
383 _ => return Err("Expected list".to_string()),
390 fn print(exp: MalVal) -> String {
394 fn rep(str: String, env: Env) -> Result<String,String> {
398 //println!("read: {}", ast);
399 match eval(ast, env) {
401 Ok(exp) => Ok(print(exp)),
408 // core.rs: defined using rust
409 let repl_env = env_new(None);
410 for (k, v) in core::ns().into_iter() { env_set(&repl_env, k, v); }
411 // see eval() for definition of "eval"
412 env_set(&repl_env, "*ARGV*".to_string(), list(vec![]));
414 // core.mal: defined using the language itself
415 let _ = rep("(def! not (fn* (a) (if a false true)))".to_string(),
417 let _ = rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))".to_string(),
420 // Invoked with command line arguments
421 let args = os::args();
423 let mv_args = args.slice(2,args.len()).iter()
424 .map(|a| string(a.to_string()))
425 .collect::<Vec<MalVal>>();
426 env_set(&repl_env, "*ARGV*".to_string(), list(mv_args));
427 match rep("(load-file \"".to_string() + args[1] + "\")".to_string(),
430 os::set_exit_status(0);
434 println!("Error: {}", str);
435 os::set_exit_status(1);
442 let line = readline::mal_readline("user> ");
443 match line { None => break, _ => () }
444 match rep(line.unwrap(), repl_env.clone()) {
445 Ok(str) => println!("{}", str),
446 Err(str) => println!("Error: {}", str),