Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions tests/snippets/bools.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,29 @@ def __bool__(self):
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

# 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
72 changes: 72 additions & 0 deletions vm/src/obj/objbool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ 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),
"__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())
});
}
Expand Down Expand Up @@ -71,6 +77,72 @@ fn bool_repr(vm: &VirtualMachine, args: PyFuncArgs) -> Result<PyObjectRef, PyObj
Ok(vm.new_str(s))
}

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)
} else {
Ok(lhs.payload::<PyInt>().unwrap().or(rhs.clone(), vm))
}
}

fn bool_or(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(lhs, None), (rhs, None)]);
do_bool_or(vm, lhs, rhs)
}

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)
} else {
Ok(lhs.payload::<PyInt>().unwrap().and(rhs.clone(), vm))
}
}

fn bool_and(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(lhs, None), (rhs, None)]);
do_bool_and(vm, lhs, rhs)
}

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)
} else {
Ok(lhs.payload::<PyInt>().unwrap().xor(rhs.clone(), vm))
}
}

fn bool_xor(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method seems duplicate with the one marked by pymethod in the class. There are at this point several styles to define object methods. The latest and the way to go is to use the pymethod markers on the class. If you mark a method as such, it will be available on the object if you use PyBool::extend_class. objint.rs is a good example file where this is used.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, ignore my comment :). I was not aware that also objint.rs was modified.

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,
Expand Down
12 changes: 4 additions & 8 deletions vm/src/obj/objint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -296,15 +296,11 @@ 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__")]
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 {
Expand All @@ -313,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)
Expand Down