diff --git a/tests/snippets/basic_types.py b/tests/snippets/basic_types.py index 8944b1355..b9dc22b27 100644 --- a/tests/snippets/basic_types.py +++ b/tests/snippets/basic_types.py @@ -25,3 +25,11 @@ 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) +try: + bytes([object()]) +except TypeError: + pass + diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 13c794d45..d52ae44a9 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/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 36c28bd50..8dfa798ec 100644 --- a/vm/src/obj/mod.rs +++ b/vm/src/obj/mod.rs @@ -1,6 +1,11 @@ +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 objtuple; pub mod objtype; diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs new file mode 100644 index 000000000..9ab541425 --- /dev/null +++ b/vm/src/obj/objbytes.rs @@ -0,0 +1,59 @@ +use super::super::pyobject::{ + AttributeProtocol, 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()) { + let mut data_bytes = vec![]; + 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), + }; + data_bytes.push(v as u8); + } + data_bytes + } else { + return Err(vm.new_type_error("Cannot construct bytes".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/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/objint.rs b/vm/src/obj/objint.rs index f617fd1ae..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: @@ -142,15 +154,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/obj/objlist.rs b/vm/src/obj/objlist.rs index 983418271..a66707647 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; @@ -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/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/obj/objtuple.rs b/vm/src/obj/objtuple.rs new file mode 100644 index 000000000..875f26bfa --- /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::Tuple { 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/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) } diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index d0501f8d5..363b9ecdd 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -1,14 +1,16 @@ use super::bytecode; 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::objtuple; 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; @@ -52,6 +54,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 +117,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 +130,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,11 +151,11 @@ impl PyContext { objfunction::init(&context); objint::init(&context); 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 } @@ -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() } @@ -556,6 +565,9 @@ pub enum PyObjectKind { Boolean { value: bool, }, + Bytes { + value: Vec, + }, List { elements: Vec, }, @@ -613,6 +625,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"), @@ -660,6 +673,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!( "[{}]", @@ -771,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 }, diff --git a/vm/src/stdlib/json.rs b/vm/src/stdlib/json.rs index c96f82522..39908a0ad 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 @@ -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()); diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 7563c5812..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?)", @@ -367,6 +367,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(); @@ -380,6 +392,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 {