diff --git a/vm/src/frame.rs b/vm/src/frame.rs index f5dc38ff0..4fd7ae687 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -1,9 +1,11 @@ -extern crate rustpython_parser; - -use self::rustpython_parser::ast; use std::cell::RefCell; use std::fmt; use std::path::PathBuf; +use std::rc::Rc; + +use num_bigint::BigInt; + +use rustpython_parser::ast; use crate::builtins; use crate::bytecode; @@ -12,6 +14,7 @@ use crate::obj::objbool; use crate::obj::objcode; use crate::obj::objdict; use crate::obj::objdict::PyDict; +use crate::obj::objint::PyInt; use crate::obj::objiter; use crate::obj::objlist; use crate::obj::objstr; @@ -21,8 +24,6 @@ use crate::pyobject::{ TypeProtocol, }; use crate::vm::VirtualMachine; -use num_bigint::BigInt; -use std::rc::Rc; /* * So a scope is a linked list of scopes. @@ -287,12 +288,12 @@ impl Frame { let mut out: Vec> = elements .into_iter() .map(|x| { - if x.is(&vm.get_none()) { + if x.is(&vm.ctx.none()) { None - } else if let PyObjectPayload::Integer { ref value } = x.payload { - Some(value.clone()) + } else if let Some(i) = x.payload::() { + Some(i.value.clone()) } else { - panic!("Expect Int or None as BUILD_SLICE arguments, got {:?}", x); + panic!("Expect Int or None as BUILD_SLICE arguments") } }) .collect(); diff --git a/vm/src/obj/objbool.rs b/vm/src/obj/objbool.rs index 7a96effd2..09e0759c7 100644 --- a/vm/src/obj/objbool.rs +++ b/vm/src/obj/objbool.rs @@ -1,12 +1,15 @@ -use super::objdict::PyDict; -use super::objfloat::PyFloat; -use super::objstr::PyString; -use super::objtype; +use num_traits::Zero; + use crate::pyobject::{ IntoPyObject, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; use crate::vm::VirtualMachine; -use num_traits::Zero; + +use super::objdict::PyDict; +use super::objfloat::PyFloat; +use super::objint::PyInt; +use super::objstr::PyString; +use super::objtype; impl IntoPyObject for bool { fn into_pyobject(self, ctx: &PyContext) -> PyResult { @@ -24,15 +27,17 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult { if let Some(dict) = obj.payload::() { return Ok(!dict.entries.borrow().is_empty()); } + if let Some(i) = obj.payload::() { + return Ok(!i.value.is_zero()); + } let result = match obj.payload { - PyObjectPayload::Integer { ref value } => !value.is_zero(), 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 { - PyObjectPayload::Integer { ref value } => !value.is_zero(), - _ => return Err(vm.new_type_error(String::from("TypeError"))), + match bool_res.payload::() { + Some(i) => !i.value.is_zero(), + None => return Err(vm.new_type_error(String::from("TypeError"))), } } else { true @@ -66,11 +71,7 @@ pub fn not(vm: &mut VirtualMachine, obj: &PyObjectRef) -> PyResult { // Retrieve inner int value: pub fn get_value(obj: &PyObjectRef) -> bool { - if let PyObjectPayload::Integer { value } = &obj.payload { - !value.is_zero() - } else { - panic!("Inner error getting inner boolean"); - } + !obj.payload::().unwrap().value.is_zero() } fn bool_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> Result { diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index a79dfb6dd..8e5f3f59c 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -1,56 +1,86 @@ -use super::objfloat; -use super::objstr; -use super::objtype; -use crate::format::FormatSpec; -use crate::pyobject::{ - FromPyObjectRef, IntoPyObject, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, - PyResult, TryFromObject, TypeProtocol, -}; -use crate::vm::VirtualMachine; +use std::hash::{Hash, Hasher}; + use num_bigint::{BigInt, ToBigInt}; use num_integer::Integer; use num_traits::{Pow, Signed, ToPrimitive, Zero}; -use std::hash::{Hash, Hasher}; -// This proxy allows for easy switching between types. -type IntType = BigInt; +use crate::format::FormatSpec; +use crate::function::PyRef; +use crate::pyobject::{ + FromPyObjectRef, IntoPyObject, PyContext, PyFuncArgs, PyObject, PyObjectPayload, + PyObjectPayload2, PyObjectRef, PyResult, TryFromObject, TypeProtocol, +}; +use crate::vm::VirtualMachine; -pub type PyInt = BigInt; +use super::objfloat; +use super::objstr; +use super::objtype; -impl IntoPyObject for PyInt { - fn into_pyobject(self, ctx: &PyContext) -> PyResult { - Ok(ctx.new_int(self)) - } +#[derive(Debug)] +pub struct PyInt { + // TODO: shouldn't be public + pub value: BigInt, } -// TODO: macro to impl for all primitive ints +pub type PyIntRef = PyRef; -impl IntoPyObject for usize { - fn into_pyobject(self, ctx: &PyContext) -> PyResult { - Ok(ctx.new_int(self)) - } -} - -impl TryFromObject for usize { - fn try_from_object(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult { - // FIXME: don't use get_value - match get_value(&obj).to_usize() { - Some(value) => Ok(value), - None => Err(vm.new_overflow_error("Int value cannot fit into Rust usize".to_string())), +impl PyInt { + pub fn new(i: T) -> Self { + PyInt { + value: i.to_bigint().unwrap(), } } } -impl TryFromObject for isize { - fn try_from_object(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult { - // FIXME: don't use get_value - match get_value(&obj).to_isize() { - Some(value) => Ok(value), - None => Err(vm.new_overflow_error("Int value cannot fit into Rust isize".to_string())), - } +impl PyObjectPayload2 for PyInt { + fn required_type(ctx: &PyContext) -> PyObjectRef { + ctx.int_type() } } +macro_rules! impl_into_pyobject_int { + ($($t:ty)*) => {$( + impl IntoPyObject for $t { + fn into_pyobject(self, ctx: &PyContext) -> PyResult { + Ok(ctx.new_int(self)) + } + } + )*}; +} + +impl_into_pyobject_int!(isize i8 i16 i32 i64 usize u8 u16 u32 u64) ; + +macro_rules! impl_try_from_object_int { + ($(($t:ty, $to_prim:ident),)*) => {$( + impl TryFromObject for $t { + fn try_from_object(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult { + match PyRef::::try_from_object(vm, obj)?.value.$to_prim() { + Some(value) => Ok(value), + None => Err( + vm.new_overflow_error(concat!( + "Int value cannot fit into Rust ", + stringify!($t) + ).to_string()) + ), + } + } + } + )*}; +} + +impl_try_from_object_int!( + (isize, to_isize), + (i8, to_i8), + (i16, to_i16), + (i32, to_i32), + (i64, to_i64), + (usize, to_usize), + (u8, to_u8), + (u16, to_u16), + (u32, to_u32), + (u64, to_u64), +); + fn int_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(int, Some(vm.ctx.int_type()))]); let v = get_value(int); @@ -77,13 +107,15 @@ fn int_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { None => Zero::zero(), }; Ok(PyObject::new( - PyObjectPayload::Integer { value: val }, + PyObjectPayload::AnyRustValue { + value: Box::new(PyInt::new(val)), + }, cls.clone(), )) } // Casting function: -pub fn to_int(vm: &mut VirtualMachine, obj: &PyObjectRef, base: u32) -> PyResult { +pub fn to_int(vm: &mut VirtualMachine, obj: &PyObjectRef, base: u32) -> PyResult { let val = if objtype::isinstance(obj, &vm.ctx.int_type()) { get_value(obj) } else if objtype::isinstance(obj, &vm.ctx.float_type()) { @@ -111,12 +143,8 @@ pub fn to_int(vm: &mut VirtualMachine, obj: &PyObjectRef, base: u32) -> PyResult } // Retrieve inner int value: -pub fn get_value(obj: &PyObjectRef) -> IntType { - if let PyObjectPayload::Integer { value } = &obj.payload { - value.clone() - } else { - panic!("Inner error getting int {:?}", obj); - } +pub fn get_value(obj: &PyObjectRef) -> BigInt { + obj.payload::().unwrap().value.clone() } impl FromPyObjectRef for BigInt { diff --git a/vm/src/obj/objrange.rs b/vm/src/obj/objrange.rs index 41a4c6964..55f736da5 100644 --- a/vm/src/obj/objrange.rs +++ b/vm/src/obj/objrange.rs @@ -1,16 +1,18 @@ use std::cell::Cell; use std::ops::Mul; -use super::objint; -use super::objtype; +use num_bigint::{BigInt, Sign}; +use num_integer::Integer; +use num_traits::{One, Signed, ToPrimitive, Zero}; + use crate::pyobject::{ PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, PyResult, TypeProtocol, }; use crate::vm::VirtualMachine; -use num_bigint::{BigInt, Sign}; -use num_integer::Integer; -use num_traits::{One, Signed, ToPrimitive, Zero}; + +use super::objint::{self, PyInt}; +use super::objtype; #[derive(Debug, Clone)] pub struct PyRange { @@ -284,14 +286,15 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let range = get_value(zelf); + if let Some(i) = subscript.payload::() { + return if let Some(int) = range.get(i.value.clone()) { + Ok(vm.ctx.new_int(int)) + } else { + Err(vm.new_index_error("range object index out of range".to_string())) + }; + } + match subscript.payload { - PyObjectPayload::Integer { ref value } => { - if let Some(int) = range.get(value) { - Ok(vm.ctx.new_int(int)) - } else { - Err(vm.new_index_error("range object index out of range".to_string())) - } - } PyObjectPayload::Slice { ref start, ref stop, diff --git a/vm/src/obj/objsequence.rs b/vm/src/obj/objsequence.rs index 46912c1b8..5f875a5b0 100644 --- a/vm/src/obj/objsequence.rs +++ b/vm/src/obj/objsequence.rs @@ -3,7 +3,7 @@ use std::marker::Sized; use std::ops::{Deref, DerefMut, Range}; use super::objbool; -use super::objint; +use super::objint::{self, PyInt}; use crate::pyobject::{IdProtocol, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol}; use crate::vm::VirtualMachine; use num_bigint::BigInt; @@ -141,8 +141,8 @@ pub fn get_item( elements: &[PyObjectRef], subscript: PyObjectRef, ) -> PyResult { - match &subscript.payload { - PyObjectPayload::Integer { value } => match value.to_i32() { + if let Some(i) = subscript.payload::() { + return match i.value.to_i32() { Some(value) => { if let Some(pos_index) = elements.to_vec().get_pos(value) { let obj = elements[pos_index].clone(); @@ -154,8 +154,9 @@ pub fn get_item( None => { Err(vm.new_index_error("cannot fit 'int' into an index-sized integer".to_string())) } - }, - + }; + } + match &subscript.payload { PyObjectPayload::Slice { .. } => Ok(PyObject::new( match &sequence.payload { PyObjectPayload::Sequence { .. } => PyObjectPayload::Sequence { diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index f498a5401..a296ea32d 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -26,7 +26,7 @@ use crate::obj::objfloat::{self, PyFloat}; use crate::obj::objframe; use crate::obj::objfunction; use crate::obj::objgenerator; -use crate::obj::objint; +use crate::obj::objint::{self, PyInt}; use crate::obj::objiter; use crate::obj::objlist; use crate::obj::objmap; @@ -247,12 +247,14 @@ impl PyContext { ); let true_value = PyObject::new( - PyObjectPayload::Integer { value: One::one() }, + PyObjectPayload::AnyRustValue { + value: Box::new(PyInt::new(BigInt::one())), + }, bool_type.clone(), ); let false_value = PyObject::new( - PyObjectPayload::Integer { - value: Zero::zero(), + PyObjectPayload::AnyRustValue { + value: Box::new(PyInt::new(BigInt::zero())), }, bool_type.clone(), ); @@ -485,8 +487,8 @@ impl PyContext { pub fn new_int(&self, i: T) -> PyObjectRef { PyObject::new( - PyObjectPayload::Integer { - value: i.to_bigint().unwrap(), + PyObjectPayload::AnyRustValue { + value: Box::new(PyInt::new(i)), }, self.int_type(), ) @@ -1465,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 { - Integer { - value: BigInt, - }, Sequence { elements: RefCell>, }, @@ -1542,7 +1541,6 @@ pub enum PyObjectPayload { impl fmt::Debug for PyObjectPayload { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - PyObjectPayload::Integer { ref value } => write!(f, "int {}", value), PyObjectPayload::MemoryView { ref obj } => write!(f, "bytes/bytearray {:?}", obj), PyObjectPayload::Sequence { .. } => write!(f, "list or tuple"), PyObjectPayload::WeakRef { .. } => write!(f, "weakref"),