diff options
Diffstat (limited to 'rust/src/core.rs')
| -rw-r--r-- | rust/src/core.rs | 161 |
1 files changed, 121 insertions, 40 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; } |
