1
1
mirror of https://github.com/kanaka/mal.git synced 2024-11-13 01:43:50 +03:00

rust: core hash-map functions.

This commit is contained in:
Joel Martin 2014-10-27 21:13:50 -05:00
parent 3744d56621
commit b12d98e4e3
3 changed files with 144 additions and 30 deletions

View File

@ -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));

View File

@ -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))
}

View File

@ -108,29 +108,6 @@
(vector 3 4 5)
;=>[3 4 5]
;; Testing conj function
(conj (list) 1)
;=>(1)
(conj (list 1) 2)
;=>(2 1)
(conj (list 2 3) 4)
;=>(4 2 3)
(conj (list 2 3) 4 5 6)
;=>(6 5 4 2 3)
(conj (list 1) (list 2 3))
;=>((2 3) 1)
(conj [] 1)
;=>[1]
(conj [1] 2)
;=>[1 2]
(conj [2 3] 4)
;=>[2 3 4]
(conj [2 3] 4 5 6)
;=>[2 3 4 5 6]
(conj [1] [2 3])
;=>[1 [2 3]]
(map? [])
;=>false
@ -207,6 +184,30 @@
;=>2
;;
;; Testing conj function
(conj (list) 1)
;=>(1)
(conj (list 1) 2)
;=>(2 1)
(conj (list 2 3) 4)
;=>(4 2 3)
(conj (list 2 3) 4 5 6)
;=>(6 5 4 2 3)
(conj (list 1) (list 2 3))
;=>((2 3) 1)
(conj [] 1)
;=>[1]
(conj [1] 2)
;=>[1 2]
(conj [2 3] 4)
;=>[2 3 4]
(conj [2 3] 4 5 6)
;=>[2 3 4 5 6]
(conj [1] [2 3])
;=>[1 [2 3]]
;;
;; Testing metadata
(meta [1 2 3])