Commit ba920e46 authored by Stefan Behnel's avatar Stefan Behnel

merge

parents aa75b693 087d29ca
...@@ -3841,6 +3841,7 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -3841,6 +3841,7 @@ class ForFromStatNode(LoopNode, StatNode):
# #
# Used internally: # Used internally:
# #
# from_range bool
# is_py_target bool # is_py_target bool
# loopvar_node ExprNode (usually a NameNode or temp node) # loopvar_node ExprNode (usually a NameNode or temp node)
# py_loopvar_node PyTempNode or None # py_loopvar_node PyTempNode or None
...@@ -3849,6 +3850,7 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -3849,6 +3850,7 @@ class ForFromStatNode(LoopNode, StatNode):
is_py_target = False is_py_target = False
loopvar_node = None loopvar_node = None
py_loopvar_node = None py_loopvar_node = None
from_range = False
def analyse_declarations(self, env): def analyse_declarations(self, env):
self.target.analyse_target_declaration(env) self.target.analyse_target_declaration(env)
...@@ -3867,13 +3869,15 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -3867,13 +3869,15 @@ class ForFromStatNode(LoopNode, StatNode):
else: else:
self.bound1 = self.bound1.coerce_to_integer(env) self.bound1 = self.bound1.coerce_to_integer(env)
self.bound2 = self.bound2.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 self.step is not None:
if isinstance(self.step, ExprNodes.UnaryMinusNode): 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) 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.analyse_types(env)
self.step = self.step.coerce_to_integer(env) self.step = self.step.coerce_to_integer(env)
if not (self.bound2.is_name or self.bound2.is_literal): if not self.step.is_literal:
self.bound2 = self.bound2.coerce_to_temp(env) self.step = self.step.coerce_to_temp(env)
target_type = self.target.type target_type = self.target.type
if not (target_type.is_pyobject or target_type.is_numeric): if not (target_type.is_pyobject or target_type.is_numeric):
error(self.target.pos, error(self.target.pos,
...@@ -3917,49 +3921,45 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -3917,49 +3921,45 @@ class ForFromStatNode(LoopNode, StatNode):
def generate_execution_code(self, code): def generate_execution_code(self, code):
old_loop_labels = code.new_loop_labels() 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.bound1.generate_evaluation_code(code)
self.bound2.generate_evaluation_code(code) self.bound2.generate_evaluation_code(code)
offset, incop = self.relation_table[self.relation1] offset, incop = self.relation_table[self.relation1]
if incop == "++":
decop = "--"
else:
decop = "++"
if self.step is not None: if self.step is not None:
self.step.generate_evaluation_code(code) self.step.generate_evaluation_code(code)
step = self.step.result() step = self.step.result()
incop = "%s=%s" % (incop[0], step) incop = "%s=%s" % (incop[0], step)
decop = "%s=%s" % (decop[0], step)
loopvar_name = self.loopvar_node.result()
if from_range: if from_range:
range_bound = code.funcstate.allocate_temp(self.bound2.type, manage_ref=False) loopvar_name = code.funcstate.allocate_temp(self.target.type, 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
))
else: else:
range_bound = self.bound2.result() loopvar_name = self.loopvar_node.result()
code.putln( code.putln(
"for (%s = %s%s; %s %s %s; %s%s) {" % ( "for (%s = %s%s; %s %s %s; %s%s) {" % (
loopvar_name, loopvar_name,
self.bound1.result(), offset, self.bound1.result(), offset,
loopvar_name, self.relation2, range_bound, loopvar_name, self.relation2, self.bound2.result(),
loopvar_name, incop)) loopvar_name, incop))
if self.py_loopvar_node: if self.py_loopvar_node:
self.py_loopvar_node.generate_evaluation_code(code) self.py_loopvar_node.generate_evaluation_code(code)
self.target.generate_assignment_code(self.py_loopvar_node, 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) self.body.generate_execution_code(code)
code.put_label(code.continue_label) code.put_label(code.continue_label)
if from_range: if self.py_loopvar_node:
# Undo last increment to maintain Python semantics: # Reassign py variable to loop var here.
code.putln("} %s%s;" % (loopvar_name, decop)) # (For consistancy, should rarely come up in practice.)
# End the outer if statement: import ExprNodes
code.putln("} /* end if */") from_py_node = ExprNodes.CoerceFromPyTypeNode(self.loopvar_node.type, self.target, None)
code.funcstate.release_temp(range_bound) from_py_node.temp_code = loopvar_name
else: from_py_node.generate_result_code(code)
code.putln("}") 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 break_label = code.break_label
code.set_loop_labels(old_loop_labels) code.set_loop_labels(old_loop_labels)
if self.else_clause: if self.else_clause:
...@@ -3974,6 +3974,8 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -3974,6 +3974,8 @@ class ForFromStatNode(LoopNode, StatNode):
if self.step is not None: if self.step is not None:
self.step.generate_disposal_code(code) self.step.generate_disposal_code(code)
self.step.free_temps(code) self.step.free_temps(code)
if from_range:
code.funcstate.release_temp(loopvar_name)
relation_table = { relation_table = {
# {relop : (initial offset, increment op)} # {relop : (initial offset, increment op)}
......
...@@ -144,7 +144,6 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -144,7 +144,6 @@ class IterationTransform(Visitor.VisitorTransform):
relation2=relation2, bound2=bound2, relation2=relation2, bound2=bound2,
step=step, body=node.body, step=step, body=node.body,
else_clause=node.else_clause, else_clause=node.else_clause,
loopvar_node=node.target,
from_range=True) from_range=True)
return for_node return for_node
......
...@@ -4,10 +4,6 @@ ...@@ -4,10 +4,6 @@
(9, 9, 8, 1, 2) (9, 9, 8, 1, 2)
>>> from_loop_indices() >>> from_loop_indices()
** Calculating step ** ** Calculating step **
** Calculating step **
** Calculating step **
** Calculating step **
** Calculating step **
(10, 10, 0) (10, 10, 0)
""" """
......
__doc__ = u""" __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 0
at 1 at 1
at 2 at 2
at 3 at 3
at 4 at 4
5 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) >>> test_func(5)
get_bound(5) get_bound(5)
at 0 at 0
...@@ -14,47 +66,61 @@ at 2 ...@@ -14,47 +66,61 @@ at 2
at 3 at 3
at 4 at 4
5 5
>>> test_f()
9
>>> f()
g called
0
1
2
2
""" """
cdef int get_bound(int m): cdef int get_bound(int m):
print "get_bound(%s)"%m print "get_bound(%s)"%m
return m return m
def test_var(int n, int m): def for_from_range(a, b):
cdef int i cdef int i = 100
for i from 0 <= i < n: 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 print "at", i
n = m
return i return i
def test_func(int n): def for_from_bound_reassignment(int bound, int fake_bound):
cdef int i cdef int i = 100
for i from 0 <= i < get_bound(n): for i from 0 <= i < bound:
print "at", i print "at", i
bound = fake_bound
return i return i
def test_f(): def for_from_step_reassignment(int bound, int step, int fake_step):
cdef int i,n cdef int i = 100
n = 10 for i from 0 <= i < bound by step:
for i in range(n): print "at", i
if i == 5: n *= 2 step = fake_step
print i 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(): def for_from_py_target_reassignment(int bound, int factor):
print "g called" cdef object i
return 3 for i from 0 <= i < bound:
print "at", i
i *= factor
return i
def f(): def for_in_target_reassignment(int bound, int factor):
cdef int i = -1 cdef int i = 100
for i in range(g()): for i in range(bound):
print i print "at", i
print 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