From 33b0863c37223e98aa094f321d9eedfa435078e2 Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Wed, 25 Apr 2007 20:42:45 -0700 Subject: [PATCH] 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 --- Cython/Compiler/Nodes.py | 15 ++++++++++++++- Cython/Compiler/Parsing.py | 12 +++++++++++- Cython/Compiler/Scanning.py | 2 +- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index b53fbfd2..6947fb85 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -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)} diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index a88e9236..d819cceb 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -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: @@ -1069,6 +1071,14 @@ def p_for_from_relation(s): return op 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 = ('<', '<=', '>', '>=') diff --git a/Cython/Compiler/Scanning.py b/Cython/Compiler/Scanning.py index 26ce042b..0d2d0ae9 100644 --- a/Cython/Compiler/Scanning.py +++ b/Cython/Compiler/Scanning.py @@ -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: -- 2.26.2