Fix for #196
authorMagnus Lie Hetland <none@none>
Fri, 30 Jan 2009 14:53:16 +0000 (15:53 +0100)
committerMagnus Lie Hetland <none@none>
Fri, 30 Jan 2009 14:53:16 +0000 (15:53 +0100)
Cython/Compiler/Nodes.py
Cython/Compiler/Optimize.py
tests/run/for_decrement.pyx [new file with mode: 0644]

index 88c4f3f949d3120ea1097da1b84fa6e7eaf15ec8..7664e0de7b3f0334cb9cd06d787ac79e615dddf4 100644 (file)
@@ -3904,9 +3904,15 @@ class ForFromStatNode(LoopNode, StatNode):
         self.bound1.generate_evaluation_code(code)
         self.bound2.generate_evaluation_code(code)
         offset, incop = self.relation_table[self.relation1]
+        if incop == "++":
+            decop = "--"
+        else:
+            decop = "++"
         if self.step is not None:
             self.step.generate_evaluation_code(code)
-            incop = "%s=%s" % (incop[0], self.step.result())
+            step = self.step.result()
+            incop = "%s=%s" % (incop[0], step)
+            decop = "%s=%s" % (decop[0], step)
         loopvar_name = self.loopvar_node.result()
         code.putln(
             "for (%s = %s%s; %s %s %s; %s%s) {" % (
@@ -3919,7 +3925,11 @@ class ForFromStatNode(LoopNode, StatNode):
             self.target.generate_assignment_code(self.py_loopvar_node, code)
         self.body.generate_execution_code(code)
         code.put_label(code.continue_label)
-        code.putln("}")
+        if getattr(self, "from_range", False):
+            # Undo last increment to maintain Python semantics:
+            code.putln("} %s%s;" % (loopvar_name, decop))
+        else:
+            code.putln("}")
         break_label = code.break_label
         code.set_loop_labels(old_loop_labels)
         if self.else_clause:
index 2c16e7114d441427432c22ef870945b2b0e3c1f9..7aec738ae84b8da6dceb57eb064a13d0da623b14 100644 (file)
@@ -144,7 +144,8 @@ class IterationTransform(Visitor.VisitorTransform):
             relation2=relation2, bound2=bound2,
             step=step, body=node.body,
             else_clause=node.else_clause,
-            loopvar_node=node.target)
+            loopvar_node=node.target,
+            from_range=True)
         return for_node
 
     def _transform_dict_iteration(self, node, dict_obj, keys, values):
diff --git a/tests/run/for_decrement.pyx b/tests/run/for_decrement.pyx
new file mode 100644 (file)
index 0000000..f9826fd
--- /dev/null
@@ -0,0 +1,43 @@
+"""
+>>> range_loop_indices()
+** Calculating step **
+(9, 9, 8, 1, 2)
+>>> from_loop_indices()
+** Calculating step **
+** Calculating step **
+** Calculating step **
+** Calculating step **
+** Calculating step **
+(10, 10, 0)
+"""
+
+cdef int get_step():
+    """
+    This should only be called once, when used in range().
+    """
+    print "** Calculating step **"
+    return 2
+
+def range_loop_indices():
+    """
+    Optimized integer for loops using range() should follow Python behavior, 
+    and leave the index variable with the last value of the range.
+    """
+    cdef int i, j, k, l, m
+    for i in range(10): pass
+    for j in range(2,10): pass
+    for k in range(0,10,get_step()): pass
+    for l in range(10,0,-1): pass
+    for m in range(10,0,-2): pass
+    return i, j, k, l, m
+
+def from_loop_indices():
+    """
+    for-from-loops should follow C behavior, and leave the index variable 
+    incremented one step after the last iteration.
+    """
+    cdef int i, j, k
+    for i from 0 <= i < 10 by get_step(): pass
+    for j from 0 <= j < 10: pass
+    for k from 10 > k > 0: pass
+    return i, j, k
\ No newline at end of file