From 1bcbb28715455171aea8fd8079764ffcaf979134 Mon Sep 17 00:00:00 2001 From: Joey Date: Thu, 7 Mar 2019 19:20:01 -0800 Subject: [PATCH] Convert list and tuple to Any payload --- vm/src/obj/objbool.rs | 35 ++++++++++--------- vm/src/obj/objiter.rs | 21 +++++------ vm/src/obj/objlist.rs | 28 ++++++++++++--- vm/src/obj/objsequence.rs | 73 ++++++++++++++++++++++++--------------- vm/src/obj/objtuple.rs | 33 +++++++++++++++--- vm/src/pyobject.rs | 16 ++++----- vm/src/vm.rs | 8 +++-- 7 files changed, 137 insertions(+), 77 deletions(-) diff --git a/vm/src/obj/objbool.rs b/vm/src/obj/objbool.rs index 09e0759c76..f71c2ea181 100644 --- a/vm/src/obj/objbool.rs +++ b/vm/src/obj/objbool.rs @@ -1,14 +1,14 @@ use num_traits::Zero; -use crate::pyobject::{ - IntoPyObject, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, -}; +use crate::pyobject::{IntoPyObject, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use crate::vm::VirtualMachine; use super::objdict::PyDict; use super::objfloat::PyFloat; use super::objint::PyInt; +use super::objlist::PyList; use super::objstr::PyString; +use super::objtuple::PyTuple; use super::objtype; impl IntoPyObject for bool { @@ -30,21 +30,22 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult { if let Some(i) = obj.payload::() { return Ok(!i.value.is_zero()); } - let result = match obj.payload { - PyObjectPayload::Sequence { ref elements } => !elements.borrow().is_empty(), - _ => { - if let Ok(f) = vm.get_method(obj.clone(), "__bool__") { - let bool_res = vm.invoke(f, PyFuncArgs::default())?; - match bool_res.payload::() { - Some(i) => !i.value.is_zero(), - None => return Err(vm.new_type_error(String::from("TypeError"))), - } - } else { - true - } + if let Some(list) = obj.payload::() { + return Ok(!list.elements.borrow().is_empty()); + } + if let Some(tuple) = obj.payload::() { + return Ok(!tuple.elements.borrow().is_empty()); + } + + Ok(if let Ok(f) = vm.get_method(obj.clone(), "__bool__") { + let bool_res = vm.invoke(f, PyFuncArgs::default())?; + match bool_res.payload::() { + Some(i) => !i.value.is_zero(), + None => return Err(vm.new_type_error(String::from("TypeError"))), } - }; - Ok(result) + } else { + true + }) } pub fn init(context: &PyContext) { diff --git a/vm/src/obj/objiter.rs b/vm/src/obj/objiter.rs index 049ea8be39..827ff1cd06 100644 --- a/vm/src/obj/objiter.rs +++ b/vm/src/obj/objiter.rs @@ -11,6 +11,7 @@ use super::objbool; use super::objbytearray::PyByteArray; use super::objbytes::PyBytes; use super::objrange::PyRange; +use super::objsequence; use super::objtype; /* @@ -156,19 +157,13 @@ fn iter_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Err(new_stop_iteration(vm)) } } else { - match iterated_obj_ref.payload { - PyObjectPayload::Sequence { ref elements } => { - if position.get() < elements.borrow().len() { - let obj_ref = elements.borrow()[position.get()].clone(); - position.set(position.get() + 1); - Ok(obj_ref) - } else { - Err(new_stop_iteration(vm)) - } - } - _ => { - panic!("NOT IMPL"); - } + let elements = objsequence::get_elements(iterated_obj_ref); + if position.get() < elements.len() { + let obj_ref = elements[position.get()].clone(); + position.set(position.get() + 1); + Ok(obj_ref) + } else { + Err(new_stop_iteration(vm)) } } } else { diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 5f2643e785..0a2ece3651 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -9,12 +9,32 @@ use super::objsequence::{ use super::objstr; use super::objtype; use crate::pyobject::{ - IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, - TypeProtocol, + IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, + PyResult, TypeProtocol, }; use crate::vm::{ReprGuard, VirtualMachine}; use num_traits::ToPrimitive; +#[derive(Debug, Default)] +pub struct PyList { + // TODO: shouldn't be public + pub elements: RefCell>, +} + +impl From> for PyList { + fn from(elements: Vec) -> Self { + PyList { + elements: RefCell::new(elements), + } + } +} + +impl PyObjectPayload2 for PyList { + fn required_type(ctx: &PyContext) -> PyObjectRef { + ctx.list_type() + } +} + // set_item: fn set_item( vm: &mut VirtualMachine, @@ -57,8 +77,8 @@ fn list_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { }; Ok(PyObject::new( - PyObjectPayload::Sequence { - elements: RefCell::new(elements), + PyObjectPayload::AnyRustValue { + value: Box::new(PyList::from(elements)), }, cls.clone(), )) diff --git a/vm/src/obj/objsequence.rs b/vm/src/obj/objsequence.rs index 5f875a5b07..f18f23e4d8 100644 --- a/vm/src/obj/objsequence.rs +++ b/vm/src/obj/objsequence.rs @@ -2,13 +2,17 @@ use std::cell::RefCell; use std::marker::Sized; use std::ops::{Deref, DerefMut, Range}; -use super::objbool; -use super::objint::{self, PyInt}; -use crate::pyobject::{IdProtocol, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol}; -use crate::vm::VirtualMachine; use num_bigint::BigInt; use num_traits::{One, Signed, ToPrimitive, Zero}; +use crate::pyobject::{IdProtocol, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol}; +use crate::vm::VirtualMachine; + +use super::objbool; +use super::objint::{self, PyInt}; +use super::objlist::PyList; +use super::objtuple::PyTuple; + pub trait PySliceableSequence { fn do_slice(&self, range: Range) -> Self; fn do_slice_reverse(&self, range: Range) -> Self; @@ -156,16 +160,27 @@ pub fn get_item( } }; } + match &subscript.payload { - PyObjectPayload::Slice { .. } => Ok(PyObject::new( - match &sequence.payload { - PyObjectPayload::Sequence { .. } => PyObjectPayload::Sequence { - elements: RefCell::new(elements.to_vec().get_slice_items(vm, &subscript)?), - }, - ref payload => panic!("sequence get_item called for non-sequence: {:?}", payload), - }, - sequence.typ(), - )), + PyObjectPayload::Slice { .. } => { + let payload = if sequence.payload::().is_some() { + PyObjectPayload::AnyRustValue { + value: Box::new(PyList::from( + elements.to_vec().get_slice_items(vm, &subscript)?, + )), + } + } else if sequence.payload::().is_some() { + PyObjectPayload::AnyRustValue { + value: Box::new(PyTuple::from( + elements.to_vec().get_slice_items(vm, &subscript)?, + )), + } + } else { + panic!("sequence get_item called for non-sequence") + }; + + Ok(PyObject::new(payload, sequence.typ())) + } _ => Err(vm.new_type_error(format!( "TypeError: indexing type {:?} with index {:?} is not supported (yet?)", sequence, subscript @@ -304,27 +319,31 @@ pub fn seq_mul(elements: &[PyObjectRef], product: &PyObjectRef) -> Vec(obj: &'a PyObjectRef) -> &'a RefCell> { - if let PyObjectPayload::Sequence { ref elements } = obj.payload { - elements - } else { - panic!("Cannot extract elements from non-sequence"); + if let Some(list) = obj.payload::() { + return &list.elements; } + if let Some(tuple) = obj.payload::() { + return &tuple.elements; + } + panic!("Cannot extract elements from non-sequence"); } pub fn get_elements<'a>(obj: &'a PyObjectRef) -> impl Deref> + 'a { - if let PyObjectPayload::Sequence { ref elements } = obj.payload { - elements.borrow() - } else { - panic!("Cannot extract elements from non-sequence"); + if let Some(list) = obj.payload::() { + return list.elements.borrow(); + } + if let Some(tuple) = obj.payload::() { + return tuple.elements.borrow(); } + panic!("Cannot extract elements from non-sequence"); } pub fn get_mut_elements<'a>(obj: &'a PyObjectRef) -> impl DerefMut> + 'a { - if let PyObjectPayload::Sequence { ref elements } = obj.payload { - elements.borrow_mut() - } 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())) + if let Some(list) = obj.payload::() { + return list.elements.borrow_mut(); + } + if let Some(tuple) = obj.payload::() { + return tuple.elements.borrow_mut(); } + panic!("Cannot extract elements from non-sequence"); } diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs index 7747d2fc92..a9f140b53c 100644 --- a/vm/src/obj/objtuple.rs +++ b/vm/src/obj/objtuple.rs @@ -1,6 +1,12 @@ use std::cell::{Cell, RefCell}; use std::hash::{Hash, Hasher}; +use crate::pyobject::{ + PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, PyResult, + TypeProtocol, +}; +use crate::vm::{ReprGuard, VirtualMachine}; + use super::objbool; use super::objint; use super::objsequence::{ @@ -8,8 +14,27 @@ use super::objsequence::{ }; use super::objstr; use super::objtype; -use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol}; -use crate::vm::{ReprGuard, VirtualMachine}; + +#[derive(Debug, Default)] +pub struct PyTuple { + // TODO: shouldn't be public + // TODO: tuples are immutable, remove this RefCell + pub elements: RefCell>, +} + +impl From> for PyTuple { + fn from(elements: Vec) -> Self { + PyTuple { + elements: RefCell::new(elements), + } + } +} + +impl PyObjectPayload2 for PyTuple { + fn required_type(ctx: &PyContext) -> PyObjectRef { + ctx.tuple_type() + } +} fn tuple_lt(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( @@ -185,8 +210,8 @@ fn tuple_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { }; Ok(PyObject::new( - PyObjectPayload::Sequence { - elements: RefCell::new(elements), + PyObjectPayload::AnyRustValue { + value: Box::new(PyTuple::from(elements)), }, cls.clone(), )) diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 8e1e45c8c3..2ce836c3ee 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -28,7 +28,7 @@ use crate::obj::objfunction; use crate::obj::objgenerator; use crate::obj::objint::{self, PyInt}; use crate::obj::objiter; -use crate::obj::objlist; +use crate::obj::objlist::{self, PyList}; use crate::obj::objmap; use crate::obj::objmemory; use crate::obj::objmodule; @@ -40,7 +40,7 @@ use crate::obj::objset::{self, PySet}; use crate::obj::objslice; use crate::obj::objstr; use crate::obj::objsuper; -use crate::obj::objtuple; +use crate::obj::objtuple::{self, PyTuple}; use crate::obj::objtype; use crate::obj::objzip; use crate::vm::VirtualMachine; @@ -549,8 +549,8 @@ impl PyContext { pub fn new_tuple(&self, elements: Vec) -> PyObjectRef { PyObject::new( - PyObjectPayload::Sequence { - elements: RefCell::new(elements), + PyObjectPayload::AnyRustValue { + value: Box::new(PyTuple::from(elements)), }, self.tuple_type(), ) @@ -558,8 +558,8 @@ impl PyContext { pub fn new_list(&self, elements: Vec) -> PyObjectRef { PyObject::new( - PyObjectPayload::Sequence { - elements: RefCell::new(elements), + PyObjectPayload::AnyRustValue { + value: Box::new(PyList::from(elements)), }, self.list_type(), ) @@ -1467,9 +1467,6 @@ into_py_native_func_tuple!((a, A), (b, B), (c, C), (d, D), (e, E)); /// of rust data for a particular python object. Determine the python type /// by using for example the `.typ()` method on a python object. pub enum PyObjectPayload { - Sequence { - elements: RefCell>, - }, Iterator { position: Cell, iterated_obj: PyObjectRef, @@ -1542,7 +1539,6 @@ impl fmt::Debug for PyObjectPayload { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { PyObjectPayload::MemoryView { ref obj } => write!(f, "bytes/bytearray {:?}", obj), - PyObjectPayload::Sequence { .. } => write!(f, "list or tuple"), PyObjectPayload::WeakRef { .. } => write!(f, "weakref"), PyObjectPayload::Iterator { .. } => write!(f, "iterator"), PyObjectPayload::EnumerateIterator { .. } => write!(f, "enumerate"), diff --git a/vm/src/vm.rs b/vm/src/vm.rs index e3d06d5fae..f67c931d30 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -20,8 +20,10 @@ use crate::obj::objcode; use crate::obj::objframe; use crate::obj::objgenerator; use crate::obj::objiter; +use crate::obj::objlist::PyList; use crate::obj::objsequence; use crate::obj::objstr; +use crate::obj::objtuple::PyTuple; use crate::obj::objtype; use crate::pyobject::{ AttributeProtocol, DictProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, @@ -446,8 +448,10 @@ impl VirtualMachine { if nargs < nexpected_args { let available_defaults = if defaults.is(&self.get_none()) { vec![] - } else if let PyObjectPayload::Sequence { ref elements } = defaults.payload { - elements.borrow().clone() + } else if let Some(list) = defaults.payload::() { + list.elements.borrow().clone() + } else if let Some(tuple) = defaults.payload::() { + tuple.elements.borrow().clone() } else { panic!("function defaults not tuple or None"); };