aboutsummaryrefslogtreecommitdiff
path: root/rust/src
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-10-27 21:13:50 -0500
committerJoel Martin <github@martintribe.org>2015-01-06 21:59:00 -0600
commitb12d98e4e3424be6b1e851c9450e9532910996ec (patch)
tree317d8b69d1e0a67f42af06ebe257ffbac2393869 /rust/src
parent3744d56621ff4c1c6c8a1fd6beb1d03123df53a5 (diff)
downloadmal-b12d98e4e3424be6b1e851c9450e9532910996ec.tar.gz
mal-b12d98e4e3424be6b1e851c9450e9532910996ec.zip
rust: core hash-map functions.
Diffstat (limited to 'rust/src')
-rw-r--r--rust/src/core.rs97
-rw-r--r--rust/src/types.rs30
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))
}