diff options
Diffstat (limited to 'Objects/complexobject.c')
-rw-r--r-- | Objects/complexobject.c | 102 |
1 files changed, 91 insertions, 11 deletions
diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 8e1f4d7..82dd7c1 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -252,12 +252,51 @@ Py_complex PyComplex_AsCComplex(PyObject *op) { Py_complex cv; + PyObject *newop = NULL; + static PyObject *complex_str = NULL; + + assert(op); + /* If op is already of type PyComplex_Type, return its value */ if (PyComplex_Check(op)) { return ((PyComplexObject *)op)->cval; } + /* If not, use op's __complex__ method, if it exists */ + + /* return -1 on failure */ + cv.real = -1.; + cv.imag = 0.; + + { + PyObject *complexfunc; + if (!complex_str) { + if (!(complex_str = PyString_FromString("__complex__"))) + return cv; + } + complexfunc = _PyType_Lookup(op->ob_type, complex_str); + /* complexfunc is a borrowed reference */ + if (complexfunc) { + newop = PyObject_CallFunctionObjArgs(complexfunc, op, NULL); + if (!newop) + return cv; + } + } + + if (newop) { + if (!PyComplex_Check(newop)) { + PyErr_SetString(PyExc_TypeError, + "__complex__ should return a complex object"); + Py_DECREF(newop); + return cv; + } + cv = ((PyComplexObject *)newop)->cval; + Py_DECREF(newop); + return cv; + } + /* If neither of the above works, interpret op as a float giving the + real part of the result, and fill in the imaginary part as 0. */ else { + /* PyFloat_AsDouble will return -1 on failure */ cv.real = PyFloat_AsDouble(op); - cv.imag = 0.; return cv; } } @@ -512,7 +551,7 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z) } else if (errno == ERANGE) { PyErr_SetString(PyExc_OverflowError, - "complex exponentiaion"); + "complex exponentiation"); return NULL; } return PyComplex_FromCComplex(p); @@ -652,7 +691,7 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v) const char *s, *start; char *end; double x=0.0, y=0.0, z; - int got_re=0, got_im=0, done=0; + int got_re=0, got_im=0, got_bracket=0, done=0; int digit_or_dot; int sw_error=0; int sign; @@ -692,10 +731,17 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v) start = s; while (*s && isspace(Py_CHARMASK(*s))) s++; - if (s[0] == '\0') { + if (s[0] == '\0') { PyErr_SetString(PyExc_ValueError, "complex() arg is an empty string"); return NULL; + } + if (s[0] == '(') { + /* Skip over possible bracket from repr(). */ + got_bracket = 1; + s++; + while (*s && isspace(Py_CHARMASK(*s))) + s++; } z = -1.0; @@ -714,13 +760,26 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v) if(!done) sw_error=1; break; + case ')': + if (!got_bracket || !(got_re || got_im)) { + sw_error=1; + break; + } + got_bracket=0; + done=1; + s++; + while (*s && isspace(Py_CHARMASK(*s))) + s++; + if (*s) sw_error=1; + break; + case '-': sign = -1; /* Fallthrough */ case '+': if (done) sw_error=1; s++; - if ( *s=='\0'||*s=='+'||*s=='-' || + if ( *s=='\0'||*s=='+'||*s=='-'||*s==')'|| isspace(Py_CHARMASK(*s)) ) sw_error=1; break; @@ -746,7 +805,7 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v) if (isspace(Py_CHARMASK(*s))) { while (*s && isspace(Py_CHARMASK(*s))) s++; - if (s[0] != '\0') + if (*s && *s != ')') sw_error=1; else done = 1; @@ -792,7 +851,7 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v) } while (s - start < len && !sw_error); - if (sw_error) { + if (sw_error || got_bracket) { PyErr_SetString(PyExc_ValueError, "complex() arg is a malformed string"); return NULL; @@ -817,12 +876,14 @@ complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds) &r, &i)) return NULL; - /* Special-case for single argument that is already complex */ + /* Special-case for a single argument when type(arg) is complex. */ if (PyComplex_CheckExact(r) && i == NULL && type == &PyComplex_Type) { /* Note that we can't know whether it's safe to return a complex *subclass* instance as-is, hence the restriction - to exact complexes here. */ + to exact complexes here. If either the input or the + output is a complex subclass, it will be handled below + as a non-orthogonal vector. */ Py_INCREF(r); return r; } @@ -873,6 +934,14 @@ complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } return NULL; } + + /* If we get this far, then the "real" and "imag" parts should + both be treated as numbers, and the constructor should return a + complex number equal to (real + imag*1j). + + Note that we do NOT assume the input to already be in canonical + form; the "real" and "imag" parts might themselves be complex + numbers, which slightly complicates the code below. */ if (PyComplex_Check(r)) { /* Note that if r is of a complex subtype, we're only retaining its real & imag parts here, and the return @@ -883,8 +952,14 @@ complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } } else { + /* The "real" part really is entirely real, and contributes + nothing in the imaginary direction. + Just treat it as a double. */ + cr.imag = 0.0; tmp = PyNumber_Float(r); if (own_r) { + /* r was a newly created complex number, rather + than the original "real" argument. */ Py_DECREF(r); } if (tmp == NULL) @@ -897,7 +972,6 @@ complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } cr.real = PyFloat_AsDouble(tmp); Py_DECREF(tmp); - cr.imag = 0.0; } if (i == NULL) { ci.real = 0.0; @@ -906,13 +980,19 @@ complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds) else if (PyComplex_Check(i)) ci = ((PyComplexObject*)i)->cval; else { + /* The "imag" part really is entirely imaginary, and + contributes nothing in the real direction. + Just treat it as a double. */ + ci.imag = 0.0; tmp = (*nbi->nb_float)(i); if (tmp == NULL) return NULL; ci.real = PyFloat_AsDouble(tmp); Py_DECREF(tmp); - ci.imag = 0.; } + /* If the input was in canonical form, then the "real" and "imag" + parts are real numbers, so that ci.real and cr.imag are zero. + We need this correction in case they were not real numbers. */ cr.real -= ci.imag; cr.imag += ci.real; return complex_subtype_from_c_complex(type, cr); |