StrictModules/Objects/numerics.cpp (1,286 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
#include "StrictModules/Objects/numerics.h"
#include "StrictModules/Objects/object_interface.h"
#include "StrictModules/Objects/objects.h"
#include "StrictModules/Objects/callable.h"
#include "StrictModules/Objects/callable_wrapper.h"
#include <cmath>
#define INT_OP_BOTH_VALUE(lhs, rhs, make, op, py_op) \
do { \
if ((lhs)->value_ && (rhs)->value_) { \
return (make)((*((lhs)->value_))op(*((rhs)->value_))); \
} else { \
Ref<> r = \
Ref<>::steal((py_op)((lhs)->getPyObject(), (rhs)->getPyObject())); \
return (make)(std::move(r)); \
} \
} while (0)
#define FLOAT_OP_BOTH_VALUE(lhs, rhs, make, op, py_op) \
do { \
auto l = (lhs)->getReal(); \
auto r = (rhs)->getReal(); \
if (l && r) { \
return (make)((*l)op(*r)); \
} else { \
Ref<> ref = \
Ref<>::steal((py_op)((lhs)->getPyObject(), (rhs)->getPyObject())); \
return (make)(std::move(ref)); \
} \
} while (0)
#define INT_CMPOP_EITHER_VALUE(lhs, rhs, make, op, cmp_op) \
do { \
if ((lhs)->value_ || (rhs)->value_) { \
return (make)(((lhs)->value_)op((rhs)->value_)); \
} else { \
bool b = PyObject_RichCompareBool( \
(lhs)->getPyObject(), (rhs)->getPyObject(), cmp_op); \
return (make)(b); \
} \
} while (0)
#define INT_CMPOP_BOTH_VALUE(lhs, rhs, make, op, cmp_op) \
do { \
if ((lhs)->value_ && (rhs)->value_) { \
return (make)((*((lhs)->value_))op((*(rhs)->value_))); \
} else { \
bool b = PyObject_RichCompareBool( \
(lhs)->getPyObject(), (rhs)->getPyObject(), cmp_op); \
return (make)(b); \
} \
} while (0)
#define FLOAT_CMPOP_BOTH_VALUE(lhs, rhs, make, op, cmp_op) \
do { \
auto l = (lhs)->getReal(); \
auto r = (rhs)->getReal(); \
if (l && r) { \
return (make)((*l)op(*r)); \
} else { \
bool res = PyObject_RichCompareBool( \
(lhs)->getPyObject(), (rhs)->getPyObject(), cmp_op); \
return (make)(res); \
} \
} while (0)
namespace strictmod::objects {
bool StrictNumeric::isHashable() const {
return true;
}
bool StrictNumeric::eq(const BaseStrictObject& other) const {
try {
const StrictNumeric& num = dynamic_cast<const StrictNumeric&>(other);
auto l = getReal();
auto r = num.getReal();
if (l.has_value() && r.has_value()) {
return l == r;
}
return PyObject_RichCompareBool(getPyObject(), num.getPyObject(), Py_EQ);
} catch (const std::bad_cast&) {
return false;
}
}
static void checkDivisionByZero(
const std::shared_ptr<StrictNumeric>& num,
const CallerContext& caller) {
if (num->getReal() == 0) {
caller.raiseExceptionStr(DivisionByZeroType(), "division by zero");
}
}
// StrictInt
StrictInt::StrictInt(
std::shared_ptr<StrictType> type,
std::weak_ptr<StrictModuleObject> creator,
int_type value)
: StrictNumeric(std::move(type), std::move(creator)),
value_(value),
pyValue_(nullptr),
displayName_() {}
StrictInt::StrictInt(
std::shared_ptr<StrictType> type,
std::shared_ptr<StrictModuleObject> creator,
int_type value)
: StrictInt(std::move(type), std::weak_ptr(creator), value) {}
StrictInt::StrictInt(
std::shared_ptr<StrictType> type,
std::weak_ptr<StrictModuleObject> creator,
PyObject* pyValue // constructor will incref on the object
)
: StrictNumeric(std::move(type), std::move(creator)),
value_(),
pyValue_(Ref<>(pyValue)),
displayName_() {
int overflow = 0;
value_ = PyLong_AsLongLongAndOverflow(pyValue, &overflow);
if (PyErr_Occurred()) {
PyErr_Clear();
value_ = std::nullopt;
} else if (overflow) {
value_ = std::nullopt;
}
}
std::optional<double> StrictInt::getReal() const {
return value_;
}
bool StrictInt::isOverflow() const {
return !value_.has_value();
}
size_t StrictInt::hash() const {
if (value_) {
return size_t(*value_);
}
return PyObject_Hash(getPyObject());
}
Ref<> StrictInt::getPyObject() const {
if (pyValue_ == nullptr) {
assert(value_.has_value());
pyValue_ = Ref<>::steal(PyLong_FromLongLong(*value_));
}
return Ref<>(pyValue_.get());
}
std::string StrictInt::getDisplayName() const {
if (displayName_.empty()) {
if (value_) {
displayName_ = std::to_string(*value_);
} else {
Ref<> pyStr = Ref<>::steal(PyObject_Str(getPyObject().get()));
displayName_ = PyUnicode_AsUTF8(pyStr.get());
}
}
return displayName_;
}
std::shared_ptr<BaseStrictObject> StrictInt::copy(const CallerContext& caller) {
if (value_) {
return std::make_shared<StrictInt>(type_, caller.caller, *value_);
}
return std::make_shared<StrictInt>(type_, caller.caller, getPyObject().get());
}
// wrapped methods
std::shared_ptr<BaseStrictObject> StrictInt::int__bool__(
std::shared_ptr<StrictInt> self,
const CallerContext&) {
return self->value_ == 0 ? StrictFalse() : StrictTrue();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__str__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller) {
return caller.makeStr(self->getDisplayName());
}
std::shared_ptr<BaseStrictObject> StrictInt::int__abs__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller) {
if (self->value_) {
return caller.makeInt(abs(*(self->value_)));
}
return caller.makeInt(Ref<>::steal(PyNumber_Absolute(self->getPyObject())));
}
std::shared_ptr<BaseStrictObject> StrictInt::int__round__(
std::shared_ptr<StrictInt> self,
const CallerContext&,
std::shared_ptr<BaseStrictObject>) {
return self;
}
std::shared_ptr<BaseStrictObject> StrictInt::int__new__(
std::shared_ptr<StrictInt>,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> instType,
std::shared_ptr<BaseStrictObject> value) {
auto type = std::dynamic_pointer_cast<StrictType>(std::move(instType));
if (!type->isSubType(IntType())) {
caller.raiseTypeError("{} is not a subtype of int", type->getName());
}
if (value == nullptr) {
return std::make_shared<StrictInt>(std::move(type), caller.caller, 0);
}
// value is numeric
auto num = std::dynamic_pointer_cast<StrictNumeric>(value);
if (num) {
auto real = num->getReal();
if (real) {
return std::make_shared<StrictInt>(
std::move(type), caller.caller, long(*real));
} else {
Ref<> l = Ref<>::steal(PyNumber_Long(num->getPyObject()));
return std::make_shared<StrictInt>(
std::move(type), caller.caller, l.get());
}
}
// value is string
auto str = std::dynamic_pointer_cast<StrictString>(value);
if (str) {
try {
int_type i = std::stoll(str->getValue());
return std::make_shared<StrictInt>(std::move(type), caller.caller, i);
} catch (const std::invalid_argument&) {
caller.raiseExceptionStr(
ValueErrorType(), "'{}' cannot be converted to int", str->getValue());
} catch (const std::out_of_range&) {
caller.raiseExceptionStr(
ValueErrorType(), "'{}' cannot be converted to int", str->getValue());
}
}
// check __int__
auto intFunc = iLoadAttrOnType(value, "__int__", nullptr, caller);
if (intFunc) {
return iCall(std::move(intFunc), kEmptyArgs, kEmptyArgNames, caller);
}
// error
caller.error<UnsupportedException>("int", value->getTypeRef().getName());
return makeUnknown(caller, "int({})", std::move(value));
}
std::shared_ptr<BaseStrictObject> fromPyNumberHelper(
const CallerContext& caller,
const Ref<>& number) {
if (PyLong_CheckExact(number.get())) {
return std::make_shared<StrictInt>(IntType(), caller.caller, number.get());
} else if (PyFloat_CheckExact(number.get())) {
return std::make_shared<StrictFloat>(
FloatType(), caller.caller, number.get());
}
return nullptr;
}
std::shared_ptr<BaseStrictObject> __pow__Helper(
std::shared_ptr<StrictNumeric> self,
const CallerContext& caller,
std::shared_ptr<StrictNumeric> num,
std::shared_ptr<BaseStrictObject> mod) {
Ref<> modObj = Ref<>(Py_None);
if (mod != nullptr && mod != NoneObject()) {
auto modNum = std::dynamic_pointer_cast<StrictNumeric>(mod);
if (modNum == nullptr) {
caller.raiseTypeError(
"unsupported operand type for pow(): '{}', '{}', '{}'",
self->getTypeRef().getName(),
num->getTypeRef().getName(),
mod->getTypeRef().getName());
}
modObj = modNum->getPyObject();
}
Ref<> selfObj = self->getPyObject();
Ref<> rhsObj = num->getPyObject();
Ref<> result = Ref<>::steal(PyNumber_Power(selfObj, rhsObj, Py_None));
std::shared_ptr<BaseStrictObject> unknown;
if (mod == nullptr) {
unknown = makeUnknown(
caller, "pow({}, {})", self->getDisplayName(), num->getDisplayName());
} else {
unknown = makeUnknown(
caller,
"pow({}, {}, {})",
self->getDisplayName(),
num->getDisplayName(),
mod->getDisplayName());
}
if (result == nullptr) {
if (PyErr_Occurred()) {
PyErr_Clear();
caller.raiseExceptionStr(ValueErrorType(), "Error calling pow");
}
return unknown;
}
auto strictResult = fromPyNumberHelper(caller, result);
if (strictResult == nullptr) {
return unknown;
}
return strictResult;
}
std::shared_ptr<BaseStrictObject> StrictInt::int__pow__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs,
std::shared_ptr<BaseStrictObject> mod) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
if (num == nullptr) {
return NotImplemented();
}
return __pow__Helper(std::move(self), caller, std::move(num), std::move(mod));
}
std::shared_ptr<BaseStrictObject> StrictInt::int__rpow__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs,
std::shared_ptr<BaseStrictObject> mod) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(lhs);
if (num == nullptr) {
return NotImplemented();
}
return __pow__Helper(std::move(num), caller, std::move(self), std::move(mod));
}
std::shared_ptr<BaseStrictObject> __divmod__Helper(
std::shared_ptr<StrictNumeric> self,
const CallerContext& caller,
std::shared_ptr<StrictNumeric> num) {
checkDivisionByZero(num, caller);
Ref<> selfObj = self->getPyObject();
Ref<> numObj = num->getPyObject();
Ref<> result = Ref<>::steal(PyNumber_Divmod(selfObj, numObj));
if (!PyTuple_Check(result.get()) || PyTuple_GET_SIZE(result.get()) != 2) {
caller.raiseTypeError(
"divmod({}, {}) did not return tuple of size 2",
self->getDisplayName(),
num->getDisplayName());
}
Ref<> fst = Ref<>(PyTuple_GET_ITEM(result.get(), 0));
Ref<> snd = Ref<>(PyTuple_GET_ITEM(result.get(), 1));
auto fstObj = fromPyNumberHelper(caller, fst);
auto sndObj = fromPyNumberHelper(caller, snd);
assert(fstObj != nullptr && sndObj != nullptr);
return caller.makePair(std::move(fstObj), std::move(sndObj));
}
std::shared_ptr<BaseStrictObject> StrictInt::int__divmod__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
return __divmod__Helper(std::move(self), caller, std::move(num));
}
std::shared_ptr<BaseStrictObject> StrictInt::int__rdivmod__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(lhs);
return __divmod__Helper(std::move(num), caller, std::move(self));
}
std::shared_ptr<BaseStrictObject> StrictInt::int__add__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_OP_BOTH_VALUE(self, rhsInt, caller.makeInt, +, PyNumber_Add);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__and__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_OP_BOTH_VALUE(self, rhsInt, caller.makeInt, &, PyNumber_And);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__floordiv__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
checkDivisionByZero(rhsInt, caller);
INT_OP_BOTH_VALUE(self, rhsInt, caller.makeInt, /, PyNumber_FloorDivide);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__lshift__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_OP_BOTH_VALUE(self, rhsInt, caller.makeInt, <<, PyNumber_Lshift);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__mod__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_OP_BOTH_VALUE(self, rhsInt, caller.makeInt, %, PyNumber_Remainder);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__mul__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_OP_BOTH_VALUE(self, rhsInt, caller.makeInt, *, PyNumber_Multiply);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__or__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_OP_BOTH_VALUE(self, rhsInt, caller.makeInt, |, PyNumber_Or);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__rshift__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_OP_BOTH_VALUE(self, rhsInt, caller.makeInt, >>, PyNumber_Rshift);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__sub__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_OP_BOTH_VALUE(self, rhsInt, caller.makeInt, -, PyNumber_Subtract);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__truediv__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
checkDivisionByZero(rhsInt, caller);
if (self->value_ && rhsInt->value_) {
return caller.makeFloat(double(*self->value_) / *rhsInt->value_);
} else {
Ref<> l = Ref<>::steal(
PyNumber_TrueDivide(self->getPyObject(), rhsInt->getPyObject()));
return caller.makeFloat(std::move(l));
}
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__xor__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_OP_BOTH_VALUE(self, rhsInt, caller.makeInt, ^, PyNumber_Xor);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__radd__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto lhsInt = std::dynamic_pointer_cast<StrictInt>(lhs);
if (lhsInt) {
INT_OP_BOTH_VALUE(lhsInt, self, caller.makeInt, +, PyNumber_Add);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__rand__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto lhsInt = std::dynamic_pointer_cast<StrictInt>(lhs);
if (lhsInt) {
INT_OP_BOTH_VALUE(lhsInt, self, caller.makeInt, &, PyNumber_And);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__rfloordiv__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto lhsInt = std::dynamic_pointer_cast<StrictInt>(lhs);
if (lhsInt) {
checkDivisionByZero(lhsInt, caller);
INT_OP_BOTH_VALUE(lhsInt, self, caller.makeInt, /, PyNumber_FloorDivide);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__rlshift__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto lhsInt = std::dynamic_pointer_cast<StrictInt>(lhs);
if (lhsInt) {
INT_OP_BOTH_VALUE(lhsInt, self, caller.makeInt, <<, PyNumber_Lshift);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__rmod__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto lhsInt = std::dynamic_pointer_cast<StrictInt>(lhs);
if (lhsInt) {
INT_OP_BOTH_VALUE(lhsInt, self, caller.makeInt, %, PyNumber_Remainder);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__rmul__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto lhsInt = std::dynamic_pointer_cast<StrictInt>(lhs);
if (lhsInt) {
INT_OP_BOTH_VALUE(lhsInt, self, caller.makeInt, *, PyNumber_Multiply);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__ror__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto lhsInt = std::dynamic_pointer_cast<StrictInt>(lhs);
if (lhsInt) {
INT_OP_BOTH_VALUE(lhsInt, self, caller.makeInt, |, PyNumber_Or);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__rrshift__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto lhsInt = std::dynamic_pointer_cast<StrictInt>(lhs);
if (lhsInt) {
INT_OP_BOTH_VALUE(lhsInt, self, caller.makeInt, >>, PyNumber_Rshift);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__rsub__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto lhsInt = std::dynamic_pointer_cast<StrictInt>(lhs);
if (lhsInt) {
INT_OP_BOTH_VALUE(lhsInt, self, caller.makeInt, -, PyNumber_Subtract);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__rtruediv__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto lhsInt = std::dynamic_pointer_cast<StrictInt>(lhs);
if (lhsInt) {
checkDivisionByZero(self, caller);
if (self->value_ && lhsInt->value_) {
return caller.makeFloat(double(*lhsInt->value_) / *self->value_);
} else {
Ref<> l = Ref<>::steal(
PyNumber_TrueDivide(lhsInt->getPyObject(), self->getPyObject()));
return caller.makeFloat(std::move(l));
}
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__rxor__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto lhsInt = std::dynamic_pointer_cast<StrictInt>(lhs);
if (lhsInt) {
INT_OP_BOTH_VALUE(lhsInt, self, caller.makeInt, ^, PyNumber_Xor);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__pos__(
std::shared_ptr<StrictInt> self,
const CallerContext&) {
return self;
}
std::shared_ptr<BaseStrictObject> StrictInt::int__neg__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller) {
if (self->value_) {
return caller.makeInt(-*self->value_);
} else {
Ref<> l = Ref<>::steal(PyNumber_Negative(self->getPyObject()));
return caller.makeInt(std::move(l));
}
}
std::shared_ptr<BaseStrictObject> StrictInt::int__invert__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller) {
if (self->value_) {
return caller.makeInt(~*self->value_);
} else {
Ref<> l = Ref<>::steal(PyNumber_Invert(self->getPyObject()));
return caller.makeInt(std::move(l));
}
}
std::shared_ptr<BaseStrictObject> StrictInt::int__eq__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsNum = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsNum) {
INT_CMPOP_EITHER_VALUE(self, rhsNum, caller.makeBool, ==, Py_EQ);
}
return NotImplemented();
}
// TODO handle both overflow case
std::shared_ptr<BaseStrictObject> StrictInt::int__ne__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_CMPOP_EITHER_VALUE(self, rhsInt, caller.makeBool, !=, Py_NE);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__lt__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_CMPOP_BOTH_VALUE(self, rhsInt, caller.makeBool, <, Py_LT);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__le__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_CMPOP_BOTH_VALUE(self, rhsInt, caller.makeBool, <=, Py_LE);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__gt__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_CMPOP_BOTH_VALUE(self, rhsInt, caller.makeBool, >, Py_GT);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictInt::int__ge__(
std::shared_ptr<StrictInt> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto rhsInt = std::dynamic_pointer_cast<StrictInt>(rhs);
if (rhsInt) {
INT_CMPOP_BOTH_VALUE(self, rhsInt, caller.makeBool, >=, Py_GE);
}
return NotImplemented();
}
// StrictIntType
std::unique_ptr<BaseStrictObject> StrictIntType::constructInstance(
std::weak_ptr<StrictModuleObject> caller) {
return std::make_unique<StrictInt>(
std::static_pointer_cast<StrictType>(shared_from_this()),
std::move(caller),
0);
}
std::shared_ptr<StrictType> StrictIntType::recreate(
std::string name,
std::weak_ptr<StrictModuleObject> caller,
std::vector<std::shared_ptr<BaseStrictObject>> bases,
std::shared_ptr<DictType> members,
std::shared_ptr<StrictType> metatype,
bool isImmutable) {
return createType<StrictIntType>(
std::move(name),
std::move(caller),
std::move(bases),
std::move(members),
std::move(metatype),
isImmutable);
}
std::vector<std::type_index> StrictIntType::getBaseTypeinfos() const {
std::vector<std::type_index> baseVec = StrictObjectType::getBaseTypeinfos();
baseVec.emplace_back(typeid(StrictIntType));
return baseVec;
}
Ref<> StrictIntType::getPyObject() const {
return Ref<>(reinterpret_cast<PyObject*>(&PyLong_Type));
}
std::shared_ptr<BaseStrictObject> StrictIntType::getTruthValue(
std::shared_ptr<BaseStrictObject> obj,
const CallerContext& caller) {
if (obj->getType() == IntType()) {
return assertStaticCast<StrictInt>(obj)->getValue() == 0 ? StrictFalse()
: StrictTrue();
}
return StrictObjectType::getTruthValue(std::move(obj), caller);
}
void StrictIntType::addMethods() {
addMethod("__add__", StrictInt::int__add__);
addMethod("__and__", StrictInt::int__and__);
addMethod("__floordiv__", StrictInt::int__floordiv__);
addMethod("__lshift__", StrictInt::int__lshift__);
addMethod("__mod__", StrictInt::int__mod__);
addMethod("__mul__", StrictInt::int__mul__);
addMethod("__or__", StrictInt::int__or__);
addMethod("__rshift__", StrictInt::int__rshift__);
addMethod("__sub__", StrictInt::int__sub__);
addMethod("__truediv__", StrictInt::int__truediv__);
addMethod("__xor__", StrictInt::int__xor__);
addMethod("__radd__", StrictInt::int__radd__);
addMethod("__rand__", StrictInt::int__rand__);
addMethod("__rfloordiv__", StrictInt::int__rfloordiv__);
addMethod("__rlshift__", StrictInt::int__rlshift__);
addMethod("__rmod__", StrictInt::int__rmod__);
addMethod("__rmul__", StrictInt::int__rmul__);
addMethod("__ror__", StrictInt::int__ror__);
addMethod("__rrshift__", StrictInt::int__rrshift__);
addMethod("__rsub__", StrictInt::int__rsub__);
addMethod("__rtruediv__", StrictInt::int__rtruediv__);
addMethod("__rxor__", StrictInt::int__rxor__);
addMethod("__pos__", StrictInt::int__pos__);
addMethod("__neg__", StrictInt::int__neg__);
addMethod("__invert__", StrictInt::int__invert__);
addMethod("__eq__", StrictInt::int__eq__);
addMethod("__ne__", StrictInt::int__ne__);
addMethod("__lt__", StrictInt::int__lt__);
addMethod("__le__", StrictInt::int__le__);
addMethod("__gt__", StrictInt::int__gt__);
addMethod("__ge__", StrictInt::int__ge__);
addMethod(kDunderBool, StrictInt::int__bool__);
addMethod(kDunderStr, StrictInt::int__str__);
addMethod("__abs__", StrictInt::int__abs__);
addMethodDefault("__round__", StrictInt::int__round__, nullptr);
addStaticMethodDefault("__new__", StrictInt::int__new__, nullptr);
addMethodDefault("__pow__", StrictInt::int__pow__, nullptr);
addMethodDefault("__rpow__", StrictInt::int__rpow__, nullptr);
addMethod("__divmod__", StrictInt::int__divmod__);
addMethod("__rdivmod__", StrictInt::int__rdivmod__);
PyObject* intType = reinterpret_cast<PyObject*>(&PyLong_Type);
addPyWrappedMethodObj<>(kDunderRepr, intType, StrictString::strFromPyObj);
addPyWrappedMethodObj<1>("__format__", intType, StrictString::strFromPyObj);
addPyWrappedMethodDefaultObj(
"to_bytes", intType, StrictBytes::bytesFromPyObj, 1, 3);
}
// StrictBool
Ref<> StrictBool::getPyObject() const {
if (pyValue_ == nullptr) {
pyValue_ = Ref<>(value_ == 0 ? Py_False : Py_True);
}
return Ref<>(pyValue_.get());
}
std::string StrictBool::getDisplayName() const {
if (displayName_.empty()) {
displayName_ = value_ == 0 ? "false" : "true";
}
return displayName_;
}
std::shared_ptr<BaseStrictObject> StrictBool::copy(
const CallerContext& caller) {
assert(value_.has_value());
return std::make_shared<StrictBool>(type_, caller.caller, *value_);
}
std::shared_ptr<BaseStrictObject> StrictBool::boolFromPyObj(
Ref<> pyObj,
const CallerContext&) {
if (pyObj.get() == Py_True) {
return StrictTrue();
}
return StrictFalse();
}
std::shared_ptr<BaseStrictObject> StrictBool::boolOrNotImplementedFromPyObj(
Ref<> pyObj,
const CallerContext& caller) {
if (pyObj.get() == Py_NotImplemented) {
return NotImplemented();
}
return boolFromPyObj(std::move(pyObj), caller);
}
std::shared_ptr<BaseStrictObject> StrictBool::bool__new__(
std::shared_ptr<StrictBool>,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> instType,
std::shared_ptr<BaseStrictObject> value) {
auto type = assertStaticCast<StrictType>(std::move(instType));
if (!type->isSubType(BoolType())) {
caller.raiseTypeError("{} is not a subtype of bool", type->getName());
}
if (!value) {
return StrictFalse();
}
return iGetTruthValue(std::move(value), caller);
}
// StrictBoolType
Ref<> StrictBoolType::getPyObject() const {
return Ref<>(reinterpret_cast<PyObject*>(&PyBool_Type));
}
std::unique_ptr<BaseStrictObject> StrictBoolType::constructInstance(
std::weak_ptr<StrictModuleObject> caller) {
return std::make_unique<StrictBool>(
std::static_pointer_cast<StrictType>(shared_from_this()),
std::move(caller),
0);
}
std::shared_ptr<StrictType> StrictBoolType::recreate(
std::string name,
std::weak_ptr<StrictModuleObject> caller,
std::vector<std::shared_ptr<BaseStrictObject>> bases,
std::shared_ptr<DictType> members,
std::shared_ptr<StrictType> metatype,
bool isImmutable) {
return createType<StrictBoolType>(
std::move(name),
std::move(caller),
std::move(bases),
std::move(members),
std::move(metatype),
isImmutable);
}
std::vector<std::type_index> StrictBoolType::getBaseTypeinfos() const {
std::vector<std::type_index> baseVec = StrictIntType::getBaseTypeinfos();
baseVec.emplace_back(typeid(StrictBoolType));
return baseVec;
}
bool StrictBoolType::isBaseType() const {
return false;
}
std::shared_ptr<BaseStrictObject> StrictBoolType::getTruthValue(
std::shared_ptr<BaseStrictObject> obj,
const CallerContext&) {
// assert since bool has no subtypes
assert(obj->getType() == BoolType());
return obj;
}
void StrictBoolType::addMethods() {
StrictIntType::addMethods();
addStaticMethodDefault("__new__", StrictBool::bool__new__, nullptr);
addPyWrappedMethodObj<>(
kDunderRepr,
reinterpret_cast<PyObject*>(&PyBool_Type),
StrictString::strFromPyObj);
addPyWrappedMethodObj<>(
kDunderStr,
reinterpret_cast<PyObject*>(&PyBool_Type),
StrictString::strFromPyObj);
}
// Float
StrictFloat::StrictFloat(
std::shared_ptr<StrictType> type,
std::weak_ptr<StrictModuleObject> creator,
double value)
: StrictNumeric(std::move(type), std::move(creator)),
value_(value),
pyValue_(nullptr),
displayName_() {}
StrictFloat::StrictFloat(
std::shared_ptr<StrictType> type,
std::shared_ptr<StrictModuleObject> creator,
double value)
: StrictFloat(std::move(type), std::weak_ptr(std::move(creator)), value) {}
StrictFloat::StrictFloat(
std::shared_ptr<StrictType> type,
std::weak_ptr<StrictModuleObject> creator,
PyObject* pyValue // constructor will incref on the object
)
: StrictNumeric(std::move(type), std::move(creator)),
value_(PyFloat_AsDouble(pyValue)),
pyValue_(Ref<>(pyValue)),
displayName_() {}
std::optional<double> StrictFloat::getReal() const {
return value_;
}
bool StrictFloat::isOverflow() const {
return false;
}
size_t StrictFloat::hash() const {
return size_t((long long)(value_));
}
Ref<> StrictFloat::getPyObject() const {
if (pyValue_ == nullptr) {
pyValue_ = Ref<>::steal(PyFloat_FromDouble(value_));
}
return Ref<>(pyValue_.get());
}
std::string StrictFloat::getDisplayName() const {
if (displayName_.empty()) {
displayName_ = std::to_string(value_);
}
return displayName_;
}
std::shared_ptr<BaseStrictObject> StrictFloat::copy(
const CallerContext& caller) {
return std::make_shared<StrictFloat>(type_, caller.caller, value_);
}
// wrapped methods
std::shared_ptr<BaseStrictObject> StrictFloat::float__bool__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller) {
return caller.makeBool(self->value_ != 0);
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__str__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller) {
return caller.makeStr(std::to_string(self->value_));
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__abs__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller) {
return caller.makeFloat(abs(self->value_));
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__round__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> ndigit) {
// no C API for round, so we have to use the float method
Ref<> selfObj = self->getPyObject();
_Py_IDENTIFIER(__round__);
Ref<> round =
Ref<>::steal(_PyObject_LookupSpecial(selfObj.get(), &PyId___round__));
if (round == nullptr) {
if (PyErr_Occurred()) {
PyErr_Clear();
}
caller.raiseTypeError(
"type {} doesn't define __round__",
self->getTypeRef().getDisplayName());
}
Ref<> result;
if (ndigit == nullptr || ndigit == NoneObject()) {
result.reset(_PyObject_CallNoArg(round.get()));
} else {
auto ndigitNum = std::dynamic_pointer_cast<StrictInt>(ndigit);
if (ndigitNum == nullptr) {
caller.raiseTypeError("{} is not an integer", ndigit->getDisplayName());
}
Ref<> ndigitObj = ndigitNum->getPyObject();
result.reset(
PyObject_CallFunctionObjArgs(round.get(), ndigitObj.get(), NULL));
}
auto strictResult = fromPyNumberHelper(caller, result);
if (strictResult == nullptr) {
return makeUnknown(
caller,
"round({}, {})",
self->getDisplayName(),
ndigit ? ndigit : NoneObject());
}
return strictResult;
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__new__(
std::shared_ptr<StrictFloat>,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> instType,
std::shared_ptr<BaseStrictObject> value) {
auto type = std::dynamic_pointer_cast<StrictType>(std::move(instType));
if (!type->isSubType(FloatType())) {
caller.raiseTypeError("{} is not a subtype of float", type->getName());
}
if (value == nullptr) {
return std::make_shared<StrictFloat>(std::move(type), caller.caller, 0.0);
}
// value is numeric
auto num = std::dynamic_pointer_cast<StrictNumeric>(value);
if (num) {
auto real = num->getReal();
if (real) {
return std::make_shared<StrictFloat>(
std::move(type), caller.caller, *real);
} else {
return std::make_shared<StrictFloat>(
std::move(type), caller.caller, num->getPyObject());
}
}
// value is string
auto str = std::dynamic_pointer_cast<StrictString>(value);
if (str) {
try {
double i = std::stod(str->getValue());
return std::make_shared<StrictFloat>(std::move(type), caller.caller, i);
} catch (const std::invalid_argument&) {
caller.raiseExceptionStr(
ValueErrorType(),
"'{}' cannot be converted to float",
str->getValue());
} catch (const std::out_of_range&) {
caller.raiseExceptionStr(
ValueErrorType(),
"'{}' cannot be converted to float",
str->getValue());
}
}
// check __float__
auto floatFunc = iLoadAttrOnType(value, "__float__", nullptr, caller);
if (floatFunc) {
return iCall(std::move(floatFunc), kEmptyArgs, kEmptyArgNames, caller);
}
// error
caller.error<UnsupportedException>("float", value->getTypeRef().getName());
return makeUnknown(caller, "float({})", std::move(value));
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__pow__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs,
std::shared_ptr<BaseStrictObject> mod) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
if (num == nullptr) {
return NotImplemented();
}
return __pow__Helper(std::move(self), caller, std::move(num), std::move(mod));
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__rpow__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs,
std::shared_ptr<BaseStrictObject> mod) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(lhs);
if (num == nullptr) {
return NotImplemented();
}
return __pow__Helper(std::move(num), caller, std::move(self), std::move(mod));
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__divmod__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
return __divmod__Helper(std::move(self), caller, std::move(num));
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__rdivmod__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(lhs);
return __divmod__Helper(std::move(num), caller, std::move(self));
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__add__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
if (num) {
FLOAT_OP_BOTH_VALUE(self, num, caller.makeFloat, +, PyNumber_Add);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__floordiv__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
checkDivisionByZero(num, caller);
if (num) {
FLOAT_OP_BOTH_VALUE(self, num, caller.makeInt, /, PyNumber_FloorDivide);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__mod__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
if (num) {
Ref<> selfFloat = self->getPyObject();
Ref<> numFloat = num->getPyObject();
Ref<> result = Ref<>::steal(PyNumber_Remainder(selfFloat, numFloat));
return caller.makeFloat(std::move(result));
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__mul__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
if (num) {
FLOAT_OP_BOTH_VALUE(self, num, caller.makeFloat, *, PyNumber_Multiply);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__sub__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
if (num) {
FLOAT_OP_BOTH_VALUE(self, num, caller.makeFloat, -, PyNumber_Subtract);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__truediv__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
checkDivisionByZero(num, caller);
if (num) {
FLOAT_OP_BOTH_VALUE(self, num, caller.makeFloat, /, PyNumber_TrueDivide);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__radd__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(lhs);
if (num) {
FLOAT_OP_BOTH_VALUE(num, self, caller.makeFloat, +, PyNumber_Add);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__rfloordiv__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(lhs);
checkDivisionByZero(self, caller);
if (num) {
FLOAT_OP_BOTH_VALUE(num, self, caller.makeInt, /, PyNumber_FloorDivide);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__rmod__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(lhs);
if (num) {
Ref<> selfFloat = self->getPyObject();
Ref<> numFloat = num->getPyObject();
Ref<> result = Ref<>::steal(PyNumber_Remainder(numFloat, selfFloat));
return caller.makeFloat(std::move(result));
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__rmul__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(lhs);
if (num) {
FLOAT_OP_BOTH_VALUE(num, self, caller.makeFloat, *, PyNumber_Multiply);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__rsub__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(lhs);
if (num) {
FLOAT_OP_BOTH_VALUE(num, self, caller.makeFloat, -, PyNumber_Subtract);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__rtruediv__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> lhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(lhs);
checkDivisionByZero(self, caller);
if (num) {
FLOAT_OP_BOTH_VALUE(num, self, caller.makeFloat, /, PyNumber_TrueDivide);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__pos__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller) {
return caller.makeFloat(self->value_);
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__neg__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller) {
return caller.makeFloat(-self->value_);
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__eq__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
if (num) {
return caller.makeBool(self->value_ == num->getReal());
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__ne__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
if (num) {
return caller.makeBool(self->value_ != num->getReal());
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__lt__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
if (num) {
FLOAT_CMPOP_BOTH_VALUE(self, num, caller.makeBool, <, Py_LT);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__le__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
if (num) {
FLOAT_CMPOP_BOTH_VALUE(self, num, caller.makeBool, <=, Py_LE);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__gt__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
if (num) {
FLOAT_CMPOP_BOTH_VALUE(self, num, caller.makeBool, >, Py_GT);
}
return NotImplemented();
}
std::shared_ptr<BaseStrictObject> StrictFloat::float__ge__(
std::shared_ptr<StrictFloat> self,
const CallerContext& caller,
std::shared_ptr<BaseStrictObject> rhs) {
auto num = std::dynamic_pointer_cast<StrictNumeric>(rhs);
if (num) {
FLOAT_CMPOP_BOTH_VALUE(self, num, caller.makeBool, >=, Py_GE);
}
return NotImplemented();
}
std::unique_ptr<BaseStrictObject> StrictFloatType::constructInstance(
std::weak_ptr<StrictModuleObject> caller) {
return std::make_unique<StrictFloat>(
std::static_pointer_cast<StrictType>(shared_from_this()),
std::move(caller),
0);
}
std::shared_ptr<StrictType> StrictFloatType::recreate(
std::string name,
std::weak_ptr<StrictModuleObject> caller,
std::vector<std::shared_ptr<BaseStrictObject>> bases,
std::shared_ptr<DictType> members,
std::shared_ptr<StrictType> metatype,
bool isImmutable) {
return createType<StrictFloatType>(
std::move(name),
std::move(caller),
std::move(bases),
std::move(members),
std::move(metatype),
isImmutable);
}
std::vector<std::type_index> StrictFloatType::getBaseTypeinfos() const {
std::vector<std::type_index> baseVec = StrictObjectType::getBaseTypeinfos();
baseVec.emplace_back(typeid(StrictFloatType));
return baseVec;
}
Ref<> StrictFloatType::getPyObject() const {
return Ref<>(reinterpret_cast<PyObject*>(&PyFloat_Type));
}
void StrictFloatType::addMethods() {
addMethod("__add__", StrictFloat::float__add__);
addMethod("__floordiv__", StrictFloat::float__floordiv__);
addMethod("__mod__", StrictFloat::float__mod__);
addMethod("__mul__", StrictFloat::float__mul__);
addMethod("__sub__", StrictFloat::float__sub__);
addMethod("__truediv__", StrictFloat::float__truediv__);
addMethod("__radd__", StrictFloat::float__radd__);
addMethod("__rfloordiv__", StrictFloat::float__rfloordiv__);
addMethod("__rmod__", StrictFloat::float__rmod__);
addMethod("__rmul__", StrictFloat::float__rmul__);
addMethod("__rsub__", StrictFloat::float__rsub__);
addMethod("__rtruediv__", StrictFloat::float__rtruediv__);
addMethod("__pos__", StrictFloat::float__pos__);
addMethod("__neg__", StrictFloat::float__neg__);
addMethod("__eq__", StrictFloat::float__eq__);
addMethod("__ne__", StrictFloat::float__ne__);
addMethod("__lt__", StrictFloat::float__lt__);
addMethod("__le__", StrictFloat::float__le__);
addMethod("__gt__", StrictFloat::float__gt__);
addMethod("__ge__", StrictFloat::float__ge__);
addMethod(kDunderBool, StrictFloat::float__bool__);
addMethod("__abs__", StrictFloat::float__abs__);
addMethodDefault("__round__", StrictFloat::float__round__, nullptr);
addStaticMethodDefault("__new__", StrictFloat::float__new__, nullptr);
addMethodDefault("__pow__", StrictFloat::float__pow__, nullptr);
addMethodDefault("__rpow__", StrictFloat::float__rpow__, nullptr);
addMethod("__divmod__", StrictFloat::float__divmod__);
addMethod("__rdivmod__", StrictFloat::float__rdivmod__);
PyObject* floatType = reinterpret_cast<PyObject*>(&PyFloat_Type);
addPyWrappedMethodObj<>(kDunderRepr, floatType, StrictString::strFromPyObj);
addPyWrappedMethodObj<>(kDunderStr, floatType, StrictString::strFromPyObj);
addPyWrappedMethodObj<1>("__format__", floatType, StrictString::strFromPyObj);
addPyWrappedMethodObj<>("is_integer", floatType, StrictBool::boolFromPyObj);
}
} // namespace strictmod::objects