Inplace operators <<= >>= //= **=
authorRobert Bradshaw <robertwb@math.washington.edu>
Wed, 28 May 2008 07:55:02 +0000 (00:55 -0700)
committerRobert Bradshaw <robertwb@math.washington.edu>
Wed, 28 May 2008 07:55:02 +0000 (00:55 -0700)
Cython/Compiler/Lexicon.py
Cython/Compiler/Nodes.py
Cython/Compiler/Parsing.py
tests/run/inplace.pyx [new file with mode: 0644]

index 0f8bc898b1110e68651322726f44e654a6a5e15f..bfc7ea97e629919ad01f8ddab53faca6422cf230 100644 (file)
@@ -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")
index db1370a061802d5eb5337229c6ceac7abd602837..8669729ae28c02a39e5b655eb93d708cd94e2108 100644 (file)
@@ -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):
index e65e557e011c7e61688960cf0d1a8ad882ce66b1..4b4c9107970c0141ad0d69503a0e2dc293ff9646 100644 (file)
@@ -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 (file)
index 0000000..22f8ac8
--- /dev/null
@@ -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