Binary ops with number protocol (partially imported)

from #4139 https://github.com/RustPython/RustPython/pull/4139
This commit is contained in:
Karatus authored and Zhiyan Xiao committed 2023-03-09 21:33:25 +09:00
1 parent 1fceeab0fc
commit 13d715e2a5
4 files changed
+490 -181

No files matched your search

+1 -1
View File
@@ -10,5 +10,5 @@ pub use buffer::{BufferDescriptor, BufferMethods, BufferResizeGuard, PyBuffer, V
pub use callable::PyCallable;
pub use iter::{PyIter, PyIterIter, PyIterReturn};
pub use mapping::{PyMapping, PyMappingMethods};
pub use number::{PyNumber, PyNumberMethods};
pub use number::{PyNumber, PyNumberMethods, PyNumberMethodsOffset};
pub use sequence::{PySequence, PySequenceMethods};
+104 -6
View File
@@ -8,6 +8,7 @@ use crate::{
VirtualMachine,
};
use crossbeam_utils::atomic::AtomicCell;
use std::ptr;
type UnaryFunc<R = PyObjectRef> = AtomicCell<Option<fn(PyNumber, &VirtualMachine) -> PyResult<R>>>;
type BinaryFunc<R = PyObjectRef> =
@@ -109,6 +110,7 @@ impl PyObject {
}
#[derive(Default)]
// #[repr(C)]
pub struct PyNumberMethods {
/* Number implementations must check *both*
arguments for proper type and implement the necessary conversions
@@ -199,6 +201,98 @@ impl PyNumberMethods {
};
}
pub enum PyNumberMethodsOffset {
Add,
Subtract,
Multiply,
Remainder,
Divmod,
Power,
Negative,
Positive,
Absolute,
Boolean,
Invert,
Lshift,
Rshift,
And,
Xor,
Or,
Int,
Float,
InplaceAdd,
InplaceSubtract,
InplaceMultiply,
InplaceRemainder,
InplaceDivmod,
InplacePower,
InplaceLshift,
InplaceRshift,
InplaceAnd,
InplaceXor,
InplaceOr,
FloorDivide,
TrueDivide,
InplaceFloorDivide,
InplaceTrueDivide,
Index,
MatrixMultiply,
InplaceMatrixMultiply,
}
impl PyNumberMethodsOffset {
pub fn method(&self, methods: &PyNumberMethods, vm: &VirtualMachine) -> PyResult<&BinaryFunc> {
use PyNumberMethodsOffset::*;
unsafe {
match self {
// BinaryFunc
Add => ptr::addr_of!(methods.add),
Subtract => ptr::addr_of!(methods.subtract),
Multiply => ptr::addr_of!(methods.multiply),
Remainder => ptr::addr_of!(methods.remainder),
Divmod => ptr::addr_of!(methods.divmod),
Power => ptr::addr_of!(methods.power),
Lshift => ptr::addr_of!(methods.lshift),
Rshift => ptr::addr_of!(methods.rshift),
And => ptr::addr_of!(methods.and),
Xor => ptr::addr_of!(methods.xor),
Or => ptr::addr_of!(methods.or),
InplaceAdd => ptr::addr_of!(methods.inplace_add),
InplaceSubtract => ptr::addr_of!(methods.inplace_subtract),
InplaceMultiply => ptr::addr_of!(methods.inplace_multiply),
InplaceRemainder => ptr::addr_of!(methods.inplace_remainder),
InplaceDivmod => ptr::addr_of!(methods.inplace_divmod),
InplacePower => ptr::addr_of!(methods.inplace_power),
InplaceLshift => ptr::addr_of!(methods.inplace_lshift),
InplaceRshift => ptr::addr_of!(methods.inplace_rshift),
InplaceAnd => ptr::addr_of!(methods.inplace_and),
InplaceXor => ptr::addr_of!(methods.inplace_xor),
InplaceOr => ptr::addr_of!(methods.inplace_or),
FloorDivide => ptr::addr_of!(methods.floor_divide),
TrueDivide => ptr::addr_of!(methods.true_divide),
InplaceFloorDivide => ptr::addr_of!(methods.inplace_floor_divide),
InplaceTrueDivide => ptr::addr_of!(methods.inplace_true_divide),
MatrixMultiply => ptr::addr_of!(methods.matrix_multiply),
InplaceMatrixMultiply => ptr::addr_of!(methods.inplace_matrix_multiply),
// UnaryFunc
Negative => ptr::null(),
Positive => ptr::null(),
Absolute => ptr::null(),
Boolean => ptr::null(),
Invert => ptr::null(),
Int => ptr::null(),
Float => ptr::null(),
Index => ptr::null(),
}
.as_ref()
.ok_or_else(|| {
vm.new_value_error("No unaryop supported for PyNumberMethodsOffset".to_owned())
})
}
}
}
#[derive(Copy, Clone)]
pub struct PyNumber<'a> {
pub obj: &'a PyObject,
methods: &'a PyNumberMethods,
@@ -220,8 +314,12 @@ impl PyNumber<'_> {
obj.class().mro_find_map(|x| x.slots.as_number.load())
}
pub fn methods(&self) -> &PyNumberMethods {
self.methods
pub fn methods<'a>(
&'a self,
op_slot: &'a PyNumberMethodsOffset,
vm: &VirtualMachine,
) -> PyResult<&BinaryFunc> {
op_slot.method(self.methods, vm)
}
// PyNumber_Check
@@ -238,12 +336,12 @@ impl PyNumber<'_> {
// PyIndex_Check
pub fn is_index(&self) -> bool {
self.methods().index.load().is_some()
self.methods.index.load().is_some()
}
#[inline]
pub fn int(self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
self.methods().int.load().map(|f| {
self.methods.int.load().map(|f| {
let ret = f(self, vm)?;
let value = if !ret.class().is(PyInt::class(vm)) {
warnings::warn(
@@ -267,7 +365,7 @@ impl PyNumber<'_> {
#[inline]
pub fn index(self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
self.methods().index.load().map(|f| {
self.methods.index.load().map(|f| {
let ret = f(self, vm)?;
let value = if !ret.class().is(PyInt::class(vm)) {
warnings::warn(
@@ -291,7 +389,7 @@ impl PyNumber<'_> {
#[inline]
pub fn float(self, vm: &VirtualMachine) -> Option<PyResult<PyRef<PyFloat>>> {
self.methods().float.load().map(|f| {
self.methods.float.load().map(|f| {
let ret = f(self, vm)?;
let value = if !ret.class().is(PyFloat::class(vm)) {
warnings::warn(
+4 -8
View File
@@ -21,7 +21,7 @@ mod builtins {
ArgBytesLike, ArgCallable, ArgIntoBool, ArgIterable, ArgMapping, ArgStrOrBytesLike,
Either, FuncArgs, KwArgs, OptionalArg, OptionalOption, PosArgs, PyArithmeticValue,
},
protocol::{PyIter, PyIterReturn},
protocol::{PyIter, PyIterReturn, PyNumberMethodsOffset},
py_io,
readline::{Readline, ReadlineResult},
stdlib::sys,
@@ -605,13 +605,9 @@ mod builtins {
modulus,
} = args;
match modulus {
None => vm.call_or_reflection(
&x,
&y,
identifier!(vm, __pow__),
identifier!(vm, __rpow__),
|vm, x, y| Err(vm.new_unsupported_binop_error(x, y, "pow")),
),
None => vm.binary_op(&x, &y, PyNumberMethodsOffset::Power, "pow", |vm, _, _| {
Ok(vm.ctx.not_implemented())
}),
Some(z) => {
let try_pow_value = |obj: &PyObject,
args: (PyObjectRef, PyObjectRef, PyObjectRef)|
+381 -166
View File
@@ -3,9 +3,10 @@ use crate::{
builtins::{PyInt, PyIntRef, PyStr, PyStrInterned, PyStrRef},
function::PyArithmeticValue,
object::{AsObject, PyObject, PyObjectRef, PyResult},
protocol::PyIterReturn,
protocol::{PyIterReturn, PyNumberMethodsOffset, PySequence},
types::PyComparisonOp,
};
use num_traits::ToPrimitive;
/// Collection of operators
impl VirtualMachine {
@@ -103,6 +104,7 @@ impl VirtualMachine {
}
}
// TODO: Should be deleted after transplanting complete number protocol
/// Calls a method on `obj` passing `arg`, if the method exists.
///
/// Otherwise, or if the result is the special `NotImplemented` built-in constant,
@@ -128,6 +130,7 @@ impl VirtualMachine {
unsupported(self, obj, arg)
}
// TODO: Should be deleted after transplanting complete number protocol
/// Calls a method, falling back to its reflection with the operands
/// reversed, and then to the value provided by `unsupported`.
///
@@ -174,160 +177,348 @@ impl VirtualMachine {
})
}
pub fn _sub(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
a,
b,
identifier!(self, __sub__),
identifier!(self, __rsub__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "-")),
)
fn binary_op1<F>(
&self,
a: &PyObject,
b: &PyObject,
op_slot: PyNumberMethodsOffset,
unsupported: F,
) -> PyResult
where
F: Fn(&VirtualMachine, &PyObject, &PyObject) -> PyResult,
{
let num_a = a.to_number();
let num_b = b.to_number();
let slot_a = num_a.methods(&op_slot, self)?.load();
let slot_b = num_b.methods(&op_slot, self)?.load();
if let Some(slot_a) = slot_a {
if let Some(slot_b) = slot_b {
// Check if `a` is subclass of `b`
if b.fast_isinstance(a.class()) {
let ret = slot_b(num_a, b, self)?;
if ret.rich_compare_bool(
self.ctx.not_implemented.as_object(),
PyComparisonOp::Ne,
self,
)? {
return Ok(ret);
}
}
}
let ret = slot_a(num_a, b, self)?;
if ret.rich_compare_bool(
self.ctx.not_implemented.as_object(),
PyComparisonOp::Ne,
self,
)? {
return Ok(ret);
}
}
// No slot_a or Not implemented
if let Some(slot_b) = slot_b {
let ret = slot_b(num_a, b, self)?;
if ret.rich_compare_bool(
self.ctx.not_implemented.as_object(),
PyComparisonOp::Ne,
self,
)? {
return Ok(ret);
}
}
// Both slot_a & slot_b don't exist or are not implemented.
unsupported(self, a, b)
}
pub fn _isub(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_unsupported(a, b, identifier!(self, __isub__), |vm, a, b| {
vm.call_or_reflection(
a,
b,
identifier!(self, __sub__),
identifier!(self, __rsub__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "-=")),
)
})
/// `binary_op()` can work only with [`PyNumberMethods::BinaryFunc`].
pub fn binary_op<F>(
&self,
a: &PyObject,
b: &PyObject,
op_slot: PyNumberMethodsOffset,
op: &str,
unsupported: F,
) -> PyResult
where
F: Fn(&VirtualMachine, &PyObject, &PyObject) -> PyResult,
{
let result = self.binary_op1(a, b, op_slot, unsupported)?;
if result.rich_compare_bool(
self.ctx.not_implemented.as_object(),
PyComparisonOp::Eq,
self,
)? {
Err(self.new_unsupported_binop_error(a, b, op))
} else {
Ok(result)
}
}
/// ### Binary in-place operators
///
/// The in-place operators are defined to fall back to the 'normal',
/// non in-place operations, if the in-place methods are not in place.
///
/// - If the left hand object has the appropriate struct members, and
/// they are filled, call the appropriate function and return the
/// result. No coercion is done on the arguments; the left-hand object
/// is the one the operation is performed on, and it's up to the
/// function to deal with the right-hand object.
///
/// - Otherwise, in-place modification is not supported. Handle it exactly as
/// a non in-place operation of the same kind.
fn binary_iop1<F>(
&self,
a: &PyObject,
b: &PyObject,
iop_slot: PyNumberMethodsOffset,
op_slot: PyNumberMethodsOffset,
unsupported: F,
) -> PyResult
where
F: Fn(&VirtualMachine, &PyObject, &PyObject) -> PyResult,
{
let num_a = a.to_number();
let slot_a = num_a.methods(&iop_slot, self)?.load();
if let Some(slot_a) = slot_a {
let ret = slot_a(num_a, b, self)?;
if ret.rich_compare_bool(
self.ctx.not_implemented.as_object(),
PyComparisonOp::Ne,
self,
)? {
return Ok(ret);
}
}
self.binary_op1(a, b, op_slot, unsupported)
}
/// `binary_iop()` can work only with [`PyNumberMethods::BinaryFunc`].
fn binary_iop<F>(
&self,
a: &PyObject,
b: &PyObject,
iop_slot: PyNumberMethodsOffset,
op_slot: PyNumberMethodsOffset,
op: &str,
unsupported: F,
) -> PyResult
where
F: Fn(&VirtualMachine, &PyObject, &PyObject) -> PyResult,
{
let result = self.binary_iop1(a, b, iop_slot, op_slot, unsupported)?;
if result.rich_compare_bool(
self.ctx.not_implemented.as_object(),
PyComparisonOp::Eq,
self,
)? {
Err(self.new_unsupported_binop_error(a, b, op))
} else {
Ok(result)
}
}
pub fn _add(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
a,
b,
identifier!(self, __add__),
identifier!(self, __radd__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "+")),
)
self.binary_op(a, b, PyNumberMethodsOffset::Add, "+", |vm, a, b| {
let seq_a = PySequence::try_protocol(a, vm);
if let Ok(seq_a) = seq_a {
let ret = seq_a.concat(b, vm)?;
if ret.rich_compare_bool(
vm.ctx.not_implemented.as_object(),
PyComparisonOp::Ne,
vm,
)? {
return Ok(ret);
}
}
Ok(vm.ctx.not_implemented())
})
}
pub fn _iadd(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_unsupported(a, b, identifier!(self, __iadd__), |vm, a, b| {
vm.call_or_reflection(
a,
b,
identifier!(self, __add__),
identifier!(self, __radd__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "+=")),
)
})
}
pub fn _mul(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
self.binary_iop(
a,
b,
identifier!(self, __mul__),
identifier!(self, __rmul__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "*")),
PyNumberMethodsOffset::InplaceAdd,
PyNumberMethodsOffset::Add,
"+=",
|vm, a, b| {
let seq_a = PySequence::try_protocol(a, vm);
if let Ok(seq_a) = seq_a {
return seq_a.inplace_concat(b, vm);
}
Ok(vm.ctx.not_implemented())
},
)
}
pub fn _imul(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_unsupported(a, b, identifier!(self, __imul__), |vm, a, b| {
vm.call_or_reflection(
a,
b,
identifier!(self, __mul__),
identifier!(self, __rmul__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "*=")),
)
pub fn _sub(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.binary_op(a, b, PyNumberMethodsOffset::Subtract, "-", |vm, _, _| {
Ok(vm.ctx.not_implemented())
})
}
pub fn _matmul(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
pub fn _isub(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.binary_iop(
a,
b,
identifier!(self, __matmul__),
identifier!(self, __rmatmul__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "@")),
PyNumberMethodsOffset::InplaceSubtract,
PyNumberMethodsOffset::Subtract,
"-=",
|vm, _, _| Ok(vm.ctx.not_implemented()),
)
}
pub fn _mul(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.binary_op(a, b, PyNumberMethodsOffset::Multiply, "*", |vm, a, b| {
// TODO: check if PySequence::with_methods can replace try_protocol
let seq_a = PySequence::try_protocol(a, vm);
let seq_b = PySequence::try_protocol(b, vm);
// TODO: I think converting to isize process should be handled in repeat function.
// TODO: This can be helpful to unify the sequence protocol's closure.
if let Ok(seq_a) = seq_a {
let n = b.try_int(vm)?.as_bigint().to_isize().ok_or_else(|| {
vm.new_overflow_error("repeated bytes are too long".to_owned())
})?;
return seq_a.repeat(n, vm);
} else if let Ok(seq_b) = seq_b {
let n = a.try_int(vm)?.as_bigint().to_isize().ok_or_else(|| {
vm.new_overflow_error("repeated bytes are too long".to_owned())
})?;
return seq_b.repeat(n, vm);
}
Ok(vm.ctx.not_implemented())
})
}
pub fn _imul(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.binary_iop(
a,
b,
PyNumberMethodsOffset::InplaceMultiply,
PyNumberMethodsOffset::Multiply,
"*=",
|vm, a, b| {
// TODO: check if PySequence::with_methods can replace try_protocol
let seq_a = PySequence::try_protocol(a, vm);
let seq_b = PySequence::try_protocol(b, vm);
if let Ok(seq_a) = seq_a {
let n = b.try_int(vm)?.as_bigint().to_isize().ok_or_else(|| {
vm.new_overflow_error("repeated bytes are too long".to_owned())
})?;
return seq_a.inplace_repeat(n, vm);
} else if let Ok(seq_b) = seq_b {
let n = a.try_int(vm)?.as_bigint().to_isize().ok_or_else(|| {
vm.new_overflow_error("repeated bytes are too long".to_owned())
})?;
/* Note that the right hand operand should not be
* mutated in this case so sq_inplace_repeat is not
* used. */
return seq_b.repeat(n, vm);
}
Ok(vm.ctx.not_implemented())
},
)
}
pub fn _matmul(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.binary_op(
a,
b,
PyNumberMethodsOffset::MatrixMultiply,
"@",
|vm, _, _| Ok(vm.ctx.not_implemented()),
)
}
pub fn _imatmul(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_unsupported(a, b, identifier!(self, __imatmul__), |vm, a, b| {
vm.call_or_reflection(
a,
b,
identifier!(self, __matmul__),
identifier!(self, __rmatmul__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "@=")),
)
})
}
pub fn _truediv(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
self.binary_iop(
a,
b,
identifier!(self, __truediv__),
identifier!(self, __rtruediv__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "/")),
PyNumberMethodsOffset::InplaceMatrixMultiply,
PyNumberMethodsOffset::MatrixMultiply,
"@=",
|vm, _, _| Ok(vm.ctx.not_implemented()),
)
}
pub fn _itruediv(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_unsupported(a, b, identifier!(self, __itruediv__), |vm, a, b| {
vm.call_or_reflection(
a,
b,
identifier!(self, __truediv__),
identifier!(self, __rtruediv__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "/=")),
)
pub fn _truediv(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.binary_op(a, b, PyNumberMethodsOffset::TrueDivide, "/", |vm, _, _| {
Ok(vm.ctx.not_implemented())
})
}
pub fn _floordiv(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
pub fn _itruediv(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.binary_iop(
a,
b,
identifier!(self, __floordiv__),
identifier!(self, __rfloordiv__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "//")),
PyNumberMethodsOffset::InplaceTrueDivide,
PyNumberMethodsOffset::TrueDivide,
"/=",
|vm, _, _| Ok(vm.ctx.not_implemented()),
)
}
pub fn _floordiv(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.binary_op(
a,
b,
PyNumberMethodsOffset::FloorDivide,
"//",
|vm, _, _| Ok(vm.ctx.not_implemented()),
)
}
pub fn _ifloordiv(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_unsupported(a, b, identifier!(self, __ifloordiv__), |vm, a, b| {
vm.call_or_reflection(
a,
b,
identifier!(self, __floordiv__),
identifier!(self, __rfloordiv__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "//=")),
)
})
}
pub fn _pow(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
self.binary_iop(
a,
b,
identifier!(self, __pow__),
identifier!(self, __rpow__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "**")),
PyNumberMethodsOffset::InplaceFloorDivide,
PyNumberMethodsOffset::FloorDivide,
"//=",
|vm, _, _| Ok(vm.ctx.not_implemented()),
)
}
pub fn _ipow(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_unsupported(a, b, identifier!(self, __ipow__), |vm, a, b| {
vm.call_or_reflection(
a,
b,
identifier!(self, __pow__),
identifier!(self, __rpow__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "**=")),
)
pub fn _pow(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.binary_op(a, b, PyNumberMethodsOffset::Power, "**", |vm, _, _| {
Ok(vm.ctx.not_implemented())
})
}
pub fn _ipow(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.binary_iop(
a,
b,
PyNumberMethodsOffset::InplacePower,
PyNumberMethodsOffset::Power,
"**=",
|vm, _, _| Ok(vm.ctx.not_implemented()),
)
}
// TODO: `str` modular opertation(mod, imod) is not supported now. Should implement it.
pub fn _mod(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
a,
@@ -336,6 +527,10 @@ impl VirtualMachine {
identifier!(self, __rmod__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "%")),
)
// self.binary_op(a, b, PyNumberMethodsOffset::Remainder, "%", |vm, _, _| {
// Ok(vm.ctx.not_implemented())
// })
}
pub fn _imod(&self, a: &PyObject, b: &PyObject) -> PyResult {
@@ -348,84 +543,76 @@ impl VirtualMachine {
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "%=")),
)
})
// self.binary_iop(
// a,
// b,
// PyNumberMethodsOffset::InplaceRemainder,
// PyNumberMethodsOffset::Remainder,
// "%=",
// |vm, _, _| Ok(vm.ctx.not_implemented()),
// )
}
pub fn _divmod(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
a,
b,
identifier!(self, __divmod__),
identifier!(self, __rdivmod__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "divmod")),
)
self.binary_op(a, b, PyNumberMethodsOffset::Divmod, "divmod", |vm, _, _| {
Ok(vm.ctx.not_implemented())
})
}
pub fn _lshift(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
a,
b,
identifier!(self, __lshift__),
identifier!(self, __rlshift__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "<<")),
)
self.binary_op(a, b, PyNumberMethodsOffset::Lshift, "<<", |vm, _, _| {
Ok(vm.ctx.not_implemented())
})
}
pub fn _ilshift(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_unsupported(a, b, identifier!(self, __ilshift__), |vm, a, b| {
vm.call_or_reflection(
a,
b,
identifier!(self, __lshift__),
identifier!(self, __rlshift__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "<<=")),
)
})
self.binary_iop(
a,
b,
PyNumberMethodsOffset::InplaceLshift,
PyNumberMethodsOffset::Lshift,
"<<=",
|vm, _, _| Ok(vm.ctx.not_implemented()),
)
}
pub fn _rshift(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
a,
b,
identifier!(self, __rshift__),
identifier!(self, __rrshift__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, ">>")),
)
self.binary_op(a, b, PyNumberMethodsOffset::Rshift, ">>", |vm, _, _| {
Ok(vm.ctx.not_implemented())
})
}
pub fn _irshift(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_unsupported(a, b, identifier!(self, __irshift__), |vm, a, b| {
vm.call_or_reflection(
a,
b,
identifier!(self, __rshift__),
identifier!(self, __rrshift__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, ">>=")),
)
})
}
pub fn _xor(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
self.binary_iop(
a,
b,
identifier!(self, __xor__),
identifier!(self, __rxor__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "^")),
PyNumberMethodsOffset::InplaceRshift,
PyNumberMethodsOffset::Rshift,
">>=",
|vm, _, _| Ok(vm.ctx.not_implemented()),
)
}
pub fn _ixor(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_unsupported(a, b, identifier!(self, __ixor__), |vm, a, b| {
vm.call_or_reflection(
a,
b,
identifier!(self, __xor__),
identifier!(self, __rxor__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "^=")),
)
pub fn _xor(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.binary_op(a, b, PyNumberMethodsOffset::Xor, "^", |vm, _, _| {
Ok(vm.ctx.not_implemented())
})
}
pub fn _ixor(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.binary_iop(
a,
b,
PyNumberMethodsOffset::InplaceXor,
PyNumberMethodsOffset::Xor,
"^=",
|vm, _, _| Ok(vm.ctx.not_implemented()),
)
}
// TODO: `or` method doesn't work because of structure of `type_::or_()`.
// TODO: It should be changed by adjusting with AsNumber.
pub fn _or(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
a,
@@ -434,6 +621,10 @@ impl VirtualMachine {
identifier!(self, __ror__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "|")),
)
// self.binary_op(a, b, PyNumberMethodsOffset::Or, "|", |vm, _, _| {
// Ok(vm.ctx.not_implemented())
// })
}
pub fn _ior(&self, a: &PyObject, b: &PyObject) -> PyResult {
@@ -446,8 +637,19 @@ impl VirtualMachine {
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "|=")),
)
})
// self.binary_iop(
// a,
// b,
// PyNumberMethodsOffset::InplaceOr,
// PyNumberMethodsOffset::Or,
// "|=",
// |vm, _, _| Ok(vm.ctx.not_implemented()),
// )
}
// TODO: `and` method doesn't work because of structure of `set`.
// TODO: It should be changed by adjusting with AsNumber.
pub fn _and(&self, a: &PyObject, b: &PyObject) -> PyResult {
self.call_or_reflection(
a,
@@ -456,6 +658,10 @@ impl VirtualMachine {
identifier!(self, __rand__),
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "&")),
)
// self.binary_op(a, b, PyNumberMethodsOffset::And, "&", |vm, _, _| {
// Ok(vm.ctx.not_implemented())
// })
}
pub fn _iand(&self, a: &PyObject, b: &PyObject) -> PyResult {
@@ -468,6 +674,15 @@ impl VirtualMachine {
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "&=")),
)
})
// self.binary_iop(
// a,
// b,
// PyNumberMethodsOffset::InplaceAnd,
// PyNumberMethodsOffset::And,
// "&=",
// |vm, _, _| Ok(vm.ctx.not_implemented()),
// )
}
pub fn _abs(&self, a: &PyObject) -> PyResult<PyObjectRef> {