From d72abebdd0a4a08e4d4624f013fc59d368f01be1 Mon Sep 17 00:00:00 2001 From: Windel Bouwman Date: Sat, 3 Nov 2018 12:26:31 +0100 Subject: [PATCH] Unify object kinds tuple and list into sequence. --- vm/src/builtins.rs | 30 ++++++++++-------------------- vm/src/exceptions.rs | 7 +++---- vm/src/import.rs | 17 ++++++----------- vm/src/obj/objbool.rs | 3 +-- vm/src/obj/objiter.rs | 2 +- vm/src/obj/objlist.rs | 30 ++++-------------------------- vm/src/obj/objsequence.rs | 29 +++++++++++++++++++++++++---- vm/src/obj/objtuple.rs | 16 ++-------------- vm/src/pyobject.rs | 35 ++++++++++------------------------- vm/src/stdlib/json.rs | 6 +++--- vm/src/stdlib/types.rs | 5 +++-- vm/src/vm.rs | 9 ++++----- 12 files changed, 72 insertions(+), 117 deletions(-) diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 4a3ba1d2c..5c989435c 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -297,26 +297,16 @@ fn builtin_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn builtin_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(obj, None)]); - match obj.borrow().kind { - PyObjectKind::Dict { ref elements } => { - Ok(vm.context().new_int(elements.len().to_bigint().unwrap())) - } - PyObjectKind::Tuple { ref elements } => { - Ok(vm.context().new_int(elements.len().to_bigint().unwrap())) - } - _ => { - let len_method_name = "__len__".to_string(); - match vm.get_method(obj.clone(), &len_method_name) { - Ok(value) => vm.invoke(value, PyFuncArgs::default()), - Err(..) => Err(vm.context().new_str( - format!( - "TypeError: object of this {:?} type has no method {:?}", - obj, len_method_name - ) - .to_string(), - )), - } - } + let len_method_name = "__len__".to_string(); + match vm.get_method(obj.clone(), &len_method_name) { + Ok(value) => vm.invoke(value, PyFuncArgs::default()), + Err(..) => Err(vm.context().new_str( + format!( + "TypeError: object of this {:?} type has no method {:?}", + obj, len_method_name + ) + .to_string(), + )), } } diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index f6071ae5a..70cdb3ca0 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -1,6 +1,5 @@ -use super::obj::objlist; +use super::obj::objsequence; use super::obj::objstr; -use super::obj::objtuple; use super::obj::objtype; use super::pyobject::{ create_type, AttributeProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol, @@ -25,11 +24,11 @@ pub fn print_exception(vm: &mut VirtualMachine, exc: &PyObjectRef) { if let Some(tb) = exc.get_attr("__traceback__") { println!("Traceback (most recent call last):"); if objtype::isinstance(&tb, &vm.ctx.list_type()) { - let mut elements = objlist::get_elements(&tb).to_vec(); + let mut elements = objsequence::get_elements(&tb).to_vec(); elements.reverse(); for element in elements.iter() { if objtype::isinstance(&element, &vm.ctx.tuple_type()) { - let element = objtuple::get_elements(&element); + let element = objsequence::get_elements(&element); let filename = if let Ok(x) = vm.to_str(&element[0]) { objstr::get_value(&x) } else { diff --git a/vm/src/import.rs b/vm/src/import.rs index 98cf3c98a..e7bc265f6 100644 --- a/vm/src/import.rs +++ b/vm/src/import.rs @@ -8,8 +8,9 @@ use std::path::PathBuf; use self::rustpython_parser::parser; use super::compile; -use super::pyobject::{DictProtocol, PyObjectKind, PyResult}; +use super::pyobject::{DictProtocol, PyResult}; use super::vm::VirtualMachine; +use obj::{objsequence, objstr}; fn import_uncached_module( vm: &mut VirtualMachine, @@ -78,16 +79,10 @@ pub fn import( fn find_source(vm: &VirtualMachine, current_path: PathBuf, name: &str) -> Result { let sys_path = vm.sys_module.get_item("path").unwrap(); - let mut paths: Vec = match sys_path.borrow().kind { - PyObjectKind::List { ref elements } => elements - .iter() - .filter_map(|item| match item.borrow().kind { - PyObjectKind::String { ref value } => Some(PathBuf::from(value)), - _ => None, - }) - .collect(), - _ => panic!("sys.path unexpectedly not a list"), - }; + let mut paths: Vec = objsequence::get_elements(&sys_path) + .iter() + .map(|item| PathBuf::from(objstr::get_value(item))) + .collect(); paths.insert(0, current_path); diff --git a/vm/src/obj/objbool.rs b/vm/src/obj/objbool.rs index 4d9404f58..211b30820 100644 --- a/vm/src/obj/objbool.rs +++ b/vm/src/obj/objbool.rs @@ -9,8 +9,7 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result !value.is_zero(), PyObjectKind::Float { value } => value != 0.0, - PyObjectKind::List { ref elements } => !elements.is_empty(), - PyObjectKind::Tuple { ref elements } => !elements.is_empty(), + PyObjectKind::Sequence { ref elements } => !elements.is_empty(), PyObjectKind::Dict { ref elements } => !elements.is_empty(), PyObjectKind::String { ref value } => !value.is_empty(), PyObjectKind::None { .. } => false, diff --git a/vm/src/obj/objiter.rs b/vm/src/obj/objiter.rs index 893f3cd2f..1e22a26e7 100644 --- a/vm/src/obj/objiter.rs +++ b/vm/src/obj/objiter.rs @@ -127,7 +127,7 @@ fn iter_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { { let iterated_obj = &*iterated_obj_ref.borrow_mut(); match iterated_obj.kind { - PyObjectKind::List { ref elements } => { + PyObjectKind::Sequence { ref elements } => { if *position < elements.len() { let obj_ref = elements[*position].clone(); *position += 1; diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 73725ee9a..16f665fd3 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -5,13 +5,13 @@ use super::super::pyobject::{ use super::super::vm::VirtualMachine; use super::objbool; use super::objint; -use super::objsequence::{get_item, seq_equal, PySliceableSequence}; +use super::objsequence::{ + get_elements, get_item, get_mut_elements, seq_equal, PySliceableSequence, +}; use super::objstr; use super::objtype; use num_bigint::ToBigInt; use num_traits::ToPrimitive; -use std::cell::{Ref, RefMut}; -use std::ops::{Deref, DerefMut}; // set_item: fn set_item( @@ -33,28 +33,6 @@ fn set_item( } } -pub fn get_elements<'a>(obj: &'a PyObjectRef) -> impl Deref> + 'a { - Ref::map(obj.borrow(), |x| { - if let PyObjectKind::List { ref elements } = x.kind { - elements - } else { - panic!("Cannot extract list elements from non-list"); - } - }) -} - -pub fn get_mut_elements<'a>(obj: &'a PyObjectRef) -> impl DerefMut> + 'a { - RefMut::map(obj.borrow_mut(), |x| { - if let PyObjectKind::List { ref mut elements } = x.kind { - elements - } else { - panic!("Cannot extract list elements from non-list"); - // TODO: raise proper error? - // Err(vm.new_type_error("list.append is called with no list".to_string())) - } - }) -} - fn list_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, @@ -74,7 +52,7 @@ fn list_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { }; Ok(PyObject::new( - PyObjectKind::List { elements: elements }, + PyObjectKind::Sequence { elements: elements }, cls.clone(), )) } diff --git a/vm/src/obj/objsequence.rs b/vm/src/obj/objsequence.rs index 5fb50fd2a..2e470c6b1 100644 --- a/vm/src/obj/objsequence.rs +++ b/vm/src/obj/objsequence.rs @@ -2,7 +2,9 @@ use super::super::pyobject::{PyObject, PyObjectKind, PyObjectRef, PyResult, Type use super::super::vm::VirtualMachine; use super::objbool; use num_traits::ToPrimitive; +use std::cell::{Ref, RefMut}; use std::marker::Sized; +use std::ops::{Deref, DerefMut}; pub trait PySliceableSequence { fn do_slice(&self, start: usize, stop: usize) -> Self; @@ -85,10 +87,7 @@ pub fn get_item( step: _, } => Ok(PyObject::new( match &(sequence.borrow()).kind { - PyObjectKind::Tuple { elements: _ } => PyObjectKind::Tuple { - elements: elements.to_vec().get_slice_items(&subscript), - }, - PyObjectKind::List { elements: _ } => PyObjectKind::List { + PyObjectKind::Sequence { elements: _ } => PyObjectKind::Sequence { elements: elements.to_vec().get_slice_items(&subscript), }, ref kind => panic!("sequence get_item called for non-sequence: {:?}", kind), @@ -120,3 +119,25 @@ pub fn seq_equal( Ok(false) } } + +pub fn get_elements<'a>(obj: &'a PyObjectRef) -> impl Deref> + 'a { + Ref::map(obj.borrow(), |x| { + if let PyObjectKind::Sequence { ref elements } = x.kind { + elements + } else { + panic!("Cannot extract elements from non-sequence"); + } + }) +} + +pub fn get_mut_elements<'a>(obj: &'a PyObjectRef) -> impl DerefMut> + 'a { + RefMut::map(obj.borrow_mut(), |x| { + if let PyObjectKind::Sequence { ref mut elements } = x.kind { + elements + } else { + panic!("Cannot extract list elements from non-sequence"); + // TODO: raise proper error? + // Err(vm.new_type_error("list.append is called with no list".to_string())) + } + }) +} diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs index 492f864a8..1d1a8bff9 100644 --- a/vm/src/obj/objtuple.rs +++ b/vm/src/obj/objtuple.rs @@ -5,13 +5,11 @@ use super::super::pyobject::{ use super::super::vm::VirtualMachine; use super::objbool; use super::objint; -use super::objsequence::{get_item, seq_equal}; +use super::objsequence::{get_elements, get_item, seq_equal}; use super::objstr; use super::objtype; use num_bigint::ToBigInt; use num_traits::ToPrimitive; -use std::cell::Ref; -use std::ops::Deref; fn tuple_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( @@ -75,7 +73,7 @@ fn tuple_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { }; Ok(PyObject::new( - PyObjectKind::Tuple { elements: elements }, + PyObjectKind::Sequence { elements: elements }, cls.clone(), )) } @@ -128,16 +126,6 @@ pub fn tuple_contains(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.new_bool(false)) } -pub fn get_elements<'a>(obj: &'a PyObjectRef) -> impl Deref> + 'a { - Ref::map(obj.borrow(), |x| { - if let PyObjectKind::Tuple { ref elements } = x.kind { - elements - } else { - panic!("Cannot extract elements from non-tuple"); - } - }) -} - pub fn init(context: &PyContext) { let ref tuple_type = context.tuple_type; tuple_type.set_attr("__eq__", context.new_rustfunc(tuple_eq)); diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index fbc508043..f1bbf02af 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -323,13 +323,16 @@ impl PyContext { pub fn new_tuple(&self, elements: Vec) -> PyObjectRef { PyObject::new( - PyObjectKind::Tuple { elements: elements }, + PyObjectKind::Sequence { elements: elements }, self.tuple_type(), ) } pub fn new_list(&self, elements: Vec) -> PyObjectRef { - PyObject::new(PyObjectKind::List { elements: elements }, self.list_type()) + PyObject::new( + PyObjectKind::Sequence { elements: elements }, + self.list_type(), + ) } pub fn new_set(&self, elements: Vec) -> PyObjectRef { @@ -673,10 +676,7 @@ pub enum PyObjectKind { Bytes { value: Vec, }, - List { - elements: Vec, - }, - Tuple { + Sequence { elements: Vec, }, Dict { @@ -737,9 +737,8 @@ impl fmt::Debug for PyObjectKind { &PyObjectKind::Integer { ref value } => write!(f, "int {}", value), &PyObjectKind::Float { ref value } => write!(f, "float {}", value), &PyObjectKind::Complex { ref value } => write!(f, "complex {}", value), - &PyObjectKind::Bytes { ref value } => write!(f, "bytes {:?}", value), - &PyObjectKind::List { elements: _ } => write!(f, "list"), - &PyObjectKind::Tuple { elements: _ } => write!(f, "tuple"), + &PyObjectKind::Bytes { ref value } => write!(f, "bytes/bytearray {:?}", value), + &PyObjectKind::Sequence { elements: _ } => write!(f, "list or tuple"), &PyObjectKind::Dict { elements: _ } => write!(f, "dict"), &PyObjectKind::Set { elements: _ } => write!(f, "set"), &PyObjectKind::Iterator { @@ -790,28 +789,14 @@ impl PyObject { PyObjectKind::Float { ref value } => format!("{:?}", value), PyObjectKind::Complex { ref value } => format!("{:?}", value), PyObjectKind::Bytes { ref value } => format!("b'{:?}'", value), - PyObjectKind::List { ref elements } => format!( - "[{}]", + PyObjectKind::Sequence { ref elements } => format!( + "(/[{}]/)", elements .iter() .map(|elem| elem.borrow().str()) .collect::>() .join(", ") ), - PyObjectKind::Tuple { ref elements } => { - if elements.len() == 1 { - format!("({},)", elements[0].borrow().str()) - } else { - format!( - "({})", - elements - .iter() - .map(|elem| elem.borrow().str()) - .collect::>() - .join(", ") - ) - } - } PyObjectKind::Dict { ref elements } => format!( "{{ {} }}", elements diff --git a/vm/src/stdlib/json.rs b/vm/src/stdlib/json.rs index 2ce306adf..1bd22d551 100644 --- a/vm/src/stdlib/json.rs +++ b/vm/src/stdlib/json.rs @@ -5,7 +5,7 @@ use serde::de::{DeserializeSeed, Visitor}; use serde::ser::{SerializeMap, SerializeSeq}; use serde_json; -use super::super::obj::{objbool, objdict, objfloat, objint, objlist, objstr, objtuple, objtype}; +use super::super::obj::{objbool, objdict, objfloat, objint, objsequence, objstr, objtype}; use super::super::pyobject::{ DictProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol, }; @@ -54,10 +54,10 @@ impl<'s> serde::Serialize for PyObjectSerializer<'s> { // Allthough this may seem nice, it does not give the right result: // v.serialize(serializer) } else if objtype::isinstance(self.pyobject, &self.ctx.list_type()) { - let elements = objlist::get_elements(self.pyobject); + let elements = objsequence::get_elements(self.pyobject); serialize_seq_elements(serializer, &elements) } else if objtype::isinstance(self.pyobject, &self.ctx.tuple_type()) { - let elements = objtuple::get_elements(self.pyobject); + let elements = objsequence::get_elements(self.pyobject); serialize_seq_elements(serializer, &elements) } else if objtype::isinstance(self.pyobject, &self.ctx.dict_type()) { let elements = objdict::get_elements(self.pyobject); diff --git a/vm/src/stdlib/types.rs b/vm/src/stdlib/types.rs index 1706b3cec..728b88c68 100644 --- a/vm/src/stdlib/types.rs +++ b/vm/src/stdlib/types.rs @@ -2,7 +2,7 @@ * Dynamic type creation and names for built in types. */ -use super::super::obj::{objstr, objtuple, objtype}; +use super::super::obj::{objsequence, objstr, objtype}; use super::super::pyobject::{ DictProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol, }; @@ -22,7 +22,7 @@ fn types_new_class(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let bases = match bases { Some(b) => { if objtype::isinstance(b, &vm.ctx.tuple_type()) { - objtuple::get_elements(b).to_vec() + objsequence::get_elements(b).to_vec() } else { return Err(vm.new_type_error("Bases must be a tuple".to_string())); } @@ -39,6 +39,7 @@ pub fn mk_module(ctx: &PyContext) -> PyObjectRef { // Number theory functions: py_mod.set_item("new_class", ctx.new_rustfunc(types_new_class)); py_mod.set_item("FunctionType", ctx.function_type()); + py_mod.set_item("LambdaType", ctx.function_type()); py_mod } diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 1d586fce9..e7a110fce 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -13,9 +13,8 @@ use super::bytecode; use super::frame::{copy_code, Frame}; use super::obj::objgenerator; use super::obj::objiter; -use super::obj::objlist; +use super::obj::objsequence; use super::obj::objstr; -use super::obj::objtuple; use super::obj::objtype; use super::pyobject::{ AttributeProtocol, DictProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, @@ -344,7 +343,7 @@ impl VirtualMachine { // function definition calls for if nargs < nexpected_args { let available_defaults = match defaults.borrow().kind { - PyObjectKind::Tuple { ref elements } => elements.clone(), + PyObjectKind::Sequence { ref elements } => elements.clone(), PyObjectKind::None => vec![], _ => panic!("function defaults not tuple or None"), }; @@ -405,9 +404,9 @@ impl VirtualMachine { ) -> Result, PyObjectRef> { // Extract elements from item, if possible: let elements = if objtype::isinstance(value, &self.ctx.tuple_type()) { - objtuple::get_elements(value).to_vec() + objsequence::get_elements(value).to_vec() } else if objtype::isinstance(value, &self.ctx.list_type()) { - objlist::get_elements(value).to_vec() + objsequence::get_elements(value).to_vec() } else { let iter = objiter::get_iter(self, value)?; objiter::get_all(self, &iter)?