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 | |
| 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')
| -rw-r--r-- | rust/src/core.rs | 161 | ||||
| -rw-r--r-- | rust/src/env.rs | 4 | ||||
| -rw-r--r-- | rust/src/reader.rs | 25 | ||||
| -rw-r--r-- | rust/src/step1_read_print.rs | 11 | ||||
| -rw-r--r-- | rust/src/step2_eval.rs | 20 | ||||
| -rw-r--r-- | rust/src/step3_env.rs | 150 | ||||
| -rw-r--r-- | rust/src/step4_if_fn_do.rs | 227 | ||||
| -rw-r--r-- | rust/src/step5_tco.rs | 256 | ||||
| -rw-r--r-- | rust/src/step6_file.rs | 283 | ||||
| -rw-r--r-- | rust/src/step7_quote.rs | 301 | ||||
| -rw-r--r-- | rust/src/step8_macros.rs | 388 | ||||
| -rw-r--r-- | rust/src/step9_try.rs | 476 | ||||
| -rw-r--r-- | rust/src/types.rs | 130 |
13 files changed, 1566 insertions, 866 deletions
diff --git a/rust/src/core.rs b/rust/src/core.rs index 98eb32a..61dc0ce 100644 --- a/rust/src/core.rs +++ b/rust/src/core.rs @@ -4,16 +4,18 @@ extern crate time; use std::collections::HashMap; use std::io::File; -use types::{MalVal,MalRet,Int,Strn,List,Vector, +use types::{MalVal,MalRet,err_val,err_str,err_string, + Int,Strn,List,Vector,Hash_Map, _nil,_true,_false,_int,string,list,func}; +use types; +use readline; use reader; use printer; // General functions - fn equal_q(a:Vec<MalVal>) -> MalRet { if a.len() != 2 { - return Err("Wrong arity to equal? call".to_string()); + return err_str("Wrong arity to equal? call"); } match a[0] == a[1] { true => Ok(_true()), @@ -21,6 +23,14 @@ fn equal_q(a:Vec<MalVal>) -> MalRet { } } +// Errors/Exceptions +fn throw(a:Vec<MalVal>) -> MalRet { + if a.len() != 1 { + return err_str("Wrong arity to throw call"); + } + err_val(a[0].clone()) +} + // String routines fn pr_str(a:Vec<MalVal>) -> MalRet { Ok(string(printer::pr_list(&a, true, "", "", " "))) @@ -40,10 +50,20 @@ fn println(a:Vec<MalVal>) -> MalRet { Ok(_nil()) } +fn readline(a:Vec<MalVal>) -> MalRet { + match *a[0] { + Strn(ref a0) => match readline::mal_readline(a0.as_slice()) { + Some(line) => Ok(string(line)), + None => err_val(_nil()), + }, + _ => err_str("read_string called with non-string"), + } +} + fn read_string(a:Vec<MalVal>) -> MalRet { match *a[0] { Strn(ref a0) => reader::read_str(a0.to_string()), - _ => Err("read_string called with non-string".to_string()), + _ => err_str("read_string called with non-string"), } } @@ -52,10 +72,10 @@ fn slurp(a:Vec<MalVal>) -> MalRet { Strn(ref a0) => { match File::open(&Path::new(a0.as_slice())).read_to_string() { Ok(s) => Ok(string(s)), - Err(e) => Err(e.to_string()), + Err(e) => err_string(e.to_string()), } }, - _ => Err("slurp called with non-string".to_string()), + _ => err_str("slurp called with non-string"), } } @@ -65,9 +85,9 @@ fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet { match *a[0] { Int(a0) => match *a[1] { Int(a1) => Ok(_int(f(a0,a1))), - _ => Err("second arg must be an int".to_string()), + _ => err_str("second arg must be an int"), }, - _ => Err("first arg must be an int".to_string()), + _ => err_str("first arg must be an int"), } } @@ -80,9 +100,9 @@ fn bool_op(f: |i:int,j:int|-> bool, a:Vec<MalVal>) -> MalRet { false => Ok(_false()), } }, - _ => Err("second arg must be an int".to_string()), + _ => err_str("second arg must be an int"), }, - _ => Err("first arg must be an int".to_string()), + _ => err_str("first arg must be an int"), } } @@ -105,19 +125,29 @@ pub fn time_ms(a:Vec<MalVal>) -> MalRet { } -// Sequence functions -pub fn _list(a:Vec<MalVal>) -> MalRet { Ok(list(a)) } - -pub fn list_q(a:Vec<MalVal>) -> MalRet { - if a.len() != 1 { - return Err("Wrong arity to list? call".to_string()); +// Hash Map functions +pub fn get(a:Vec<MalVal>) -> MalRet { + if a.len() != 2 { + return err_str("Wrong arity to get call"); } - match *a[0].clone() { - List(_) => Ok(_true()), - _ => Ok(_false()), + let a0 = a[0].clone(); + let hm: &HashMap<String,MalVal> = match *a0 { + Hash_Map(ref hm) => hm, + _ => return err_str("get of non-hash map"), + }; + match *a[1] { + Strn(ref key) => { + match hm.find_copy(key) { + Some(v) => Ok(v), + None => Ok(_nil()), + } + }, + _ => return err_str("get with non-string key"), } } + +// Sequence functions pub fn cons(a:Vec<MalVal>) -> MalRet { match *a[1] { List(ref v) | Vector(ref v) => { @@ -125,7 +155,7 @@ pub fn cons(a:Vec<MalVal>) -> MalRet { new_v.insert(0, a[0].clone()); Ok(list(new_v)) }, - _ => Err("Second arg to cons not a sequence".to_string()), + _ => err_str("Second arg to cons not a sequence"), } } @@ -136,7 +166,7 @@ pub fn concat(a:Vec<MalVal>) -> MalRet { List(ref l) | Vector(ref l) => { new_v.push_all(l.as_slice()); }, - _ => return Err("concat called with non-sequence".to_string()), + _ => return err_str("concat called with non-sequence"), } } Ok(list(new_v)) @@ -144,13 +174,13 @@ pub fn concat(a:Vec<MalVal>) -> MalRet { pub fn nth(a:Vec<MalVal>) -> MalRet { if a.len() != 2 { - return Err("Wrong arity to nth call".to_string()); + return err_str("Wrong arity to nth call"); } let a0 = a[0].clone(); let a1 = a[1].clone(); let seq = match *a0 { List(ref v) | Vector(ref v) => v, - _ => return Err("nth called with non-sequence".to_string()), + _ => return err_str("nth called with non-sequence"), }; let idx = match *a1 { Int(i) => { @@ -159,7 +189,7 @@ pub fn nth(a:Vec<MalVal>) -> MalRet { None => return Ok(_nil()), } }, - _ => return Err("nth called with non-integer index".to_string()), + _ => return err_str("nth called with non-integer index"), }; if idx >= seq.len() { Ok(_nil()) @@ -170,12 +200,12 @@ pub fn nth(a:Vec<MalVal>) -> MalRet { pub fn first(a:Vec<MalVal>) -> MalRet { if a.len() != 1 { - return Err("Wrong arity to first call".to_string()); + return err_str("Wrong arity to first call"); } let a0 = a[0].clone(); let seq = match *a0 { List(ref v) | Vector(ref v) => v, - _ => return Err("first called with non-sequence".to_string()), + _ => return err_str("first called with non-sequence"), }; if seq.len() == 0 { Ok(_nil()) @@ -186,12 +216,12 @@ pub fn first(a:Vec<MalVal>) -> MalRet { pub fn rest(a:Vec<MalVal>) -> MalRet { if a.len() != 1 { - return Err("Wrong arity to rest call".to_string()); + return err_str("Wrong arity to rest call"); } let a0 = a[0].clone(); let seq = match *a0 { List(ref v) | Vector(ref v) => v, - _ => return Err("rest called with non-sequence".to_string()), + _ => return err_str("rest called with non-sequence"), }; if seq.len() == 0 { Ok(list(vec![])) @@ -200,31 +230,67 @@ pub fn rest(a:Vec<MalVal>) -> MalRet { } } -pub fn count(a:Vec<MalVal>) -> MalRet { +pub fn empty_q(a:Vec<MalVal>) -> MalRet { if a.len() != 1 { - return Err("Wrong arity to count call".to_string()); + return err_str("Wrong arity to empty? call"); } match *a[0].clone() { List(ref v) | Vector(ref v) => { - Ok(_int(v.len().to_int().unwrap())) + match v.len() { + 0 => Ok(_true()), + _ => Ok(_false()), + } }, - _ => Err("count called on non-sequence".to_string()), + _ => err_str("empty? called on non-sequence"), } } -pub fn empty_q(a:Vec<MalVal>) -> MalRet { +pub fn count(a:Vec<MalVal>) -> MalRet { if a.len() != 1 { - return Err("Wrong arity to empty? call".to_string()); + return err_str("Wrong arity to count call"); } match *a[0].clone() { List(ref v) | Vector(ref v) => { - match v.len() { - 0 => Ok(_true()), - _ => Ok(_false()), + Ok(_int(v.len().to_int().unwrap())) + }, + _ => err_str("count called on non-sequence"), + } +} + +pub fn apply(a:Vec<MalVal>) -> MalRet { + if a.len() < 2 { + return err_str("apply call needs 2 or more arguments"); + } + let ref f = a[0]; + let mut args = a.slice(1,a.len()-1).to_vec(); + match *a[a.len()-1] { + List(ref v) | Vector(ref v) => { + args.push_all(v.as_slice()); + f.apply(args) + }, + _ => err_str("apply call with non-sequence"), + } +} + +pub fn map(a:Vec<MalVal>) -> MalRet { + if a.len() != 2 { + return err_str("Wrong arity to map call"); + } + let mut results:Vec<MalVal> = vec![]; + let ref f = a[0].clone(); + let seq = a[1].clone(); + match *seq { + List(ref v) | Vector(ref v) => { + for mv in v.iter() { + match f.apply(vec![mv.clone()]) { + Ok(res) => results.push(res), + Err(e) => return Err(e), + } } }, - _ => Err("empty? called on non-sequence".to_string()), + _ => return err_str("map call with non-sequence"), } + Ok(list(results)) } @@ -233,11 +299,17 @@ pub fn ns() -> HashMap<String,MalVal> { let mut ns: HashMap<String,MalVal> = HashMap::new();; ns.insert("=".to_string(), func(equal_q)); + ns.insert("throw".to_string(), func(throw)); + ns.insert("nil?".to_string(), func(types::nil_q)); + ns.insert("true?".to_string(), func(types::true_q)); + ns.insert("false?".to_string(), func(types::false_q)); + ns.insert("symbol?".to_string(), func(types::symbol_q)); ns.insert("pr-str".to_string(), func(pr_str)); ns.insert("str".to_string(), func(str)); ns.insert("prn".to_string(), func(prn)); ns.insert("println".to_string(), func(println)); + ns.insert("readline".to_string(), func(readline)); ns.insert("read-string".to_string(), func(read_string)); ns.insert("slurp".to_string(), func(slurp)); @@ -251,8 +323,15 @@ pub fn ns() -> HashMap<String,MalVal> { ns.insert("/".to_string(), func(div)); ns.insert("time-ms".to_string(), func(time_ms)); - ns.insert("list".to_string(), func(_list)); - ns.insert("list?".to_string(), func(list_q)); + ns.insert("list".to_string(), func(types::listv)); + ns.insert("list?".to_string(), func(types::list_q)); + ns.insert("vector".to_string(), func(types::vectorv)); + ns.insert("vector?".to_string(), func(types::vector_q)); + ns.insert("hash-map".to_string(), func(types::hash_mapv)); + ns.insert("map?".to_string(), func(types::hash_map_q)); + ns.insert("get".to_string(), func(get)); + + ns.insert("sequential?".to_string(), func(types::sequential_q)); ns.insert("cons".to_string(), func(cons)); ns.insert("concat".to_string(), func(concat)); ns.insert("empty?".to_string(), func(empty_q)); @@ -260,6 +339,8 @@ pub fn ns() -> HashMap<String,MalVal> { ns.insert("first".to_string(), func(first)); ns.insert("rest".to_string(), func(rest)); ns.insert("count".to_string(), func(count)); + ns.insert("apply".to_string(), func(apply)); + ns.insert("map".to_string(), func(map)); return ns; } diff --git a/rust/src/env.rs b/rust/src/env.rs index 730010a..0d72e62 100644 --- a/rust/src/env.rs +++ b/rust/src/env.rs @@ -5,7 +5,7 @@ use std::cell::RefCell; use std::collections::HashMap; use std::fmt; -use types::{MalVal,MalRet,Sym,List,_nil,list}; +use types::{MalVal,MalRet,Sym,List,_nil,list,err_string}; struct EnvType { data: HashMap<String,MalVal>, @@ -89,7 +89,7 @@ pub fn env_get(env: Env, key: String) -> MalRet { None => Ok(_nil()), } }, - None => Err("'".to_string() + key + "' not found".to_string()), + None => err_string("'".to_string() + key + "' not found".to_string()), } } diff --git a/rust/src/reader.rs b/rust/src/reader.rs index 6a52dd2..652a7d7 100644 --- a/rust/src/reader.rs +++ b/rust/src/reader.rs @@ -5,8 +5,9 @@ extern crate pcre; -use types::{MalVal,MalRet, - _nil,_true,_false,_int,symbol,string,list,vector,hash_mapv}; +use types::{MalVal,MalRet,ErrString,ErrMalVal, + _nil,_true,_false,_int,symbol,string,list,vector,hash_mapv, + err_str,err_string,err_val}; use self::pcre::Pcre; use super::printer::unescape_str; @@ -58,7 +59,7 @@ fn tokenize(str :String) -> Vec<String> { fn read_atom(rdr : &mut Reader) -> MalRet { let otoken = rdr.next(); //println!("read_atom: {}", otoken); - if otoken.is_none() { return Err("read_atom underflow".to_string()); } + if otoken.is_none() { return err_str("read_atom underflow"); } let stoken = otoken.unwrap(); let token = stoken.as_slice(); if regex!(r"^-?[0-9]+$").is_match(token) { @@ -101,7 +102,8 @@ fn read_seq(rdr : &mut Reader, start: &str, end: &str) -> Result<Vec<MalVal>,Str match read_form(rdr) { Ok(mv) => ast_vec.push(mv), - Err(e) => return Err(e), + Err(ErrString(es)) => return Err(es), + Err(ErrMalVal(_)) => return Err("read_seq exception".to_string()), } } rdr.next(); @@ -112,21 +114,21 @@ fn read_seq(rdr : &mut Reader, start: &str, end: &str) -> Result<Vec<MalVal>,Str fn read_list(rdr : &mut Reader) -> MalRet { match read_seq(rdr, "(", ")") { Ok(seq) => Ok(list(seq)), - Err(e) => Err(e), + Err(es) => err_string(es), } } fn read_vector(rdr : &mut Reader) -> MalRet { match read_seq(rdr, "[", "]") { Ok(seq) => Ok(vector(seq)), - Err(e) => Err(e), + Err(es) => err_string(es), } } fn read_hash_map(rdr : &mut Reader) -> MalRet { match read_seq(rdr, "{", "}") { Ok(seq) => hash_mapv(seq), - Err(e) => Err(e), + Err(es) => err_string(es), } } @@ -165,13 +167,13 @@ fn read_form(rdr : &mut Reader) -> MalRet { } }, - ")" => Err("unexected ')'".to_string()), + ")" => err_str("unexected ')'"), "(" => read_list(rdr), - "]" => Err("unexected ']'".to_string()), + "]" => err_str("unexected ']'"), "[" => read_vector(rdr), - "}" => Err("unexected '}'".to_string()), + "}" => err_str("unexected '}'"), "{" => read_hash_map(rdr), _ => read_atom(rdr) @@ -181,7 +183,8 @@ fn read_form(rdr : &mut Reader) -> MalRet { pub fn read_str(str :String) -> MalRet { let tokens = tokenize(str); if tokens.len() == 0 { - return Err("<empty line>".to_string()); + // any malval as the error slot means empty line + return err_val(_nil()) } //println!("tokens: {}", tokens); let rdr = &mut Reader{tokens: tokens, position: 0}; diff --git a/rust/src/step1_read_print.rs b/rust/src/step1_read_print.rs index d69ea6d..3ce11e6 100644 --- a/rust/src/step1_read_print.rs +++ b/rust/src/step1_read_print.rs @@ -4,7 +4,7 @@ extern crate regex_macros; extern crate regex; -use types::{MalVal,MalRet}; +use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal}; mod readline; mod types; mod env; @@ -26,7 +26,7 @@ fn print(exp: MalVal) -> String { exp.pr_str(true) } -fn rep(str: String) -> Result<String,String> { +fn rep(str: String) -> Result<String,MalError> { match read(str) { Err(e) => Err(e), Ok(ast) => { @@ -45,11 +45,8 @@ fn main() { match line { None => break, _ => () } match rep(line.unwrap()) { Ok(str) => println!("{}", str), - Err(str) => { - if str.as_slice() != "<empty line>" { - println!("Error: {}", str) - } - } + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), } } } diff --git a/rust/src/step2_eval.rs b/rust/src/step2_eval.rs index 4a0fcb5..29c53d9 100644 --- a/rust/src/step2_eval.rs +++ b/rust/src/step2_eval.rs @@ -6,13 +6,14 @@ extern crate regex; use std::collections::HashMap; -use types::{MalVal,MalRet,Int,Sym,List,Vector,Hash_Map, +use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str, + Int,Sym,List,Vector,Hash_Map, _nil,_int,list,vector,hash_map,func}; mod readline; mod types; -mod env; mod reader; mod printer; +mod env; // because types uses env // read fn read(str: String) -> MalRet { @@ -71,7 +72,7 @@ fn eval(ast: MalVal, env: &HashMap<String,MalVal>) -> MalRet { let ref f = args.clone()[0]; f.apply(args.slice(1,args.len()).to_vec()) } - _ => Err("Invalid apply".to_string()), + _ => err_str("Invalid apply"), } } } @@ -82,8 +83,8 @@ fn print(exp: MalVal) -> String { exp.pr_str(true) } -fn rep(str: String, env: &HashMap<String,MalVal>) -> Result<String,String> { - match read(str) { +fn rep(str: &str, env: &HashMap<String,MalVal>) -> Result<String,MalError> { + match read(str.to_string()) { Err(e) => Err(e), Ok(ast) => { //println!("read: {}", ast); @@ -99,9 +100,9 @@ fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet { match *a[0] { Int(a0) => match *a[1] { Int(a1) => Ok(_int(f(a0,a1))), - _ => Err("second arg must be an int".to_string()), + _ => err_str("second arg must be an int"), }, - _ => Err("first arg must be an int".to_string()), + _ => err_str("first arg must be an int"), } } fn add(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i+j }, a) } @@ -119,9 +120,10 @@ fn main() { loop { let line = readline::mal_readline("user> "); match line { None => break, _ => () } - match rep(line.unwrap(), &repl_env) { + match rep(line.unwrap().as_slice(), &repl_env) { Ok(str) => println!("{}", str), - Err(str) => println!("Error: {}", str), + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), } } } diff --git a/rust/src/step3_env.rs b/rust/src/step3_env.rs index f9f79ea..ac7199c 100644 --- a/rust/src/step3_env.rs +++ b/rust/src/step3_env.rs @@ -6,7 +6,8 @@ extern crate regex; use std::collections::HashMap; -use types::{MalVal,MalRet,Int,Sym,List,Vector,Hash_Map, +use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str, + Int,Sym,List,Vector,Hash_Map, _int,list,vector,hash_map,func}; use env::{Env,env_new,env_set,env_get}; mod readline; @@ -67,84 +68,88 @@ fn eval(ast: MalVal, 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(ast); } 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()), - } - return eval(a2, let_env.clone()); + 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), } - // function call + }, + "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"), + } + return eval(a2, let_env.clone()); + }, + _ => { // function call return match eval_ast(ast, env) { Err(e) => Err(e), Ok(el) => { - match *el { - List(ref args) => { - let ref f = args.clone()[0]; - f.apply(args.slice(1,args.len()).to_vec()) - } - _ => Err("Invalid apply".to_string()), - } + let args = match *el { + List(ref args) => args, + _ => return err_str("Invalid apply"), + }; + let ref f = args.clone()[0]; + f.apply(args.slice(1,args.len()).to_vec()) } - } - } - _ => Err("Expected list".to_string()), + }; + }, } } @@ -153,8 +158,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); @@ -170,9 +175,9 @@ fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet { match *a[0] { Int(a0) => match *a[1] { Int(a1) => Ok(_int(f(a0,a1))), - _ => Err("second arg must be an int".to_string()), + _ => err_str("second arg must be an int"), }, - _ => Err("first arg must be an int".to_string()), + _ => err_str("first arg must be an int"), } } fn add(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i+j }, a) } @@ -190,9 +195,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), } } } diff --git a/rust/src/step4_if_fn_do.rs b/rust/src/step4_if_fn_do.rs index 0f3603d..c5c9413 100644 --- a/rust/src/step4_if_fn_do.rs +++ b/rust/src/step4_if_fn_do.rs @@ -6,7 +6,8 @@ extern crate regex; use std::collections::HashMap; -use types::{MalVal,MalRet,Nil,False,Sym,List,Vector,Hash_Map, +use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str, + Nil,False,Sym,List,Vector,Hash_Map, _nil,list,vector,hash_map,malfunc}; use env::{Env,env_new,env_set,env_get}; mod readline; @@ -68,123 +69,129 @@ fn eval(ast: MalVal, 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(ast); } 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()), - } - return eval(a2, let_env.clone()); - }, - "do" => { - let el = list(args.slice(1,args.len()).to_vec()); - match eval_ast(el, env.clone()) { - Err(e) => return Err(e), - Ok(el) => { - match *el { - List(ref lst) => { - let ref last = lst[lst.len()-1]; - return Ok(last.clone()); - } - _ => (), - } - }, - } - }, - "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(); - return eval(a3, env.clone()); - } else { - return Ok(_nil()); - } - }, - _ => { - let a2 = (*args)[2].clone(); - return eval(a2, env.clone()); - }, - } - }, - "fn*" => { - let a1 = (*args)[1].clone(); - let a2 = (*args)[2].clone(); - return Ok(malfunc(eval, a2, env.clone(), a1)); + 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), } - // function call - return match eval_ast(ast, env.clone()) { - Err(e) => 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"), + } + return eval(a2, let_env.clone()); + }, + "do" => { + let el = list(args.slice(1,args.len()).to_vec()); + return match eval_ast(el, env.clone()) { + Err(e) => return Err(e), Ok(el) => { match *el { - List(ref args) => { - let ref f = args.clone()[0]; - f.apply(args.slice(1,args.len()).to_vec()) + List(ref lst) => { + let ref last = lst[lst.len()-1]; + return Ok(last.clone()); } - _ => Err("Invalid apply".to_string()), + _ => return err_str("invalid do call"), } + }, + }; + }, + "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(); + return eval(a3, env.clone()); + } else { + return Ok(_nil()); + } + }, + _ => { + let a2 = (*args)[2].clone(); + return eval(a2, env.clone()); + }, } } - } - _ => Err("Expected list".to_string()), + }, + "fn*" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + return Ok(malfunc(eval, a2, env.clone(), a1)); + }, + _ => { // function call + return match eval_ast(ast, env.clone()) { + Err(e) => Err(e), + Ok(el) => { + let args = match *el { + List(ref args) => args, + _ => return err_str("Invalid apply"), + }; + let ref f = args.clone()[0]; + f.apply(args.slice(1,args.len()).to_vec()) + } + }; + }, } } @@ -193,8 +200,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); @@ -207,18 +214,20 @@ fn rep(str: String, env: Env) -> Result<String,String> { } fn main() { + // core.rs: defined using rust let repl_env = env_new(None); for (k, v) in core::ns().into_iter() { env_set(&repl_env, k, v); } - let _ = rep("(def! not (fn* (a) (if a false true)))".to_string(), - repl_env.clone()); + // core.mal: defined using the language itself + let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone()); 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), } } } diff --git a/rust/src/step5_tco.rs b/rust/src/step5_tco.rs index 9c826c7..c86e249 100644 --- a/rust/src/step5_tco.rs +++ b/rust/src/step5_tco.rs @@ -6,7 +6,8 @@ extern crate regex; use std::collections::HashMap; -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,list,vector,hash_map,malfunc}; use env::{Env,env_new,env_bind,env_set,env_get}; mod readline; @@ -63,149 +64,154 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { //println!("eval: {}, {}", ast, env.borrow()); //println!("eval: {}", ast); let ast2 = ast.clone(); + let ast3 = ast.clone(); match *ast2 { List(_) => (), // continue _ => return eval_ast(ast2, env), } // apply list - let ast3 = ast2.clone(); 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)); + 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)); + }, + _ => { // 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()), + }, } } @@ -216,8 +222,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); @@ -235,15 +241,15 @@ fn main() { for (k, v) in core::ns().into_iter() { env_set(&repl_env, k, v); } // 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! not (fn* (a) (if a false true)))", repl_env.clone()); 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), } } } 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), } } } diff --git a/rust/src/step7_quote.rs b/rust/src/step7_quote.rs index 3427eea..ac0634d 100644 --- a/rust/src/step7_quote.rs +++ b/rust/src/step7_quote.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,symbol,string,list,vector,hash_map,malfunc}; use env::{Env,env_new,env_bind,env_root,env_set,env_get}; mod readline; @@ -115,7 +116,6 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { //println!("eval: {}, {}", ast, env.borrow()); //println!("eval: {}", ast); let ast2 = ast.clone(); - let ast3 = ast.clone(); match *ast2 { List(_) => (), // continue _ => return eval_ast(ast2, env), @@ -123,160 +123,166 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { // apply list match *ast2 { + List(_) => (), // continue + _ => return Ok(ast2), + } + let ast3 = ast2.clone(); + + 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; - }, - "quote" => { - return Ok((*args)[1].clone()); - }, - "quasiquote" => { - let a1 = (*args)[1].clone(); - ast = quasiquote(a1); - 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; + }, + "quote" => { + return Ok((*args)[1].clone()); + }, + "quasiquote" => { + let a1 = (*args)[1].clone(); + ast = quasiquote(a1); + 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()), + }, } } @@ -287,8 +293,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); @@ -308,10 +314,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(); @@ -320,8 +324,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; @@ -337,9 +341,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), } } } diff --git a/rust/src/step8_macros.rs b/rust/src/step8_macros.rs index 1c84c58..a79df33 100644 --- a/rust/src/step8_macros.rs +++ b/rust/src/step8_macros.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,symbol,string,list,vector,hash_map,malfunc,malfuncd}; use env::{Env,env_new,env_bind,env_root,env_find,env_set,env_get}; mod readline; @@ -105,27 +106,26 @@ fn is_macro_call(ast: MalVal, env: Env) -> bool { fn macroexpand(mut ast: MalVal, env: Env) -> MalRet { while is_macro_call(ast.clone(), env.clone()) { - match *ast.clone() { - List(ref args) => { - let ref a0 = args[0]; - match **a0 { - Sym(ref s) => { - match env_get(env.clone(), s.to_string()) { - Ok(mf) => { - match *mf { - MalFunc(_) => { - match mf.apply(args.slice(1,args.len()).to_vec()) { - Ok(r) => ast = r, - Err(e) => return Err(e), - } - }, - _ => break, - } - }, - Err(e) => return Err(e), - } - }, - _ => break, + let ast2 = ast.clone(); + let args = match *ast2 { + List(ref args) => args, + _ => break, + }; + let ref a0 = args[0]; + let mf = match **a0 { + Sym(ref s) => { + match env_get(env.clone(), s.to_string()) { + Ok(mf) => mf, + Err(e) => return Err(e), + } + }, + _ => break, + }; + match *mf { + MalFunc(_) => { + match mf.apply(args.slice(1,args.len()).to_vec()) { + Ok(r) => ast = r, + Err(e) => return Err(e), } }, _ => break, @@ -193,194 +193,189 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { } let ast3 = ast2.clone(); - match *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), - } + 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); }, - "let*" => { - let let_env = env_new(Some(env.clone())); - let a1 = (*args)[1].clone(); - let a2 = (*args)[2].clone(); + _ => { + 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; + }, + "quote" => { + return Ok((*args)[1].clone()); + }, + "quasiquote" => { + let a1 = (*args)[1].clone(); + ast = quasiquote(a1); + continue 'tco; + }, + "defmacro!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + match eval(a2, env.clone()) { + Ok(r) => { + match *r { + MalFunc(ref mfd) => { 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()); - }, - } - } + Sym(ref s) => { + let mut new_mfd = mfd.clone(); + new_mfd.is_macro = true; + let mf = malfuncd(new_mfd); + env_set(&env.clone(), s.clone(), mf.clone()); + return Ok(mf); }, - _ => return Err("let* with non-list bindings".to_string()), + _ => return err_str("def! of non-symbol"), } - ast = a2; - env = let_env.clone(); - continue 'tco; - }, - "quote" => { - return Ok((*args)[1].clone()); }, - "quasiquote" => { - let a1 = (*args)[1].clone(); - ast = quasiquote(a1); - continue 'tco; - }, - "defmacro!" => { - let a1 = (*args)[1].clone(); - let a2 = (*args)[2].clone(); - match eval(a2, env.clone()) { - Ok(r) => { - match *r { - MalFunc(ref mfd) => { - match *a1 { - Sym(ref s) => { - let mut new_mfd = mfd.clone(); - new_mfd.is_macro = true; - let mf = malfuncd(new_mfd); - env_set(&env.clone(), s.clone(), mf.clone()); - return Ok(mf); - }, - _ => return Err("def! of non-symbol".to_string()), - } - }, - _ => return Err("def! of non-symbol".to_string()), - } - }, - Err(e) => return Err(e), - } - }, - "macroexpand" => { - let a1 = (*args)[1].clone(); - return macroexpand(a1, env.clone()) - }, - "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), - } - }, - _ => () + _ => return err_str("def! of non-symbol"), } + }, + Err(e) => return Err(e), + } + }, + "macroexpand" => { + let a1 = (*args)[1].clone(); + return macroexpand(a1, env.clone()) + }, + "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 - /* - if is_macro_call(ast3.clone(), env.clone()) { - println!("macro 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()), + }, } } @@ -391,8 +386,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); @@ -412,10 +407,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(); @@ -424,8 +417,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; @@ -441,9 +434,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), } } } diff --git a/rust/src/step9_try.rs b/rust/src/step9_try.rs new file mode 100644 index 0000000..f6dde04 --- /dev/null +++ b/rust/src/step9_try.rs @@ -0,0 +1,476 @@ +// support precompiled regexes in reader.rs +#![feature(phase)] +#[phase(plugin)] +extern crate regex_macros; +extern crate regex; + +use std::collections::HashMap; +use std::os; + +use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str, + Nil,False,Sym,List,Vector,Hash_Map,Func,MalFunc, + _nil,symbol,string,list,vector,hash_map,malfunc,malfuncd}; +use env::{Env,env_new,env_bind,env_root,env_find,env_set,env_get}; +mod readline; +mod types; +mod reader; +mod printer; +mod env; +mod core; + +// read +fn read(str: String) -> MalRet { + reader::read_str(str) +} + +// eval +fn is_pair(x: MalVal) -> bool { + match *x { + List(ref lst) => lst.len() > 0, + _ => false, + } +} + +fn quasiquote(ast: MalVal) -> MalVal { + if !is_pair(ast.clone()) { + return list(vec![symbol("quote"), ast]) + } + + match *ast.clone() { + List(ref args) => { + let ref a0 = args[0]; + match **a0 { + Sym(ref s) => { + if s.to_string() == "unquote".to_string() { + let ref a1 = args[1]; + return a1.clone(); + } + }, + _ => (), + } + if is_pair(a0.clone()) { + match **a0 { + List(ref a0args) => { + let a00 = a0args[0].clone(); + match *a00 { + Sym(ref s) => { + if s.to_string() == "splice-unquote".to_string() { + return list(vec![symbol("concat"), + a0args[1].clone(), + quasiquote(list(args.slice(1,args.len()).to_vec()))]) + } + }, + _ => (), + } + }, + _ => (), + } + } + let rest = list(args.slice(1,args.len()).to_vec()); + return list(vec![symbol("cons"), + quasiquote(a0.clone()), + quasiquote(rest)]) + }, + _ => _nil(), // should never reach + } +} + +fn is_macro_call(ast: MalVal, env: Env) -> bool { + match *ast { + List(ref lst) => { + let ref a0 = *lst[0]; + match *a0 { + Sym(ref a0sym) => { + if env_find(env.clone(), a0sym.to_string()).is_some() { + match env_get(env, a0sym.to_string()) { + Ok(f) => { + match *f { + MalFunc(ref mfd) => { + mfd.is_macro + }, + _ => false, + } + }, + _ => false, + } + } else { + false + } + }, + _ => false, + } + }, + _ => false, + } +} + +fn macroexpand(mut ast: MalVal, env: Env) -> MalRet { + while is_macro_call(ast.clone(), env.clone()) { + let ast2 = ast.clone(); + let args = match *ast2 { + List(ref args) => args, + _ => break, + }; + let ref a0 = args[0]; + let mf = match **a0 { + Sym(ref s) => { + match env_get(env.clone(), s.to_string()) { + Ok(mf) => mf, + Err(e) => return Err(e), + } + }, + _ => break, + }; + match *mf { + MalFunc(_) => { + match mf.apply(args.slice(1,args.len()).to_vec()) { + Ok(r) => ast = r, + Err(e) => return Err(e), + } + }, + _ => break, + } + } + Ok(ast) +} + +fn eval_ast(ast: MalVal, env: Env) -> MalRet { + let ast2 = ast.clone(); + match *ast2 { + //match *ast { + Sym(ref sym) => { + env_get(env.clone(), sym.clone()) + }, + List(ref a) | Vector(ref a) => { + let mut ast_vec : Vec<MalVal> = vec![]; + for mv in a.iter() { + let mv2 = mv.clone(); + match eval(mv2, env.clone()) { + Ok(mv) => { ast_vec.push(mv); }, + Err(e) => { return Err(e); }, + } + } + Ok(match *ast { List(_) => list(ast_vec), + _ => vector(ast_vec) }) + }, + Hash_Map(ref hm) => { + let mut new_hm: HashMap<String,MalVal> = HashMap::new(); + for (key, value) in hm.iter() { + match eval(value.clone(), env.clone()) { + Ok(mv) => { new_hm.insert(key.to_string(), mv); }, + Err(e) => return Err(e), + } + } + Ok(hash_map(new_hm)) + }, + _ => { + Ok(ast) + } + } +} + +fn eval(mut ast: MalVal, mut env: Env) -> MalRet { + 'tco: loop { + + //println!("eval: {}, {}", ast, env.borrow()); + //println!("eval: {}", ast); + let mut ast2 = ast.clone(); + match *ast2 { + List(_) => (), // continue + _ => return eval_ast(ast2, env), + } + + // apply list + match macroexpand(ast2, env.clone()) { + Ok(a) => { + ast2 = a; + }, + Err(e) => return Err(e), + } + match *ast2 { + List(_) => (), // continue + _ => return Ok(ast2), + } + let ast3 = ast2.clone(); + + 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) => (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; + }, + "quote" => { + return Ok((*args)[1].clone()); + }, + "quasiquote" => { + let a1 = (*args)[1].clone(); + ast = quasiquote(a1); + continue 'tco; + }, + "defmacro!" => { + let a1 = (*args)[1].clone(); + let a2 = (*args)[2].clone(); + match eval(a2, env.clone()) { + Ok(r) => { + match *r { + MalFunc(ref mfd) => { + match *a1 { + Sym(ref s) => { + let mut new_mfd = mfd.clone(); + new_mfd.is_macro = true; + let mf = malfuncd(new_mfd); + env_set(&env.clone(), s.clone(), mf.clone()); + return Ok(mf); + }, + _ => return err_str("def! of non-symbol"), + } + }, + _ => return err_str("def! of non-symbol"), + } + }, + Err(e) => return Err(e), + } + }, + "macroexpand" => { + let a1 = (*args)[1].clone(); + return macroexpand(a1, env.clone()) + }, + "try*" => { + let a1 = (*args)[1].clone(); + match eval(a1, env.clone()) { + Ok(res) => return Ok(res), + Err(err) => { + if args.len() < 3 { return Err(err); } + let a2 = (*args)[2].clone(); + let cat = match *a2 { + List(ref cat) => cat, + _ => return err_str("invalid catch* clause"), + }; + if cat.len() != 3 { + return err_str("wrong arity to catch* clause"); + } + let c1 = (*cat)[1].clone(); + let bstr = match *c1 { + Sym(ref s) => s, + _ => return err_str("invalid catch* binding"), + }; + let exc = match err { + ErrMalVal(mv) => mv, + ErrString(s) => string(s), + }; + let bind_env = env_new(Some(env.clone())); + env_set(&bind_env, bstr.to_string(), exc); + let c2 = (*cat)[2].clone(); + return eval(c2, bind_env); + }, + }; + } + "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; + }, + } + } + }, + "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) => { + 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(e) => err_str(e.as_slice()), + } + }, + _ => err_str("attempt to call non-function"), + } + } + } + }, + } + + } +} + +// print +fn print(exp: MalVal) -> String { + exp.pr_str(true) +} + +fn rep(str: &str, env: Env) -> Result<String,MalError> { + match read(str.to_string()) { + Err(e) => Err(e), + Ok(ast) => { + //println!("read: {}", ast); + match eval(ast, env) { + Err(e) => Err(e), + Ok(exp) => Ok(print(exp)), + } + } + } +} + +fn main() { + // core.rs: defined using rust + let repl_env = env_new(None); + for (k, v) in core::ns().into_iter() { env_set(&repl_env, k, v); } + // see eval() for definition of "eval" + env_set(&repl_env, "*ARGV*".to_string(), list(vec![])); + + // core.mal: defined using the language itself + let _ = rep("(def! *host-language* \"rust\")", 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(); + if args.len() > 1 { + let mv_args = args.slice(2,args.len()).iter() + .map(|a| string(a.to_string())) + .collect::<Vec<MalVal>>(); + env_set(&repl_env, "*ARGV*".to_string(), list(mv_args)); + 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; + }, + Err(str) => { + println!("Error: {}", str); + os::set_exit_status(1); + return; + }, + } + } + + // repl loop + let _ = rep("(println (str \"Mal [\" *host-language* \"]\"))", repl_env.clone()); + loop { + let line = readline::mal_readline("user> "); + match line { None => break, _ => () } + match rep(line.unwrap().as_slice(), repl_env.clone()) { + Ok(str) => println!("{}", str), + Err(ErrMalVal(_)) => (), // Blank line + Err(ErrString(s)) => println!("Error: {}", s), + } + } +} diff --git a/rust/src/types.rs b/rust/src/types.rs index e540ff1..97915cb 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -26,7 +26,35 @@ pub enum MalType { pub type MalVal = Rc<MalType>; -pub type MalRet = Result<MalVal,String>; +#[deriving(Show)] +pub enum MalError { + ErrString(String), + ErrMalVal(MalVal), +} + +pub type MalRet = Result<MalVal,MalError>; + + +pub fn err_string(s: String) -> MalRet { + Err(ErrString(s)) +} + +pub fn err_str(s: &str) -> MalRet { + Err(ErrString(s.to_string())) +} + +pub fn err_val(mv: MalVal) -> MalRet { + Err(ErrMalVal(mv)) +} + +/* +pub enum MalRet { + Val(MalVal), + MalErr(MalVal), + StringErr(String), +} +*/ + #[deriving(Clone)] pub struct MalFuncData { @@ -98,10 +126,10 @@ impl MalType { let new_env = env_new(Some(mfc.env.clone())); match env_bind(&new_env, mfc.params, alst) { Ok(_) => (mfc.eval)(mfc.exp, new_env), - Err(e) => Err(e), + Err(e) => err_string(e), } }, - _ => Err("attempt to call non-function".to_string()), + _ => err_str("attempt to call non-function"), } } @@ -136,23 +164,90 @@ impl fmt::Show for MalType { } -// Convenience constructor functions +// Scalars pub fn _nil() -> MalVal { Rc::new(Nil) } +pub fn nil_q(a:Vec<MalVal>) -> MalRet { + if a.len() != 1 { + return err_str("Wrong arity to nil? call"); + } + match *a[0].clone() { + Nil => Ok(_true()), + _ => Ok(_false()), + } +} + pub fn _true() -> MalVal { Rc::new(True) } +pub fn true_q(a:Vec<MalVal>) -> MalRet { + if a.len() != 1 { + return err_str("Wrong arity to true? call"); + } + match *a[0].clone() { + True => Ok(_true()), + _ => Ok(_false()), + } +} + pub fn _false() -> MalVal { Rc::new(False) } +pub fn false_q(a:Vec<MalVal>) -> MalRet { + if a.len() != 1 { + return err_str("Wrong arity to false? call"); + } + match *a[0].clone() { + False => Ok(_true()), + _ => Ok(_false()), + } +} + pub fn _int(i: int) -> MalVal { Rc::new(Int(i)) } + +// Symbols pub fn symbol(strn: &str) -> MalVal { Rc::new(Sym(strn.to_string())) } +pub fn symbol_q(a:Vec<MalVal>) -> MalRet { + if a.len() != 1 { + return err_str("Wrong arity to symbol? call"); + } + match *a[0].clone() { + Sym(_) => Ok(_true()), + _ => Ok(_false()), + } +} + +// Strings pub fn strn(strn: &str) -> MalVal { Rc::new(Strn(strn.to_string())) } pub fn string(strn: String) -> MalVal { Rc::new(Strn(strn)) } +// Lists pub fn list(seq: Vec<MalVal>) -> MalVal { Rc::new(List(seq)) } +pub fn listv(seq:Vec<MalVal>) -> MalRet { Ok(list(seq)) } +pub fn list_q(a:Vec<MalVal>) -> MalRet { + if a.len() != 1 { + return err_str("Wrong arity to list? call"); + } + match *a[0].clone() { + List(_) => Ok(_true()), + _ => Ok(_false()), + } +} + +// Vectors pub fn vector(seq: Vec<MalVal>) -> MalVal { Rc::new(Vector(seq)) } -pub fn hash_map(hm: HashMap<String,MalVal>) -> MalVal { Rc::new(Hash_Map(hm)) } +pub fn vectorv(seq: Vec<MalVal>) -> MalRet { Ok(vector(seq)) } +pub fn vector_q(a:Vec<MalVal>) -> MalRet { + if a.len() != 1 { + return err_str("Wrong arity to vector? call"); + } + match *a[0].clone() { + Vector(_) => Ok(_true()), + _ => Ok(_false()), + } +} +// Hash Maps +pub fn hash_map(hm: HashMap<String,MalVal>) -> MalVal { Rc::new(Hash_Map(hm)) } pub fn hash_mapv(seq: Vec<MalVal>) -> MalRet { if seq.len() % 2 == 1 { - return Err("odd number of elements to hash-map".to_string()); + return err_str("odd number of elements to hash-map"); } let mut new_hm: HashMap<String,MalVal> = HashMap::new(); let mut it = seq.iter(); @@ -160,7 +255,7 @@ pub fn hash_mapv(seq: Vec<MalVal>) -> MalRet { let k = match it.next() { Some(mv) => match *mv.clone() { Strn(ref s) => s.to_string(), - _ => return Err("key is not a string in hash-map call".to_string()), + _ => return err_str("key is not a string in hash-map call"), }, None => break, }; @@ -169,6 +264,15 @@ pub fn hash_mapv(seq: Vec<MalVal>) -> MalRet { } Ok(Rc::new(Hash_Map(new_hm))) } +pub fn hash_map_q(a:Vec<MalVal>) -> MalRet { + if a.len() != 1 { + return err_str("Wrong arity to map? call"); + } + match *a[0].clone() { + Hash_Map(_) => Ok(_true()), + _ => Ok(_false()), + } +} pub fn func(f: fn(Vec<MalVal>) -> MalRet ) -> MalVal { Rc::new(Func(f)) @@ -181,3 +285,15 @@ pub fn malfunc(eval: fn(MalVal, Env) -> MalRet, pub fn malfuncd(mfd: MalFuncData) -> MalVal { Rc::new(MalFunc(mfd)) } + + +// General functions +pub fn sequential_q(a:Vec<MalVal>) -> MalRet { + if a.len() != 1 { + return err_str("Wrong arity to sequential? call"); + } + match *a[0].clone() { + List(_) | Vector(_) => Ok(_true()), + _ => Ok(_false()), + } +} |
