Commit ba920e46 authored by Stefan Behnel's avatar Stefan Behnel

merge

parents aa75b693 087d29ca
......@@ -3841,6 +3841,7 @@ class ForFromStatNode(LoopNode, StatNode):
#
# Used internally:
#
# from_range bool
# is_py_target bool
# loopvar_node ExprNode (usually a NameNode or temp node)
# py_loopvar_node PyTempNode or None
......@@ -3849,6 +3850,7 @@ class ForFromStatNode(LoopNode, StatNode):
is_py_target = False
loopvar_node = None
py_loopvar_node = None
from_range = False
def analyse_declarations(self, env):
self.target.analyse_target_declaration(env)
......@@ -3867,13 +3869,15 @@ class ForFromStatNode(LoopNode, StatNode):
else:
self.bound1 = self.bound1.coerce_to_integer(env)
self.bound2 = self.bound2.coerce_to_integer(env)
if not self.bound2.is_literal:
self.bound2 = self.bound2.coerce_to_temp(env)
if self.step is not None:
if isinstance(self.step, ExprNodes.UnaryMinusNode):
warning(self.step.pos, "Probable infinite loop in for-from-by statment. Consider switching the directions of the relations.", 2)
self.step.analyse_types(env)
self.step = self.step.coerce_to_integer(env)
if not (self.bound2.is_name or self.bound2.is_literal):
self.bound2 = self.bound2.coerce_to_temp(env)
if not self.step.is_literal:
self.step = self.step.coerce_to_temp(env)
target_type = self.target.type
if not (target_type.is_pyobject or target_type.is_numeric):
error(self.target.pos,
......@@ -3917,49 +3921,45 @@ class ForFromStatNode(LoopNode, StatNode):
def generate_execution_code(self, code):
old_loop_labels = code.new_loop_labels()
from_range = getattr(self, "from_range", False)
from_range = self.from_range
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)
step = self.step.result()
incop = "%s=%s" % (incop[0], step)
decop = "%s=%s" % (decop[0], step)
loopvar_name = self.loopvar_node.result()
if from_range:
range_bound = code.funcstate.allocate_temp(self.bound2.type, manage_ref=False)
code.putln("%s = %s;" % (range_bound, self.bound2.result()))
# Skip the loop entirely (and avoid assigning to the loopvar) if
# the loop is empty:
code.putln("if (%s%s %s %s) {" % (
self.bound1.result(), offset, self.relation2, range_bound
))
loopvar_name = code.funcstate.allocate_temp(self.target.type, False)
else:
range_bound = self.bound2.result()
loopvar_name = self.loopvar_node.result()
code.putln(
"for (%s = %s%s; %s %s %s; %s%s) {" % (
loopvar_name,
self.bound1.result(), offset,
loopvar_name, self.relation2, range_bound,
loopvar_name, self.relation2, self.bound2.result(),
loopvar_name, incop))
if self.py_loopvar_node:
self.py_loopvar_node.generate_evaluation_code(code)
self.target.generate_assignment_code(self.py_loopvar_node, code)
elif from_range:
code.putln("%s = %s;" % (
self.target.result(), loopvar_name))
self.body.generate_execution_code(code)
code.put_label(code.continue_label)
if from_range:
# Undo last increment to maintain Python semantics:
code.putln("} %s%s;" % (loopvar_name, decop))
# End the outer if statement:
code.putln("} /* end if */")
code.funcstate.release_temp(range_bound)
else:
code.putln("}")
if self.py_loopvar_node:
# Reassign py variable to loop var here.
# (For consistancy, should rarely come up in practice.)
import ExprNodes
from_py_node = ExprNodes.CoerceFromPyTypeNode(self.loopvar_node.type, self.target, None)
from_py_node.temp_code = loopvar_name
from_py_node.generate_result_code(code)
code.putln("}")
if self.py_loopvar_node:
# This is potentially wasteful, but we don't want the semantics to
# depend on whether or not the loop is a python type.
self.py_loopvar_node.generate_evaluation_code(code)
self.target.generate_assignment_code(self.py_loopvar_node, code)
break_label = code.break_label
code.set_loop_labels(old_loop_labels)
if self.else_clause:
......@@ -3974,6 +3974,8 @@ class ForFromStatNode(LoopNode, StatNode):
if self.step is not None:
self.step.generate_disposal_code(code)
self.step.free_temps(code)
if from_range:
code.funcstate.release_temp(loopvar_name)
relation_table = {
# {relop : (initial offset, increment op)}
......
......@@ -144,7 +144,6 @@ class IterationTransform(Visitor.VisitorTransform):
relation2=relation2, bound2=bound2,
step=step, body=node.body,
else_clause=node.else_clause,
loopvar_node=node.target,
from_range=True)
return for_node
......
......@@ -4,10 +4,6 @@
(9, 9, 8, 1, 2)
>>> from_loop_indices()
** Calculating step **
** Calculating step **
** Calculating step **
** Calculating step **
** Calculating step **
(10, 10, 0)
"""
......
__doc__ = u"""
>>> test_var(10, 5)
>>> for_from_range(5, 10)
range(5)
at 0
at 1
at 2
at 3
at 4
range(5, 10)
at 5
at 6
at 7
at 8
at 9
range(5, 10, 2)
at 5
at 7
at 9
9
>>> for_from_range(-5, -10)
range(-5)
range(-5, -10)
range(-5, -10, 2)
100
>>> for_from_bound_reassignment(5, 1)
at 0
at 1
at 2
at 3
at 4
5
>>> for_from_step_reassignment(15, 5, 2)
at 0
at 5
at 10
15
>>> for_from_target_reassignment(10, 2)
at 0
at 1
at 3
at 7
15
>>> for_from_py_target_reassignment(10, 2)
at 0
at 1
at 3
at 7
15
>>> for_in_target_reassignment(10, 2)
at 0
at 1
at 2
at 3
at 4
at 5
at 6
at 7
at 8
at 9
18
>>> test_func(5)
get_bound(5)
at 0
......@@ -14,47 +66,61 @@ at 2
at 3
at 4
5
>>> test_f()
9
>>> f()
g called
0
1
2
2
"""
cdef int get_bound(int m):
print "get_bound(%s)"%m
return m
def test_var(int n, int m):
cdef int i
for i from 0 <= i < n:
def for_from_range(a, b):
cdef int i = 100
print "range(%s)" % a
for i in range(a):
print "at", i
print "range(%s, %s)" % (a, b)
for i in range(a, b):
print "at", i
print "range(%s, %s, %s)" % (a, b, 2)
for i in range(a, b, 2):
print "at", i
n = m
return i
def test_func(int n):
cdef int i
for i from 0 <= i < get_bound(n):
def for_from_bound_reassignment(int bound, int fake_bound):
cdef int i = 100
for i from 0 <= i < bound:
print "at", i
bound = fake_bound
return i
def test_f():
cdef int i,n
n = 10
for i in range(n):
if i == 5: n *= 2
print i
def for_from_step_reassignment(int bound, int step, int fake_step):
cdef int i = 100
for i from 0 <= i < bound by step:
print "at", i
step = fake_step
return i
def for_from_target_reassignment(int bound, int factor):
cdef int i = 100
for i from 0 <= i < bound:
print "at", i
i *= factor
return i
cdef int g():
print "g called"
return 3
def for_from_py_target_reassignment(int bound, int factor):
cdef object i
for i from 0 <= i < bound:
print "at", i
i *= factor
return i
def f():
cdef int i = -1
for i in range(g()):
print i
print i
def for_in_target_reassignment(int bound, int factor):
cdef int i = 100
for i in range(bound):
print "at", i
i *= factor
return i
def test_func(int n):
cdef int i = 100
for i from 0 <= i < get_bound(n):
print "at", i
return i
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment