|
1 | 1 | #include "PyNumber.hpp" |
| 2 | +#include "NotImplemented.hpp" |
2 | 3 | #include "PyFloat.hpp" |
3 | 4 | #include "PyInteger.hpp" |
| 5 | +#include "PyNone.hpp" |
| 6 | +#include "PyObject.hpp" |
4 | 7 | #include "PyString.hpp" |
5 | 8 | #include "PyType.hpp" |
6 | 9 | #include "TypeError.hpp" |
7 | | -#include "PyNone.hpp" |
8 | | -#include "PyObject.hpp" |
9 | 10 | #include "Value.hpp" |
10 | | -#include "NotImplemented.hpp" |
| 11 | +#include "runtime/PyTuple.hpp" |
| 12 | +#include "runtime/ValueError.hpp" |
11 | 13 | #include "types/builtin.hpp" |
12 | 14 |
|
13 | 15 | #include "interpreter/Interpreter.hpp" |
| 16 | +#include <cmath> |
14 | 17 | #include <variant> |
15 | 18 |
|
16 | 19 | namespace py { |
@@ -96,34 +99,79 @@ PyResult<PyObject *> PyNumber::__mod__(const PyObject *obj) const |
96 | 99 | } |
97 | 100 | } |
98 | 101 |
|
99 | | -PyResult<PyObject *> PyNumber::__mul__(const PyObject *obj) const |
| 102 | +PyResult<PyObject *> PyNumber::__divmod__(PyObject *obj) |
100 | 103 | { |
101 | 104 | if (auto rhs = as_number(obj)) { |
102 | | - return PyNumber::create(m_value * rhs->value()); |
| 105 | + if (rhs->value() == Number{ 0 }) { |
| 106 | + // TODO: implement ZeroDivisionError |
| 107 | + return Err(value_error("ZeroDivisionError")); |
| 108 | + } |
| 109 | + return std::visit( |
| 110 | + overloaded{ |
| 111 | + [](const mpz_class &lhs_value, const mpz_class &rhs_value) -> PyResult<PyTuple *> { |
| 112 | + // For integers, the result is the same as (a // b, a % b) |
| 113 | + return PyTuple::create( |
| 114 | + Number{ lhs_value / rhs_value }, Number{ lhs_value % rhs_value }); |
| 115 | + }, |
| 116 | + [](const mpz_class &lhs_value, const double &rhs_value) -> PyResult<PyTuple *> { |
| 117 | + // For floating-point numbers the result is (q, a % b), where q is usually |
| 118 | + // math.floor(a / b) but may be 1 less than that |
| 119 | + const auto r = std::remainder(lhs_value.get_d(), rhs_value); |
| 120 | + const auto q = Number{ (-r + lhs_value.get_d()) / rhs_value }; |
| 121 | + return PyTuple::create(q, Number{ r }); |
| 122 | + }, |
| 123 | + [](const double &lhs_value, const mpz_class &rhs_value) -> PyResult<PyTuple *> { |
| 124 | + // For floating-point numbers the result is (q, a % b), where q is usually |
| 125 | + // math.floor(a / b) but may be 1 less than that |
| 126 | + const auto r = std::remainder(lhs_value, rhs_value.get_d()); |
| 127 | + const auto q = Number{ (-r + lhs_value) / rhs_value.get_d() }; |
| 128 | + return PyTuple::create(q, Number{ r }); |
| 129 | + }, |
| 130 | + [](const double &lhs_value, const double &rhs_value) -> PyResult<PyTuple *> { |
| 131 | + // For floating-point numbers the result is (q, a % b), where q is usually |
| 132 | + // math.floor(a / b) but may be 1 less than that |
| 133 | + const auto r = std::remainder(lhs_value, rhs_value); |
| 134 | + const auto q = Number{ (-r + lhs_value) / rhs_value }; |
| 135 | + return PyTuple::create(q, Number{ r }); |
| 136 | + }, |
| 137 | + }, |
| 138 | + m_value.value, |
| 139 | + rhs->m_value.value); |
103 | 140 | } else { |
104 | | - return Err(type_error("unsupported operand type(s) for *: \'{}\' and \'{}\'", |
| 141 | + return Err(type_error("unsupported operand type(s) for %: \'{}\' and \'{}\'", |
105 | 142 | type()->name(), |
106 | 143 | obj->type()->name())); |
107 | 144 | } |
108 | 145 | } |
109 | 146 |
|
| 147 | +PyResult<PyObject *> PyNumber::__mul__(const PyObject *obj) const |
| 148 | +{ |
| 149 | + if (auto rhs = as_number(obj)) { |
| 150 | + return PyNumber::create(m_value * rhs->value()); |
| 151 | + } else { |
| 152 | + return Ok(not_implemented()); |
| 153 | + } |
| 154 | +} |
| 155 | + |
110 | 156 | PyResult<PyObject *> PyNumber::__pow__(const PyObject *obj, const PyObject *modulo_obj) const |
111 | 157 | { |
112 | 158 | if (auto rhs_ = as_number(obj)) { |
113 | | - if (modulo_obj == py_none()) { |
114 | | - return PyObject::from(m_value.exp(rhs_->value())); |
115 | | - } |
| 159 | + if (modulo_obj == py_none()) { return PyObject::from(m_value.exp(rhs_->value())); } |
116 | 160 | auto modulo_ = as_number(modulo_obj); |
117 | | - if (!modulo_) { |
118 | | - return Ok(not_implemented()); |
119 | | - } |
| 161 | + if (!modulo_) { return Ok(not_implemented()); } |
120 | 162 | mpz_class result{}; |
121 | | - mpz_class lhs = std::holds_alternative<BigIntType>( m_value.value) ? std::get<BigIntType>(m_value.value) : BigIntType{std::get<double>(m_value.value)}; |
122 | | - mpz_class rhs = std::holds_alternative<BigIntType>( rhs_->value().value) ? std::get<BigIntType>(rhs_->value().value) : BigIntType{std::get<double>(rhs_->value().value)}; |
123 | | - mpz_class modulo = std::holds_alternative<BigIntType>( modulo_->value().value) ? std::get<BigIntType>(modulo_->value().value) : BigIntType{std::get<double>(modulo_->value().value)}; |
| 163 | + mpz_class lhs = std::holds_alternative<BigIntType>(m_value.value) |
| 164 | + ? std::get<BigIntType>(m_value.value) |
| 165 | + : BigIntType{ std::get<double>(m_value.value) }; |
| 166 | + mpz_class rhs = std::holds_alternative<BigIntType>(rhs_->value().value) |
| 167 | + ? std::get<BigIntType>(rhs_->value().value) |
| 168 | + : BigIntType{ std::get<double>(rhs_->value().value) }; |
| 169 | + mpz_class modulo = std::holds_alternative<BigIntType>(modulo_->value().value) |
| 170 | + ? std::get<BigIntType>(modulo_->value().value) |
| 171 | + : BigIntType{ std::get<double>(modulo_->value().value) }; |
124 | 172 | mpz_powm(result.get_mpz_t(), lhs.get_mpz_t(), rhs.get_mpz_t(), modulo.get_mpz_t()); |
125 | 173 |
|
126 | | - return PyNumber::create(Number{result}); |
| 174 | + return PyNumber::create(Number{ result }); |
127 | 175 | } else { |
128 | 176 | return Err(type_error("unsupported operand type(s) for **: \'{}\' and \'{}\'", |
129 | 177 | type()->name(), |
|
0 commit comments