1use super::VirtualMachine;
2use crate::{
3 builtins::{PyInt, PyIntRef, PyStr, PyStrRef},
4 object::{AsObject, PyObject, PyObjectRef, PyResult},
5 protocol::{PyIterReturn, PyNumberBinaryOp, PyNumberTernaryOp, PySequence},
6 types::PyComparisonOp,
7};
8use num_traits::ToPrimitive;
9
10macro_rules! binary_func {
11 ($fn:ident, $op_slot:ident, $op:expr) => {
12 pub fn $fn(&self, a: &PyObject, b: &PyObject) -> PyResult {
13 self.binary_op(a, b, PyNumberBinaryOp::$op_slot, $op)
14 }
15 };
16}
17
18macro_rules! ternary_func {
19 ($fn:ident, $op_slot:ident, $op:expr) => {
20 pub fn $fn(&self, a: &PyObject, b: &PyObject, c: &PyObject) -> PyResult {
21 self.ternary_op(a, b, c, PyNumberTernaryOp::$op_slot, $op)
22 }
23 };
24}
25
26macro_rules! inplace_binary_func {
27 ($fn:ident, $iop_slot:ident, $op_slot:ident, $op:expr) => {
28 pub fn $fn(&self, a: &PyObject, b: &PyObject) -> PyResult {
29 self.binary_iop(
30 a,
31 b,
32 PyNumberBinaryOp::$iop_slot,
33 PyNumberBinaryOp::$op_slot,
34 $op,
35 )
36 }
37 };
38}
39
40macro_rules! inplace_ternary_func {
41 ($fn:ident, $iop_slot:ident, $op_slot:ident, $op:expr) => {
42 pub fn $fn(&self, a: &PyObject, b: &PyObject, c: &PyObject) -> PyResult {
43 self.ternary_iop(
44 a,
45 b,
46 c,
47 PyNumberTernaryOp::$iop_slot,
48 PyNumberTernaryOp::$op_slot,
49 $op,
50 )
51 }
52 };
53}
54
55impl VirtualMachine {
57 #[inline]
58 pub fn bool_eq(&self, a: &PyObject, b: &PyObject) -> PyResult<bool> {
59 a.rich_compare_bool(b, PyComparisonOp::Eq, self)
60 }
61
62 pub fn identical_or_equal(&self, a: &PyObject, b: &PyObject) -> PyResult<bool> {
63 if a.is(b) {
64 Ok(true)
65 } else {
66 self.bool_eq(a, b)
67 }
68 }
69
70 pub fn bool_seq_lt(&self, a: &PyObject, b: &PyObject) -> PyResult<Option<bool>> {
71 let value = if a.rich_compare_bool(b, PyComparisonOp::Lt, self)? {
72 Some(true)
73 } else if !self.bool_eq(a, b)? {
74 Some(false)
75 } else {
76 None
77 };
78 Ok(value)
79 }
80
81 pub fn bool_seq_gt(&self, a: &PyObject, b: &PyObject) -> PyResult<Option<bool>> {
82 let value = if a.rich_compare_bool(b, PyComparisonOp::Gt, self)? {
83 Some(true)
84 } else if !self.bool_eq(a, b)? {
85 Some(false)
86 } else {
87 None
88 };
89 Ok(value)
90 }
91
92 pub fn length_hint_opt(&self, iter: PyObjectRef) -> PyResult<Option<usize>> {
93 match iter.length(self) {
94 Ok(len) => return Ok(Some(len)),
95 Err(e) => {
96 if !e.fast_isinstance(self.ctx.exceptions.type_error) {
97 return Err(e);
98 }
99 }
100 }
101 let hint = match self.get_method(iter, identifier!(self, __length_hint__)) {
102 Some(hint) => hint?,
103 None => return Ok(None),
104 };
105 let result = match hint.call((), self) {
106 Ok(res) => {
107 if res.is(&self.ctx.not_implemented) {
108 return Ok(None);
109 }
110 res
111 }
112 Err(e) => {
113 return if e.fast_isinstance(self.ctx.exceptions.type_error) {
114 Ok(None)
115 } else {
116 Err(e)
117 }
118 }
119 };
120 let hint = result
121 .payload_if_subclass::<PyInt>(self)
122 .ok_or_else(|| {
123 self.new_type_error(format!(
124 "'{}' object cannot be interpreted as an integer",
125 result.class().name()
126 ))
127 })?
128 .try_to_primitive::<isize>(self)?;
129 if hint.is_negative() {
130 Err(self.new_value_error("__length_hint__() should return >= 0".to_owned()))
131 } else {
132 Ok(Some(hint as usize))
133 }
134 }
135
136 pub fn check_repeat_or_overflow_error(&self, length: usize, n: isize) -> PyResult<usize> {
139 if n <= 0 {
140 Ok(0)
141 } else {
142 let n = n as usize;
143 if length > crate::stdlib::sys::MAXSIZE as usize / n {
144 Err(self.new_overflow_error("repeated value are too long".to_owned()))
145 } else {
146 Ok(n)
147 }
148 }
149 }
150
151 pub fn binary_op1(&self, a: &PyObject, b: &PyObject, op_slot: PyNumberBinaryOp) -> PyResult {
158 let class_a = a.class();
159 let class_b = b.class();
160
161 let slot_a = class_a.slots.as_number.left_binary_op(op_slot);
162 let mut slot_b = None;
163
164 if !class_a.is(class_b) {
165 let slot_bb = class_b.slots.as_number.right_binary_op(op_slot);
166 if slot_bb.map(|x| x as usize) != slot_a.map(|x| x as usize) {
167 slot_b = slot_bb;
168 }
169 }
170
171 if let Some(slot_a) = slot_a {
172 if let Some(slot_bb) = slot_b {
173 if class_b.fast_issubclass(class_a) {
174 let ret = slot_bb(a, b, self)?;
175 if !ret.is(&self.ctx.not_implemented) {
176 return Ok(ret);
177 }
178 slot_b = None;
179 }
180 }
181 let ret = slot_a(a, b, self)?;
182 if !ret.is(&self.ctx.not_implemented) {
183 return Ok(ret);
184 }
185 }
186
187 if let Some(slot_b) = slot_b {
188 let ret = slot_b(a, b, self)?;
189 if !ret.is(&self.ctx.not_implemented) {
190 return Ok(ret);
191 }
192 }
193
194 Ok(self.ctx.not_implemented())
195 }
196
197 pub fn binary_op(
198 &self,
199 a: &PyObject,
200 b: &PyObject,
201 op_slot: PyNumberBinaryOp,
202 op: &str,
203 ) -> PyResult {
204 let result = self.binary_op1(a, b, op_slot)?;
205 if !result.is(&self.ctx.not_implemented) {
206 return Ok(result);
207 }
208 Err(self.new_unsupported_binop_error(a, b, op))
209 }
210
211 fn binary_iop1(
225 &self,
226 a: &PyObject,
227 b: &PyObject,
228 iop_slot: PyNumberBinaryOp,
229 op_slot: PyNumberBinaryOp,
230 ) -> PyResult {
231 if let Some(slot) = a.class().slots.as_number.left_binary_op(iop_slot) {
232 let x = slot(a, b, self)?;
233 if !x.is(&self.ctx.not_implemented) {
234 return Ok(x);
235 }
236 }
237 self.binary_op1(a, b, op_slot)
238 }
239
240 fn binary_iop(
241 &self,
242 a: &PyObject,
243 b: &PyObject,
244 iop_slot: PyNumberBinaryOp,
245 op_slot: PyNumberBinaryOp,
246 op: &str,
247 ) -> PyResult {
248 let result = self.binary_iop1(a, b, iop_slot, op_slot)?;
249 if !result.is(&self.ctx.not_implemented) {
250 return Ok(result);
251 }
252 Err(self.new_unsupported_binop_error(a, b, op))
253 }
254
255 fn ternary_op(
256 &self,
257 a: &PyObject,
258 b: &PyObject,
259 c: &PyObject,
260 op_slot: PyNumberTernaryOp,
261 op_str: &str,
262 ) -> PyResult {
263 let class_a = a.class();
264 let class_b = b.class();
265 let class_c = c.class();
266
267 let slot_a = class_a.slots.as_number.left_ternary_op(op_slot);
268 let mut slot_b = None;
269
270 if !class_a.is(class_b) {
271 let slot_bb = class_b.slots.as_number.right_ternary_op(op_slot);
272 if slot_bb.map(|x| x as usize) != slot_a.map(|x| x as usize) {
273 slot_b = slot_bb;
274 }
275 }
276
277 if let Some(slot_a) = slot_a {
278 if let Some(slot_bb) = slot_b {
279 if class_b.fast_issubclass(class_a) {
280 let ret = slot_bb(a, b, c, self)?;
281 if !ret.is(&self.ctx.not_implemented) {
282 return Ok(ret);
283 }
284 slot_b = None;
285 }
286 }
287 let ret = slot_a(a, b, c, self)?;
288 if !ret.is(&self.ctx.not_implemented) {
289 return Ok(ret);
290 }
291 }
292
293 if let Some(slot_b) = slot_b {
294 let ret = slot_b(a, b, c, self)?;
295 if !ret.is(&self.ctx.not_implemented) {
296 return Ok(ret);
297 }
298 }
299
300 if let Some(slot_c) = class_c.slots.as_number.left_ternary_op(op_slot) {
301 if slot_a.map_or(false, |slot_a| (slot_a as usize) != (slot_c as usize))
302 && slot_b.map_or(false, |slot_b| (slot_b as usize) != (slot_c as usize))
303 {
304 let ret = slot_c(a, b, c, self)?;
305 if !ret.is(&self.ctx.not_implemented) {
306 return Ok(ret);
307 }
308 }
309 }
310
311 Err(if self.is_none(c) {
312 self.new_type_error(format!(
313 "unsupported operand type(s) for {}: \
314 '{}' and '{}'",
315 op_str,
316 a.class(),
317 b.class()
318 ))
319 } else {
320 self.new_type_error(format!(
321 "unsupported operand type(s) for {}: \
322 '{}' and '{}', '{}'",
323 op_str,
324 a.class(),
325 b.class(),
326 c.class()
327 ))
328 })
329 }
330
331 fn ternary_iop(
332 &self,
333 a: &PyObject,
334 b: &PyObject,
335 c: &PyObject,
336 iop_slot: PyNumberTernaryOp,
337 op_slot: PyNumberTernaryOp,
338 op_str: &str,
339 ) -> PyResult {
340 if let Some(slot) = a.class().slots.as_number.left_ternary_op(iop_slot) {
341 let x = slot(a, b, c, self)?;
342 if !x.is(&self.ctx.not_implemented) {
343 return Ok(x);
344 }
345 }
346 self.ternary_op(a, b, c, op_slot, op_str)
347 }
348
349 binary_func!(_sub, Subtract, "-");
350 binary_func!(_mod, Remainder, "%");
351 binary_func!(_divmod, Divmod, "divmod");
352 binary_func!(_lshift, Lshift, "<<");
353 binary_func!(_rshift, Rshift, ">>");
354 binary_func!(_and, And, "&");
355 binary_func!(_xor, Xor, "^");
356 binary_func!(_or, Or, "|");
357 binary_func!(_floordiv, FloorDivide, "//");
358 binary_func!(_truediv, TrueDivide, "/");
359 binary_func!(_matmul, MatrixMultiply, "@");
360
361 inplace_binary_func!(_isub, InplaceSubtract, Subtract, "-=");
362 inplace_binary_func!(_imod, InplaceRemainder, Remainder, "%=");
363 inplace_binary_func!(_ilshift, InplaceLshift, Lshift, "<<=");
364 inplace_binary_func!(_irshift, InplaceRshift, Rshift, ">>=");
365 inplace_binary_func!(_iand, InplaceAnd, And, "&=");
366 inplace_binary_func!(_ixor, InplaceXor, Xor, "^=");
367 inplace_binary_func!(_ior, InplaceOr, Or, "|=");
368 inplace_binary_func!(_ifloordiv, InplaceFloorDivide, FloorDivide, "//=");
369 inplace_binary_func!(_itruediv, InplaceTrueDivide, TrueDivide, "/=");
370 inplace_binary_func!(_imatmul, InplaceMatrixMultiply, MatrixMultiply, "@=");
371
372 ternary_func!(_pow, Power, "** or pow()");
373 inplace_ternary_func!(_ipow, InplacePower, Power, "**=");
374
375 pub fn _add(&self, a: &PyObject, b: &PyObject) -> PyResult {
376 let result = self.binary_op1(a, b, PyNumberBinaryOp::Add)?;
377 if !result.is(&self.ctx.not_implemented) {
378 return Ok(result);
379 }
380 if let Ok(seq_a) = PySequence::try_protocol(a, self) {
381 let result = seq_a.concat(b, self)?;
382 if !result.is(&self.ctx.not_implemented) {
383 return Ok(result);
384 }
385 }
386 Err(self.new_unsupported_binop_error(a, b, "+"))
387 }
388
389 pub fn _iadd(&self, a: &PyObject, b: &PyObject) -> PyResult {
390 let result = self.binary_iop1(a, b, PyNumberBinaryOp::InplaceAdd, PyNumberBinaryOp::Add)?;
391 if !result.is(&self.ctx.not_implemented) {
392 return Ok(result);
393 }
394 if let Ok(seq_a) = PySequence::try_protocol(a, self) {
395 let result = seq_a.inplace_concat(b, self)?;
396 if !result.is(&self.ctx.not_implemented) {
397 return Ok(result);
398 }
399 }
400 Err(self.new_unsupported_binop_error(a, b, "+="))
401 }
402
403 pub fn _mul(&self, a: &PyObject, b: &PyObject) -> PyResult {
404 let result = self.binary_op1(a, b, PyNumberBinaryOp::Multiply)?;
405 if !result.is(&self.ctx.not_implemented) {
406 return Ok(result);
407 }
408 if let Ok(seq_a) = PySequence::try_protocol(a, self) {
409 let n =
410 b.try_index(self)?.as_bigint().to_isize().ok_or_else(|| {
411 self.new_overflow_error("repeated bytes are too long".to_owned())
412 })?;
413 return seq_a.repeat(n, self);
414 } else if let Ok(seq_b) = PySequence::try_protocol(b, self) {
415 let n =
416 a.try_index(self)?.as_bigint().to_isize().ok_or_else(|| {
417 self.new_overflow_error("repeated bytes are too long".to_owned())
418 })?;
419 return seq_b.repeat(n, self);
420 }
421 Err(self.new_unsupported_binop_error(a, b, "*"))
422 }
423
424 pub fn _imul(&self, a: &PyObject, b: &PyObject) -> PyResult {
425 let result = self.binary_iop1(
426 a,
427 b,
428 PyNumberBinaryOp::InplaceMultiply,
429 PyNumberBinaryOp::Multiply,
430 )?;
431 if !result.is(&self.ctx.not_implemented) {
432 return Ok(result);
433 }
434 if let Ok(seq_a) = PySequence::try_protocol(a, self) {
435 let n =
436 b.try_index(self)?.as_bigint().to_isize().ok_or_else(|| {
437 self.new_overflow_error("repeated bytes are too long".to_owned())
438 })?;
439 return seq_a.inplace_repeat(n, self);
440 } else if let Ok(seq_b) = PySequence::try_protocol(b, self) {
441 let n =
442 a.try_index(self)?.as_bigint().to_isize().ok_or_else(|| {
443 self.new_overflow_error("repeated bytes are too long".to_owned())
444 })?;
445 return seq_b.repeat(n, self);
449 }
450 Err(self.new_unsupported_binop_error(a, b, "*="))
451 }
452
453 pub fn _abs(&self, a: &PyObject) -> PyResult<PyObjectRef> {
454 self.get_special_method(a, identifier!(self, __abs__))?
455 .ok_or_else(|| self.new_unsupported_unary_error(a, "abs()"))?
456 .invoke((), self)
457 }
458
459 pub fn _pos(&self, a: &PyObject) -> PyResult {
460 self.get_special_method(a, identifier!(self, __pos__))?
461 .ok_or_else(|| self.new_unsupported_unary_error(a, "unary +"))?
462 .invoke((), self)
463 }
464
465 pub fn _neg(&self, a: &PyObject) -> PyResult {
466 self.get_special_method(a, identifier!(self, __neg__))?
467 .ok_or_else(|| self.new_unsupported_unary_error(a, "unary -"))?
468 .invoke((), self)
469 }
470
471 pub fn _invert(&self, a: &PyObject) -> PyResult {
472 self.get_special_method(a, identifier!(self, __invert__))?
473 .ok_or_else(|| self.new_unsupported_unary_error(a, "unary ~"))?
474 .invoke((), self)
475 }
476
477 pub fn format(&self, obj: &PyObject, format_spec: PyStrRef) -> PyResult<PyStrRef> {
479 if format_spec.is_empty() {
480 let obj = match obj.to_owned().downcast_exact::<PyStr>(self) {
481 Ok(s) => return Ok(s.into_pyref()),
482 Err(obj) => obj,
483 };
484 if obj.class().is(self.ctx.types.int_type) {
485 return obj.str(self);
486 }
487 }
488 let bound_format = self
489 .get_special_method(obj, identifier!(self, __format__))?
490 .ok_or_else(|| {
491 self.new_type_error(format!(
492 "Type {} doesn't define __format__",
493 obj.class().name()
494 ))
495 })?;
496 let formatted = bound_format.invoke((format_spec,), self)?;
497 formatted.downcast().map_err(|result| {
498 self.new_type_error(format!(
499 "__format__ must return a str, not {}",
500 &result.class().name()
501 ))
502 })
503 }
504
505 fn _membership_iter_search(
507 &self,
508 haystack: &PyObject,
509 needle: PyObjectRef,
510 ) -> PyResult<PyIntRef> {
511 let iter = haystack.get_iter(self)?;
512 loop {
513 if let PyIterReturn::Return(element) = iter.next(self)? {
514 if self.bool_eq(&element, &needle)? {
515 return Ok(self.ctx.new_bool(true));
516 } else {
517 continue;
518 }
519 } else {
520 return Ok(self.ctx.new_bool(false));
521 }
522 }
523 }
524
525 pub fn _contains(&self, haystack: &PyObject, needle: &PyObject) -> PyResult<bool> {
526 let seq = haystack.to_sequence();
527 seq.contains(needle, self)
528 }
529}