Commit d7ca3ad8 authored by Robert Bradshaw's avatar Robert Bradshaw

fix most loop tests

--HG--
extra : transplant_source : %0C%16_W%14l%E8%11%CC%EBc%97%B3%23%B2%87%7D%C0uY
parent 0a1e62d9
...@@ -3890,6 +3890,7 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -3890,6 +3890,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
...@@ -3898,6 +3899,7 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -3898,6 +3899,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)
...@@ -3916,13 +3918,15 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -3916,13 +3918,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,
...@@ -3966,49 +3970,37 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -3966,49 +3970,37 @@ 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:
code.putln("} %s%s;" % (loopvar_name, decop)) self.py_loopvar_node.generate_evaluation_code(code)
# End the outer if statement: self.target.generate_assignment_code(self.py_loopvar_node, code)
code.putln("} /* end if */") code.putln("}")
code.funcstate.release_temp(range_bound)
else:
code.putln("}")
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:
...@@ -4023,6 +4015,8 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -4023,6 +4015,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
......
...@@ -17,6 +17,11 @@ at 5 ...@@ -17,6 +17,11 @@ at 5
at 7 at 7
at 9 at 9
9 9
>>> for_from_range(-5, -10)
range(-5)
range(-5, -10)
range(-5, -10, 2)
100
>>> for_from_bound_reassignment(5, 1) >>> for_from_bound_reassignment(5, 1)
at 0 at 0
at 1 at 1
...@@ -62,8 +67,12 @@ at 3 ...@@ -62,8 +67,12 @@ at 3
at 4 at 4
5 5
""" """
cdef int get_bound(int m):
print "get_bound(%s)"%m
return m
def for_from_range(a, b): def for_from_range(a, b):
cdef int i cdef int i = 100
print "range(%s)" % a print "range(%s)" % a
for i in range(a): for i in range(a):
print "at", i print "at", i
...@@ -75,26 +84,22 @@ def for_from_range(a, b): ...@@ -75,26 +84,22 @@ def for_from_range(a, b):
print "at", i print "at", i
return i return i
cdef int get_bound(int m):
print "get_bound(%s)"%m
return m
def for_from_bound_reassignment(int bound, int fake_bound): def for_from_bound_reassignment(int bound, int fake_bound):
cdef int i cdef int i = 100
for i from 0 <= i < bound: for i from 0 <= i < bound:
print "at", i print "at", i
bound = fake_bound bound = fake_bound
return i return i
def for_from_step_reassignment(int bound, int step, int fake_step): def for_from_step_reassignment(int bound, int step, int fake_step):
cdef int i cdef int i = 100
for i from 0 <= i < bound by step: for i from 0 <= i < bound by step:
print "at", i print "at", i
step = fake_step step = fake_step
return i return i
def for_from_target_reassignment(int bound, int factor): def for_from_target_reassignment(int bound, int factor):
cdef int i cdef int i = 100
for i from 0 <= i < bound: for i from 0 <= i < bound:
print "at", i print "at", i
i *= factor i *= factor
...@@ -108,14 +113,14 @@ def for_from_py_target_reassignment(int bound, int factor): ...@@ -108,14 +113,14 @@ def for_from_py_target_reassignment(int bound, int factor):
return i return i
def for_in_target_reassignment(int bound, int factor): def for_in_target_reassignment(int bound, int factor):
cdef int i cdef int i = 100
for i in range(bound): for i in range(bound):
print "at", i print "at", i
i *= factor i *= factor
return i return i
def test_func(int n): def test_func(int n):
cdef int i cdef int i = 100
for i from 0 <= i < get_bound(n): for i from 0 <= i < get_bound(n):
print "at", i print "at", i
return 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