diff options
| author | Joel Martin <github@martintribe.org> | 2014-10-27 20:45:27 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-01-06 21:58:59 -0600 |
| commit | 3744d56621ff4c1c6c8a1fd6beb1d03123df53a5 (patch) | |
| tree | 579e72e9bd66a8e8ea30d30e0c4a6c52dc51cc04 /rust/src/step6_file.rs | |
| parent | 5939404b0fb822fd29a483dc0d0a4d716cef206e (diff) | |
| download | mal-3744d56621ff4c1c6c8a1fd6beb1d03123df53a5.tar.gz mal-3744d56621ff4c1c6c8a1fd6beb1d03123df53a5.zip | |
rust: add step9_try. Refactor error handling.
Additional core functions.
Diffstat (limited to 'rust/src/step6_file.rs')
| -rw-r--r-- | rust/src/step6_file.rs | 283 |
1 files changed, 144 insertions, 139 deletions
diff --git a/rust/src/step6_file.rs b/rust/src/step6_file.rs index 237b7f0..86e0672 100644 --- a/rust/src/step6_file.rs +++ b/rust/src/step6_file.rs @@ -7,7 +7,8 @@ extern crate regex; use std::collections::HashMap; use std::os; -use types::{MalVal,MalRet,MalFunc,Nil,False,Sym,List,Vector,Hash_Map,Func, +use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str, + Nil,False,Sym,List,Vector,Hash_Map,Func,MalFunc, _nil,string,list,vector,hash_map,malfunc}; use env::{Env,env_new,env_bind,env_root,env_set,env_get}; mod readline; @@ -72,152 +73,157 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { // apply list match *ast2 { + List(_) => (), // continue + _ => return Ok(ast2), + } + + let (args, a0sym) = match *ast2 { List(ref args) => { if args.len() == 0 { return Ok(ast3); } let ref a0 = *args[0]; match *a0 { - Sym(ref a0sym) => { - match a0sym.as_slice() { - "def!" => { - let a1 = (*args)[1].clone(); - let a2 = (*args)[2].clone(); - let res = eval(a2, env.clone()); - match res { - Ok(r) => { - match *a1 { - Sym(ref s) => { - env_set(&env.clone(), s.clone(), r.clone()); - return Ok(r); - }, - _ => { - return Err("def! of non-symbol".to_string()) - } - } - }, - Err(e) => return Err(e), - } - }, - "let*" => { - let let_env = env_new(Some(env.clone())); - let a1 = (*args)[1].clone(); - let a2 = (*args)[2].clone(); - match *a1 { - List(ref binds) | Vector(ref binds) => { - let mut it = binds.iter(); - while it.len() >= 2 { - let b = it.next().unwrap(); - let exp = it.next().unwrap(); - match **b { - Sym(ref bstr) => { - match eval(exp.clone(), let_env.clone()) { - Ok(r) => { - env_set(&let_env, bstr.clone(), r); - }, - Err(e) => { - return Err(e); - }, - } - }, - _ => { - return Err("let* with non-symbol binding".to_string()); - }, - } - } - }, - _ => return Err("let* with non-list bindings".to_string()), - } - ast = a2; - env = let_env.clone(); - continue 'tco; - }, - "do" => { - let el = list(args.slice(1,args.len()-1).to_vec()); - match eval_ast(el, env.clone()) { - Err(e) => return Err(e), - Ok(_) => { - let ref last = args[args.len()-1]; - ast = last.clone(); - continue 'tco; - }, - } - }, - "if" => { - let a1 = (*args)[1].clone(); - let cond = eval(a1, env.clone()); - if cond.is_err() { return cond; } - match *cond.unwrap() { - False | Nil => { - if args.len() >= 4 { - let a3 = (*args)[3].clone(); - ast = a3; - env = env.clone(); - continue 'tco; - } else { - return Ok(_nil()); - } - }, - _ => { - let a2 = (*args)[2].clone(); - ast = a2; - env = env.clone(); - continue 'tco; - }, - } - }, - "fn*" => { - let a1 = (*args)[1].clone(); - let a2 = (*args)[2].clone(); - return Ok(malfunc(eval, a2, env.clone(), a1)); - }, - "eval" => { - let a1 = (*args)[1].clone(); - match eval(a1, env.clone()) { - Ok(exp) => { - ast = exp; - env = env_root(&env); - continue 'tco; - }, - Err(e) => return Err(e), - } + Sym(ref a0sym) => (args, a0sym.as_slice()), + _ => (args, "__<fn*>__"), + } + }, + _ => return err_str("Expected list"), + }; + + match a0sym { + "def!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + let res = eval(a2, env.clone()); + match res { + Ok(r) => { + match *a1 { + Sym(ref s) => { + env_set(&env.clone(), s.clone(), r.clone()); + return Ok(r); }, - _ => () + _ => { + return err_str("def! of non-symbol") + } + } + }, + Err(e) => return Err(e), + } + }, + "let*" => { + let let_env = env_new(Some(env.clone())); + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + match *a1 { + List(ref binds) | Vector(ref binds) => { + let mut it = binds.iter(); + while it.len() >= 2 { + let b = it.next().unwrap(); + let exp = it.next().unwrap(); + match **b { + Sym(ref bstr) => { + match eval(exp.clone(), let_env.clone()) { + Ok(r) => { + env_set(&let_env, bstr.clone(), r); + }, + Err(e) => { + return Err(e); + }, + } + }, + _ => { + return err_str("let* with non-symbol binding"); + }, + } } + }, + _ => return err_str("let* with non-list bindings"), + } + ast = a2; + env = let_env.clone(); + continue 'tco; + }, + "do" => { + let el = list(args.slice(1,args.len()-1).to_vec()); + match eval_ast(el, env.clone()) { + Err(e) => return Err(e), + Ok(_) => { + let ref last = args[args.len()-1]; + ast = last.clone(); + continue 'tco; + }, + } + }, + "if" => { + let a1 = (*args)[1].clone(); + let cond = eval(a1, env.clone()); + match cond { + Err(e) => return Err(e), + Ok(c) => match *c { + False | Nil => { + if args.len() >= 4 { + let a3 = (*args)[3].clone(); + ast = a3; + env = env.clone(); + continue 'tco; + } else { + return Ok(_nil()); + } + }, + _ => { + let a2 = (*args)[2].clone(); + ast = a2; + env = env.clone(); + continue 'tco; + }, } - _ => (), } - // function call + }, + "fn*" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + return Ok(malfunc(eval, a2, env.clone(), a1)); + }, + "eval" => { + let a1 = (*args)[1].clone(); + match eval(a1, env.clone()) { + Ok(exp) => { + ast = exp; + env = env_root(&env); + continue 'tco; + }, + Err(e) => return Err(e), + } + }, + _ => { // function call return match eval_ast(ast3, env.clone()) { Err(e) => Err(e), Ok(el) => { - match *el { - List(ref args) => { - let args2 = args.clone(); - match *args2[0] { - Func(f) => f(args.slice(1,args.len()).to_vec()), - MalFunc(ref mf) => { - let mfc = mf.clone(); - let alst = list(args.slice(1,args.len()).to_vec()); - let new_env = env_new(Some(mfc.env.clone())); - match env_bind(&new_env, mfc.params, alst) { - Ok(_) => { - ast = mfc.exp; - env = new_env; - continue 'tco; - }, - Err(e) => Err(e), - } + let args = match *el { + List(ref args) => args, + _ => return err_str("Invalid apply"), + }; + match *args.clone()[0] { + Func(f) => f(args.slice(1,args.len()).to_vec()), + MalFunc(ref mf) => { + let mfc = mf.clone(); + let alst = list(args.slice(1,args.len()).to_vec()); + let new_env = env_new(Some(mfc.env.clone())); + match env_bind(&new_env, mfc.params, alst) { + Ok(_) => { + ast = mfc.exp; + env = new_env; + continue 'tco; }, - _ => Err("attempt to call non-function".to_string()), + Err(e) => err_str(e.as_slice()), } - } - _ => Err("Invalid apply".to_string()), + }, + _ => err_str("attempt to call non-function"), } } } - } - _ => return Err("Expected list".to_string()), + }, } } @@ -228,8 +234,8 @@ fn print(exp: MalVal) -> String { exp.pr_str(true) } -fn rep(str: String, env: Env) -> Result<String,String> { - match read(str) { +fn rep(str: &str, env: Env) -> Result<String,MalError> { + match read(str.to_string()) { Err(e) => Err(e), Ok(ast) => { //println!("read: {}", ast); @@ -249,10 +255,8 @@ fn main() { env_set(&repl_env, "*ARGV*".to_string(), list(vec![])); // core.mal: defined using the language itself - let _ = rep("(def! not (fn* (a) (if a false true)))".to_string(), - repl_env.clone()); - let _ = rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))".to_string(), - repl_env.clone()); + let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone()); + let _ = rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", repl_env.clone()); // Invoked with command line arguments let args = os::args(); @@ -261,8 +265,8 @@ fn main() { .map(|a| string(a.to_string())) .collect::<Vec<MalVal>>(); env_set(&repl_env, "*ARGV*".to_string(), list(mv_args)); - match rep("(load-file \"".to_string() + args[1] + "\")".to_string(), - repl_env.clone()) { + let lf = "(load-file \"".to_string() + args[1] + "\")".to_string(); + match rep(lf.as_slice(), repl_env.clone()) { Ok(_) => { os::set_exit_status(0); return; @@ -278,9 +282,10 @@ fn main() { loop { let line = readline::mal_readline("user> "); match line { None => break, _ => () } - match rep(line.unwrap(), repl_env.clone()) { + match rep(line.unwrap().as_slice(), repl_env.clone()) { Ok(str) => println!("{}", str), - Err(str) => println!("Error: {}", str), + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), } } } |
