From f9538af3f27079b07e4634a9e246e73ea7c80837 Mon Sep 17 00:00:00 2001 From: Windel Bouwman Date: Fri, 31 Aug 2018 22:10:10 +0200 Subject: [PATCH 1/5] Add bytes object class --- tests/snippets/basic_types.py | 4 +++ vm/src/builtins.rs | 1 + vm/src/obj/mod.rs | 1 + vm/src/obj/objbytes.rs | 55 +++++++++++++++++++++++++++++++++++ vm/src/obj/objint.rs | 48 ++++++++++++++++++++++++++++++ vm/src/pyobject.rs | 14 +++++++++ vm/src/vm.rs | 15 ++++++++++ 7 files changed, 138 insertions(+) create mode 100644 vm/src/obj/objbytes.rs diff --git a/tests/snippets/basic_types.py b/tests/snippets/basic_types.py index 8944b1355..c878115c4 100644 --- a/tests/snippets/basic_types.py +++ b/tests/snippets/basic_types.py @@ -25,3 +25,7 @@ assert type(2 / 3) is float x = 1 assert type(x) is int assert type(x - 1) is int + +a = bytes([1, 2, 3]) +print(a) + diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 788a4452e..fd89e747e 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -322,6 +322,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { dict.insert(String::from("all"), ctx.new_rustfunc(builtin_all)); dict.insert(String::from("any"), ctx.new_rustfunc(builtin_any)); dict.insert(String::from("bool"), ctx.bool_type()); + dict.insert(String::from("bytes"), ctx.bytes_type()); dict.insert(String::from("chr"), ctx.new_rustfunc(builtin_chr)); dict.insert(String::from("compile"), ctx.new_rustfunc(builtin_compile)); dict.insert(String::from("dict"), ctx.dict_type()); diff --git a/vm/src/obj/mod.rs b/vm/src/obj/mod.rs index 36c28bd50..fb1cad5ac 100644 --- a/vm/src/obj/mod.rs +++ b/vm/src/obj/mod.rs @@ -1,3 +1,4 @@ +pub mod objbytes; pub mod objdict; pub mod objfloat; pub mod objint; diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs new file mode 100644 index 000000000..ebaa3cbd1 --- /dev/null +++ b/vm/src/obj/objbytes.rs @@ -0,0 +1,55 @@ +use super::super::pyobject::{ + AttributeProtocol, FromPyObjectRef, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, + TypeProtocol, +}; +use super::super::vm::VirtualMachine; +use super::objint; +use super::objlist; +use super::objtype; +// Binary data support + +// Fill bytes class methods: +pub fn init(context: &PyContext) { + let ref bytes_type = context.bytes_type; + bytes_type.set_attr("__init__", context.new_rustfunc(bytes_init)); + bytes_type.set_attr("__str__", context.new_rustfunc(bytes_str)); +} + +// __init__ (store value into objectkind) +fn bytes_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(zelf, Some(vm.ctx.bytes_type())), (arg, None)] + ); + let val = if objtype::isinstance(arg.clone(), vm.ctx.list_type()) { + objlist::get_elements(arg.clone()) + .into_iter() + .map(|e| objint::get_value(&e) as u8) + .collect() + } else { + return Err(vm.new_type_error("Cannot construct int".to_string())); + }; + set_value(zelf, val); + Ok(vm.get_none()) +} + +pub fn get_value(obj: &PyObjectRef) -> Vec { + if let PyObjectKind::Bytes { value } = &obj.borrow().kind { + value.clone() + } else { + panic!("Inner error getting int {:?}", obj); + } +} + +fn set_value(obj: &PyObjectRef, value: Vec) { + obj.borrow_mut().kind = PyObjectKind::Bytes { value }; +} + +fn bytes_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytes_type()))]); + let data = get_value(obj); + let data: Vec = data.into_iter().map(|b| format!("\\x{:02x}", b)).collect(); + let data = data.join(""); + Ok(vm.new_str(format!("b'{}'", data))) +} diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index f617fd1ae..4fe985185 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -142,15 +142,63 @@ fn int_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } +fn int_xor(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(i, Some(vm.ctx.int_type())), (i2, None)] + ); + let v1 = get_value(i); + if objtype::isinstance(i2.clone(), vm.ctx.int_type()) { + let v2 = get_value(i2); + Ok(vm.ctx.new_int(v1 ^ v2)) + } else { + Err(vm.new_type_error(format!("Cannot xor {:?} and {:?}", i, i2))) + } +} + +fn int_or(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(i, Some(vm.ctx.int_type())), (i2, None)] + ); + let v1 = get_value(i); + if objtype::isinstance(i2.clone(), vm.ctx.int_type()) { + let v2 = get_value(i2); + Ok(vm.ctx.new_int(v1 | v2)) + } else { + Err(vm.new_type_error(format!("Cannot or {:?} and {:?}", i, i2))) + } +} + +fn int_and(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(i, Some(vm.ctx.int_type())), (i2, None)] + ); + let v1 = get_value(i); + if objtype::isinstance(i2.clone(), vm.ctx.int_type()) { + let v2 = get_value(i2); + Ok(vm.ctx.new_int(v1 & v2)) + } else { + Err(vm.new_type_error(format!("Cannot and {:?} and {:?}", i, i2))) + } +} + pub fn init(context: &PyContext) { let ref int_type = context.int_type; int_type.set_attr("__add__", context.new_rustfunc(int_add)); + int_type.set_attr("__and__", context.new_rustfunc(int_and)); int_type.set_attr("__init__", context.new_rustfunc(int_init)); int_type.set_attr("__mod__", context.new_rustfunc(int_mod)); int_type.set_attr("__mul__", context.new_rustfunc(int_mul)); + int_type.set_attr("__or__", context.new_rustfunc(int_or)); int_type.set_attr("__pow__", context.new_rustfunc(int_pow)); int_type.set_attr("__repr__", context.new_rustfunc(str)); int_type.set_attr("__str__", context.new_rustfunc(str)); int_type.set_attr("__sub__", context.new_rustfunc(int_sub)); int_type.set_attr("__truediv__", context.new_rustfunc(int_truediv)); + int_type.set_attr("__xor__", context.new_rustfunc(int_xor)); } diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 078e03829..260ae2036 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -1,5 +1,6 @@ use super::bytecode; use super::exceptions; +use super::obj::objbytes; use super::obj::objdict; use super::obj::objfloat; use super::obj::objint; @@ -52,6 +53,7 @@ pub struct PyContext { pub dict_type: PyObjectRef, pub int_type: PyObjectRef, pub float_type: PyObjectRef, + pub bytes_type: PyObjectRef, pub bool_type: PyObjectRef, pub list_type: PyObjectRef, pub tuple_type: PyObjectRef, @@ -114,6 +116,7 @@ impl PyContext { let list_type = create_type("list", &type_type, &object_type, &dict_type); let int_type = create_type("int", &type_type, &object_type, &dict_type); let float_type = create_type("float", &type_type, &object_type, &dict_type); + let bytes_type = create_type("bytes", &type_type, &object_type, &dict_type); let tuple_type = create_type("tuple", &type_type, &object_type, &dict_type); let bool_type = create_type("bool", &type_type, &object_type, &dict_type); let exceptions = exceptions::ExceptionZoo::new(&type_type, &object_type, &dict_type); @@ -126,6 +129,7 @@ impl PyContext { let context = PyContext { int_type: int_type, float_type: float_type, + bytes_type: bytes_type, list_type: list_type, bool_type: bool_type, tuple_type: tuple_type, @@ -146,6 +150,7 @@ impl PyContext { objfunction::init(&context); objint::init(&context); objfloat::init(&context); + objbytes::init(&context); objstr::init(&context); objbool::init(&context); exceptions::init(&context); @@ -162,6 +167,10 @@ impl PyContext { self.float_type.clone() } + pub fn bytes_type(&self) -> PyObjectRef { + self.bytes_type.clone() + } + pub fn list_type(&self) -> PyObjectRef { self.list_type.clone() } @@ -547,6 +556,9 @@ pub enum PyObjectKind { Boolean { value: bool, }, + Bytes { + value: Vec, + }, List { elements: Vec, }, @@ -604,6 +616,7 @@ impl fmt::Debug for PyObjectKind { &PyObjectKind::String { ref value } => write!(f, "str \"{}\"", value), &PyObjectKind::Integer { ref value } => write!(f, "int {}", value), &PyObjectKind::Float { ref value } => write!(f, "float {}", value), + &PyObjectKind::Bytes { ref value } => write!(f, "bytes {:?}", value), &PyObjectKind::Boolean { ref value } => write!(f, "boolean {}", value), &PyObjectKind::List { elements: _ } => write!(f, "list"), &PyObjectKind::Tuple { elements: _ } => write!(f, "tuple"), @@ -651,6 +664,7 @@ impl PyObject { PyObjectKind::String { ref value } => value.clone(), PyObjectKind::Integer { ref value } => format!("{:?}", value), PyObjectKind::Float { ref value } => format!("{:?}", value), + PyObjectKind::Bytes { ref value } => format!("b'{:?}'", value), PyObjectKind::Boolean { ref value } => format!("{:?}", value), PyObjectKind::List { ref elements } => format!( "[{}]", diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 86be94b33..1c5de630b 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -360,6 +360,18 @@ impl VirtualMachine { self.call_method(a, "__mod__".to_string(), vec![b]) } + fn _xor(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_method(a, "__xor__".to_string(), vec![b]) + } + + fn _or(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_method(a, "__or__".to_string(), vec![b]) + } + + fn _and(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_method(a, "__and__".to_string(), vec![b]) + } + fn execute_binop(&mut self, op: &bytecode::BinaryOperator) -> Option { let b_ref = self.pop_value(); let a_ref = self.pop_value(); @@ -373,6 +385,9 @@ impl VirtualMachine { &bytecode::BinaryOperator::Divide => self._div(a_ref, b_ref), &bytecode::BinaryOperator::Subscript => self.subscript(a_ref, b_ref), &bytecode::BinaryOperator::Modulo => self._modulo(a_ref, b_ref), + &bytecode::BinaryOperator::Xor => self._xor(a_ref, b_ref), + &bytecode::BinaryOperator::Or => self._or(a_ref, b_ref), + &bytecode::BinaryOperator::And => self._and(a_ref, b_ref), _ => panic!("NOT IMPL {:?}", op), }; match result { From 5cdd0ab7b8f31f0df12f1ebf60b885c19b9cd22a Mon Sep 17 00:00:00 2001 From: Windel Bouwman Date: Sat, 1 Sep 2018 09:54:58 +0200 Subject: [PATCH 2/5] Check list elements on int type --- tests/snippets/basic_types.py | 4 ++++ vm/src/obj/objbytes.rs | 15 ++++++++++----- vm/src/obj/objint.rs | 24 ++++++++++++++++++------ vm/src/obj/objtype.rs | 16 ++++++++++++++-- 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/tests/snippets/basic_types.py b/tests/snippets/basic_types.py index c878115c4..b9dc22b27 100644 --- a/tests/snippets/basic_types.py +++ b/tests/snippets/basic_types.py @@ -28,4 +28,8 @@ assert type(x - 1) is int a = bytes([1, 2, 3]) print(a) +try: + bytes([object()]) +except TypeError: + pass diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs index ebaa3cbd1..9aa4722d7 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -23,12 +23,17 @@ fn bytes_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { required = [(zelf, Some(vm.ctx.bytes_type())), (arg, None)] ); let val = if objtype::isinstance(arg.clone(), vm.ctx.list_type()) { - objlist::get_elements(arg.clone()) - .into_iter() - .map(|e| objint::get_value(&e) as u8) - .collect() + let mut data_bytes = vec![]; + for elem in objlist::get_elements(arg.clone()) { + let v = match objint::to_int(vm, &elem) { + Ok(int_ref) => int_ref, + Err(err) => return Err(err), + }; + data_bytes.push(v as u8); + } + data_bytes } else { - return Err(vm.new_type_error("Cannot construct int".to_string())); + return Err(vm.new_type_error("Cannot construct bytes".to_string())); }; set_value(zelf, val); Ok(vm.get_none()) diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index 4fe985185..e68cad0b7 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -19,15 +19,27 @@ fn int_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { args, required = [(zelf, Some(vm.ctx.int_type())), (arg, None)] ); - let val = if objtype::isinstance(arg.clone(), vm.ctx.int_type()) { - get_value(arg) - } else if objtype::isinstance(arg.clone(), vm.ctx.float_type()) { - objfloat::get_value(arg) as i32 + + // Try to cast to int: + let val = match to_int(vm, arg) { + Ok(val) => val, + Err(err) => return Err(err), + }; + + set_value(zelf, val); + Ok(vm.get_none()) +} + +// Casting function: +pub fn to_int(vm: &mut VirtualMachine, obj: &PyObjectRef) -> Result { + let val = if objtype::isinstance(obj.clone(), vm.ctx.int_type()) { + get_value(obj) + } else if objtype::isinstance(obj.clone(), vm.ctx.float_type()) { + objfloat::get_value(obj) as i32 } else { return Err(vm.new_type_error("Cannot construct int".to_string())); }; - set_value(zelf, val); - Ok(vm.get_none()) + Ok(val) } // Retrieve inner int value: diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index 771a96f35..d7b99a4eb 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -113,10 +113,22 @@ pub fn type_call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { debug!("type_call: {:?}", args); let typ = args.shift(); let new = typ.get_attr("__new__").unwrap(); - let obj = vm.invoke(new, args.insert(typ.clone()))?; + let obj = match vm.invoke(new, args.insert(typ.clone())) { + Ok(res) => res, + Err(err) => return Err(err), + }; if let Some(init) = obj.typ().get_attr("__init__") { - let _ = vm.invoke(init, args.insert(obj.clone())).unwrap(); + match vm.invoke(init, args.insert(obj.clone())) { + Ok(res) => { + // TODO: assert that return is none? + if !isinstance(res, vm.get_none()) { + // panic!("__init__ must return none"); + // return Err(vm.new_type_error("__init__ must return None".to_string())); + } + } + Err(err) => return Err(err), + } } Ok(obj) } From 40cf7f4579f842e03abe86c88116d2f0dbd98569 Mon Sep 17 00:00:00 2001 From: Windel Bouwman Date: Sat, 1 Sep 2018 10:00:55 +0200 Subject: [PATCH 3/5] Move more objects to obj folder --- vm/src/lib.rs | 3 --- vm/src/obj/mod.rs | 3 +++ vm/src/{ => obj}/objfunction.rs | 4 ++-- vm/src/obj/objlist.rs | 2 +- vm/src/{ => obj}/objobject.rs | 8 ++++---- vm/src/{ => obj}/objsequence.rs | 4 ++-- vm/src/obj/objstr.rs | 2 +- vm/src/pyobject.rs | 4 ++-- vm/src/stdlib/json.rs | 4 ++-- vm/src/vm.rs | 4 ++-- 10 files changed, 19 insertions(+), 19 deletions(-) rename vm/src/{ => obj}/objfunction.rs (87%) rename vm/src/{ => obj}/objobject.rs (94%) rename vm/src/{ => obj}/objsequence.rs (96%) diff --git a/vm/src/lib.rs b/vm/src/lib.rs index b979ac9b0..a6d8f61de 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -22,9 +22,6 @@ mod frame; mod import; mod obj; mod objbool; -mod objfunction; -mod objobject; -mod objsequence; pub mod pyobject; pub mod stdlib; mod sysmodule; diff --git a/vm/src/obj/mod.rs b/vm/src/obj/mod.rs index fb1cad5ac..a5039ae02 100644 --- a/vm/src/obj/mod.rs +++ b/vm/src/obj/mod.rs @@ -1,7 +1,10 @@ pub mod objbytes; pub mod objdict; pub mod objfloat; +pub mod objfunction; pub mod objint; pub mod objlist; +pub mod objobject; +pub mod objsequence; pub mod objstr; pub mod objtype; diff --git a/vm/src/objfunction.rs b/vm/src/obj/objfunction.rs similarity index 87% rename from vm/src/objfunction.rs rename to vm/src/obj/objfunction.rs index 355754ec3..e6c165559 100644 --- a/vm/src/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -1,5 +1,5 @@ -use super::pyobject::{AttributeProtocol, PyContext, PyFuncArgs, PyResult}; -use super::vm::VirtualMachine; +use super::super::pyobject::{AttributeProtocol, PyContext, PyFuncArgs, PyResult}; +use super::super::vm::VirtualMachine; pub fn init(context: &PyContext) { let ref function_type = context.function_type; diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 983418271..2c1537a2c 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -1,8 +1,8 @@ -use super::super::objsequence::PySliceableSequence; use super::super::pyobject::{ AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol, }; use super::super::vm::VirtualMachine; +use super::objsequence::PySliceableSequence; use super::objstr; use super::objtype; diff --git a/vm/src/objobject.rs b/vm/src/obj/objobject.rs similarity index 94% rename from vm/src/objobject.rs rename to vm/src/obj/objobject.rs index 3dbcf388c..1de6cd83d 100644 --- a/vm/src/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -1,10 +1,10 @@ -use super::obj::objdict; -use super::obj::objtype; -use super::pyobject::{ +use super::super::pyobject::{ AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult, TypeProtocol, }; -use super::vm::VirtualMachine; +use super::super::vm::VirtualMachine; +use super::objdict; +use super::objtype; pub fn new_instance(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { // more or less __new__ operator diff --git a/vm/src/objsequence.rs b/vm/src/obj/objsequence.rs similarity index 96% rename from vm/src/objsequence.rs rename to vm/src/obj/objsequence.rs index 7647b0fcd..9005b5f58 100644 --- a/vm/src/objsequence.rs +++ b/vm/src/obj/objsequence.rs @@ -1,5 +1,5 @@ -use super::pyobject::{PyObject, PyObjectKind, PyObjectRef, PyResult}; -use super::vm::VirtualMachine; +use super::super::pyobject::{PyObject, PyObjectKind, PyObjectRef, PyResult}; +use super::super::vm::VirtualMachine; use std::marker::Sized; pub trait PySliceableSequence { diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 5c4976280..b64e862db 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -1,9 +1,9 @@ -use super::super::objsequence::PySliceableSequence; use super::super::pyobject::{ AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol, }; use super::super::vm::VirtualMachine; use super::objint; +use super::objsequence::PySliceableSequence; use super::objtype; pub fn init(context: &PyContext) { diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index c0bb6d1e4..2fbf025c8 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -3,13 +3,13 @@ use super::exceptions; use super::obj::objbytes; use super::obj::objdict; use super::obj::objfloat; +use super::obj::objfunction; use super::obj::objint; use super::obj::objlist; +use super::obj::objobject; use super::obj::objstr; use super::obj::objtype; use super::objbool; -use super::objfunction; -use super::objobject; use super::vm::VirtualMachine; use std::cell::RefCell; use std::cmp::Ordering; diff --git a/vm/src/stdlib/json.rs b/vm/src/stdlib/json.rs index c96f82522..63a2b296f 100644 --- a/vm/src/stdlib/json.rs +++ b/vm/src/stdlib/json.rs @@ -6,13 +6,13 @@ use serde::de::Visitor; use serde::ser::{SerializeMap, SerializeSeq}; use serde_json; -use super::super::obj::{objdict, objfloat, objint, objlist, objstr, objtype}; +use super::super::obj::{objdict, objfloat, objint, objlist, objsequence, objstr, objtype}; +use super::super::objbool; use super::super::pyobject::{ DictProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult, TypeProtocol, }; use super::super::VirtualMachine; -use super::super::{objbool, objsequence}; // We need to have a VM available to serialise a PyObject based on its subclass, so we implement // PyObject serialisation via a proxy object which holds a reference to a VM diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 22972c5ff..39c14ee20 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -16,10 +16,10 @@ use super::bytecode; use super::frame::{copy_code, Block, Frame}; use super::import::import; use super::obj::objlist; +use super::obj::objobject; use super::obj::objstr; use super::obj::objtype; use super::objbool; -use super::objobject; use super::pyobject::{ AttributeProtocol, DictProtocol, IdProtocol, ParentProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult, ToRust, @@ -296,7 +296,7 @@ impl VirtualMachine { match &a2.kind { PyObjectKind::String { ref value } => objstr::subscript(self, value, b), PyObjectKind::List { ref elements } | PyObjectKind::Tuple { ref elements } => { - super::objsequence::get_item(self, &a, elements, b) + super::obj::objsequence::get_item(self, &a, elements, b) } _ => Err(self.new_type_error(format!( "TypeError: indexing type {:?} with index {:?} is not supported (yet?)", From f563856dc49d1f064be8abb8503b1e9e190cd52c Mon Sep 17 00:00:00 2001 From: Windel Bouwman Date: Sat, 1 Sep 2018 10:19:51 +0200 Subject: [PATCH 4/5] Add some tuple class methods --- vm/src/obj/mod.rs | 1 + vm/src/obj/objbytes.rs | 5 ++--- vm/src/obj/objlist.rs | 21 ++++++++----------- vm/src/obj/objtuple.rs | 46 ++++++++++++++++++++++++++++++++++++++++++ vm/src/pyobject.rs | 4 ++-- vm/src/stdlib/json.rs | 2 +- 6 files changed, 60 insertions(+), 19 deletions(-) create mode 100644 vm/src/obj/objtuple.rs diff --git a/vm/src/obj/mod.rs b/vm/src/obj/mod.rs index a5039ae02..8dfa798ec 100644 --- a/vm/src/obj/mod.rs +++ b/vm/src/obj/mod.rs @@ -7,4 +7,5 @@ pub mod objlist; pub mod objobject; pub mod objsequence; pub mod objstr; +pub mod objtuple; pub mod objtype; diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs index 9aa4722d7..9ab541425 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -1,6 +1,5 @@ use super::super::pyobject::{ - AttributeProtocol, FromPyObjectRef, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, - TypeProtocol, + AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol, }; use super::super::vm::VirtualMachine; use super::objint; @@ -24,7 +23,7 @@ fn bytes_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { ); let val = if objtype::isinstance(arg.clone(), vm.ctx.list_type()) { let mut data_bytes = vec![]; - for elem in objlist::get_elements(arg.clone()) { + for elem in objlist::get_elements(arg) { let v = match objint::to_int(vm, &elem) { Ok(int_ref) => int_ref, Err(err) => return Err(err), diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 2c1537a2c..a66707647 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -26,7 +26,7 @@ pub fn set_item( } } -pub fn get_elements(obj: PyObjectRef) -> Vec { +pub fn get_elements(obj: &PyObjectRef) -> Vec { if let PyObjectKind::List { elements } = &obj.borrow().kind { elements.to_vec() } else { @@ -42,8 +42,8 @@ fn list_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { ); if objtype::isinstance(o2.clone(), vm.ctx.list_type()) { - let e1 = get_elements(o.clone()); - let e2 = get_elements(o2.clone()); + let e1 = get_elements(o); + let e2 = get_elements(o2); let elements = e1.iter().chain(e2.iter()).map(|e| e.clone()).collect(); Ok(vm.ctx.new_list(elements)) } else { @@ -54,7 +54,7 @@ fn list_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn list_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(o, Some(vm.ctx.list_type()))]); - let elements = get_elements(o.clone()); + let elements = get_elements(o); let mut str_parts = vec![]; for elem in elements { match vm.to_str(elem) { @@ -95,15 +95,10 @@ fn clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } -fn len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - trace!("list.len called with: {:?}", args); +fn list_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(list, Some(vm.ctx.list_type()))]); - let list_obj = list.borrow(); - if let PyObjectKind::List { ref elements } = list_obj.kind { - Ok(vm.context().new_int(elements.len() as i32)) - } else { - Err(vm.new_type_error("list.len is called with no list".to_string())) - } + let elements = get_elements(list); + Ok(vm.context().new_int(elements.len() as i32)) } fn reverse(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -121,7 +116,7 @@ fn reverse(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { pub fn init(context: &PyContext) { let ref list_type = context.list_type; list_type.set_attr("__add__", context.new_rustfunc(list_add)); - list_type.set_attr("__len__", context.new_rustfunc(len)); + list_type.set_attr("__len__", context.new_rustfunc(list_len)); list_type.set_attr("__str__", context.new_rustfunc(list_str)); list_type.set_attr("append", context.new_rustfunc(append)); list_type.set_attr("clear", context.new_rustfunc(clear)); diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs new file mode 100644 index 000000000..8463f831c --- /dev/null +++ b/vm/src/obj/objtuple.rs @@ -0,0 +1,46 @@ +use super::super::pyobject::{ + AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol, +}; +use super::super::vm::VirtualMachine; +use super::objstr; +use super::objtype; + +fn tuple_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(o, Some(vm.ctx.tuple_type()))]); + + let elements = get_elements(o); + let mut str_parts = vec![]; + for elem in elements { + match vm.to_str(elem) { + Ok(s) => str_parts.push(objstr::get_value(&s)), + Err(err) => return Err(err), + } + } + + let s = if str_parts.len() == 1 { + format!("({},)", str_parts.join(", ")) + } else { + format!("({})", str_parts.join(", ")) + }; + Ok(vm.new_str(s)) +} + +pub fn get_elements(obj: &PyObjectRef) -> Vec { + if let PyObjectKind::List { elements } = &obj.borrow().kind { + elements.to_vec() + } else { + panic!("Cannot extract elements from non-tuple"); + } +} + +fn tuple_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(tuple, Some(vm.ctx.tuple_type()))]); + let elements = get_elements(tuple); + Ok(vm.context().new_int(elements.len() as i32)) +} + +pub fn init(context: &PyContext) { + let ref tuple_type = context.tuple_type; + tuple_type.set_attr("__len__", context.new_rustfunc(tuple_len)); + tuple_type.set_attr("__str__", context.new_rustfunc(tuple_str)); +} diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 2fbf025c8..a2b9cf92a 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -8,6 +8,7 @@ use super::obj::objint; use super::obj::objlist; use super::obj::objobject; use super::obj::objstr; +use super::obj::objtuple; use super::obj::objtype; use super::objbool; use super::vm::VirtualMachine; @@ -152,10 +153,9 @@ impl PyContext { objfloat::init(&context); objbytes::init(&context); objstr::init(&context); + objtuple::init(&context); objbool::init(&context); exceptions::init(&context); - // TODO: create exception hierarchy here? - // exceptions::create_zoo(&context); context } diff --git a/vm/src/stdlib/json.rs b/vm/src/stdlib/json.rs index 63a2b296f..39908a0ad 100644 --- a/vm/src/stdlib/json.rs +++ b/vm/src/stdlib/json.rs @@ -52,7 +52,7 @@ impl<'s> serde::Serialize for PyObjectSerializer<'s> { } else if objtype::isinstance(self.pyobject.clone(), self.vm.ctx.bool_type()) { serializer.serialize_bool(objbool::get_value(self.pyobject)) } else if objtype::isinstance(self.pyobject.clone(), self.vm.ctx.list_type()) { - let elements = objlist::get_elements(self.pyobject.clone()); + let elements = objlist::get_elements(self.pyobject); serialize_seq_elements(serializer, elements) } else if objtype::isinstance(self.pyobject.clone(), self.vm.ctx.tuple_type()) { let elements = objsequence::get_elements(self.pyobject.clone()); From bcf5e8acc9fdcfec8991f353b724357d9cb1b97c Mon Sep 17 00:00:00 2001 From: Windel Bouwman Date: Sat, 1 Sep 2018 10:37:25 +0200 Subject: [PATCH 5/5] Repair tuple get elements --- vm/src/obj/objtuple.rs | 2 +- vm/src/pyobject.rs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs index 8463f831c..875f26bfa 100644 --- a/vm/src/obj/objtuple.rs +++ b/vm/src/obj/objtuple.rs @@ -26,7 +26,7 @@ fn tuple_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn get_elements(obj: &PyObjectRef) -> Vec { - if let PyObjectKind::List { elements } = &obj.borrow().kind { + if let PyObjectKind::Tuple { elements } = &obj.borrow().kind { elements.to_vec() } else { panic!("Cannot extract elements from non-tuple"); diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index a2b9cf92a..363b9ecdd 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -785,11 +785,6 @@ impl PartialEq for PyObject { (PyObjectKind::String { value: ref v1i }, PyObjectKind::String { value: ref v2i }) => { *v2i == *v1i } - /* - (&NativeType::Float(ref v1f), &NativeType::Float(ref v2f)) => { - curr_frame.stack.push(Rc::new(NativeType::Boolean(v2f == v1f))); - }, - */ (PyObjectKind::List { elements: ref l1 }, PyObjectKind::List { elements: ref l2 }) | ( PyObjectKind::Tuple { elements: ref l1 },