Skip to content

Convert list and tuple to Any payload #627

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions vm/src/obj/objbool.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -30,21 +30,22 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult<bool> {
if let Some(i) = obj.payload::<PyInt>() {
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::<PyInt>() {
Some(i) => !i.value.is_zero(),
None => return Err(vm.new_type_error(String::from("TypeError"))),
}
} else {
true
}
if let Some(list) = obj.payload::<PyList>() {
return Ok(!list.elements.borrow().is_empty());
}
if let Some(tuple) = obj.payload::<PyTuple>() {
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::<PyInt>() {
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) {
Expand Down
21 changes: 8 additions & 13 deletions vm/src/obj/objiter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/*
Expand Down Expand Up @@ -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 {
Expand Down
28 changes: 24 additions & 4 deletions vm/src/obj/objlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<PyObjectRef>>,
}

impl From<Vec<PyObjectRef>> for PyList {
fn from(elements: Vec<PyObjectRef>) -> 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,
Expand Down Expand Up @@ -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(),
))
Expand Down
73 changes: 46 additions & 27 deletions vm/src/obj/objsequence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<usize>) -> Self;
fn do_slice_reverse(&self, range: Range<usize>) -> Self;
Expand Down Expand Up @@ -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::<PyList>().is_some() {
PyObjectPayload::AnyRustValue {
value: Box::new(PyList::from(
elements.to_vec().get_slice_items(vm, &subscript)?,
)),
}
} else if sequence.payload::<PyTuple>().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
Expand Down Expand Up @@ -304,27 +319,31 @@ pub fn seq_mul(elements: &[PyObjectRef], product: &PyObjectRef) -> Vec<PyObjectR
}

pub fn get_elements_cell<'a>(obj: &'a PyObjectRef) -> &'a RefCell<Vec<PyObjectRef>> {
if let PyObjectPayload::Sequence { ref elements } = obj.payload {
elements
} else {
panic!("Cannot extract elements from non-sequence");
if let Some(list) = obj.payload::<PyList>() {
return &list.elements;
}
if let Some(tuple) = obj.payload::<PyTuple>() {
return &tuple.elements;
}
panic!("Cannot extract elements from non-sequence");
}

pub fn get_elements<'a>(obj: &'a PyObjectRef) -> impl Deref<Target = Vec<PyObjectRef>> + '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::<PyList>() {
return list.elements.borrow();
}
if let Some(tuple) = obj.payload::<PyTuple>() {
return tuple.elements.borrow();
}
panic!("Cannot extract elements from non-sequence");
}

pub fn get_mut_elements<'a>(obj: &'a PyObjectRef) -> impl DerefMut<Target = Vec<PyObjectRef>> + '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::<PyList>() {
return list.elements.borrow_mut();
}
if let Some(tuple) = obj.payload::<PyTuple>() {
return tuple.elements.borrow_mut();
}
panic!("Cannot extract elements from non-sequence");
}
33 changes: 29 additions & 4 deletions vm/src/obj/objtuple.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,40 @@
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::{
get_elements, get_item, seq_equal, seq_ge, seq_gt, seq_le, seq_lt, seq_mul,
};
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<Vec<PyObjectRef>>,
}

impl From<Vec<PyObjectRef>> for PyTuple {
fn from(elements: Vec<PyObjectRef>) -> 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!(
Expand Down Expand Up @@ -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(),
))
Expand Down
16 changes: 6 additions & 10 deletions vm/src/pyobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -549,17 +549,17 @@ impl PyContext {

pub fn new_tuple(&self, elements: Vec<PyObjectRef>) -> PyObjectRef {
PyObject::new(
PyObjectPayload::Sequence {
elements: RefCell::new(elements),
PyObjectPayload::AnyRustValue {
value: Box::new(PyTuple::from(elements)),
},
self.tuple_type(),
)
}

pub fn new_list(&self, elements: Vec<PyObjectRef>) -> PyObjectRef {
PyObject::new(
PyObjectPayload::Sequence {
elements: RefCell::new(elements),
PyObjectPayload::AnyRustValue {
value: Box::new(PyList::from(elements)),
},
self.list_type(),
)
Expand Down Expand Up @@ -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<Vec<PyObjectRef>>,
},
Iterator {
position: Cell<usize>,
iterated_obj: PyObjectRef,
Expand Down Expand Up @@ -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"),
Expand Down
8 changes: 6 additions & 2 deletions vm/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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::<PyList>() {
list.elements.borrow().clone()
} else if let Some(tuple) = defaults.payload::<PyTuple>() {
tuple.elements.borrow().clone()
} else {
panic!("function defaults not tuple or None");
};
Expand Down