Skip to content

Commit 3c4aaa0

Browse files
Merge pull request #188 from RustPython/sub
Implement __sub__/__rsub__.
2 parents c69b43d + bacaef0 commit 3c4aaa0

File tree

3 files changed

+70
-17
lines changed

3 files changed

+70
-17
lines changed

tests/snippets/subtraction.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
assert 5 - 3 == 2
2+
3+
class Complex():
4+
def __init__(self, real, imag):
5+
self.real = real
6+
self.imag = imag
7+
8+
def __repr__(self):
9+
return "Com" + str((self.real, self.imag))
10+
11+
def __sub__(self, other):
12+
return Complex(self.real - other, self.imag)
13+
14+
def __rsub__(self, other):
15+
return Complex(other - self.real, -self.imag)
16+
17+
def __eq__(self, other):
18+
return self.real == other.real and self.imag == other.imag
19+
20+
assert Complex(4, 5) - 3 == Complex(1, 5)
21+
assert 7 - Complex(4, 5) == Complex(3, -5)

vm/src/obj/objint.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ fn int_sub(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
226226
.ctx
227227
.new_float(i.to_f64().unwrap() - objfloat::get_value(i2)))
228228
} else {
229-
Err(vm.new_type_error(format!("Cannot substract {:?} and {:?}", i, i2)))
229+
Err(vm.new_not_implemented_error(format!("Cannot substract {:?} and {:?}", i, i2)))
230230
}
231231
}
232232

vm/src/vm.rs

+48-16
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ impl VirtualMachine {
8383
self.new_exception(value_error, msg)
8484
}
8585

86+
pub fn new_not_implemented_error(&mut self, msg: String) -> PyObjectRef {
87+
let value_error = self.ctx.exceptions.not_implemented_error.clone();
88+
self.new_exception(value_error, msg)
89+
}
90+
8691
pub fn new_scope(&mut self, parent_scope: Option<PyObjectRef>) -> PyObjectRef {
8792
// let parent_scope = self.current_frame_mut().locals.clone();
8893
self.ctx.new_scope(parent_scope)
@@ -447,23 +452,50 @@ impl VirtualMachine {
447452
}
448453

449454
pub fn _sub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
450-
// Try __sub__, next __rsub__, next, give up
451-
self.call_method(&a, "__sub__", vec![b])
452-
/*
453-
if a.has_attr("__sub__") {
454-
self.call_method(&a, "__sub__", vec![b])
455-
} else if b.has_attr("__rsub__") {
456-
self.call_method(&b, "__rsub__", vec![a])
457-
} else {
458-
// Cannot sub a and b
459-
let a_type_name = objtype::get_type_name(&a.typ());
460-
let b_type_name = objtype::get_type_name(&b.typ());
461-
Err(self.new_type_error(format!(
462-
"Unsupported operand types for '-': '{}' and '{}'",
463-
a_type_name, b_type_name
464-
)))
455+
// 1. Try __sub__, next __rsub__, next, give up
456+
if let Ok(method) = self.get_method(a.clone(), "__sub__") {
457+
match self.invoke(
458+
method,
459+
PyFuncArgs {
460+
args: vec![b.clone()],
461+
kwargs: vec![],
462+
},
463+
) {
464+
Ok(value) => return Ok(value),
465+
Err(err) => {
466+
if !objtype::isinstance(&err, &self.ctx.exceptions.not_implemented_error) {
467+
return Err(err);
468+
}
469+
}
470+
}
465471
}
466-
*/
472+
473+
// 2. try __rsub__
474+
if let Ok(method) = self.get_method(b.clone(), "__rsub__") {
475+
match self.invoke(
476+
method,
477+
PyFuncArgs {
478+
args: vec![a.clone()],
479+
kwargs: vec![],
480+
},
481+
) {
482+
Ok(value) => return Ok(value),
483+
Err(err) => {
484+
if !objtype::isinstance(&err, &self.ctx.exceptions.not_implemented_error) {
485+
return Err(err);
486+
}
487+
}
488+
}
489+
}
490+
491+
// 3. It all failed :(
492+
// Cannot sub a and b
493+
let a_type_name = objtype::get_type_name(&a.typ());
494+
let b_type_name = objtype::get_type_name(&b.typ());
495+
Err(self.new_type_error(format!(
496+
"Unsupported operand types for '-': '{}' and '{}'",
497+
a_type_name, b_type_name
498+
)))
467499
}
468500

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

0 commit comments

Comments
 (0)