From ea347dfdeca1c7548513ad8deb89c6b66810cfe1 Mon Sep 17 00:00:00 2001 From: "Y. Sapir" Date: Fri, 3 May 2019 01:04:52 +0300 Subject: [PATCH] Implement bool.__or__, __and__ and __xor__ --- tests/snippets/bools.py | 12 ++++++++++++ vm/src/obj/objbool.rs | 39 +++++++++++++++++++++++++++++++++++++++ vm/src/obj/objint.rs | 6 +++--- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/tests/snippets/bools.py b/tests/snippets/bools.py index 0c277143b..b781668b6 100644 --- a/tests/snippets/bools.py +++ b/tests/snippets/bools.py @@ -51,3 +51,15 @@ assert True > 0 assert int(True) == 1 assert True.conjugate() == 1 assert isinstance(True.conjugate(), int) + +# Boolean operations on pairs of Bools should return Bools, not ints +assert (False | True) is True +assert (False & True) is False +assert (False ^ True) is True +# But only if both are Bools +assert (False | 1) is not True +assert (0 | True) is not True +assert (False & 1) is not False +assert (0 & True) is not False +assert (False ^ 1) is not True +assert (0 ^ True) is not True diff --git a/vm/src/obj/objbool.rs b/vm/src/obj/objbool.rs index 724c8bc5a..e96324f67 100644 --- a/vm/src/obj/objbool.rs +++ b/vm/src/obj/objbool.rs @@ -42,6 +42,9 @@ The class bool is a subclass of the class int, and cannot be subclassed."; extend_class!(context, bool_type, { "__new__" => context.new_rustfunc(bool_new), "__repr__" => context.new_rustfunc(bool_repr), + "__or__" => context.new_rustfunc(bool_or), + "__and__" => context.new_rustfunc(bool_and), + "__xor__" => context.new_rustfunc(bool_xor), "__doc__" => context.new_str(bool_doc.to_string()) }); } @@ -71,6 +74,42 @@ fn bool_repr(vm: &VirtualMachine, args: PyFuncArgs) -> Result Result { + arg_check!(vm, args, required = [(lhs, None), (rhs, None)]); + + if objtype::isinstance(lhs, &vm.ctx.bool_type()) && objtype::isinstance(rhs, &vm.ctx.bool_type()) { + let lhs = get_value(lhs); + let rhs = get_value(rhs); + (lhs || rhs).into_pyobject(vm) + } else { + Ok(lhs.payload::().unwrap().or(rhs.clone(), vm)) + } +} + +fn bool_and(vm: &VirtualMachine, args: PyFuncArgs) -> Result { + arg_check!(vm, args, required = [(lhs, None), (rhs, None)]); + + if objtype::isinstance(lhs, &vm.ctx.bool_type()) && objtype::isinstance(rhs, &vm.ctx.bool_type()) { + let lhs = get_value(lhs); + let rhs = get_value(rhs); + (lhs && rhs).into_pyobject(vm) + } else { + Ok(lhs.payload::().unwrap().and(rhs.clone(), vm)) + } +} + +fn bool_xor(vm: &VirtualMachine, args: PyFuncArgs) -> Result { + arg_check!(vm, args, required = [(lhs, None), (rhs, None)]); + + if objtype::isinstance(lhs, &vm.ctx.bool_type()) && objtype::isinstance(rhs, &vm.ctx.bool_type()) { + let lhs = get_value(lhs); + let rhs = get_value(rhs); + (lhs ^ rhs).into_pyobject(vm) + } else { + Ok(lhs.payload::().unwrap().xor(rhs.clone(), vm)) + } +} + fn bool_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index fdb0459af..1b728a53f 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -286,7 +286,7 @@ impl PyInt { } #[pymethod(name = "__xor__")] - fn xor(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { + pub fn xor(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { if objtype::isinstance(&other, &vm.ctx.int_type()) { vm.ctx.new_int((&self.value) ^ get_value(&other)) } else { @@ -300,7 +300,7 @@ impl PyInt { } #[pymethod(name = "__or__")] - fn or(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { + pub fn or(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { if objtype::isinstance(&other, &vm.ctx.int_type()) { vm.ctx.new_int((&self.value) | get_value(&other)) } else { @@ -309,7 +309,7 @@ impl PyInt { } #[pymethod(name = "__and__")] - fn and(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { + pub fn and(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { if objtype::isinstance(&other, &vm.ctx.int_type()) { let v2 = get_value(&other); vm.ctx.new_int((&self.value) & v2)