Ticket #196: for-dec-patch.txt

File for-dec-patch.txt, 3.5 KB (added by mlh, 3 years ago)

Suggested fix.

Line 
1# HG changeset patch
2# User Magnus Lie Hetland <magnus@hetland.org>
3# Date 1233323896 -3600
4# Node ID 8ec1acab2e2236e48dede5f44b066a6ca0460daf
5# Parent  41ac022ba25ce119cbd22455de2a8291c7281d5a
6Fixed #196
7
8diff -r 41ac022ba25c -r 8ec1acab2e22 Cython/Compiler/Nodes.py
9--- a/Cython/Compiler/Nodes.py  Fri Jan 30 10:54:11 2009 +0100
10+++ b/Cython/Compiler/Nodes.py  Fri Jan 30 14:58:16 2009 +0100
11@@ -3904,9 +3904,15 @@
12         self.bound1.generate_evaluation_code(code)
13         self.bound2.generate_evaluation_code(code)
14         offset, incop = self.relation_table[self.relation1]
15+        if incop == "++":
16+            decop = "--"
17+        else:
18+            decop = "++"
19         if self.step is not None:
20             self.step.generate_evaluation_code(code)
21-            incop = "%s=%s" % (incop[0], self.step.result())
22+            step = self.step.result()
23+            incop = "%s=%s" % (incop[0], step)
24+            decop = "%s=%s" % (decop[0], step)
25         loopvar_name = self.loopvar_node.result()
26         code.putln(
27             "for (%s = %s%s; %s %s %s; %s%s) {" % (
28@@ -3919,7 +3925,11 @@
29             self.target.generate_assignment_code(self.py_loopvar_node, code)
30         self.body.generate_execution_code(code)
31         code.put_label(code.continue_label)
32-        code.putln("}")
33+        if getattr(self, "from_range", False):
34+            # Undo last increment to maintain Python semantics:
35+            code.putln("} %s%s;" % (loopvar_name, decop))
36+        else:
37+            code.putln("}")
38         break_label = code.break_label
39         code.set_loop_labels(old_loop_labels)
40         if self.else_clause:
41diff -r 41ac022ba25c -r 8ec1acab2e22 Cython/Compiler/Optimize.py
42--- a/Cython/Compiler/Optimize.py       Fri Jan 30 10:54:11 2009 +0100
43+++ b/Cython/Compiler/Optimize.py       Fri Jan 30 14:58:16 2009 +0100
44@@ -144,7 +144,8 @@
45             relation2=relation2, bound2=bound2,
46             step=step, body=node.body,
47             else_clause=node.else_clause,
48-            loopvar_node=node.target)
49+            loopvar_node=node.target,
50+            from_range=True)
51         return for_node
52 
53     def _transform_dict_iteration(self, node, dict_obj, keys, values):
54diff -r 41ac022ba25c -r 8ec1acab2e22 tests/run/for_decrement.pyx
55--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
56+++ b/tests/run/for_decrement.pyx       Fri Jan 30 14:58:16 2009 +0100
57@@ -0,0 +1,43 @@
58+"""
59+>>> range_loop_indices()
60+** Calculating step **
61+(9, 9, 8, 1, 2)
62+>>> from_loop_indices()
63+** Calculating step **
64+** Calculating step **
65+** Calculating step **
66+** Calculating step **
67+** Calculating step **
68+(10, 10, 0)
69+"""
70+
71+cdef int get_step():
72+    """
73+    This should only be called once, when used in range().
74+    """
75+    print "** Calculating step **"
76+    return 2
77+
78+def range_loop_indices():
79+    """
80+    Optimized integer for loops using range() should follow Python behavior,
81+    and leave the index variable with the last value of the range.
82+    """
83+    cdef int i, j, k, l, m
84+    for i in range(10): pass
85+    for j in range(2,10): pass
86+    for k in range(0,10,get_step()): pass
87+    for l in range(10,0,-1): pass
88+    for m in range(10,0,-2): pass
89+    return i, j, k, l, m
90+
91+def from_loop_indices():
92+    """
93+    for-from-loops should follow C behavior, and leave the index variable
94+    incremented one step after the last iteration.
95+    """
96+    cdef int i, j, k
97+    for i from 0 <= i < 10 by get_step(): pass
98+    for j from 0 <= j < 10: pass
99+    for k from 10 > k > 0: pass
100+    return i, j, k
101\ No newline at end of file