fold sliced literal sequences (e.g. from DEFs) into constants
authorStefan Behnel <stefan_ml@behnel.de>
Sat, 23 Feb 2013 13:09:44 +0000 (14:09 +0100)
committerStefan Behnel <stefan_ml@behnel.de>
Sat, 23 Feb 2013 13:09:44 +0000 (14:09 +0100)
Cython/Compiler/ExprNodes.py
Cython/Compiler/Optimize.py
tests/run/constant_folding.py

index e7d9ed4..732afcf 100755 (executable)
@@ -1068,6 +1068,9 @@ class BytesNode(ConstNode):
     # start off as Python 'bytes' to support len() in O(1)
     type = bytes_type
 
+    def calculate_constant_result(self):
+        self.constant_result = self.value
+
     def compile_time_value(self, denv):
         return self.value
 
@@ -1149,6 +1152,9 @@ class UnicodeNode(PyConstNode):
     bytes_value = None
     type = unicode_type
 
+    def calculate_constant_result(self):
+        self.constant_result = self.value
+
     def coerce_to(self, dst_type, env):
         if dst_type is self.type:
             pass
@@ -1214,6 +1220,9 @@ class StringNode(PyConstNode):
     is_identifier = None
     unicode_value = None
 
+    def calculate_constant_result(self):
+        self.constant_result = self.value
+
     def coerce_to(self, dst_type, env):
         if dst_type is not py_object_type and not str_type.subtype_of(dst_type):
 #            if dst_type is Builtin.bytes_type:
index 56aae13..dd4b893 100644 (file)
@@ -1,3 +1,4 @@
+from Cython.Compiler.ExprNodes import not_a_constant
 import cython
 cython.declare(UtilityCode=object, EncodedString=object, BytesLiteral=object,
                Nodes=object, ExprNodes=object, PyrexTypes=object, Builtin=object,
@@ -3190,10 +3191,33 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
     def visit_SliceIndexNode(self, node):
         self._calculate_const(node)
         # normalise start/stop values
-        if node.start and node.start.constant_result is None:
-            node.start = None
-        if node.stop and node.stop.constant_result is None:
-            node.stop = None
+        if node.start is None or node.start.constant_result is None:
+            start = node.start = None
+        else:
+            start = node.start.constant_result
+        if node.stop is None or node.stop.constant_result is None:
+            stop = node.stop = None
+        else:
+            stop = node.stop.constant_result
+        # cut down sliced constant sequences
+        if node.constant_result is not not_a_constant:
+            base = node.base
+            if base.is_sequence_constructor:
+                base.args = base.args[start:stop]
+                return base
+            elif base.is_string_literal:
+                value = type(base.value)(node.constant_result)
+                value.encoding = base.value.encoding
+                base.value = value
+                if isinstance(base, ExprNodes.StringNode):
+                    if base.unicode_value is not None:
+                        base.unicode_value = EncodedString(
+                            base.unicode_value[start:stop])
+                elif isinstance(base, ExprNodes.UnicodeNode):
+                    if base.bytes_value is not None:
+                        base.bytes_value = BytesLiteral(
+                            base.bytes_value[start:stop])
+                return base
         return node
 
     def visit_ForInStatNode(self, node):
index 6d27322..70670c6 100644 (file)
@@ -1,3 +1,4 @@
+# coding=utf8
 # mode: run
 # tag: constant_folding
 
@@ -86,3 +87,47 @@ def binop_bool():
     ormix3 = False | 0 | False | True
     xor3   = False ^ True ^ False ^ True
     return plus1, pmix1, minus1, and1, or1, ormix1, xor1, plus3, pmix3, minus3, and3, or3, ormix3, xor3
+
+
+@cython.test_fail_if_path_exists(
+    "//SliceIndexNode",
+)
+def slicing2():
+    """
+    >>> slicing2()
+    ([1, 2, 3, 4], [3, 4], [1, 2, 3, 4], [3, 4], (1, 2, 3, 4), (3, 4), (1, 2, 3, 4), (3, 4))
+    """
+    lst0 = [1, 2, 3, 4][:]
+    lst1 = [1, 2, 3, 4][2:]
+    lst2 = [1, 2, 3, 4][:4]
+    lst3 = [1, 2, 3, 4][2:4]
+
+    tpl0 = (1, 2, 3, 4)[:]
+    tpl1 = (1, 2, 3, 4)[2:]
+    tpl2 = (1, 2, 3, 4)[:4]
+    tpl3 = (1, 2, 3, 4)[2:4]
+
+    return lst0, lst1, lst2, lst3, tpl0, tpl1, tpl2, tpl3
+
+
+@cython.test_fail_if_path_exists(
+    "//SliceIndexNode",
+)
+def str_slicing2():
+    """
+    >>> a,b,c,d = str_slicing2()
+    >>> a == 'abc\\xE9def'[:]
+    True
+    >>> b == 'abc\\xE9def'[2:]
+    True
+    >>> c == 'abc\\xE9def'[:4]
+    True
+    >>> d == 'abc\\xE9def'[2:4]
+    True
+    """
+    str0 = 'abc\xE9def'[:]
+    str1 = 'abc\xE9def'[2:]
+    str2 = 'abc\xE9def'[:4]
+    str3 = 'abc\xE9def'[2:4]
+
+    return str0, str1, str2, str3