Commit 33b0863c authored by Robert Bradshaw's avatar Robert Bradshaw

Added for i from ... ['by' step] syntax.

E.g.

for i from 0 <= i < 10 by 2:
    print i

0
2
4
6
8

Old for-from loops remain exactly the same (using the ++ or --). If step is specified, the increment operator will be += step or -= step, depending on the orientation of the inequalities (as before).

NOTE: 'by' is now a keyword
parent eb232ced
......@@ -3297,6 +3297,7 @@ class ForFromStatNode(StatNode):
# relation1 string
# relation2 string
# bound2 ExprNode
# step ExprNode or None
# body StatNode
# else_clause StatNode or None
#
......@@ -3318,6 +3319,9 @@ class ForFromStatNode(StatNode):
self.bound2.analyse_types(env)
self.bound1 = self.bound1.coerce_to_integer(env)
self.bound2 = self.bound2.coerce_to_integer(env)
if self.step is not None:
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)
target_type = self.target.type
......@@ -3337,6 +3341,8 @@ class ForFromStatNode(StatNode):
ExprNodes.CloneNode(c_loopvar_node).coerce_to_pyobject(env)
self.bound1.allocate_temps(env)
self.bound2.allocate_temps(env)
if self.step is not None:
self.step.allocate_temps(env)
if self.py_loopvar_node:
self.py_loopvar_node.allocate_temps(env)
self.target.allocate_target_temps(env)
......@@ -3350,6 +3356,8 @@ class ForFromStatNode(StatNode):
self.else_clause.analyse_expressions(env)
self.bound1.release_temp(env)
self.bound2.release_temp(env)
if self.step is not None:
self.step.release_temp(env)
#env.recycle_pending_temps() # TEMPORARY
def generate_execution_code(self, code):
......@@ -3357,12 +3365,15 @@ class ForFromStatNode(StatNode):
self.bound1.generate_evaluation_code(code)
self.bound2.generate_evaluation_code(code)
offset, incop = self.relation_table[self.relation1]
if self.step is not None:
self.step.generate_evaluation_code(code)
incop = "%s=%s" % (incop[0], self.step.result_code)
code.putln(
"for (%s = %s%s; %s %s %s; %s%s) {" % (
self.loopvar_name,
self.bound1.result_code, offset,
self.loopvar_name, self.relation2, self.bound2.result_code,
incop, self.loopvar_name))
self.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)
......@@ -3378,6 +3389,8 @@ class ForFromStatNode(StatNode):
code.put_label(break_label)
self.bound1.generate_disposal_code(code)
self.bound2.generate_disposal_code(code)
if self.step is not None:
self.step.generate_disposal_code(code)
relation_table = {
# {relop : (initial offset, increment op)}
......
......@@ -1047,6 +1047,7 @@ def p_for_bounds(s):
rel2_pos = s.position()
rel2 = p_for_from_relation(s)
bound2 = p_bit_expr(s)
step = p_for_from_step(s)
if not target.is_name:
error(target.pos,
"Target of for-from statement must be a variable name")
......@@ -1060,7 +1061,8 @@ def p_for_bounds(s):
'bound1': bound1,
'relation1': rel1,
'relation2': rel2,
'bound2': bound2 }
'bound2': bound2,
'step': step }
def p_for_from_relation(s):
if s.sy in inequality_relations:
......@@ -1070,6 +1072,14 @@ def p_for_from_relation(s):
else:
s.error("Expected one of '<', '<=', '>' '>='")
def p_for_from_step(s):
if s.sy == 'by':
s.next()
step = p_bit_expr(s)
return step
else:
return None
inequality_relations = ('<', '<=', '>', '>=')
def p_for_target(s):
......
......@@ -138,7 +138,7 @@ reserved_words = [
"raise", "import", "exec", "try", "except", "finally",
"while", "if", "elif", "else", "for", "in", "assert",
"and", "or", "not", "is", "in", "lambda", "from",
"NULL", "cimport"
"NULL", "cimport", "by"
]
class Method:
......
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