Add Map __eq__, contains, and get methods
* __eq__ recursively checks equality (need a way to check for cycles) * contains checks if the map contains a given index * get will get an item from the map, but return nil if it doesn't exist as a key Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
102
src/obj/map.rs
102
src/obj/map.rs
@@ -62,6 +62,26 @@ impl Map {
|
||||
self.hash_builder.build_hasher()
|
||||
}
|
||||
|
||||
/// Helper function to look up values in the index.
|
||||
fn index_lookup(this: ObjP, index: ObjP, vm: &mut Vm) -> Option<ObjP> {
|
||||
let hash = map_hash_index(vm, &this, &index);
|
||||
|
||||
with_obj_downcast(this.clone(), |map: &Map| {
|
||||
map.table()
|
||||
.find(hash, |(key, _)| {
|
||||
let method = index
|
||||
.borrow()
|
||||
.get_vtable_attr(index.clone(), "__eq__")
|
||||
.unwrap();
|
||||
let result = vm.call(method, &[key.clone()]);
|
||||
let is_truthy = result.borrow().is_truthy();
|
||||
is_truthy
|
||||
})
|
||||
.cloned()
|
||||
})
|
||||
.map(|(_key, value)| value)
|
||||
}
|
||||
|
||||
impl_create!();
|
||||
}
|
||||
|
||||
@@ -165,27 +185,77 @@ impl Map {
|
||||
List::create(list)
|
||||
}
|
||||
|
||||
pub(crate) fn eq(vm: &mut Vm) -> ObjP {
|
||||
let this = vm.frame_stack()[0].clone();
|
||||
let other_ptr = vm.frame_stack()[1].clone();
|
||||
|
||||
let result = if let (Some(this), Some(other)) = (
|
||||
this.borrow().as_any().downcast_ref::<Map>(),
|
||||
other_ptr.borrow().as_any().downcast_ref::<Map>(),
|
||||
) {
|
||||
if this.table().len() != other.table().len() {
|
||||
return Bool::create(false);
|
||||
}
|
||||
|
||||
let index_method = other.get_vtable_attr(other_ptr.clone(), "get").unwrap();
|
||||
let contains_method = other
|
||||
.get_vtable_attr(other_ptr.clone(), "contains")
|
||||
.unwrap();
|
||||
this.table().iter().all(|(key, value)| {
|
||||
let contains = vm.call(contains_method.clone(), &[key.clone()]);
|
||||
if contains.borrow().is_truthy() {
|
||||
let other_value = vm.call(index_method.clone(), &[key.clone()]);
|
||||
let eq_method = value
|
||||
.borrow()
|
||||
.get_vtable_attr(value.clone(), "__eq__")
|
||||
.unwrap();
|
||||
let eq = vm.call(eq_method, &[other_value]);
|
||||
let is_truthy = eq.borrow().is_truthy();
|
||||
|
||||
// check if this[key] == other[key]
|
||||
is_truthy
|
||||
} else {
|
||||
// key in this, not in other
|
||||
false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// this and other are not both Map
|
||||
false
|
||||
};
|
||||
|
||||
Bool::create(result)
|
||||
}
|
||||
|
||||
pub(crate) fn contains(vm: &mut Vm) -> ObjP {
|
||||
let this = vm.frame_stack()[0].clone();
|
||||
let index = vm.frame_stack()[1].clone();
|
||||
|
||||
let result = Map::index_lookup(this, index, vm);
|
||||
|
||||
Bool::create(result.is_some())
|
||||
}
|
||||
|
||||
pub(crate) fn get(vm: &mut Vm) -> ObjP {
|
||||
let this = vm.frame_stack()[0].clone();
|
||||
let index = vm.frame_stack()[1].clone();
|
||||
|
||||
let result = Map::index_lookup(this, index, vm);
|
||||
|
||||
if let Some(value) = result {
|
||||
value
|
||||
} else {
|
||||
Nil::create()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn index(vm: &mut Vm) -> ObjP {
|
||||
let this = vm.frame_stack()[0].clone();
|
||||
let index = vm.frame_stack()[1].clone();
|
||||
|
||||
let hash = map_hash_index(vm, &this, &index);
|
||||
let result = Map::index_lookup(this, index, vm);
|
||||
|
||||
let result = with_obj_downcast(this.clone(), |map: &Map| {
|
||||
map.table()
|
||||
.find(hash, |(key, _)| {
|
||||
let method = index
|
||||
.borrow()
|
||||
.get_vtable_attr(index.clone(), "__eq__")
|
||||
.unwrap();
|
||||
let result = vm.call(method, &[key.clone()]);
|
||||
let is_truthy = result.borrow().is_truthy();
|
||||
is_truthy
|
||||
})
|
||||
.cloned()
|
||||
});
|
||||
|
||||
if let Some((_key, value)) = result {
|
||||
if let Some(value) = result {
|
||||
value
|
||||
} else {
|
||||
// TODO Map::index - throw an exception when no value is found in the index
|
||||
|
||||
@@ -221,9 +221,12 @@ pub fn init_types() {
|
||||
to_list => BuiltinFunction::create("to_list", Map::to_list, 1),
|
||||
|
||||
// Operators
|
||||
__eq__ => BuiltinFunction::create("__eq__", Map::eq, 2),
|
||||
__index__ => BuiltinFunction::create("__index__", Map::index, 2),
|
||||
|
||||
// Methods
|
||||
contains => BuiltinFunction::create("contains", Map::contains, 2),
|
||||
get => BuiltinFunction::create("get", Map::get, 2),
|
||||
len => BuiltinFunction::create("len", Map::len, 1),
|
||||
insert => BuiltinFunction::create("insert", Map::insert, 3),
|
||||
remove => BuiltinFunction::create("remove", Map::remove, 2),
|
||||
|
||||
Reference in New Issue
Block a user