From fb8f6996cbd4ee1a54274110660ec158532f1963 Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Wed, 28 May 2008 00:55:02 -0700 Subject: [PATCH] Inplace operators <<= >>= //= **= --- Cython/Compiler/Lexicon.py | 4 +++- Cython/Compiler/Nodes.py | 21 +++++++++++++++++++-- Cython/Compiler/Parsing.py | 4 ++-- tests/run/inplace.pyx | 28 ++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 tests/run/inplace.pyx diff --git a/Cython/Compiler/Lexicon.py b/Cython/Compiler/Lexicon.py index 0f8bc898..bfc7ea97 100644 --- a/Cython/Compiler/Lexicon.py +++ b/Cython/Compiler/Lexicon.py @@ -68,7 +68,9 @@ def make_lexicon(): bra = Any("([{") ket = Any(")]}") punct = Any(":,;+-*/|&<>=.%`~^?") - diphthong = Str("==", "<>", "!=", "<=", ">=", "<<", ">>", "**", "+=", "-=", "*=", "/=", "%=", "|=", "^=", "&=", "//") + diphthong = Str("==", "<>", "!=", "<=", ">=", "<<", ">>", "**", "//", + "+=", "-=", "*=", "/=", "%=", "|=", "^=", "&=", + "<<=", ">>=", "**=", "//=") spaces = Rep1(Any(" \t\f")) comment = Str("#") + Rep(AnyBut("\n")) escaped_newline = Str("\\\n") diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index db1370a0..8669729a 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -2440,21 +2440,34 @@ class InPlaceAssignmentNode(AssignmentNode): self.rhs.generate_evaluation_code(code) self.dup.generate_subexpr_evaluation_code(code) self.dup.generate_result_code(code) + if self.operator == "**": + extra = ", Py_None" + else: + extra = "" if self.lhs.type.is_pyobject: code.putln( - "%s = %s(%s, %s); %s" % ( + "%s = %s(%s, %s%s); %s" % ( self.result.result_code, self.py_operation_function(), self.dup.py_result(), self.rhs.py_result(), + extra, code.error_goto_if_null(self.result.py_result(), self.pos))) self.result.generate_evaluation_code(code) # May be a type check... self.rhs.generate_disposal_code(code) self.dup.generate_disposal_code(code) self.lhs.generate_assignment_code(self.result, code) else: + c_op = self.operator + if c_op == "//": + c_op = "/" + elif c_op == "**": + if self.lhs.type.is_int and self.rhs.type.is_int: + error(self.pos, "** with two C int types is ambiguous") + else: + error(self.pos, "No C inplace power operator") # have to do assignment directly to avoid side-effects - code.putln("%s %s= %s;" % (self.lhs.result_code, self.operator, self.rhs.result_code) ) + code.putln("%s %s= %s;" % (self.lhs.result_code, c_op, self.rhs.result_code) ) self.rhs.generate_disposal_code(code) if self.dup.is_temp: self.dup.generate_subexpr_disposal_code(code) @@ -2484,6 +2497,10 @@ class InPlaceAssignmentNode(AssignmentNode): "*": "PyNumber_InPlaceMultiply", "/": "PyNumber_InPlaceDivide", "%": "PyNumber_InPlaceRemainder", + "<<": "PyNumber_InPlaceLshift", + ">>": "PyNumber_InPlaceRshift", + "**": "PyNumber_InPlacePower", + "//": "PyNumber_InPlaceFloorDivide", } def annotate(self, code): diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index e65e557e..4b4c9107 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -755,11 +755,11 @@ def p_expression_or_assignment(s): s.next() expr_list.append(p_expr(s)) if len(expr_list) == 1: - if re.match("[+*/\%^\&|-]=", s.sy): + if re.match(r"([+*/\%^\&|-]|<<|>>|\*\*|//)=", s.sy): lhs = expr_list[0] if not isinstance(lhs, (ExprNodes.AttributeNode, ExprNodes.IndexNode, ExprNodes.NameNode) ): error(lhs.pos, "Illegal operand for inplace operation.") - operator = s.sy[0] + operator = s.sy[:-1] s.next() rhs = p_expr(s) return Nodes.InPlaceAssignmentNode(lhs.pos, operator = operator, lhs = lhs, rhs = rhs) diff --git a/tests/run/inplace.pyx b/tests/run/inplace.pyx new file mode 100644 index 00000000..22f8ac83 --- /dev/null +++ b/tests/run/inplace.pyx @@ -0,0 +1,28 @@ +__doc__ = u""" + >>> f(5, 7) + 29509034655744 + + >>> g(13, 4) + 32 + + >>> h(56, 7) + 105.0 +""" + +def f(a,b): + a += b + a *= b + a **= b + return a + +def g(int a, int b): + a -= b + a /= b + a <<= b + return a + +def h(double a, double b): + a /= b + a += b + a *= b + return a -- 2.26.2