summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Bradshaw <robertwb@gmail.com>2020-05-23 22:42:48 -0700
committerRobert Bradshaw <robertwb@gmail.com>2020-05-23 23:27:54 -0700
commitd849fb2379f4f892c8374b52385991c399c31a49 (patch)
tree1dd8c4e0296d5e3a39b79c0f5bc0283fbe4fe1d7
parente6a812402b0368cf930a55ed465a38820f606054 (diff)
downloadcython-d849fb2379f4f892c8374b52385991c399c31a49.tar.gz
Add support for pow operator.
-rw-r--r--Cython/Compiler/ModuleNode.py11
-rw-r--r--Cython/Utility/ExtensionTypes.c8
-rw-r--r--tests/run/binop_reverse_methods_GH2056.pyx13
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__)