Commit 47f126ad authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #793 from Daetalus/test_unary

Some improvements to make test unary could pass
parents 7c2b76ca 4881de13
# expected: fail
"""Test compiler changes for unary ops (+, -, ~) introduced in Python 2.2"""
import unittest
......
......@@ -198,6 +198,11 @@ extern "C" Box* complexDiv(BoxedComplex* lhs, Box* rhs) {
}
}
Box* complexPos(BoxedComplex* self) {
assert(self->cls == complex_cls);
return PyComplex_FromDoubles(self->real, self->imag);
}
// str and repr
// For now, just print the same way as ordinary doubles.
// TODO this is wrong, e.g. if real or imaginary part is an integer, there should
......@@ -260,6 +265,60 @@ Box* complexNew(Box* _cls, Box* real, Box* imag) {
return new BoxedComplex(real_f, imag_f);
}
static PyObject* complex_richcompare(PyObject* v, PyObject* w, int op) noexcept {
PyObject* res;
int equal;
if (op != Py_EQ && op != Py_NE) {
/* for backwards compatibility, comparisons with non-numbers return
* NotImplemented. Only comparisons with core numeric types raise
* TypeError.
*/
if (PyInt_Check(w) || PyLong_Check(w) || PyFloat_Check(w) || PyComplex_Check(w)) {
PyErr_SetString(PyExc_TypeError, "no ordering relation is defined "
"for complex numbers");
return NULL;
}
return Py_NotImplemented;
}
assert(PyComplex_Check(v));
BoxedComplex* lhs = static_cast<BoxedComplex*>(v);
if (PyInt_Check(w) || PyLong_Check(w)) {
/* Check for 0->g0 imaginary part first to avoid the rich
* comparison when possible->g
*/
if (lhs->imag == 0.0) {
PyObject* j, *sub_res;
j = PyFloat_FromDouble(lhs->real);
if (j == NULL)
return NULL;
sub_res = PyObject_RichCompare(j, w, op);
Py_DECREF(j);
return sub_res;
} else {
equal = 0;
}
} else if (PyFloat_Check(w)) {
equal = (lhs->real == PyFloat_AsDouble(w) && lhs->imag == 0.0);
} else if (PyComplex_Check(w)) {
BoxedComplex* rhs = static_cast<BoxedComplex*>(w);
equal = (lhs->real == rhs->real && lhs->imag == rhs->imag);
} else {
return Py_NotImplemented;
}
if (equal == (op == Py_EQ))
res = Py_True;
else
res = Py_False;
Py_INCREF(res);
return res;
}
void setupComplex() {
complex_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)complexNew, UNKNOWN, 3, 2, false, false),
{ boxInt(0), boxInt(0) }));
......@@ -276,6 +335,7 @@ void setupComplex() {
_addFunc("__div__", BOXED_COMPLEX, (void*)complexDivComplex, (void*)complexDivFloat, (void*)complexDivInt,
(void*)complexDiv);
complex_cls->giveAttr("__pos__", new BoxedFunction(boxRTFunction((void*)complexPos, BOXED_COMPLEX, 1)));
complex_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)complexStr, STR, 1)));
complex_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)complexRepr, STR, 1)));
complex_cls->giveAttr("real",
......@@ -283,6 +343,7 @@ void setupComplex() {
complex_cls->giveAttr("imag",
new BoxedMemberDescriptor(BoxedMemberDescriptor::DOUBLE, offsetof(BoxedComplex, imag)));
complex_cls->freeze();
complex_cls->tp_richcompare = complex_richcompare;
}
void teardownComplex() {
......
......@@ -537,6 +537,11 @@ Box* floatNeg(BoxedFloat* self) {
return boxFloat(-self->d);
}
Box* floatPos(BoxedFloat* self) {
assert(self->cls == float_cls);
return PyFloat_FromDouble(self->d);
}
bool floatNonzeroUnboxed(BoxedFloat* self) {
assert(self->cls == float_cls);
return self->d != 0.0;
......@@ -1475,6 +1480,7 @@ void setupFloat() {
"__new__", new BoxedFunction(boxRTFunction((void*)floatNew, UNKNOWN, 2, 1, false, false), { boxFloat(0.0) }));
float_cls->giveAttr("__neg__", new BoxedFunction(boxRTFunction((void*)floatNeg, BOXED_FLOAT, 1)));
float_cls->giveAttr("__pos__", new BoxedFunction(boxRTFunction((void*)floatPos, BOXED_FLOAT, 1)));
CLFunction* nonzero = boxRTFunction((void*)floatNonzeroUnboxed, BOOL, 1);
addRTFunction(nonzero, (void*)floatNonzero, UNKNOWN);
......
......@@ -4378,10 +4378,11 @@ extern "C" Box* unaryop(Box* operand, int op_type) {
BoxedString* op_name = getOpName(op_type);
// TODO: this code looks very old and like it should be a callattr instead?
Box* attr_func = getclsattrInternal(operand, op_name, NULL);
RELEASE_ASSERT(attr_func, "%s.%s", getTypeName(operand), op_name->c_str());
Box* rtn = runtimeCallInternal<CXX>(attr_func, NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
CallattrFlags callattr_flags{.cls_only = true, .null_on_nonexistent = true, .argspec = ArgPassSpec(0) };
Box* rtn = callattr(operand, op_name, callattr_flags, NULL, NULL, NULL, NULL, NULL);
if (rtn == NULL) {
raiseExcHelper(TypeError, "bad operand type for unary '%s': '%s'", op_name->c_str(), getTypeName(operand));
}
return rtn;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment