Added for i from ... ['by' step] syntax.
authorRobert Bradshaw <robertwb@math.washington.edu>
Thu, 26 Apr 2007 03:42:45 +0000 (20:42 -0700)
committerRobert Bradshaw <robertwb@math.washington.edu>
Thu, 26 Apr 2007 03:42:45 +0000 (20:42 -0700)
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
Cython/Compiler/Parsing.py
Cython/Compiler/Scanning.py

index b53fbfd258afc141d18ac5bbae11a87de9698fcf..6947fb85454b2e2f224356ac58a31fefe9bc61a9 100644 (file)
@@ -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)}
index a88e92367414abece6b9c6371300c6bace886adc..d819ccebbc0a1b56313569f0fb7412b03bdda33b 100644 (file)
@@ -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 = ('<', '<=', '>', '>=')
 
index 26ce042bb7391b304534778c7f6ededf2651dee4..0d2d0ae9ee6b1f40b1b4d8c56ec8f5b3428348bf 100644 (file)
@@ -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: