Skip to content

Commit fa148a4

Browse files
authored
Merge branch 'master' into float-round
2 parents c951cb3 + 3e7d43e commit fa148a4

21 files changed

+412
-288
lines changed

tests/snippets/builtin_complex.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
assert complex(1, 2) != 'foo'
2525
assert complex(1, 2).__eq__('foo') == NotImplemented
2626

27+
# __mul__
28+
29+
assert complex(2, -3) * complex(-5, 7) == complex(11, 29)
30+
assert complex(2, -3) * 5 == complex(10, -15)
31+
2732
# __neg__
2833

2934
assert -complex(1, -1) == complex(-1, 1)

tests/snippets/builtin_range.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727
assert range(4, 10, 2).count(7) == 0
2828
assert range(10).count("foo") == 0
2929

30+
# __eq__
31+
assert range(1, 2, 3) == range(1, 2, 3)
32+
assert range(1, 2, 1) == range(1, 2)
33+
assert range(2) == range(0, 2)
34+
3035
# __bool__
3136
assert bool(range(1))
3237
assert bool(range(1, 2))
@@ -54,3 +59,9 @@
5459
# range retains the original int refs
5560
i = 2**64
5661
assert range(i).stop is i
62+
63+
# negative index
64+
assert range(10)[-1] == 9
65+
assert_raises(IndexError, lambda: range(10)[-11], 'out of bound')
66+
assert range(10)[-2:4] == range(8, 4)
67+
assert range(10)[-6:-2] == range(4, 8)

tests/snippets/bytearray.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,9 @@
6565
pass
6666
else:
6767
assert False
68+
69+
a = bytearray(b'appen')
70+
assert len(a) == 5
71+
a.append(100)
72+
assert len(a) == 6
73+
assert a.pop() == 100

tests/snippets/floats.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
b = 1.3
99
c = 1.2
1010
z = 2
11+
ov = 10 ** 1000
1112

1213
assert -a == -1.2
1314

@@ -37,6 +38,20 @@
3738
assert 6 / a == 5.0
3839
assert 2.0 % z == 0.0
3940
assert z % 2.0 == 0.0
41+
assert_raises(OverflowError, lambda: a + ov)
42+
assert_raises(OverflowError, lambda: a - ov)
43+
assert_raises(OverflowError, lambda: a * ov)
44+
assert_raises(OverflowError, lambda: a / ov)
45+
assert_raises(OverflowError, lambda: a // ov)
46+
assert_raises(OverflowError, lambda: a % ov)
47+
assert_raises(OverflowError, lambda: a ** ov)
48+
assert_raises(OverflowError, lambda: ov + a)
49+
assert_raises(OverflowError, lambda: ov - a)
50+
assert_raises(OverflowError, lambda: ov * a)
51+
assert_raises(OverflowError, lambda: ov / a)
52+
assert_raises(OverflowError, lambda: ov // a)
53+
assert_raises(OverflowError, lambda: ov % a)
54+
# assert_raises(OverflowError, lambda: ov ** a)
4055

4156
assert a < 5
4257
assert a <= 5
@@ -91,6 +106,8 @@
91106
assert 2.0.__rmul__(1.0) == 2.0
92107
assert 1.0.__truediv__(2.0) == 0.5
93108
assert 1.0.__rtruediv__(2.0) == 2.0
109+
assert 2.5.__divmod__(2.0) == (1.0, 0.5)
110+
assert 2.0.__rdivmod__(2.5) == (1.0, 0.5)
94111

95112
assert 1.0.__add__(1) == 2.0
96113
assert 1.0.__radd__(1) == 2.0
@@ -105,6 +122,11 @@
105122
assert_raises(ZeroDivisionError, lambda: 2.0 / 0)
106123
assert_raises(ZeroDivisionError, lambda: 2.0 // 0)
107124
assert_raises(ZeroDivisionError, lambda: 2.0 % 0)
125+
assert_raises(ZeroDivisionError, lambda: divmod(2.0, 0))
126+
assert_raises(ZeroDivisionError, lambda: 2 / 0.0)
127+
assert_raises(ZeroDivisionError, lambda: 2 // 0.0)
128+
assert_raises(ZeroDivisionError, lambda: 2 % 0.0)
129+
# assert_raises(ZeroDivisionError, lambda: divmod(2, 0.0))
108130

109131
assert 1.2.__int__() == 1
110132
assert 1.2.__float__() == 1.2
@@ -123,6 +145,10 @@
123145
assert_raises(OverflowError, float('inf').__round__)
124146
assert_raises(ValueError, float('nan').__round__)
125147

148+
assert 1.2 ** 2 == 1.44
149+
assert_raises(OverflowError, lambda: 1.2 ** (10 ** 1000))
150+
assert 3 ** 2.0 == 9.0
151+
126152
assert (1.7).real == 1.7
127153
assert (1.3).is_integer() == False
128154
assert (1.0).is_integer() == True

tests/snippets/ints.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,37 @@
7474
with assertRaises(TypeError):
7575
# check that first parameter is truly positional only
7676
int(val_options=1)
77+
78+
class A(object):
79+
def __int__(self):
80+
return 10
81+
82+
assert int(A()) == 10
83+
84+
class B(object):
85+
pass
86+
87+
b = B()
88+
b.__int__ = lambda: 20
89+
90+
with assertRaises(TypeError):
91+
assert int(b) == 20
92+
93+
class C(object):
94+
def __int__(self):
95+
return 'str'
96+
97+
with assertRaises(TypeError):
98+
int(C())
99+
100+
class I(int):
101+
def __int__(self):
102+
return 3
103+
104+
assert int(I(1)) == 3
105+
106+
class F(float):
107+
def __int__(self):
108+
return 3
109+
110+
assert int(F(1.2)) == 3

tests/snippets/testutils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ def assert_raises(exc_type, expr, msg=None):
1414
except exc_type:
1515
pass
1616
else:
17-
failmsg = '{!s} was not raised'.format(exc_type.__name__)
17+
failmsg = '{} was not raised'.format(exc_type.__name__)
1818
if msg is not None:
19-
failmsg += ': {!s}'.format(msg)
19+
failmsg += ': {}'.format(msg)
2020
assert False, failmsg
2121

2222

@@ -29,8 +29,8 @@ def __enter__(self):
2929

3030
def __exit__(self, exc_type, exc_val, exc_tb):
3131
if exc_type is None:
32-
failmsg = '{!s} was not raised'.format(self.expected.__name__)
33-
assert False, failmsg
32+
failmsg = '{} was not raised'.format(self.expected.__name__)
33+
assert False, failmsg
3434
if not issubclass(exc_type, self.expected):
3535
return False
3636
return True

vm/src/builtins.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,14 @@ fn builtin_dir(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
123123
}
124124

125125
fn builtin_divmod(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
126-
arg_check!(vm, args, required = [(x, None), (y, None)]);
127-
match vm.get_method(x.clone(), "__divmod__") {
128-
Ok(attrib) => vm.invoke(attrib, vec![y.clone()]),
129-
Err(..) => Err(vm.new_type_error("unsupported operand type(s) for divmod".to_string())),
130-
}
126+
arg_check!(vm, args, required = [(a, None), (b, None)]);
127+
vm.call_or_reflection(
128+
a.clone(),
129+
b.clone(),
130+
"__divmod__",
131+
"__rdivmod__",
132+
|vm, a, b| Err(vm.new_unsupported_operand_error(a, b, "divmod")),
133+
)
131134
}
132135

133136
/// Implements `eval`.

vm/src/obj/objbytearray.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::ops::{Deref, DerefMut};
77
use num_traits::ToPrimitive;
88

99
use crate::function::OptionalArg;
10-
use crate::pyobject::{PyContext, PyObjectRef, PyRef, PyResult, PyValue};
10+
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
1111
use crate::vm::VirtualMachine;
1212

1313
use super::objint;
@@ -79,15 +79,12 @@ pub fn init(context: &PyContext) {
7979
"istitle" =>context.new_rustfunc(PyByteArrayRef::istitle),
8080
"isupper" => context.new_rustfunc(PyByteArrayRef::isupper),
8181
"lower" => context.new_rustfunc(PyByteArrayRef::lower),
82+
"append" => context.new_rustfunc(PyByteArrayRef::append),
8283
"pop" => context.new_rustfunc(PyByteArrayRef::pop),
8384
"upper" => context.new_rustfunc(PyByteArrayRef::upper)
8485
});
8586

86-
let bytearrayiterator_type = &context.bytearrayiterator_type;
87-
extend_class!(context, bytearrayiterator_type, {
88-
"__next__" => context.new_rustfunc(PyByteArrayIteratorRef::next),
89-
"__iter__" => context.new_rustfunc(PyByteArrayIteratorRef::iter),
90-
});
87+
PyByteArrayIterator::extend_class(context, &context.bytearrayiterator_type);
9188
}
9289

9390
fn bytearray_new(
@@ -213,6 +210,10 @@ impl PyByteArrayRef {
213210
self.value.borrow_mut().clear();
214211
}
215212

213+
fn append(self, x: u8, _vm: &VirtualMachine) {
214+
self.value.borrow_mut().push(x);
215+
}
216+
216217
fn pop(self, vm: &VirtualMachine) -> PyResult<u8> {
217218
let mut bytes = self.value.borrow_mut();
218219
bytes
@@ -282,6 +283,7 @@ mod tests {
282283
}
283284
}
284285

286+
#[pyclass]
285287
#[derive(Debug)]
286288
pub struct PyByteArrayIterator {
287289
position: Cell<usize>,
@@ -294,10 +296,10 @@ impl PyValue for PyByteArrayIterator {
294296
}
295297
}
296298

297-
type PyByteArrayIteratorRef = PyRef<PyByteArrayIterator>;
298-
299-
impl PyByteArrayIteratorRef {
300-
fn next(self, vm: &VirtualMachine) -> PyResult<u8> {
299+
#[pyimpl]
300+
impl PyByteArrayIterator {
301+
#[pymethod(name = "__next__")]
302+
fn next(&self, vm: &VirtualMachine) -> PyResult<u8> {
301303
if self.position.get() < self.bytearray.value.borrow().len() {
302304
let ret = self.bytearray.value.borrow()[self.position.get()];
303305
self.position.set(self.position.get() + 1);
@@ -307,7 +309,8 @@ impl PyByteArrayIteratorRef {
307309
}
308310
}
309311

310-
fn iter(self, _vm: &VirtualMachine) -> Self {
311-
self
312+
#[pymethod(name = "__iter__")]
313+
fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
314+
zelf
312315
}
313316
}

vm/src/obj/objbytes.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,7 @@ pub fn init(context: &PyContext) {
6464
extend_class!(context, bytes_type, {
6565
"fromhex" => context.new_rustfunc(PyBytesRef::fromhex),
6666
});
67-
let bytesiterator_type = &context.bytesiterator_type;
68-
extend_class!(context, bytesiterator_type, {
69-
"__next__" => context.new_rustfunc(PyBytesIteratorRef::next),
70-
"__iter__" => context.new_rustfunc(PyBytesIteratorRef::iter),
71-
});
67+
PyBytesIterator::extend_class(context, &context.bytesiterator_type);
7268
}
7369

7470
#[pyimpl]
@@ -271,6 +267,7 @@ impl PyBytesRef {
271267
}
272268
}
273269

270+
#[pyclass]
274271
#[derive(Debug)]
275272
pub struct PyBytesIterator {
276273
position: Cell<usize>,
@@ -283,10 +280,10 @@ impl PyValue for PyBytesIterator {
283280
}
284281
}
285282

286-
type PyBytesIteratorRef = PyRef<PyBytesIterator>;
287-
288-
impl PyBytesIteratorRef {
289-
fn next(self, vm: &VirtualMachine) -> PyResult<u8> {
283+
#[pyimpl]
284+
impl PyBytesIterator {
285+
#[pymethod(name = "__next__")]
286+
fn next(&self, vm: &VirtualMachine) -> PyResult<u8> {
290287
if self.position.get() < self.bytes.inner.len() {
291288
let ret = self.bytes[self.position.get()];
292289
self.position.set(self.position.get() + 1);
@@ -296,7 +293,8 @@ impl PyBytesIteratorRef {
296293
}
297294
}
298295

299-
fn iter(self, _vm: &VirtualMachine) -> Self {
300-
self
296+
#[pymethod(name = "__iter__")]
297+
fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
298+
zelf
301299
}
302300
}

vm/src/obj/objcomplex.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ impl PyComplexRef {
6767
}
6868

6969
fn to_complex(value: PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<Complex64>> {
70-
if objtype::isinstance(&value, &vm.ctx.int_type()) {
70+
if objtype::isinstance(&value, &vm.ctx.complex_type()) {
71+
Ok(Some(get_value(&value)))
72+
} else if objtype::isinstance(&value, &vm.ctx.int_type()) {
7173
match objint::get_value(&value).to_f64() {
7274
Some(v) => Ok(Some(Complex64::new(v, 0.0))),
7375
None => Err(vm.new_overflow_error("int too large to convert to float".to_string())),
@@ -161,6 +163,28 @@ impl PyComplex {
161163
vm.ctx.new_bool(result)
162164
}
163165

166+
#[pymethod(name = "__float__")]
167+
fn float(&self, vm: &VirtualMachine) -> PyResult {
168+
return Err(vm.new_type_error(String::from("Can't convert complex to float")));
169+
}
170+
171+
#[pymethod(name = "__int__")]
172+
fn int(&self, vm: &VirtualMachine) -> PyResult {
173+
return Err(vm.new_type_error(String::from("Can't convert complex to int")));
174+
}
175+
176+
#[pymethod(name = "__mul__")]
177+
fn mul(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
178+
match to_complex(other, vm) {
179+
Ok(Some(other)) => Ok(vm.ctx.new_complex(Complex64::new(
180+
self.value.re * other.re - self.value.im * other.im,
181+
self.value.re * other.im + self.value.im * other.re,
182+
))),
183+
Ok(None) => Ok(vm.ctx.not_implemented()),
184+
Err(err) => Err(err),
185+
}
186+
}
187+
164188
#[pymethod(name = "__neg__")]
165189
fn neg(&self, _vm: &VirtualMachine) -> PyComplex {
166190
PyComplex::from(-self.value)

vm/src/obj/objenumerate.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ use num_bigint::BigInt;
55
use num_traits::Zero;
66

77
use crate::function::OptionalArg;
8-
use crate::pyobject::{PyContext, PyObjectRef, PyRef, PyResult, PyValue};
8+
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
99
use crate::vm::VirtualMachine;
1010

1111
use super::objint::PyIntRef;
1212
use super::objiter;
1313
use super::objtype::PyClassRef;
1414

15+
#[pyclass]
1516
#[derive(Debug)]
1617
pub struct PyEnumerate {
1718
counter: RefCell<BigInt>,
@@ -44,8 +45,10 @@ fn enumerate_new(
4445
.into_ref_with_type(vm, cls)
4546
}
4647

47-
impl PyEnumerateRef {
48-
fn next(self, vm: &VirtualMachine) -> PyResult {
48+
#[pyimpl]
49+
impl PyEnumerate {
50+
#[pymethod(name = "__next__")]
51+
fn next(&self, vm: &VirtualMachine) -> PyResult {
4952
let iterator = &self.iterator;
5053
let counter = &self.counter;
5154
let next_obj = objiter::call_next(vm, iterator)?;
@@ -58,16 +61,15 @@ impl PyEnumerateRef {
5861
Ok(result)
5962
}
6063

61-
fn iter(self, _vm: &VirtualMachine) -> Self {
62-
self
64+
#[pymethod(name = "__iter__")]
65+
fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
66+
zelf
6367
}
6468
}
6569

6670
pub fn init(context: &PyContext) {
67-
let enumerate_type = &context.enumerate_type;
68-
extend_class!(context, enumerate_type, {
71+
PyEnumerate::extend_class(context, &context.enumerate_type);
72+
extend_class!(context, &context.enumerate_type, {
6973
"__new__" => context.new_rustfunc(enumerate_new),
70-
"__next__" => context.new_rustfunc(PyEnumerateRef::next),
71-
"__iter__" => context.new_rustfunc(PyEnumerateRef::iter),
7274
});
7375
}

0 commit comments

Comments
 (0)