Skip to content

Commit a17fb3f

Browse files
Merge pull request RustPython#197 from BojanKogoj/bojan/vm-call_or_unsupported
WIP: Added call_or_unsupported to vm.rs
2 parents cd3429c + 0da1f73 commit a17fb3f

File tree

1 file changed

+38
-54
lines changed

1 file changed

+38
-54
lines changed

vm/src/vm.rs

+38-54
Original file line numberDiff line numberDiff line change
@@ -455,9 +455,31 @@ impl VirtualMachine {
455455
}
456456
}
457457

458-
pub fn _sub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
459-
// 1. Try __sub__, next __rsub__, next, give up
460-
if let Ok(method) = self.get_method(a.clone(), "__sub__") {
458+
/// Calls default method, reverse method or exception
459+
///
460+
/// * `a` - First argument.
461+
/// * `b` - Second argument.
462+
/// * `d` - Default method to try and call (such as `__and__`).
463+
/// * `r` - Reverse method to try and call (such as `__rand__`), in case first one fails.
464+
/// * `op` - Operator for the exception text, for example `&`.
465+
///
466+
/// Given the above example, it will
467+
/// 1. Try to call `__and__` with `a` and `b`
468+
/// 2. If above fails try to call `__rand__` with `a` and `b`
469+
/// 3. If above fails throw an exception:
470+
/// `TypeError: Unsupported operand types for '&': 'float' and 'int'`
471+
/// if `a` is of type float and `b` of type int
472+
///
473+
pub fn call_or_unsupported(
474+
&mut self,
475+
a: PyObjectRef,
476+
b: PyObjectRef,
477+
d: &str,
478+
r: &str,
479+
op: &str,
480+
) -> PyResult {
481+
// Try to call the first method
482+
if let Ok(method) = self.get_method(a.clone(), d) {
461483
match self.invoke(
462484
method,
463485
PyFuncArgs {
@@ -474,8 +496,8 @@ impl VirtualMachine {
474496
}
475497
}
476498

477-
// 2. try __rsub__
478-
if let Ok(method) = self.get_method(b.clone(), "__rsub__") {
499+
// 2. Try to call reverse method
500+
if let Ok(method) = self.get_method(b.clone(), r) {
479501
match self.invoke(
480502
method,
481503
PyFuncArgs {
@@ -492,16 +514,21 @@ impl VirtualMachine {
492514
}
493515
}
494516

495-
// 3. It all failed :(
496-
// Cannot sub a and b
517+
// 3. Both failed, throw an exception
518+
// TODO: Move this chunk somewhere else, it should be
519+
// called in other methods as well (for example objint.rs)
497520
let a_type_name = objtype::get_type_name(&a.typ());
498521
let b_type_name = objtype::get_type_name(&b.typ());
499522
Err(self.new_type_error(format!(
500-
"Unsupported operand types for '-': '{}' and '{}'",
501-
a_type_name, b_type_name
523+
"Unsupported operand types for '{}': '{}' and '{}'",
524+
op, a_type_name, b_type_name
502525
)))
503526
}
504527

528+
pub fn _sub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
529+
self.call_or_unsupported(a, b, "__sub__", "__rsub__", "-")
530+
}
531+
505532
pub fn _add(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
506533
self.call_method(&a, "__add__", vec![b])
507534
}
@@ -527,54 +554,11 @@ impl VirtualMachine {
527554
}
528555

529556
pub fn _or(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
530-
self.call_method(&a, "__or__", vec![b])
557+
self.call_or_unsupported(a, b, "__or__", "__ror__", "|")
531558
}
532559

533560
pub fn _and(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
534-
// 1. Try __and__, next __rand__, next, give up
535-
if let Ok(method) = self.get_method(a.clone(), "__and__") {
536-
match self.invoke(
537-
method,
538-
PyFuncArgs {
539-
args: vec![b.clone()],
540-
kwargs: vec![],
541-
},
542-
) {
543-
Ok(value) => return Ok(value),
544-
Err(err) => {
545-
if !objtype::isinstance(&err, &self.ctx.exceptions.not_implemented_error) {
546-
return Err(err);
547-
}
548-
}
549-
}
550-
}
551-
552-
// 2. try __rand__
553-
if let Ok(method) = self.get_method(b.clone(), "__rand__") {
554-
match self.invoke(
555-
method,
556-
PyFuncArgs {
557-
args: vec![a.clone()],
558-
kwargs: vec![],
559-
},
560-
) {
561-
Ok(value) => return Ok(value),
562-
Err(err) => {
563-
if !objtype::isinstance(&err, &self.ctx.exceptions.not_implemented_error) {
564-
return Err(err);
565-
}
566-
}
567-
}
568-
}
569-
570-
// 3. It all failed :(
571-
// Cannot and a and b
572-
let a_type_name = objtype::get_type_name(&a.typ());
573-
let b_type_name = objtype::get_type_name(&b.typ());
574-
Err(self.new_type_error(format!(
575-
"Unsupported operand types for '&': '{}' and '{}'",
576-
a_type_name, b_type_name
577-
)))
561+
self.call_or_unsupported(a, b, "__and__", "__rand__", "&")
578562
}
579563

580564
pub fn _eq(&mut self, a: &PyObjectRef, b: PyObjectRef) -> PyResult {

0 commit comments

Comments
 (0)