From 26306b528f513efc849c2f031c90f7efd99e8cda Mon Sep 17 00:00:00 2001 From: "Y. Sapir" Date: Fri, 3 May 2019 01:38:32 +0300 Subject: [PATCH 1/4] Simplify PyInt.rxor to reuse PyInt.xor --- vm/src/obj/objint.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index 3687ed2b0..fdb0459af 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -296,11 +296,7 @@ impl PyInt { #[pymethod(name = "__rxor__")] fn rxor(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { - if objtype::isinstance(&other, &vm.ctx.int_type()) { - vm.ctx.new_int(get_value(&other) ^ (&self.value)) - } else { - vm.ctx.not_implemented() - } + self.xor(other, vm) } #[pymethod(name = "__or__")] From ea347dfdeca1c7548513ad8deb89c6b66810cfe1 Mon Sep 17 00:00:00 2001 From: "Y. Sapir" Date: Fri, 3 May 2019 01:04:52 +0300 Subject: [PATCH 2/4] 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) From 6f66e8440dca8f96c1fb45723e8c4342b209276a Mon Sep 17 00:00:00 2001 From: "Y. Sapir" Date: Fri, 3 May 2019 01:41:52 +0300 Subject: [PATCH 3/4] Add tests for return type of bool.__or__ etc. --- tests/snippets/bools.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/snippets/bools.py b/tests/snippets/bools.py index b781668b6..23f22dce7 100644 --- a/tests/snippets/bools.py +++ b/tests/snippets/bools.py @@ -63,3 +63,17 @@ assert (False & 1) is not False assert (0 & True) is not False assert (False ^ 1) is not True assert (0 ^ True) is not True + +# Check that the same works with __XXX__ methods +assert False.__or__(0) is not False +assert False.__or__(False) is False +assert False.__ror__(0) is not False +assert False.__ror__(False) is False +assert False.__and__(0) is not False +assert False.__and__(False) is False +assert False.__rand__(0) is not False +assert False.__rand__(False) is False +assert False.__xor__(0) is not False +assert False.__xor__(False) is False +assert False.__rxor__(0) is not False +assert False.__rxor__(False) is False From 45d7c383cdbffd29d7b42fbed6680b5bee13fd61 Mon Sep 17 00:00:00 2001 From: "Y. Sapir" Date: Fri, 3 May 2019 01:54:10 +0300 Subject: [PATCH 4/4] Implement bool.__ror__, __rand__ and __rxor__ --- vm/src/obj/objbool.rs | 49 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/vm/src/obj/objbool.rs b/vm/src/obj/objbool.rs index e96324f67..c1a999e45 100644 --- a/vm/src/obj/objbool.rs +++ b/vm/src/obj/objbool.rs @@ -43,8 +43,11 @@ The class bool is a subclass of the class int, and cannot be subclassed."; "__new__" => context.new_rustfunc(bool_new), "__repr__" => context.new_rustfunc(bool_repr), "__or__" => context.new_rustfunc(bool_or), + "__ror__" => context.new_rustfunc(bool_ror), "__and__" => context.new_rustfunc(bool_and), + "__rand__" => context.new_rustfunc(bool_rand), "__xor__" => context.new_rustfunc(bool_xor), + "__rxor__" => context.new_rustfunc(bool_rxor), "__doc__" => context.new_str(bool_doc.to_string()) }); } @@ -74,10 +77,10 @@ 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()) { +fn do_bool_or(vm: &VirtualMachine, lhs: &PyObjectRef, rhs: &PyObjectRef) -> PyResult { + 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) @@ -86,10 +89,20 @@ fn bool_or(vm: &VirtualMachine, args: PyFuncArgs) -> Result Result { +fn bool_or(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(lhs, None), (rhs, None)]); + do_bool_or(vm, lhs, rhs) +} - if objtype::isinstance(lhs, &vm.ctx.bool_type()) && objtype::isinstance(rhs, &vm.ctx.bool_type()) { +fn bool_ror(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(rhs, None), (lhs, None)]); + do_bool_or(vm, lhs, rhs) +} + +fn do_bool_and(vm: &VirtualMachine, lhs: &PyObjectRef, rhs: &PyObjectRef) -> PyResult { + 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) @@ -98,10 +111,20 @@ fn bool_and(vm: &VirtualMachine, args: PyFuncArgs) -> Result Result { +fn bool_and(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(lhs, None), (rhs, None)]); + do_bool_and(vm, lhs, rhs) +} - if objtype::isinstance(lhs, &vm.ctx.bool_type()) && objtype::isinstance(rhs, &vm.ctx.bool_type()) { +fn bool_rand(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(rhs, None), (lhs, None)]); + do_bool_and(vm, lhs, rhs) +} + +fn do_bool_xor(vm: &VirtualMachine, lhs: &PyObjectRef, rhs: &PyObjectRef) -> PyResult { + 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) @@ -110,6 +133,16 @@ fn bool_xor(vm: &VirtualMachine, args: PyFuncArgs) -> Result PyResult { + arg_check!(vm, args, required = [(lhs, None), (rhs, None)]); + do_bool_xor(vm, lhs, rhs) +} + +fn bool_rxor(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(rhs, None), (lhs, None)]); + do_bool_xor(vm, lhs, rhs) +} + fn bool_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm,