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()
|
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!();
|
impl_create!();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,27 +185,77 @@ impl Map {
|
|||||||
List::create(list)
|
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 {
|
pub(crate) fn index(vm: &mut Vm) -> ObjP {
|
||||||
let this = vm.frame_stack()[0].clone();
|
let this = vm.frame_stack()[0].clone();
|
||||||
let index = vm.frame_stack()[1].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| {
|
if let Some(value) = result {
|
||||||
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 {
|
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
// TODO Map::index - throw an exception when no value is found in the index
|
// 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),
|
to_list => BuiltinFunction::create("to_list", Map::to_list, 1),
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
|
__eq__ => BuiltinFunction::create("__eq__", Map::eq, 2),
|
||||||
__index__ => BuiltinFunction::create("__index__", Map::index, 2),
|
__index__ => BuiltinFunction::create("__index__", Map::index, 2),
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
|
contains => BuiltinFunction::create("contains", Map::contains, 2),
|
||||||
|
get => BuiltinFunction::create("get", Map::get, 2),
|
||||||
len => BuiltinFunction::create("len", Map::len, 1),
|
len => BuiltinFunction::create("len", Map::len, 1),
|
||||||
insert => BuiltinFunction::create("insert", Map::insert, 3),
|
insert => BuiltinFunction::create("insert", Map::insert, 3),
|
||||||
remove => BuiltinFunction::create("remove", Map::remove, 2),
|
remove => BuiltinFunction::create("remove", Map::remove, 2),
|
||||||
|
|||||||
Reference in New Issue
Block a user