]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Convert while loops into simple loops
authorJürg Billeter <j@bitron.ch>
Sat, 6 Jun 2009 13:58:44 +0000 (15:58 +0200)
committerJürg Billeter <j@bitron.ch>
Sat, 6 Jun 2009 15:19:57 +0000 (17:19 +0200)
Simplifies and fixes bugs in semantic and flow analysis and code
generation. Based on patch by Levi Bard, fixes bug 570091.

14 files changed:
codegen/valaccodebasemodule.vala
codegen/valaccodecontrolflowmodule.vala
codegen/valaccodegenerator.vala
codegen/valaccodemodule.vala
vala/Makefile.am
vala/valablock.vala
vala/valacodevisitor.vala
vala/valacodewriter.vala
vala/valaexpression.vala
vala/valaflowanalyzer.vala
vala/valaloop.vala [new file with mode: 0644]
vala/valanullchecker.vala
vala/valasymbolresolver.vala
vala/valawhilestatement.vala

index fa55b8d76be06173ec29c16ff171a24fde29895e..3cc49d63974f10835fc54a778bb20c500d158503 100644 (file)
@@ -2231,7 +2231,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
                }
                
                if (stop_at_loop) {
-                       if (b.parent_node is DoStatement || b.parent_node is WhileStatement ||
+                       if (b.parent_node is DoStatement || b.parent_node is Loop ||
                            b.parent_node is ForStatement || b.parent_node is ForeachStatement ||
                            b.parent_node is SwitchStatement) {
                                return;
index 4c2b6011232405e82d70bda16830f330a257aab4..192ad8aa33fa5814c2bb4cb91985be0f9e24db5e 100644 (file)
@@ -221,12 +221,10 @@ internal class Vala.CCodeControlFlowModule : CCodeMethodModule {
                label.accept_children (codegen);
        }
 
-       public override void visit_while_statement (WhileStatement stmt) {
+       public override void visit_loop (Loop stmt) {
                stmt.accept_children (codegen);
 
-               stmt.ccodenode = new CCodeWhileStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode);
-               
-               create_temp_decl (stmt, stmt.condition.temp_vars);
+               stmt.ccodenode = new CCodeWhileStatement (new CCodeConstant ("TRUE"), (CCodeStatement) stmt.body.ccodenode);
        }
 
        public override void visit_do_statement (DoStatement stmt) {
index 52b57d60f796c4da14c6744008778ce998da3b9d..263c9182b3b1cb4c23dbcbd6454ad11f197d45c1 100644 (file)
@@ -189,8 +189,8 @@ public class Vala.CCodeGenerator : CodeGenerator {
                head.visit_switch_label (label);
        }
 
-       public override void visit_while_statement (WhileStatement stmt) {
-               head.visit_while_statement (stmt);
+       public override void visit_loop (Loop stmt) {
+               head.visit_loop (stmt);
        }
 
        public override void visit_do_statement (DoStatement stmt) {
index 8dff9bf5a9a4ef8b9d6e9e5cbb4679b02183f65b..1da365d4b9545a373cd3d0bb530a45c333571166 100644 (file)
@@ -168,8 +168,8 @@ public abstract class Vala.CCodeModule {
                next.visit_switch_label (label);
        }
 
-       public virtual void visit_while_statement (WhileStatement stmt) {
-               next.visit_while_statement (stmt);
+       public virtual void visit_loop (Loop stmt) {
+               next.visit_loop (stmt);
        }
 
        public virtual void visit_do_statement (DoStatement stmt) {
index ea92234d3fcbc2e99ea1c7bb61a753c4d1b14372..0b1044e24d27f614afecec96ad392b8572a9d5e4 100644 (file)
@@ -89,6 +89,7 @@ libvalacore_la_VALASOURCES = \
        valalocalvariable.vala \
        valalockable.vala \
        valalockstatement.vala \
+       valaloop.vala \
        valamember.vala \
        valamemberaccess.vala \
        valamemberinitializer.vala \
index d392c96ea66edfa40e85e96d816b6901b06bf3ed..9c99ec838ad49ab960f91447ad9e9dae500164b7 100644 (file)
@@ -51,10 +51,12 @@ public class Vala.Block : Symbol, Statement {
         * @param stmt a statement
         */
        public void add_statement (Statement stmt) {
+               stmt.parent_node = this;
                statement_list.add (stmt);
        }
 
        public void insert_statement (int index, Statement stmt) {
+               stmt.parent_node = this;
                statement_list.insert (index, stmt);
        }
 
index d3f57e765c9e3e358994cf9c06a7c7aca9e49e3d..65ddb23ead1c7d4ff23edf30097c2efca7f91ae0 100644 (file)
@@ -300,6 +300,14 @@ public abstract class Vala.CodeVisitor {
        public virtual void visit_switch_label (SwitchLabel label) {
        }
 
+       /**
+        * Visit operation called for loops.
+        *
+        * @param stmt a loop
+        */
+       public virtual void visit_loop (Loop stmt) {
+       }
+
        /**
         * Visit operation called for while statements.
         *
index 047e1ed842381bf8a76adb694e584ea5eed3d36d..72ba348c29ba3f5bc86f80d99542eaf7ca5c2f09 100644 (file)
@@ -1098,6 +1098,13 @@ public class Vala.CodeWriter : CodeVisitor {
                }
        }
 
+       public override void visit_loop (Loop stmt) {
+               write_indent ();
+               write_string ("loop");
+               stmt.body.accept (this);
+               write_newline ();
+       }
+
        public override void visit_while_statement (WhileStatement stmt) {
                write_indent ();
                write_string ("while (");
index 8f37efd7a82b78b6e1271b2374e5ff3a6d02fc04..ce67db8c50829c76b06a38fbcc7c6ec31266c941 100644 (file)
@@ -103,13 +103,10 @@ public abstract class Vala.Expression : CodeNode {
        }
 
        public Block prepare_condition_split (SemanticAnalyzer analyzer) {
-               var while_stmt = parent_statement as WhileStatement;
                var do_stmt = parent_statement as DoStatement;
                var for_stmt = parent_statement as ForStatement;
 
-               if (while_stmt != null) {
-                       return while_stmt.prepare_condition_split (analyzer);
-               } else if (do_stmt != null) {
+               if (do_stmt != null) {
                        return do_stmt.prepare_condition_split (analyzer);
                } else if (for_stmt != null) {
                        return for_stmt.prepare_condition_split (analyzer);
index dde54469d33551c3765c945789c279770cc59b71..33fe0da6ad407f5cee6c5ac36fda748294cf878e 100644 (file)
@@ -655,45 +655,35 @@ public class Vala.FlowAnalyzer : CodeVisitor {
                jump_stack.remove_at (jump_stack.size - 1);
        }
 
-       public override void visit_while_statement (WhileStatement stmt) {
+       public override void visit_loop (Loop stmt) {
                if (unreachable (stmt)) {
                        return;
                }
 
-               var condition_block = new BasicBlock ();
-               jump_stack.add (new JumpTarget.continue_target (condition_block));
+               var loop_block = new BasicBlock ();
+               jump_stack.add (new JumpTarget.continue_target (loop_block));
                var after_loop_block = new BasicBlock ();
                jump_stack.add (new JumpTarget.break_target (after_loop_block));
 
-               // condition
+               // loop block
                var last_block = current_block;
-               last_block.connect (condition_block);
-               current_block = condition_block;
-               current_block.add_node (stmt.condition);
-
-               handle_errors (stmt.condition);
+               last_block.connect (loop_block);
+               current_block = loop_block;
 
-               // loop block
-               if (always_false (stmt.condition)) {
-                       current_block = null;
-                       unreachable_reported = false;
-               } else {
-                       current_block = new BasicBlock ();
-                       condition_block.connect (current_block);
-               }
                stmt.body.accept (this);
                // end of loop block reachable?
                if (current_block != null) {
-                       current_block.connect (condition_block);
+                       current_block.connect (loop_block);
                }
 
                // after loop
                // reachable?
-               if (always_true (stmt.condition) && after_loop_block.get_predecessors ().size == 0) {
+               if (after_loop_block.get_predecessors ().size == 0) {
+                       // after loop block not reachable
                        current_block = null;
                        unreachable_reported = false;
                } else {
-                       condition_block.connect (after_loop_block);
+                       // after loop block reachable
                        current_block = after_loop_block;
                }
 
diff --git a/vala/valaloop.vala b/vala/valaloop.vala
new file mode 100644 (file)
index 0000000..a0281e9
--- /dev/null
@@ -0,0 +1,78 @@
+/* valaloop.vala
+ *
+ * Copyright (C) 2009  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+
+/**
+ * Represents an endless loop.
+ */
+public class Vala.Loop : CodeNode, Statement {
+       /**
+        * Specifies the loop body.
+        */
+       public Block body {
+               get {
+                       return _body;
+               }
+               set {
+                       _body = value;
+                       _body.parent_node = this;
+               }
+       }
+
+       private Block _body;
+
+       /**
+        * Creates a new loop.
+        *
+        * @param body   loop body
+        * @param source reference to source code
+        * @return       newly created while statement
+        */
+       public Loop (Block body, SourceReference? source_reference = null) {
+               this.body = body;
+               this.source_reference = source_reference;
+       }
+
+       public override void accept (CodeVisitor visitor) {
+               visitor.visit_loop (this);
+       }
+
+       public override void accept_children (CodeVisitor visitor) {
+               body.accept (visitor);
+       }
+
+       public override bool check (SemanticAnalyzer analyzer) {
+               if (checked) {
+                       return !error;
+               }
+
+               checked = true;
+
+               body.check (analyzer);
+
+               add_error_types (body.get_error_types ());
+
+               return !error;
+       }
+}
+
index d2ba8245d5b4748b4c33ddacacf3f6b34ea9e378..0d0bffa8227f7baff5fca8296bf3054533cdd634 100644 (file)
@@ -1,6 +1,6 @@
 /* valanullchecker.vala
  *
- * Copyright (C) 2008  Jürg Billeter
+ * Copyright (C) 2008-2009  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -152,10 +152,8 @@ public class Vala.NullChecker : CodeVisitor {
                section.accept_children (this);
        }
 
-       public override void visit_while_statement (WhileStatement stmt) {
+       public override void visit_loop (Loop stmt) {
                stmt.accept_children (this);
-
-               check_non_null (stmt.condition);
        }
 
        public override void visit_do_statement (DoStatement stmt) {
index f5be4211f782b8e3bb037d38ad5c749084bc65b4..24612f1642f9e6c1ad32553a30eac5d91612217a 100644 (file)
@@ -380,6 +380,10 @@ public class Vala.SymbolResolver : CodeVisitor {
                label.accept_children (this);
        }
 
+       public override void visit_loop (Loop stmt) {
+               stmt.accept_children (this);
+       }
+
        public override void visit_while_statement (WhileStatement stmt) {
                stmt.accept_children (this);
        }
index 64c8e1ce251bdb685c95b5fd6ef427ca3a484095..71f5405943fabe1606f868841ed6430bbef51133 100644 (file)
@@ -1,6 +1,6 @@
 /* valawhilestatement.vala
  *
- * Copyright (C) 2006-2008  Jürg Billeter
+ * Copyright (C) 2006-2009  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -81,55 +81,29 @@ public class Vala.WhileStatement : CodeNode, Statement {
                body.accept (visitor);
        }
 
-       public override void replace_expression (Expression old_node, Expression new_node) {
-               if (condition == old_node) {
-                       condition = new_node;
-               }
+       bool always_true (Expression condition) {
+               var literal = condition as BooleanLiteral;
+               return (literal != null && literal.value);
        }
 
        public override bool check (SemanticAnalyzer analyzer) {
-               if (checked) {
-                       return !error;
-               }
-
-               checked = true;
-
-               condition.check (analyzer);
-               
-               body.check (analyzer);
-
-               if (condition.error) {
-                       /* if there was an error in the condition, skip this check */
-                       error = true;
-                       return false;
+               // convert to simple loop
+
+               // do not generate if block if condition is always true
+               if (!always_true (condition)) {
+                       var if_condition = new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, condition, condition.source_reference);
+                       var true_block = new Block (condition.source_reference);
+                       true_block.add_statement (new BreakStatement (condition.source_reference));
+                       var if_stmt = new IfStatement (if_condition, true_block, null, condition.source_reference);
+                       body.insert_statement (0, if_stmt);
                }
 
-               if (!condition.value_type.compatible (analyzer.bool_type)) {
-                       error = true;
-                       Report.error (condition.source_reference, "Condition must be boolean");
-                       return false;
-               }
-
-               add_error_types (condition.get_error_types ());
-               add_error_types (body.get_error_types ());
-
-               return !error;
-       }
-
-       public Block prepare_condition_split (SemanticAnalyzer analyzer) {
-               // move condition into the loop body to allow split
-               // in multiple statements
-
-               var if_condition = new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, condition, condition.source_reference);
-               var true_block = new Block (condition.source_reference);
-               true_block.add_statement (new BreakStatement (condition.source_reference));
-               var if_stmt = new IfStatement (if_condition, true_block, null, condition.source_reference);
-               body.insert_statement (0, if_stmt);
+               var loop = new Loop (body, source_reference);
 
-               condition = new BooleanLiteral (true, source_reference);
-               condition.check (analyzer);
+               var parent_block = (Block) parent_node;
+               parent_block.replace_statement (this, loop);
 
-               return body;
+               return loop.check (analyzer);
        }
 }