diff options
author | Robert Bradshaw <robertwb@gmail.com> | 2020-05-23 22:42:48 -0700 |
---|---|---|
committer | Robert Bradshaw <robertwb@gmail.com> | 2020-05-23 23:27:54 -0700 |
commit | d849fb2379f4f892c8374b52385991c399c31a49 (patch) | |
tree | 1dd8c4e0296d5e3a39b79c0f5bc0283fbe4fe1d7 | |
parent | e6a812402b0368cf930a55ed465a38820f606054 (diff) | |
download | cython-d849fb2379f4f892c8374b52385991c399c31a49.tar.gz |
Add support for pow operator.
-rw-r--r-- | Cython/Compiler/ModuleNode.py | 11 | ||||
-rw-r--r-- | Cython/Utility/ExtensionTypes.c | 8 | ||||
-rw-r--r-- | tests/run/binop_reverse_methods_GH2056.pyx | 13 |
3 files changed, 29 insertions, 3 deletions
diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 193e01ee8..112e17e4a 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -1904,6 +1904,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if scope.directives['c_api_binop_methods']: code.putln('#define %s %s' % (func_name, slot.left_slot.slot_code(scope))) else: + if slot.left_slot.signature == TypeSlots.binaryfunc: + extra_arg = extra_arg_decl = '' + elif slot.left_slot.signature == TypeSlots.ternaryfunc: + extra_arg = ', extra_arg' + extra_arg_decl = ', PyObject* extra_arg' + else: + error(entry.pos, "Unexpected type lost signature: %s" % slot) def has_slot_method(method_name): entry = scope.lookup(method_name) return bool(entry and entry.is_special and entry.func_cname) @@ -1914,7 +1921,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): else: operands = "left, right" if entry and entry.is_special and entry.func_cname: - return "%s(%s)" % (entry.func_cname, operands) + return "%s(%s%s)" % (entry.func_cname, operands, extra_arg) else: py_ident = code.intern_identifier(EncodedString(method_name)) return "%s_maybe_call_super(%s, %s)" % (func_name, operands, py_ident) @@ -1928,6 +1935,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): "call_left": call_slot_method(slot.left_slot.method_name, reverse=False), "call_right": call_slot_method(slot.right_slot.method_name, reverse=True), "type_cname": '((PyTypeObject*) %s)' % scope.namespace_cname, + "extra_arg": extra_arg, + "extra_arg_decl": extra_arg_decl, }).impl.strip()) code.putln() if preprocessor_guard: diff --git a/Cython/Utility/ExtensionTypes.c b/Cython/Utility/ExtensionTypes.c index d34916642..a60d73d0d 100644 --- a/Cython/Utility/ExtensionTypes.c +++ b/Cython/Utility/ExtensionTypes.c @@ -281,7 +281,7 @@ __PYX_GOOD: /////////////// BinopSlot /////////////// -static CYTHON_INLINE PyObject *{{func_name}}_maybe_call_super(PyObject *self, PyObject *other, PyObject* name) { +static CYTHON_INLINE PyObject *{{func_name}}_maybe_call_super(PyObject *self, PyObject *other, PyObject* name {{extra_arg_decl}}) { PyObject *res; PyObject *method; if (!Py_TYPE(self)->tp_base) { @@ -293,7 +293,11 @@ static CYTHON_INLINE PyObject *{{func_name}}_maybe_call_super(PyObject *self, Py PyErr_Clear(); return Py_INCREF(Py_NotImplemented), Py_NotImplemented; } + #if {{int(not extra_arg)}} res = __Pyx_PyObject_Call2Args(method, self, other); + #else + res = PyObject_CallFunctionObjArgs(method, self, other {{extra_arg}}, NULL); + #endif Py_DECREF(method); if (!res) { return Py_INCREF(Py_NotImplemented), Py_NotImplemented; @@ -301,7 +305,7 @@ static CYTHON_INLINE PyObject *{{func_name}}_maybe_call_super(PyObject *self, Py return res; } -static PyObject *{{func_name}}(PyObject *left, PyObject *right) { +static PyObject *{{func_name}}(PyObject *left, PyObject *right {{extra_arg_decl}}) { PyObject *res; int maybe_self_is_left, maybe_self_is_right = 0; maybe_self_is_left = Py_TYPE(left) == Py_TYPE(right) diff --git a/tests/run/binop_reverse_methods_GH2056.pyx b/tests/run/binop_reverse_methods_GH2056.pyx index 480853d93..8a89cfa38 100644 --- a/tests/run/binop_reverse_methods_GH2056.pyx +++ b/tests/run/binop_reverse_methods_GH2056.pyx @@ -8,6 +8,13 @@ class Base(object): 'Base.__add__(Base(), 2)' >>> 2 + Base() 'Base.__radd__(Base(), 2)' + + >>> Base() ** 2 + 'Base.__pow__(Base(), 2, None)' + >>> 2 ** Base() + 'Base.__rpow__(Base(), 2, None)' + >>> pow(Base(), 2, 100) + 'Base.__pow__(Base(), 2, 100)' """ def __add__(self, other): return "Base.__add__(%s, %s)" % (self, other) @@ -15,6 +22,12 @@ class Base(object): def __radd__(self, other): return "Base.__radd__(%s, %s)" % (self, other) + def __pow__(self, other, mod): + return "Base.__pow__(%s, %s, %s)" % (self, other, mod) + + def __rpow__(self, other, mod): + return "Base.__rpow__(%s, %s, %s)" % (self, other, mod) + def __repr__(self): return "%s()" % (self.__class__.__name__) |