[vala] Convert while loops into simple loops
- From: Jürg Billeter <juergbi src gnome org>
- To: svn-commits-list gnome org
- Subject: [vala] Convert while loops into simple loops
- Date: Sat, 6 Jun 2009 11:20:47 -0400 (EDT)
commit 14cb3893cf381f6b9136eccccdba86bc42786a56
Author: Jürg Billeter <j bitron ch>
Date: Sat Jun 6 15:58:44 2009 +0200
Convert while loops into simple loops
Simplifies and fixes bugs in semantic and flow analysis and code
generation. Based on patch by Levi Bard, fixes bug 570091.
---
codegen/valaccodebasemodule.vala | 2 +-
codegen/valaccodecontrolflowmodule.vala | 6 +--
codegen/valaccodegenerator.vala | 4 +-
codegen/valaccodemodule.vala | 4 +-
vala/Makefile.am | 1 +
vala/valablock.vala | 2 +
vala/valacodevisitor.vala | 8 +++
vala/valacodewriter.vala | 7 +++
vala/valaexpression.vala | 5 +--
vala/valaflowanalyzer.vala | 30 ++++--------
vala/valaloop.vala | 78 +++++++++++++++++++++++++++++++
vala/valanullchecker.vala | 6 +--
vala/valasymbolresolver.vala | 4 ++
vala/valawhilestatement.vala | 60 +++++++-----------------
14 files changed, 137 insertions(+), 80 deletions(-)
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index fa55b8d..3cc49d6 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -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;
diff --git a/codegen/valaccodecontrolflowmodule.vala b/codegen/valaccodecontrolflowmodule.vala
index 4c2b601..192ad8a 100644
--- a/codegen/valaccodecontrolflowmodule.vala
+++ b/codegen/valaccodecontrolflowmodule.vala
@@ -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) {
diff --git a/codegen/valaccodegenerator.vala b/codegen/valaccodegenerator.vala
index 52b57d6..263c918 100644
--- a/codegen/valaccodegenerator.vala
+++ b/codegen/valaccodegenerator.vala
@@ -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) {
diff --git a/codegen/valaccodemodule.vala b/codegen/valaccodemodule.vala
index 8dff9bf..1da365d 100644
--- a/codegen/valaccodemodule.vala
+++ b/codegen/valaccodemodule.vala
@@ -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) {
diff --git a/vala/Makefile.am b/vala/Makefile.am
index ea92234..0b1044e 100644
--- a/vala/Makefile.am
+++ b/vala/Makefile.am
@@ -89,6 +89,7 @@ libvalacore_la_VALASOURCES = \
valalocalvariable.vala \
valalockable.vala \
valalockstatement.vala \
+ valaloop.vala \
valamember.vala \
valamemberaccess.vala \
valamemberinitializer.vala \
diff --git a/vala/valablock.vala b/vala/valablock.vala
index d392c96..9c99ec8 100644
--- a/vala/valablock.vala
+++ b/vala/valablock.vala
@@ -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);
}
diff --git a/vala/valacodevisitor.vala b/vala/valacodevisitor.vala
index d3f57e7..65ddb23 100644
--- a/vala/valacodevisitor.vala
+++ b/vala/valacodevisitor.vala
@@ -301,6 +301,14 @@ public abstract class Vala.CodeVisitor {
}
/**
+ * Visit operation called for loops.
+ *
+ * @param stmt a loop
+ */
+ public virtual void visit_loop (Loop stmt) {
+ }
+
+ /**
* Visit operation called for while statements.
*
* @param stmt an while statement
diff --git a/vala/valacodewriter.vala b/vala/valacodewriter.vala
index 047e1ed..72ba348 100644
--- a/vala/valacodewriter.vala
+++ b/vala/valacodewriter.vala
@@ -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 (");
diff --git a/vala/valaexpression.vala b/vala/valaexpression.vala
index 8f37efd..ce67db8 100644
--- a/vala/valaexpression.vala
+++ b/vala/valaexpression.vala
@@ -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);
diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala
index dde5446..33fe0da 100644
--- a/vala/valaflowanalyzer.vala
+++ b/vala/valaflowanalyzer.vala
@@ -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
index 0000000..a0281e9
--- /dev/null
+++ b/vala/valaloop.vala
@@ -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;
+ }
+}
+
diff --git a/vala/valanullchecker.vala b/vala/valanullchecker.vala
index d2ba824..0d0bffa 100644
--- a/vala/valanullchecker.vala
+++ b/vala/valanullchecker.vala
@@ -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) {
diff --git a/vala/valasymbolresolver.vala b/vala/valasymbolresolver.vala
index f5be421..24612f1 100644
--- a/vala/valasymbolresolver.vala
+++ b/vala/valasymbolresolver.vala
@@ -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);
}
diff --git a/vala/valawhilestatement.vala b/vala/valawhilestatement.vala
index 64c8e1c..71f5405 100644
--- a/vala/valawhilestatement.vala
+++ b/vala/valawhilestatement.vala
@@ -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);
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]