simplify and extend in/not-in and is/is-not optimisation, add test
authorStefan Behnel <stefan_ml@behnel.de>
Wed, 21 Aug 2013 18:53:17 +0000 (20:53 +0200)
committerStefan Behnel <stefan_ml@behnel.de>
Wed, 21 Aug 2013 18:53:17 +0000 (20:53 +0200)
Cython/Compiler/Optimize.py
tests/run/isnot.pyx [new file with mode: 0644]

index 05fc613..18575ee 100644 (file)
@@ -19,6 +19,7 @@ from StringEncoding import EncodedString, BytesLiteral
 from Errors import error
 from ParseTreeTransforms import SkipDeclarations
 
+import copy
 import codecs
 
 try:
@@ -3068,21 +3069,21 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
             return self._handle_UnaryMinusNode(node)
         return node
 
+    _negate_operator = {
+        'in': 'not_in',
+        'not_in': 'in',
+        'is': 'is_not',
+        'is_not': 'is'
+    }.get
+
     def _handle_UnaryNotNode(self, node):
-        if isinstance(node.operand, ExprNodes.PrimaryCmpNode):
-            cmp_node = node.operand
-            if cmp_node.operator == 'in':
-                operator = 'not_in'
-            elif cmp_node.operator == 'is':
-                operator = 'is_not'
-            else:
-                return node
-            return ExprNodes.PrimaryCmpNode(
-                cmp_node.pos,
-                operand1=cmp_node.operand1,
-                operand2=cmp_node.operand2,
-                operator=operator,
-                cascade=cmp_node.cascade)
+        operand = node.operand
+        if isinstance(operand, ExprNodes.PrimaryCmpNode):
+            operator = self._negate_operator(operand.operator)
+            if operator:
+                node = copy.copy(operand)
+                node.operator = operator
+                node = self.visit_PrimaryCmpNode(node)
         return node
 
     def _handle_UnaryMinusNode(self, node):
diff --git a/tests/run/isnot.pyx b/tests/run/isnot.pyx
new file mode 100644 (file)
index 0000000..9baabbc
--- /dev/null
@@ -0,0 +1,72 @@
+# mode: run
+# tag: is_not
+
+cimport cython
+
+@cython.test_fail_if_path_exists('//NotNode')
+def is_not(a, b):
+    """
+    >>> is_not(1, 2)
+    True
+    >>> x = 1
+    >>> is_not(x, x)
+    False
+    """
+    return a is not b
+
+
+@cython.test_fail_if_path_exists('//NotNode')
+def not_is_not(a, b):
+    """
+    >>> not_is_not(1, 2)
+    False
+    >>> x = 1
+    >>> not_is_not(x, x)
+    True
+    """
+    return not a is not b
+
+
+@cython.test_fail_if_path_exists('//NotNode')
+def not_is(a, b):
+    """
+    >>> not_is(1, 2)
+    True
+    >>> x = 1
+    >>> not_is(x, x)
+    False
+    """
+    return not a is b
+
+
+@cython.test_fail_if_path_exists('//NotNode')
+def is_not_None(a):
+    """
+    >>> is_not_None(1)
+    True
+    >>> is_not_None(None)
+    False
+    """
+    return a is not None
+
+
+@cython.test_fail_if_path_exists('//NotNode')
+def not_is_not_None(a):
+    """
+    >>> not_is_not_None(1)
+    False
+    >>> not_is_not_None(None)
+    True
+    """
+    return not a is not None
+
+
+@cython.test_fail_if_path_exists('//NotNode')
+def not_is_None(a):
+    """
+    >>> not_is_None(1)
+    True
+    >>> not_is_None(None)
+    False
+    """
+    return not a is None