From 104bc56bc12fd4adcce9505277cc92ec0d66968d Mon Sep 17 00:00:00 2001 From: Windel Bouwman Date: Sun, 21 Oct 2018 23:33:06 +0200 Subject: [PATCH] Add hash builtin function. --- vm/src/builtins.rs | 8 +++++++- vm/src/obj/objint.rs | 8 ++++++++ vm/src/obj/objobject.rs | 8 ++++++++ vm/src/obj/objtuple.rs | 20 ++++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index f97d962fc..df15bdee4 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -237,7 +237,12 @@ fn builtin_hasattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } -// builtin_hash +fn builtin_hash(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(obj, None)]); + + vm.call_method(obj, "__hash__", vec![]) +} + // builtin_help // builtin_hex @@ -522,6 +527,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { dict.insert(String::from("float"), ctx.float_type()); dict.insert(String::from("getattr"), ctx.new_rustfunc(builtin_getattr)); dict.insert(String::from("hasattr"), ctx.new_rustfunc(builtin_hasattr)); + dict.insert(String::from("hash"), ctx.new_rustfunc(builtin_hash)); dict.insert(String::from("id"), ctx.new_rustfunc(builtin_id)); dict.insert(String::from("int"), ctx.int_type()); dict.insert( diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index 22835fa6a..9fcb321b2 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -99,6 +99,13 @@ fn int_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.ctx.new_bool(result)) } +fn int_hash(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(zelf, Some(vm.ctx.int_type()))]); + + // TODO: how to hash int? + Ok(zelf.clone()) +} + fn int_abs(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(i, Some(vm.ctx.int_type()))]); Ok(vm.ctx.new_int(get_value(i).abs())) @@ -283,6 +290,7 @@ pub fn init(context: &PyContext) { int_type.set_attr("__and__", context.new_rustfunc(int_and)); int_type.set_attr("__divmod__", context.new_rustfunc(int_divmod)); int_type.set_attr("__floordiv__", context.new_rustfunc(int_floordiv)); + int_type.set_attr("__hash__", context.new_rustfunc(int_hash)); int_type.set_attr("__new__", context.new_rustfunc(int_new)); int_type.set_attr("__mod__", context.new_rustfunc(int_mod)); int_type.set_attr("__mul__", context.new_rustfunc(int_mul)); diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index dea6bc508..8e1aa37e1 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -49,6 +49,13 @@ fn object_ne(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { objbool::not(vm, &eq) } +fn object_hash(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(_zelf, Some(vm.ctx.object()))]); + + // For now default to non hashable + Err(vm.new_type_error("unhashable type".to_string())) +} + // TODO: is object the right place for delattr? fn object_delattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( @@ -91,6 +98,7 @@ pub fn init(context: &PyContext) { object.set_attr("__ne__", context.new_rustfunc(object_ne)); object.set_attr("__delattr__", context.new_rustfunc(object_delattr)); object.set_attr("__dict__", context.new_member_descriptor(object_dict)); + object.set_attr("__hash__", context.new_rustfunc(object_hash)); object.set_attr("__str__", context.new_rustfunc(object_str)); object.set_attr("__repr__", context.new_rustfunc(object_repr)); } diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs index f449bbc69..b3479e086 100644 --- a/vm/src/obj/objtuple.rs +++ b/vm/src/obj/objtuple.rs @@ -3,6 +3,7 @@ use super::super::pyobject::{ }; use super::super::vm::VirtualMachine; use super::objbool; +use super::objint; use super::objsequence::{get_item, seq_equal}; use super::objstr; use super::objtype; @@ -24,6 +25,24 @@ fn tuple_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.ctx.new_bool(result)) } +fn tuple_hash(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(zelf, Some(vm.ctx.tuple_type()))]); + + let mut x: usize = 0x345678; + let elements = get_elements(zelf); + let len: usize = elements.len(); + let mut mult = 0xf4243; + + for elem in &elements { + let y: usize = objint::get_value(&vm.call_method(elem, "__hash__", vec![])?) as usize; + x = (x ^ y) * mult; + mult = mult + 82520 + len * 2; + } + x += 97531; + + Ok(vm.ctx.new_int(x as i32)) +} + fn tuple_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(zelf, Some(vm.ctx.tuple_type()))]); let elements = get_elements(zelf); @@ -93,6 +112,7 @@ pub fn init(context: &PyContext) { tuple_type.set_attr("__eq__", context.new_rustfunc(tuple_eq)); tuple_type.set_attr("__contains__", context.new_rustfunc(tuple_contains)); tuple_type.set_attr("__getitem__", context.new_rustfunc(tuple_getitem)); + tuple_type.set_attr("__hash__", context.new_rustfunc(tuple_hash)); tuple_type.set_attr("__len__", context.new_rustfunc(tuple_len)); tuple_type.set_attr("__repr__", context.new_rustfunc(tuple_repr)); }