Commits

Victor Stinner committed 57d179c

Remove empty loop

  • Participants
  • Parent commits 398601d

Comments (0)

Files changed (5)

 ChangeLog
 =========
 
+Version 0.6
+-----------
+
+ * Remove empty loop. Example:
+   ``for i in (1, 2, 3): pass`` => ``i = 3``.
+
 Version 0.5 (2013-03-26)
 ------------------------
 
 Misc
 ====
 
- * remove empty loop: need to assign to the last value of the iterator
  * automatically detect pure functions: see pythran.analysis.PureFunctions of
    pythran project, depend on ArgumentEffects and GlobalEffects analysys
  * replace '(a and b) and c' (2 op) with 'a and b and c' (1 op),

File astoptimizer/optimizer.py

         if self.config.unroll_limit <= 0:
             return UNSET
 
-        itercst = self.get_constant(node.iter, tuple,
+        itercst = self.get_constant(node.iter, IMMUTABLE_ITERABLE_TYPES,
                                     max_length=self.config.unroll_limit)
         if itercst is UNSET:
             return UNSET
         if not was_unassigned:
             self.namespace._unassigned.remove(target_id)
 
-#       TODO: remove empty loop
-#        if (self.config.remove_dead_code
-#        and is_empty_body(node.body)):
-#            return UNSET
+        if (self.config.remove_dead_code
+        and is_empty_body(node.body)):
+            self.log_node_removal(node)
+
+            value = new_constant(node, itercst[-1])
+            assign = ast.Assign(targets=[target], value=value)
+            copy_lineno(node, assign)
+
+            node_list = [assign]
+            node_list.extend(node.orelse)
+            return self.if_block(node, node_list)
 
         unroll = []
         for cst in itercst:
             return
         generator = node.generators[0]
 
-        # FIXME: support more than 1 generator
-        if len(node.generators) != 1:
-            return
-        generator = node.generators[0]
-
         if generator.ifs:
             return
 
-        itercst = self.get_constant(generator.iter, tuple,
+        itercst = self.get_constant(generator.iter, IMMUTABLE_ITERABLE_TYPES,
                                     max_length=self.config.unroll_limit)
         if itercst is UNSET:
             return
         self.unassign(node.target)
         node.body = self.visit_list(node.body, conditional=True)
         node.orelse = self.visit_list(node.orelse, conditional=True)
-
-#       TODO: remove empty loop
-#       FIXME: assign target to the last iterm of iter
-#        if (self.config.remove_dead_code
-#        and is_empty_body(node.body)):
-#            self.log_node_removal(node)
-#            return self.if_block(node, node.orelse)
-
         return node
 
     def fullvisit_arguments(self, node):

File astoptimizer/tests.py

                                  config=no_unroll)
         self.check('for i in (1, 2, 3):\n print(i)',
                    self.text_ast('i=1; print(i); i=2; print(i); i=3; print(i)'))
-        self.check('for i in (1, 2, 3):\n pass\n pass',
-                   self.text_ast('i=1; i=2; i=3'))
-#       TODO: remove empty loop
-        #self.check('for i in (1, 2, 3):\n pass\n pass',
-        #           self.text_ast('i=3'))
+        self.check('for i in (1, 2, 3):\n pass',
+                   self.text_ast('i=3'),
+                   info=re.compile('Remove dead code: For'))
 
     def test_max_tuple_length(self):
         config = self.create_config('builtin_funcs')
         return config
 
     def check_line(self, line_number, line):
-        if not line.startswith('   - ``'):
+        if ('`' not in line) or ('=>' not in line):
             return
-        line = line[7:].rstrip()
         line = line.replace(r'\\', '\\')
         parts = line.split('``')
+        parts = parts[1:]
         before = parts[0]
         after = parts[2]
         after2 = None
             after = 'if a and b:\n print("true")'
         if 'return 1; return 2' in before:
             info = re.compile('Remove unreachable code')
-        elif ' 3; return s' in before:
+        elif before in ('for i in (1, 2, 3): pass',
+                        'def f(a, b): s = a+b; 3; return s'):
             info = re.compile('Remove dead code')
 
         if 'if DEBUG:' in before:

File astoptimizer/version.py

 PACKAGE = "astoptimizer"
-VERSION = "0.5"
+VERSION = "0.6"
 WEBSITE = "https://bitbucket.org/haypo/astoptimizer"
 LICENSE = "BSD (2 clauses)"