diff --git a/tests/snippets/builtin_range.py b/tests/snippets/builtin_range.py index 8d0ab0b65..c8efb189d 100644 --- a/tests/snippets/builtin_range.py +++ b/tests/snippets/builtin_range.py @@ -27,6 +27,7 @@ assert len(range(5, 10, 2)) == 3, 'Expected length 3, for elements: 5, 7, 9' assert range(10).index(6) == 6 assert range(4, 10).index(6) == 2 assert range(4, 10, 2).index(6) == 1 +assert range(10, 4, -2).index(8) == 1 # index raises value error on out of bounds assert_raises(lambda _: range(10).index(-1), ValueError) @@ -34,3 +35,25 @@ assert_raises(lambda _: range(10).index(10), ValueError) # index raises value error if out of step assert_raises(lambda _: range(4, 10, 2).index(5), ValueError) + +# index raises value error if needle is not an int +assert_raises(lambda _: range(10).index('foo'), ValueError) + +# __bool__ +assert range(1).__bool__() +assert range(1, 2).__bool__() + +assert not range(0).__bool__() +assert not range(1, 1).__bool__() + +# __contains__ +assert range(10).__contains__(6) +assert range(4, 10).__contains__(6) +assert range(4, 10, 2).__contains__(6) +assert range(10, 4, -2).__contains__(10) +assert range(10, 4, -2).__contains__(8) + +assert not range(10).__contains__(-1) +assert not range(10, 4, -2).__contains__(9) +assert not range(10, 4, -2).__contains__(4) +assert not range(10).__contains__('foo') diff --git a/tests/snippets/tuple.py b/tests/snippets/tuple.py index eb5102fa3..38617d036 100644 --- a/tests/snippets/tuple.py +++ b/tests/snippets/tuple.py @@ -19,3 +19,5 @@ assert x > y, "tuple __gt__ failed" b = (1,2,3) assert b.index(2) == 1 + +assert b.__doc__ == "tuple() -> empty tuple\ntuple(iterable) -> tuple initialized from iterable's items\n\nIf the argument is a tuple, the return value is the same object." diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index db08624e4..264bf163f 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -136,11 +136,11 @@ fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let mode = { let mode = objstr::get_value(mode); - if mode == String::from("exec") { + if mode == "exec" { compile::Mode::Exec - } else if mode == "eval".to_string() { + } else if mode == "eval" { compile::Mode::Eval - } else if mode == "single".to_string() { + } else if mode == "single" { compile::Mode::Single } else { return Err( diff --git a/vm/src/compile.rs b/vm/src/compile.rs index fb9215341..9050e59ce 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -45,9 +45,8 @@ pub fn compile( }, }; - match result { - Err(msg) => return Err(vm.new_exception(syntax_error.clone(), msg)), - _ => {} + if let Err(msg) = result { + return Err(vm.new_exception(syntax_error.clone(), msg)); } let code = compiler.pop_code_object(); @@ -589,7 +588,7 @@ impl Compiler { ast::Statement::Assign { targets, value } => { self.compile_expression(value)?; - for (i, target) in targets.into_iter().enumerate() { + for (i, target) in targets.iter().enumerate() { if i + 1 != targets.len() { self.emit(Instruction::Duplicate); } @@ -665,7 +664,7 @@ impl Compiler { let mut flags = bytecode::FunctionOpArg::empty(); if have_kwargs { - flags = flags | bytecode::FunctionOpArg::HAS_DEFAULTS; + flags |= bytecode::FunctionOpArg::HAS_DEFAULTS; } Ok(flags) diff --git a/vm/src/format.rs b/vm/src/format.rs index 5b4035ef7..6dfa77c7e 100644 --- a/vm/src/format.rs +++ b/vm/src/format.rs @@ -314,7 +314,7 @@ impl FormatSpec { } None => Ok(magnitude.to_str_radix(10)), }; - if !raw_magnitude_string_result.is_ok() { + if raw_magnitude_string_result.is_err() { return raw_magnitude_string_result; } let magnitude_string = format!( diff --git a/vm/src/frame.rs b/vm/src/frame.rs index d19ceeeb7..54fbf415b 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -610,7 +610,7 @@ impl Frame { .iter() .skip(*before) .take(middle) - .map(|x| x.clone()) + .cloned() .collect(); let t = vm.ctx.new_list(middle_elements); self.push_value(t); @@ -886,25 +886,25 @@ impl Frame { ) -> FrameResult { let b_ref = self.pop_value(); let a_ref = self.pop_value(); - let value = match op { - &bytecode::BinaryOperator::Subtract => vm._sub(a_ref, b_ref), - &bytecode::BinaryOperator::Add => vm._add(a_ref, b_ref), - &bytecode::BinaryOperator::Multiply => vm._mul(a_ref, b_ref), - &bytecode::BinaryOperator::MatrixMultiply => { + let value = match *op { + bytecode::BinaryOperator::Subtract => vm._sub(a_ref, b_ref), + bytecode::BinaryOperator::Add => vm._add(a_ref, b_ref), + bytecode::BinaryOperator::Multiply => vm._mul(a_ref, b_ref), + bytecode::BinaryOperator::MatrixMultiply => { vm.call_method(&a_ref, "__matmul__", vec![b_ref]) } - &bytecode::BinaryOperator::Power => vm._pow(a_ref, b_ref), - &bytecode::BinaryOperator::Divide => vm._div(a_ref, b_ref), - &bytecode::BinaryOperator::FloorDivide => { + bytecode::BinaryOperator::Power => vm._pow(a_ref, b_ref), + bytecode::BinaryOperator::Divide => vm._div(a_ref, b_ref), + bytecode::BinaryOperator::FloorDivide => { vm.call_method(&a_ref, "__floordiv__", vec![b_ref]) } - &bytecode::BinaryOperator::Subscript => self.subscript(vm, a_ref, b_ref), - &bytecode::BinaryOperator::Modulo => vm._modulo(a_ref, b_ref), - &bytecode::BinaryOperator::Lshift => vm.call_method(&a_ref, "__lshift__", vec![b_ref]), - &bytecode::BinaryOperator::Rshift => vm.call_method(&a_ref, "__rshift__", vec![b_ref]), - &bytecode::BinaryOperator::Xor => vm._xor(a_ref, b_ref), - &bytecode::BinaryOperator::Or => vm._or(a_ref, b_ref), - &bytecode::BinaryOperator::And => vm._and(a_ref, b_ref), + bytecode::BinaryOperator::Subscript => self.subscript(vm, a_ref, b_ref), + bytecode::BinaryOperator::Modulo => vm._modulo(a_ref, b_ref), + bytecode::BinaryOperator::Lshift => vm.call_method(&a_ref, "__lshift__", vec![b_ref]), + bytecode::BinaryOperator::Rshift => vm.call_method(&a_ref, "__rshift__", vec![b_ref]), + bytecode::BinaryOperator::Xor => vm._xor(a_ref, b_ref), + bytecode::BinaryOperator::Or => vm._or(a_ref, b_ref), + bytecode::BinaryOperator::And => vm._and(a_ref, b_ref), }?; self.push_value(value); @@ -917,11 +917,11 @@ impl Frame { op: &bytecode::UnaryOperator, ) -> FrameResult { let a = self.pop_value(); - let value = match op { - &bytecode::UnaryOperator::Minus => vm.call_method(&a, "__neg__", vec![])?, - &bytecode::UnaryOperator::Plus => vm.call_method(&a, "__pos__", vec![])?, - &bytecode::UnaryOperator::Invert => vm.call_method(&a, "__invert__", vec![])?, - &bytecode::UnaryOperator::Not => { + let value = match *op { + bytecode::UnaryOperator::Minus => vm.call_method(&a, "__neg__", vec![])?, + bytecode::UnaryOperator::Plus => vm.call_method(&a, "__pos__", vec![])?, + bytecode::UnaryOperator::Invert => vm.call_method(&a, "__invert__", vec![])?, + bytecode::UnaryOperator::Not => { let value = objbool::boolval(vm, a)?; vm.ctx.new_bool(!value) } @@ -994,17 +994,17 @@ impl Frame { ) -> FrameResult { let b = self.pop_value(); let a = self.pop_value(); - let value = match op { - &bytecode::ComparisonOperator::Equal => vm._eq(&a, b)?, - &bytecode::ComparisonOperator::NotEqual => vm._ne(&a, b)?, - &bytecode::ComparisonOperator::Less => vm._lt(&a, b)?, - &bytecode::ComparisonOperator::LessOrEqual => vm._le(&a, b)?, - &bytecode::ComparisonOperator::Greater => vm._gt(&a, b)?, - &bytecode::ComparisonOperator::GreaterOrEqual => vm._ge(&a, b)?, - &bytecode::ComparisonOperator::Is => vm.ctx.new_bool(self._is(a, b)), - &bytecode::ComparisonOperator::IsNot => self._is_not(vm, a, b)?, - &bytecode::ComparisonOperator::In => self._in(vm, a, b)?, - &bytecode::ComparisonOperator::NotIn => self._not_in(vm, a, b)?, + let value = match *op { + bytecode::ComparisonOperator::Equal => vm._eq(&a, b)?, + bytecode::ComparisonOperator::NotEqual => vm._ne(&a, b)?, + bytecode::ComparisonOperator::Less => vm._lt(&a, b)?, + bytecode::ComparisonOperator::LessOrEqual => vm._le(&a, b)?, + bytecode::ComparisonOperator::Greater => vm._gt(&a, b)?, + bytecode::ComparisonOperator::GreaterOrEqual => vm._ge(&a, b)?, + bytecode::ComparisonOperator::Is => vm.ctx.new_bool(self._is(a, b)), + bytecode::ComparisonOperator::IsNot => self._is_not(vm, a, b)?, + bytecode::ComparisonOperator::In => self._in(vm, a, b)?, + bytecode::ComparisonOperator::NotIn => self._not_in(vm, a, b)?, }; self.push_value(value); diff --git a/vm/src/import.rs b/vm/src/import.rs index e560d3b18..be8807881 100644 --- a/vm/src/import.rs +++ b/vm/src/import.rs @@ -103,7 +103,7 @@ fn find_source(vm: &VirtualMachine, current_path: PathBuf, name: &str) -> Result } } - match filepaths.iter().filter(|p| p.exists()).next() { + match filepaths.iter().find(|p| p.exists()) { Some(path) => Ok(path.to_path_buf()), None => Err(format!("No module named '{}'", name)), } diff --git a/vm/src/obj/objbool.rs b/vm/src/obj/objbool.rs index f3a2fafb8..dbec65a7c 100644 --- a/vm/src/obj/objbool.rs +++ b/vm/src/obj/objbool.rs @@ -20,6 +20,7 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result !value.is_zero(), _ => return Err(vm.new_type_error(String::from("TypeError"))), }; + v } else { true @@ -81,7 +82,7 @@ fn bool_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(match val { Some(val) => { let bv = boolval(vm, val.clone())?; - vm.new_bool(bv.clone()) + vm.new_bool(bv) } None => vm.context().new_bool(false), }) diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs index 8a468aa73..1909247cb 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -14,12 +14,29 @@ use std::ops::Deref; // Fill bytes class methods: pub fn init(context: &PyContext) { let bytes_type = &context.bytes_type; + + let bytes_doc = + "bytes(iterable_of_ints) -> bytes\n\ + bytes(string, encoding[, errors]) -> bytes\n\ + bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer\n\ + bytes(int) -> bytes object of size given by the parameter initialized with null bytes\n\ + bytes() -> empty bytes object\n\nConstruct an immutable array of bytes from:\n \ + - an iterable yielding integers in range(256)\n \ + - a text string encoded using the specified encoding\n \ + - any object implementing the buffer API.\n \ + - an integer"; + context.set_attr(bytes_type, "__eq__", context.new_rustfunc(bytes_eq)); context.set_attr(bytes_type, "__hash__", context.new_rustfunc(bytes_hash)); context.set_attr(bytes_type, "__new__", context.new_rustfunc(bytes_new)); context.set_attr(bytes_type, "__repr__", context.new_rustfunc(bytes_repr)); context.set_attr(bytes_type, "__len__", context.new_rustfunc(bytes_len)); - context.set_attr(bytes_type, "__iter__", context.new_rustfunc(bytes_iter)) + context.set_attr(bytes_type, "__iter__", context.new_rustfunc(bytes_iter)); + context.set_attr( + bytes_type, + "__doc__", + context.new_str(bytes_doc.to_string()), + ); } fn bytes_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { diff --git a/vm/src/obj/objdict.rs b/vm/src/obj/objdict.rs index 0a3a0cb11..8a3e77ff8 100644 --- a/vm/src/obj/objdict.rs +++ b/vm/src/obj/objdict.rs @@ -5,7 +5,7 @@ use super::super::vm::VirtualMachine; use super::objiter; use super::objstr; use super::objtype; -use std::cell::{Ref, RefMut}; +use std::cell::{Ref, RefCell, RefMut}; use std::collections::HashMap; use std::ops::{Deref, DerefMut}; @@ -105,10 +105,7 @@ pub fn contains_key_str(dict: &PyObjectRef, key: &str) -> bool { pub fn content_contains_key_str(elements: &DictContentType, key: &str) -> bool { // TODO: let hash: usize = key; - match elements.get(key) { - Some(_) => true, - None => false, - } + elements.get(key).is_some() } // Python dict methods: @@ -139,7 +136,7 @@ fn dict_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let elem_iter = objiter::get_iter(vm, &element)?; let needle = objiter::get_next_object(vm, &elem_iter)?.ok_or_else(|| err(vm))?; let value = objiter::get_next_object(vm, &elem_iter)?.ok_or_else(|| err(vm))?; - if let Some(_) = objiter::get_next_object(vm, &elem_iter)? { + if objiter::get_next_object(vm, &elem_iter)?.is_some() { return Err(err(vm)); } set_item(&dict, &needle, &value); @@ -276,7 +273,7 @@ fn dict_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { pub fn create_type(type_type: PyObjectRef, object_type: PyObjectRef, dict_type: PyObjectRef) { (*dict_type.borrow_mut()).payload = PyObjectPayload::Class { name: String::from("dict"), - dict: new(dict_type.clone()), + dict: RefCell::new(HashMap::new()), mro: vec![object_type], }; (*dict_type.borrow_mut()).typ = Some(type_type.clone()); diff --git a/vm/src/obj/objfloat.rs b/vm/src/obj/objfloat.rs index 4cb996a51..1bb57e572 100644 --- a/vm/src/obj/objfloat.rs +++ b/vm/src/obj/objfloat.rs @@ -268,6 +268,9 @@ fn float_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { pub fn init(context: &PyContext) { let float_type = &context.float_type; + + let float_doc = "Convert a string or number to a floating point number, if possible."; + context.set_attr(&float_type, "__eq__", context.new_rustfunc(float_eq)); context.set_attr(&float_type, "__lt__", context.new_rustfunc(float_lt)); context.set_attr(&float_type, "__le__", context.new_rustfunc(float_le)); @@ -291,4 +294,9 @@ pub fn init(context: &PyContext) { context.set_attr(&float_type, "__pow__", context.new_rustfunc(float_pow)); context.set_attr(&float_type, "__sub__", context.new_rustfunc(float_sub)); context.set_attr(&float_type, "__repr__", context.new_rustfunc(float_repr)); + context.set_attr( + &float_type, + "__doc__", + context.new_str(float_doc.to_string()), + ); } diff --git a/vm/src/obj/objfunction.rs b/vm/src/obj/objfunction.rs index f04897481..01c05aab1 100644 --- a/vm/src/obj/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -1,6 +1,6 @@ use super::super::pyobject::{ - AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, - PyResult, TypeProtocol, + AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, + TypeProtocol, }; use super::super::vm::VirtualMachine; use super::objtype; @@ -110,12 +110,7 @@ fn classmethod_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { trace!("classmethod.__new__ {:?}", args.args); arg_check!(vm, args, required = [(cls, None), (callable, None)]); - let py_obj = PyObject::new( - PyObjectPayload::Instance { - dict: vm.ctx.new_dict(), - }, - cls.clone(), - ); + let py_obj = vm.ctx.new_instance(cls.clone(), None); vm.ctx.set_attr(&py_obj, "function", callable.clone()); Ok(py_obj) } @@ -148,12 +143,7 @@ fn staticmethod_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { trace!("staticmethod.__new__ {:?}", args.args); arg_check!(vm, args, required = [(cls, None), (callable, None)]); - let py_obj = PyObject::new( - PyObjectPayload::Instance { - dict: vm.ctx.new_dict(), - }, - cls.clone(), - ); + let py_obj = vm.ctx.new_instance(cls.clone(), None); vm.ctx.set_attr(&py_obj, "function", callable.clone()); Ok(py_obj) } diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 2ce90714d..ed8e552bc 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -171,7 +171,7 @@ fn list_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { if objtype::isinstance(o2, &vm.ctx.list_type()) { let e1 = get_elements(o); let e2 = get_elements(o2); - let elements = e1.iter().chain(e2.iter()).map(|e| e.clone()).collect(); + let elements = e1.iter().chain(e2.iter()).cloned().collect(); Ok(vm.ctx.new_list(elements)) } else { Err(vm.new_type_error(format!("Cannot add {} and {}", o.borrow(), o2.borrow()))) @@ -223,7 +223,7 @@ fn list_count(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { for element in elements.iter() { let is_eq = vm._eq(element, value.clone())?; if objbool::boolval(vm, is_eq)? { - count = count + 1; + count += 1; } } Ok(vm.context().new_int(count)) diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index 190f3078b..cb5065b20 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -1,25 +1,25 @@ use super::super::pyobject::{ - AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, - PyResult, TypeProtocol, + AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, + TypeProtocol, }; use super::super::vm::VirtualMachine; use super::objbool; -use super::objdict; use super::objstr; use super::objtype; +use std::cell::RefCell; +use std::collections::HashMap; pub fn new_instance(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { // more or less __new__ operator let type_ref = args.shift(); - let dict = vm.new_dict(); - let obj = PyObject::new(PyObjectPayload::Instance { dict }, type_ref.clone()); + let obj = vm.ctx.new_instance(type_ref.clone(), None); Ok(obj) } -pub fn create_object(type_type: PyObjectRef, object_type: PyObjectRef, dict_type: PyObjectRef) { +pub fn create_object(type_type: PyObjectRef, object_type: PyObjectRef, _dict_type: PyObjectRef) { (*object_type.borrow_mut()).payload = PyObjectPayload::Class { name: String::from("object"), - dict: objdict::new(dict_type), + dict: RefCell::new(HashMap::new()), mro: vec![], }; (*object_type.borrow_mut()).typ = Some(type_type.clone()); @@ -62,15 +62,14 @@ fn object_delattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { ] ); - // Get dict: - let dict = match zelf.borrow().payload { - PyObjectPayload::Class { ref dict, .. } => dict.clone(), - PyObjectPayload::Instance { ref dict, .. } => dict.clone(), - _ => return Err(vm.new_type_error("TypeError: no dictionary.".to_string())), - }; - - // Delete attr from dict: - vm.call_method(&dict, "__delitem__", vec![attr.clone()]) + match zelf.borrow().payload { + PyObjectPayload::Class { ref dict, .. } | PyObjectPayload::Instance { ref dict, .. } => { + let attr_name = objstr::get_value(attr); + dict.borrow_mut().remove(&attr_name); + Ok(vm.get_none()) + } + _ => Err(vm.new_type_error("TypeError: no dictionary.".to_string())), + } } fn object_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -116,8 +115,13 @@ fn object_init(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult { fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { match args.args[0].borrow().payload { - PyObjectPayload::Class { ref dict, .. } => Ok(dict.clone()), - PyObjectPayload::Instance { ref dict, .. } => Ok(dict.clone()), + PyObjectPayload::Class { ref dict, .. } | PyObjectPayload::Instance { ref dict, .. } => { + let new_dict = vm.new_dict(); + for (attr, value) in dict.borrow().iter() { + vm.ctx.set_item(&new_dict, &attr, value.clone()); + } + Ok(new_dict) + } _ => Err(vm.new_type_error("TypeError: no dictionary.".to_string())), } } diff --git a/vm/src/obj/objproperty.rs b/vm/src/obj/objproperty.rs index 1d146889b..7ec52a9fd 100644 --- a/vm/src/obj/objproperty.rs +++ b/vm/src/obj/objproperty.rs @@ -2,9 +2,7 @@ */ -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, -}; +use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use super::super::vm::VirtualMachine; use super::objtype; @@ -55,12 +53,7 @@ fn property_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { trace!("property.__new__ {:?}", args.args); arg_check!(vm, args, required = [(cls, None), (fget, None)]); - let py_obj = PyObject::new( - PyObjectPayload::Instance { - dict: vm.ctx.new_dict(), - }, - cls.clone(), - ); + let py_obj = vm.ctx.new_instance(cls.clone(), None); vm.ctx.set_attr(&py_obj, "fget", fget.clone()); Ok(py_obj) } diff --git a/vm/src/obj/objrange.rs b/vm/src/obj/objrange.rs index d1524f103..906167a64 100644 --- a/vm/src/obj/objrange.rs +++ b/vm/src/obj/objrange.rs @@ -39,16 +39,29 @@ impl RangeType { } #[inline] - pub fn index_of(&self, value: &BigInt) -> Option { - if value < &self.start || value >= &self.end { - return None; + fn offset(&self, value: &BigInt) -> Option { + match self.step.sign() { + Sign::Plus if value >= &self.start && value < &self.end => Some(value - &self.start), + Sign::Minus if value <= &self.start && value > &self.end => Some(&self.start - value), + _ => None, } + } - let offset = value - &self.start; - if offset.is_multiple_of(&self.step) { - Some(offset / &self.step) - } else { - None + #[inline] + pub fn contains(&self, value: &BigInt) -> bool { + match self.offset(value) { + Some(ref offset) => offset.is_multiple_of(&self.step), + None => false, + } + } + + #[inline] + pub fn index_of(&self, value: &BigInt) -> Option { + match self.offset(value) { + Some(ref offset) if offset.is_multiple_of(&self.step) => { + Some((offset / &self.step).abs()) + } + Some(_) | None => None, } } @@ -97,6 +110,12 @@ pub fn init(context: &PyContext) { context.new_rustfunc(range_getitem), ); context.set_attr(&range_type, "__repr__", context.new_rustfunc(range_repr)); + context.set_attr(&range_type, "__bool__", context.new_rustfunc(range_bool)); + context.set_attr( + &range_type, + "__contains__", + context.new_rustfunc(range_contains), + ); context.set_attr(&range_type, "index", context.new_rustfunc(range_index)); } @@ -240,6 +259,34 @@ fn range_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.ctx.new_str(s)) } +fn range_bool(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(zelf, Some(vm.ctx.range_type()))]); + + let len = match zelf.borrow().payload { + PyObjectPayload::Range { ref range } => range.len(), + _ => unreachable!(), + }; + + Ok(vm.ctx.new_bool(len > 0)) +} + +fn range_contains(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(zelf, Some(vm.ctx.range_type())), (needle, None)] + ); + + if let PyObjectPayload::Range { ref range } = zelf.borrow().payload { + Ok(vm.ctx.new_bool(match needle.borrow().payload { + PyObjectPayload::Integer { ref value } => range.contains(value), + _ => false, + })) + } else { + unreachable!() + } +} + fn range_index(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, diff --git a/vm/src/obj/objsequence.rs b/vm/src/obj/objsequence.rs index c5504b22d..d2fbb2a96 100644 --- a/vm/src/obj/objsequence.rs +++ b/vm/src/obj/objsequence.rs @@ -34,17 +34,17 @@ pub trait PySliceableSequence { // TODO: we could potentially avoid this copy and use slice match &(slice.borrow()).payload { PyObjectPayload::Slice { start, stop, step } => { - let start = match start { - &Some(start) => self.get_pos(start), - &None => 0, + let start = match *start { + Some(start) => self.get_pos(start), + None => 0, }; - let stop = match stop { - &Some(stop) => self.get_pos(stop), - &None => self.len() as usize, + let stop = match *stop { + Some(stop) => self.get_pos(stop), + None => self.len() as usize, }; - match step { - &None | &Some(1) => self.do_slice(start, stop), - &Some(num) => { + match *step { + None | Some(1) => self.do_slice(start, stop), + Some(num) => { if num < 0 { unimplemented!("negative step indexing not yet supported") }; diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index c0877a03f..5ac7507d6 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -66,15 +66,10 @@ fn set_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Some(iterable) => { let mut elements = HashMap::new(); let iterator = objiter::get_iter(vm, iterable)?; - loop { - match vm.call_method(&iterator, "__next__", vec![]) { - Ok(v) => { - // TODO: should we use the hash function here? - let key = v.get_id(); - elements.insert(key, v); - } - _ => break, - } + while let Ok(v) = vm.call_method(&iterator, "__next__", vec![]) { + // TODO: should we use the hash function here? + let key = v.get_id(); + elements.insert(key, v); } elements } @@ -151,6 +146,11 @@ fn frozenset_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { pub fn init(context: &PyContext) { let set_type = &context.set_type; + + let set_doc = "set() -> new empty set object\n\ + set(iterable) -> new set object\n\n\ + Build an unordered collection of unique elements."; + context.set_attr( &set_type, "__contains__", @@ -159,15 +159,26 @@ pub fn init(context: &PyContext) { context.set_attr(&set_type, "__len__", context.new_rustfunc(set_len)); context.set_attr(&set_type, "__new__", context.new_rustfunc(set_new)); context.set_attr(&set_type, "__repr__", context.new_rustfunc(set_repr)); + context.set_attr(&set_type, "__doc__", context.new_str(set_doc.to_string())); context.set_attr(&set_type, "add", context.new_rustfunc(set_add)); let frozenset_type = &context.frozenset_type; + + let frozenset_doc = "frozenset() -> empty frozenset object\n\ + frozenset(iterable) -> frozenset object\n\n\ + Build an immutable unordered collection of unique elements."; + context.set_attr( &frozenset_type, "__contains__", context.new_rustfunc(set_contains), ); context.set_attr(&frozenset_type, "__len__", context.new_rustfunc(set_len)); + context.set_attr( + &frozenset_type, + "__doc__", + context.new_str(frozenset_doc.to_string()), + ); context.set_attr( &frozenset_type, "__repr__", diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 73f1816b6..fbdf58fc4 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -511,12 +511,11 @@ fn str_zfill(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { ); let value = get_value(&s); let len = objint::get_value(&len).to_usize().unwrap(); - let new_str: String; - if len <= value.len() { - new_str = value; + let new_str = if len <= value.len() { + value } else { - new_str = format!("{}{}", "0".repeat(len - value.len()), value); - } + format!("{}{}", "0".repeat(len - value.len()), value) + }; Ok(vm.ctx.new_str(new_str)) } @@ -572,7 +571,7 @@ fn str_index(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok((start, end)) => (start, end), Err(e) => return Err(vm.new_index_error(e)), }; - let ind: usize = match value[start..end + 1].find(&sub) { + let ind: usize = match value[start..=end].find(&sub) { Some(num) => num, None => { return Err(vm.new_value_error("substring not found".to_string())); @@ -597,7 +596,7 @@ fn str_find(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok((start, end)) => (start, end), Err(e) => return Err(vm.new_index_error(e)), }; - let ind: i128 = match value[start..end + 1].find(&sub) { + let ind: i128 = match value[start..=end].find(&sub) { Some(num) => num as i128, None => -1 as i128, }; @@ -796,7 +795,7 @@ fn str_istitle(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { if value.is_empty() { is_titled = false; } else { - for word in value.split(" ") { + for word in value.split(' ') { if word != make_title(&word) { is_titled = false; break; @@ -887,7 +886,7 @@ fn str_rindex(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok((start, end)) => (start, end), Err(e) => return Err(vm.new_index_error(e)), }; - let ind: i64 = match value[start..end + 1].rfind(&sub) { + let ind: i64 = match value[start..=end].rfind(&sub) { Some(num) => num as i64, None => { return Err(vm.new_value_error("substring not found".to_string())); @@ -912,7 +911,7 @@ fn str_rfind(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok((start, end)) => (start, end), Err(e) => return Err(vm.new_index_error(e)), }; - let ind = match value[start..end + 1].rfind(&sub) { + let ind = match value[start..=end].rfind(&sub) { Some(num) => num as i128, None => -1 as i128, }; @@ -1051,8 +1050,8 @@ pub fn subscript(vm: &mut VirtualMachine, value: &str, b: PyObjectRef) -> PyResu } } } else { - match &(*b.borrow()).payload { - &PyObjectPayload::Slice { .. } => { + match (*b.borrow()).payload { + PyObjectPayload::Slice { .. } => { Ok(vm.new_str(value.to_string().get_slice_items(&b).to_string())) } _ => panic!( diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs index fc95e819d..2d99db2d4 100644 --- a/vm/src/obj/objtuple.rs +++ b/vm/src/obj/objtuple.rs @@ -109,7 +109,7 @@ fn tuple_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { if objtype::isinstance(other, &vm.ctx.tuple_type()) { let e1 = get_elements(zelf); let e2 = get_elements(other); - let elements = e1.iter().chain(e2.iter()).map(|e| e.clone()).collect(); + let elements = e1.iter().chain(e2.iter()).cloned().collect(); Ok(vm.ctx.new_tuple(elements)) } else { Err(vm.new_type_error(format!( @@ -131,7 +131,7 @@ fn tuple_count(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { for element in elements.iter() { let is_eq = vm._eq(element, value.clone())?; if objbool::boolval(vm, is_eq)? { - count = count + 1; + count += 1; } } Ok(vm.context().new_int(count)) @@ -290,6 +290,10 @@ pub fn tuple_contains(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { pub fn init(context: &PyContext) { let tuple_type = &context.tuple_type; + let tuple_doc = "tuple() -> empty tuple +tuple(iterable) -> tuple initialized from iterable's items + +If the argument is a tuple, the return value is the same object."; context.set_attr(&tuple_type, "__add__", context.new_rustfunc(tuple_add)); context.set_attr(&tuple_type, "__eq__", context.new_rustfunc(tuple_eq)); context.set_attr( @@ -313,5 +317,10 @@ pub fn init(context: &PyContext) { context.set_attr(&tuple_type, "__le__", context.new_rustfunc(tuple_le)); context.set_attr(&tuple_type, "__gt__", context.new_rustfunc(tuple_gt)); context.set_attr(&tuple_type, "__ge__", context.new_rustfunc(tuple_ge)); + context.set_attr( + &tuple_type, + "__doc__", + context.new_str(tuple_doc.to_string()), + ); context.set_attr(&tuple_type, "index", context.new_rustfunc(tuple_index)); } diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index 7b2ed48c5..ce98e0f4c 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -1,21 +1,22 @@ use super::super::pyobject::{ - AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, - PyResult, TypeProtocol, + AttributeProtocol, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObject, PyObjectPayload, + PyObjectRef, PyResult, TypeProtocol, }; use super::super::vm::VirtualMachine; use super::objdict; use super::objstr; use super::objtype; // Required for arg_check! to use isinstance +use std::cell::RefCell; use std::collections::HashMap; /* * The magical type type */ -pub fn create_type(type_type: PyObjectRef, object_type: PyObjectRef, dict_type: PyObjectRef) { +pub fn create_type(type_type: PyObjectRef, object_type: PyObjectRef, _dict_type: PyObjectRef) { (*type_type.borrow_mut()).payload = PyObjectPayload::Class { name: String::from("type"), - dict: objdict::new(dict_type), + dict: RefCell::new(PyAttributes::new()), mro: vec![object_type], }; (*type_type.borrow_mut()).typ = Some(type_type.clone()); @@ -119,12 +120,22 @@ pub fn type_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let mut bases = vm.extract_elements(bases)?; bases.push(vm.context().object()); let name = objstr::get_value(name); - new(typ.clone(), &name, bases, dict.clone()) + new(typ.clone(), &name, bases, py_dict_to_attributes(dict)) } else { Err(vm.new_type_error(format!(": type_new: {:?}", args))) } } +/// Take a python dictionary and convert it to attributes. +fn py_dict_to_attributes(dict: &PyObjectRef) -> PyAttributes { + let mut attrs = PyAttributes::new(); + for (key, value) in objdict::get_key_value_pairs(dict) { + let key = objstr::get_value(&key); + attrs.insert(key, value); + } + attrs +} + pub fn type_call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { debug!("type_call: {:?}", args); let cls = args.shift(); @@ -204,18 +215,16 @@ pub fn type_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult } } -pub fn get_attributes(obj: &PyObjectRef) -> HashMap { +pub fn get_attributes(obj: &PyObjectRef) -> PyAttributes { // Gather all members here: - let mut attributes: HashMap = HashMap::new(); + let mut attributes = PyAttributes::new(); // Get class attributes: let mut base_classes = objtype::base_classes(obj); base_classes.reverse(); for bc in base_classes { if let PyObjectPayload::Class { dict, .. } = &bc.borrow().payload { - let elements = objdict::get_key_value_pairs(dict); - for (name, value) in elements.iter() { - let name = objstr::get_value(name); + for (name, value) in dict.borrow().iter() { attributes.insert(name.to_string(), value.clone()); } } @@ -223,9 +232,7 @@ pub fn get_attributes(obj: &PyObjectRef) -> HashMap { // Get instance attributes: if let PyObjectPayload::Instance { dict } = &obj.borrow().payload { - let elements = objdict::get_key_value_pairs(dict); - for (name, value) in elements.iter() { - let name = objstr::get_value(name); + for (name, value) in dict.borrow().iter() { attributes.insert(name.to_string(), value.clone()); } } @@ -242,8 +249,8 @@ fn take_next_base( for base in &bases { let head = base[0].clone(); if !(&bases) - .into_iter() - .any(|x| x[1..].into_iter().any(|x| x.get_id() == head.get_id())) + .iter() + .any(|x| x[1..].iter().any(|x| x.get_id() == head.get_id())) { next = Some(head); break; @@ -265,7 +272,7 @@ fn linearise_mro(mut bases: Vec>) -> Option> { debug!("Linearising MRO: {:?}", bases); let mut result = vec![]; loop { - if (&bases).into_iter().all(|x| x.is_empty()) { + if (&bases).iter().all(|x| x.is_empty()) { break; } match take_next_base(bases) { @@ -279,13 +286,18 @@ fn linearise_mro(mut bases: Vec>) -> Option> { Some(result) } -pub fn new(typ: PyObjectRef, name: &str, bases: Vec, dict: PyObjectRef) -> PyResult { +pub fn new( + typ: PyObjectRef, + name: &str, + bases: Vec, + dict: HashMap, +) -> PyResult { let mros = bases.into_iter().map(|x| _mro(x).unwrap()).collect(); let mro = linearise_mro(mros).unwrap(); Ok(PyObject::new( PyObjectPayload::Class { name: String::from(name), - dict, + dict: RefCell::new(dict), mro, }, typ, @@ -305,7 +317,7 @@ fn type_prepare(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult { #[cfg(test)] mod tests { use super::{linearise_mro, new}; - use super::{IdProtocol, PyContext, PyObjectRef}; + use super::{HashMap, IdProtocol, PyContext, PyObjectRef}; fn map_ids(obj: Option>) -> Option> { match obj { @@ -320,20 +332,8 @@ mod tests { let object = context.object; let type_type = context.type_type; - let a = new( - type_type.clone(), - "A", - vec![object.clone()], - type_type.clone(), - ) - .unwrap(); - let b = new( - type_type.clone(), - "B", - vec![object.clone()], - type_type.clone(), - ) - .unwrap(); + let a = new(type_type.clone(), "A", vec![object.clone()], HashMap::new()).unwrap(); + let b = new(type_type.clone(), "B", vec![object.clone()], HashMap::new()).unwrap(); assert_eq!( map_ids(linearise_mro(vec![ diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 8b3ced6b6..424cf7646 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -70,6 +70,10 @@ pub type PyObjectWeakRef = Weak>; /// since exceptions are also python objects. pub type PyResult = Result; // A valid value, or an exception +/// For attributes we do not use a dict, but a hashmap. This is probably +/// faster, unordered, and only supports strings as keys. +pub type PyAttributes = HashMap; + impl fmt::Display for PyObject { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::TypeProtocol; @@ -161,14 +165,9 @@ pub fn create_type( name: &str, type_type: &PyObjectRef, base: &PyObjectRef, - dict_type: &PyObjectRef, + _dict_type: &PyObjectRef, ) -> PyObjectRef { - let dict = PyObject::new( - PyObjectPayload::Dict { - elements: HashMap::new(), - }, - dict_type.clone(), - ); + let dict = PyAttributes::new(); objtype::new(type_type.clone(), name, vec![base.clone()], dict).unwrap() } @@ -411,12 +410,7 @@ impl PyContext { } pub fn new_object(&self) -> PyObjectRef { - PyObject::new( - PyObjectPayload::Instance { - dict: self.new_dict(), - }, - self.object(), - ) + self.new_instance(self.object(), None) } pub fn new_int(&self, i: T) -> PyObjectRef { @@ -482,7 +476,7 @@ impl PyContext { } pub fn new_class(&self, name: &str, base: PyObjectRef) -> PyObjectRef { - objtype::new(self.type_type(), name, vec![base], self.new_dict()).unwrap() + objtype::new(self.type_type(), name, vec![base], PyAttributes::new()).unwrap() } pub fn new_scope(&self, parent: Option) -> PyObjectRef { @@ -536,12 +530,7 @@ impl PyContext { function: F, ) -> PyObjectRef { let fget = self.new_rustfunc(function); - let py_obj = PyObject::new( - PyObjectPayload::Instance { - dict: self.new_dict(), - }, - self.property_type(), - ); + let py_obj = self.new_instance(self.property_type(), None); self.set_attr(&py_obj, "fget", fget.clone()); py_obj } @@ -577,13 +566,23 @@ impl PyContext { &self, function: F, ) -> PyObjectRef { - let dict = self.new_dict(); - self.set_item(&dict, "function", self.new_rustfunc(function)); - self.new_instance(dict, self.member_descriptor_type()) + let mut dict = PyAttributes::new(); + dict.insert("function".to_string(), self.new_rustfunc(function)); + self.new_instance(self.member_descriptor_type(), Some(dict)) } - pub fn new_instance(&self, dict: PyObjectRef, class: PyObjectRef) -> PyObjectRef { - PyObject::new(PyObjectPayload::Instance { dict }, class) + pub fn new_instance(&self, class: PyObjectRef, dict: Option) -> PyObjectRef { + let dict = if let Some(dict) = dict { + dict + } else { + PyAttributes::new() + }; + PyObject::new( + PyObjectPayload::Instance { + dict: RefCell::new(dict), + }, + class, + ) } // Item set/get: @@ -611,8 +610,9 @@ impl PyContext { pub fn set_attr(&self, obj: &PyObjectRef, attr_name: &str, value: PyObjectRef) { match obj.borrow().payload { PyObjectPayload::Module { ref dict, .. } => self.set_item(dict, attr_name, value), - PyObjectPayload::Instance { ref dict } => self.set_item(dict, attr_name, value), - PyObjectPayload::Class { ref dict, .. } => self.set_item(dict, attr_name, value), + PyObjectPayload::Instance { ref dict } | PyObjectPayload::Class { ref dict, .. } => { + dict.borrow_mut().insert(attr_name.to_string(), value); + } ref payload => unimplemented!("set_attr unimplemented for: {:?}", payload), }; } @@ -673,10 +673,7 @@ pub trait ParentProtocol { impl ParentProtocol for PyObjectRef { fn has_parent(&self) -> bool { match self.borrow().payload { - PyObjectPayload::Scope { ref scope } => match scope.parent { - Some(_) => true, - None => false, - }, + PyObjectPayload::Scope { ref scope } => scope.parent.is_some(), _ => panic!("Only scopes have parent (not {:?}", self), } } @@ -700,7 +697,7 @@ pub trait AttributeProtocol { fn class_get_item(class: &PyObjectRef, attr_name: &str) -> Option { let class = class.borrow(); match class.payload { - PyObjectPayload::Class { ref dict, .. } => dict.get_item(attr_name), + PyObjectPayload::Class { ref dict, .. } => dict.borrow().get(attr_name).map(|v| v.clone()), _ => panic!("Only classes should be in MRO!"), } } @@ -708,7 +705,7 @@ fn class_get_item(class: &PyObjectRef, attr_name: &str) -> Option { fn class_has_item(class: &PyObjectRef, attr_name: &str) -> bool { let class = class.borrow(); match class.payload { - PyObjectPayload::Class { ref dict, .. } => dict.contains_key(attr_name), + PyObjectPayload::Class { ref dict, .. } => dict.borrow().contains_key(attr_name), _ => panic!("Only classes should be in MRO!"), } } @@ -729,7 +726,9 @@ impl AttributeProtocol for PyObjectRef { } None } - PyObjectPayload::Instance { ref dict } => dict.get_item(attr_name), + PyObjectPayload::Instance { ref dict } => { + dict.borrow().get(attr_name).map(|v| v.clone()) + } _ => None, } } @@ -739,10 +738,9 @@ impl AttributeProtocol for PyObjectRef { match obj.payload { PyObjectPayload::Module { ref dict, .. } => dict.contains_key(attr_name), PyObjectPayload::Class { ref mro, .. } => { - class_has_item(self, attr_name) - || mro.into_iter().any(|d| class_has_item(d, attr_name)) + class_has_item(self, attr_name) || mro.iter().any(|d| class_has_item(d, attr_name)) } - PyObjectPayload::Instance { ref dict } => dict.contains_key(attr_name), + PyObjectPayload::Instance { ref dict } => dict.borrow().contains_key(attr_name), _ => false, } } @@ -935,14 +933,14 @@ pub enum PyObjectPayload { None, Class { name: String, - dict: PyObjectRef, + dict: RefCell, mro: Vec, }, WeakRef { referent: PyObjectWeakRef, }, Instance { - dict: PyObjectRef, + dict: RefCell, }, RustFunction { function: Box PyResult>, diff --git a/vm/src/stdlib/ast.rs b/vm/src/stdlib/ast.rs index 81f8aac27..6703534f4 100644 --- a/vm/src/stdlib/ast.rs +++ b/vm/src/stdlib/ast.rs @@ -45,8 +45,7 @@ fn program_to_ast(ctx: &PyContext, program: &ast::Program) -> PyObjectRef { fn create_node(ctx: &PyContext, _name: &str) -> PyObjectRef { // TODO: instantiate a class of type given by name // TODO: lookup in the current module? - let node = ctx.new_object(); - node + ctx.new_object() } fn statements_to_ast(ctx: &PyContext, statements: &[ast::LocatedStatement]) -> PyObjectRef { @@ -99,18 +98,9 @@ fn statement_to_ast(ctx: &PyContext, statement: &ast::LocatedStatement) -> PyObj ctx.set_attr(&node, "decorator_list", py_decorator_list); node } - ast::Statement::Continue => { - let node = create_node(ctx, "Continue"); - node - } - ast::Statement::Break => { - let node = create_node(ctx, "Break"); - node - } - ast::Statement::Pass => { - let node = create_node(ctx, "Pass"); - node - } + ast::Statement::Continue => create_node(ctx, "Continue"), + ast::Statement::Break => create_node(ctx, "Break"), + ast::Statement::Pass => create_node(ctx, "Pass"), ast::Statement::Assert { test, msg } => { let node = create_node(ctx, "Pass"); @@ -127,12 +117,8 @@ fn statement_to_ast(ctx: &PyContext, statement: &ast::LocatedStatement) -> PyObj ast::Statement::Delete { targets } => { let node = create_node(ctx, "Delete"); - let py_targets = ctx.new_tuple( - targets - .into_iter() - .map(|v| expression_to_ast(ctx, v)) - .collect(), - ); + let py_targets = + ctx.new_tuple(targets.iter().map(|v| expression_to_ast(ctx, v)).collect()); ctx.set_attr(&node, "targets", py_targets); node @@ -141,12 +127,7 @@ fn statement_to_ast(ctx: &PyContext, statement: &ast::LocatedStatement) -> PyObj let node = create_node(ctx, "Return"); let py_value = if let Some(value) = value { - ctx.new_tuple( - value - .into_iter() - .map(|v| expression_to_ast(ctx, v)) - .collect(), - ) + ctx.new_tuple(value.iter().map(|v| expression_to_ast(ctx, v)).collect()) } else { ctx.none() }; diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 2fe2c2255..e254b2417 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -27,7 +27,7 @@ use super::super::pyobject::{ use super::super::vm::VirtualMachine; fn compute_c_flag(mode: &str) -> u16 { - match mode.as_ref() { + match mode { "w" => 512, "x" => 512, "a" => 8, @@ -85,11 +85,8 @@ fn buffered_reader_read(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { .map_err(|_| vm.new_value_error("IO Error".to_string()))?; //Copy bytes from the buffer vector into the results vector - match buffer.borrow_mut().payload { - PyObjectPayload::Bytes { ref mut value } => { - result.extend(value.iter().cloned()); - } - _ => {} + if let PyObjectPayload::Bytes { ref mut value } = buffer.borrow_mut().payload { + result.extend(value.iter().cloned()); }; let len = vm.get_method(buffer.clone(), &"__len__".to_string()); @@ -171,16 +168,14 @@ fn file_io_readinto(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let handle = os::rust_file(raw_fd); let mut f = handle.take(length); - match obj.borrow_mut().payload { + if let PyObjectPayload::Bytes { ref mut value } = obj.borrow_mut().payload { //TODO: Implement for MemoryView - PyObjectPayload::Bytes { ref mut value } => { - value.clear(); - match f.read_to_end(&mut *value) { - Ok(_) => {} - Err(_) => return Err(vm.new_value_error("Error reading from Take".to_string())), - } + + value.clear(); + match f.read_to_end(&mut *value) { + Ok(_) => {} + Err(_) => return Err(vm.new_value_error("Error reading from Take".to_string())), } - _ => {} }; let updated = os::raw_file_number(f.into_inner()); @@ -318,7 +313,7 @@ pub fn io_open(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { //the operation in the mode. //There are 3 possible classes here, each inheriting from the RawBaseIO // creating || writing || appending => BufferedWriter - let buffered = if rust_mode.contains("w") { + let buffered = if rust_mode.contains('w') { vm.invoke( buffered_writer_class, PyFuncArgs::new(vec![file_io.clone()], vec![]), @@ -332,7 +327,7 @@ pub fn io_open(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { //TODO: updating => PyBufferedRandom }; - if rust_mode.contains("t") { + if rust_mode.contains('t') { //If the mode is text this buffer type is consumed on construction of //a TextIOWrapper which is subsequently returned. vm.invoke( diff --git a/vm/src/stdlib/types.rs b/vm/src/stdlib/types.rs index 2060ad1f1..a744d89b7 100644 --- a/vm/src/stdlib/types.rs +++ b/vm/src/stdlib/types.rs @@ -3,7 +3,9 @@ */ use super::super::obj::{objsequence, objstr, objtype}; -use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use super::super::pyobject::{ + PyAttributes, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol, +}; use super::super::VirtualMachine; fn types_new_class(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -15,7 +17,6 @@ fn types_new_class(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { ); let name = objstr::get_value(name); - let dict = vm.ctx.new_dict(); let bases = match bases { Some(b) => { @@ -28,7 +29,7 @@ fn types_new_class(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { None => vec![vm.ctx.object()], }; - objtype::new(vm.ctx.type_type(), &name, bases, dict) + objtype::new(vm.ctx.type_type(), &name, bases, PyAttributes::new()) } pub fn mk_module(ctx: &PyContext) -> PyObjectRef { diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 876718bb3..6354309ae 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -91,8 +91,7 @@ impl VirtualMachine { }; // Call function: - let exception = self.invoke(exc_type, args).unwrap(); - exception + self.invoke(exc_type, args).unwrap() } pub fn new_type_error(&mut self, msg: String) -> PyObjectRef {