@@ -455,9 +455,31 @@ impl VirtualMachine {
455
455
}
456
456
}
457
457
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) {
461
483
match self . invoke (
462
484
method,
463
485
PyFuncArgs {
@@ -474,8 +496,8 @@ impl VirtualMachine {
474
496
}
475
497
}
476
498
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 ) {
479
501
match self . invoke (
480
502
method,
481
503
PyFuncArgs {
@@ -492,16 +514,21 @@ impl VirtualMachine {
492
514
}
493
515
}
494
516
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)
497
520
let a_type_name = objtype:: get_type_name ( & a. typ ( ) ) ;
498
521
let b_type_name = objtype:: get_type_name ( & b. typ ( ) ) ;
499
522
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
502
525
) ) )
503
526
}
504
527
528
+ pub fn _sub ( & mut self , a : PyObjectRef , b : PyObjectRef ) -> PyResult {
529
+ self . call_or_unsupported ( a, b, "__sub__" , "__rsub__" , "-" )
530
+ }
531
+
505
532
pub fn _add ( & mut self , a : PyObjectRef , b : PyObjectRef ) -> PyResult {
506
533
self . call_method ( & a, "__add__" , vec ! [ b] )
507
534
}
@@ -527,54 +554,11 @@ impl VirtualMachine {
527
554
}
528
555
529
556
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__" , "|" )
531
558
}
532
559
533
560
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__" , "&" )
578
562
}
579
563
580
564
pub fn _eq ( & mut self , a : & PyObjectRef , b : PyObjectRef ) -> PyResult {
0 commit comments