diff options
| author | Joel Martin <github@martintribe.org> | 2014-10-27 21:13:50 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-01-06 21:59:00 -0600 |
| commit | b12d98e4e3424be6b1e851c9450e9532910996ec (patch) | |
| tree | 317d8b69d1e0a67f42af06ebe257ffbac2393869 /rust/src | |
| parent | 3744d56621ff4c1c6c8a1fd6beb1d03123df53a5 (diff) | |
| download | mal-b12d98e4e3424be6b1e851c9450e9532910996ec.tar.gz mal-b12d98e4e3424be6b1e851c9450e9532910996ec.zip | |
rust: core hash-map functions.
Diffstat (limited to 'rust/src')
| -rw-r--r-- | rust/src/core.rs | 97 | ||||
| -rw-r--r-- | rust/src/types.rs | 30 |
2 files changed, 120 insertions, 7 deletions
diff --git a/rust/src/core.rs b/rust/src/core.rs index 61dc0ce..5eafa4c 100644 --- a/rust/src/core.rs +++ b/rust/src/core.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; use std::io::File; use types::{MalVal,MalRet,err_val,err_str,err_string, - Int,Strn,List,Vector,Hash_Map, + Nil,Int,Strn,List,Vector,Hash_Map, _nil,_true,_false,_int,string,list,func}; use types; use readline; @@ -126,6 +126,36 @@ pub fn time_ms(a:Vec<MalVal>) -> MalRet { // Hash Map functions +pub fn assoc(a:Vec<MalVal>) -> MalRet { + if a.len() < 3 { + return err_str("Wrong arity to assoc call"); + } + match *a[0] { + Hash_Map(ref hm) => { + types::_assoc(hm, a.slice(1,a.len()).to_vec()) + }, + Nil => { + types::hash_mapv(a.slice(1,a.len()).to_vec()) + } + _ => return err_str("assoc onto non-hash map"), + } +} + +pub fn dissoc(a:Vec<MalVal>) -> MalRet { + if a.len() < 2 { + return err_str("Wrong arity to dissoc call"); + } + match *a[0] { + Hash_Map(ref hm) => { + types::_dissoc(hm, a.slice(1,a.len()).to_vec()) + }, + Nil => { + Ok(_nil()) + } + _ => return err_str("dissoc onto non-hash map"), + } +} + pub fn get(a:Vec<MalVal>) -> MalRet { if a.len() != 2 { return err_str("Wrong arity to get call"); @@ -133,7 +163,8 @@ pub fn get(a:Vec<MalVal>) -> MalRet { 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"), + Nil => return Ok(_nil()), + _ => return err_str("get on non-hash map"), }; match *a[1] { Strn(ref key) => { @@ -146,6 +177,63 @@ pub fn get(a:Vec<MalVal>) -> MalRet { } } +pub fn contains_q(a:Vec<MalVal>) -> MalRet { + if a.len() != 2 { + return err_str("Wrong arity to contains? call"); + } + let a0 = a[0].clone(); + let hm: &HashMap<String,MalVal> = match *a0 { + Hash_Map(ref hm) => hm, + Nil => return Ok(_false()), + _ => return err_str("contains? on non-hash map"), + }; + match *a[1] { + Strn(ref key) => { + match hm.contains_key(key) { + true => Ok(_true()), + false => Ok(_false()), + } + }, + _ => return err_str("contains? with non-string key"), + } +} + +pub fn keys(a:Vec<MalVal>) -> MalRet { + if a.len() != 1 { + return err_str("Wrong arity to keys call"); + } + let a0 = a[0].clone(); + let hm: &HashMap<String,MalVal> = match *a0 { + Hash_Map(ref hm) => hm, + Nil => return Ok(_nil()), + _ => return err_str("contains? on non-hash map"), + }; + if hm.len() == 0 { return Ok(_nil()); } + let mut keys = vec![]; + for k in hm.keys() { + keys.push(string(k.to_string())); + } + Ok(list(keys)) +} + +pub fn vals(a:Vec<MalVal>) -> MalRet { + if a.len() != 1 { + return err_str("Wrong arity to values call"); + } + let a0 = a[0].clone(); + let hm: &HashMap<String,MalVal> = match *a0 { + Hash_Map(ref hm) => hm, + Nil => return Ok(_nil()), + _ => return err_str("contains? on non-hash map"), + }; + if hm.len() == 0 { return Ok(_nil()); } + let mut vals = vec![]; + for k in hm.values() { + vals.push(k.clone()); + } + Ok(list(vals)) +} + // Sequence functions pub fn cons(a:Vec<MalVal>) -> MalRet { @@ -329,7 +417,12 @@ pub fn ns() -> HashMap<String,MalVal> { 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("assoc".to_string(), func(assoc)); + ns.insert("dissoc".to_string(), func(dissoc)); ns.insert("get".to_string(), func(get)); + ns.insert("contains?".to_string(), func(contains_q)); + ns.insert("keys".to_string(), func(keys)); + ns.insert("vals".to_string(), func(vals)); ns.insert("sequential?".to_string(), func(types::sequential_q)); ns.insert("cons".to_string(), func(cons)); diff --git a/rust/src/types.rs b/rust/src/types.rs index 97915cb..80079ce 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -245,12 +245,12 @@ pub fn vector_q(a:Vec<MalVal>) -> MalRet { // 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_str("odd number of elements to hash-map"); +pub fn _assoc(hm: &HashMap<String,MalVal>, a:Vec<MalVal>) -> MalRet { + if a.len() % 2 == 1 { + return err_str("odd number of hash-map keys/values"); } - let mut new_hm: HashMap<String,MalVal> = HashMap::new(); - let mut it = seq.iter(); + let mut new_hm = hm.clone(); + let mut it = a.iter(); loop { let k = match it.next() { Some(mv) => match *mv.clone() { @@ -264,6 +264,25 @@ pub fn hash_mapv(seq: Vec<MalVal>) -> MalRet { } Ok(Rc::new(Hash_Map(new_hm))) } +pub fn _dissoc(hm: &HashMap<String,MalVal>, a:Vec<MalVal>) -> MalRet { + let mut new_hm = hm.clone(); + let mut it = a.iter(); + loop { + let k = match it.next() { + Some(mv) => match *mv.clone() { + Strn(ref s) => s.to_string(), + _ => return err_str("key is not a string in hash-map call"), + }, + None => break, + }; + new_hm.remove(&k); + } + Ok(Rc::new(Hash_Map(new_hm))) +} +pub fn hash_mapv(seq: Vec<MalVal>) -> MalRet { + let new_hm: HashMap<String,MalVal> = HashMap::new(); + _assoc(&new_hm, seq) +} pub fn hash_map_q(a:Vec<MalVal>) -> MalRet { if a.len() != 1 { return err_str("Wrong arity to map? call"); @@ -274,6 +293,7 @@ pub fn hash_map_q(a:Vec<MalVal>) -> MalRet { } } +// Functions pub fn func(f: fn(Vec<MalVal>) -> MalRet ) -> MalVal { Rc::new(Func(f)) } |
