[vala/wip/transform: 6/50] Move DoStatement transformation into the code transformer



commit 61cdeedbb3bf3c46d5abcdcd82b10df806f8663c
Author: Luca Bruno <lucabru src gnome org>
Date:   Tue Aug 30 13:42:39 2011 +0200

    Move DoStatement transformation into the code transformer
    
    Fixes bug 574352.

 vala/valacodetransformer.vala |   39 ++++++++++++++++++++++++++++-
 vala/valadostatement.vala     |   54 ++++++++++++++++++----------------------
 vala/valaflowanalyzer.vala    |   48 ++++++++++++++++++++++++++++++++++++
 3 files changed, 110 insertions(+), 31 deletions(-)
---
diff --git a/vala/valacodetransformer.vala b/vala/valacodetransformer.vala
index 7f0b423..fe06ba5 100644
--- a/vala/valacodetransformer.vala
+++ b/vala/valacodetransformer.vala
@@ -203,7 +203,44 @@ public class Vala.CodeTransformer : CodeVisitor {
 	}
 
 	public override void visit_do_statement (DoStatement stmt) {
-		stmt.accept_children (this);
+		// convert to simple loop
+
+		// do not generate variable and if block if condition is always true
+		if (always_true (stmt.condition)) {
+			var loop = new Loop (stmt.body, stmt.source_reference);
+
+			var parent_block = (Block) stmt.parent_node;
+			parent_block.replace_statement (stmt, loop);
+
+			check (loop);
+			return;
+		}
+
+		var block = new Block (stmt.source_reference);
+
+		var first_local = new LocalVariable (context.analyzer.bool_type.copy (), stmt.get_temp_name (), new BooleanLiteral (true, stmt.source_reference), stmt.source_reference);
+		block.add_statement (new DeclarationStatement (first_local, stmt.source_reference));
+
+		var if_condition = new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, stmt.condition, stmt.condition.source_reference);
+		var true_block = new Block (stmt.condition.source_reference);
+		true_block.add_statement (new BreakStatement (stmt.condition.source_reference));
+		var if_stmt = new IfStatement (if_condition, true_block, null, stmt.condition.source_reference);
+
+		var condition_block = new Block (stmt.condition.source_reference);
+		condition_block.add_statement (if_stmt);
+
+		var first_if = new IfStatement (new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, new MemberAccess.simple (first_local.name, stmt.source_reference), stmt.source_reference), condition_block, null, stmt.source_reference);
+		stmt.body.insert_statement (0, first_if);
+		var first_assign = new ExpressionStatement (new Assignment (new MemberAccess.simple (first_local.name, stmt.source_reference), new BooleanLiteral (false, stmt.source_reference), AssignmentOperator.SIMPLE, stmt.source_reference), stmt.source_reference);
+		stmt.body.insert_statement (1, first_assign);
+
+		block.add_statement (new Loop (stmt.body, stmt.source_reference));
+
+		var parent_block = (Block) stmt.parent_node;
+		parent_block.replace_statement (stmt, block);
+
+		stmt.body.checked = false;
+		check (block);
 	}
 
 	public override void visit_for_statement (ForStatement stmt) {
diff --git a/vala/valadostatement.vala b/vala/valadostatement.vala
index 6bf72c0..940e61f 100644
--- a/vala/valadostatement.vala
+++ b/vala/valadostatement.vala
@@ -81,46 +81,40 @@ public class Vala.DoStatement : CodeNode, Statement {
 		visitor.visit_end_full_expression (condition);
 	}
 
-	bool always_true (Expression condition) {
-		var literal = condition as BooleanLiteral;
-		return (literal != null && literal.value);
+	public override void replace_expression (Expression old_node, Expression new_node) {
+		if (condition == old_node) {
+			condition = new_node;
+		}
 	}
 
 	public override bool check (CodeContext context) {
-		// convert to simple loop
-
-		// do not generate variable and if block if condition is always true
-		if (always_true (condition)) {
-			var loop = new Loop (body, source_reference);
-
-			var parent_block = (Block) parent_node;
-			parent_block.replace_statement (this, loop);
-
-			return loop.check (context);
+		if (checked) {
+			return !error;
 		}
 
-		var block = new Block (source_reference);
+		checked = true;
 
-		var first_local = new LocalVariable (context.analyzer.bool_type.copy (), get_temp_name (), new BooleanLiteral (true, source_reference), source_reference);
-		block.add_statement (new DeclarationStatement (first_local, source_reference));
+		condition.target_type = context.analyzer.bool_type.copy ();
 
-		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);
+		condition.check (context);
 
-		var condition_block = new Block (condition.source_reference);
-		condition_block.add_statement (if_stmt);
-
-		var first_if = new IfStatement (new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, new MemberAccess.simple (first_local.name, source_reference), source_reference), condition_block, null, source_reference);
-		body.insert_statement (0, first_if);
-		body.insert_statement (1, new ExpressionStatement (new Assignment (new MemberAccess.simple (first_local.name, source_reference), new BooleanLiteral (false, source_reference), AssignmentOperator.SIMPLE, source_reference), source_reference));
+		if (condition.error) {
+			/* if there was an error in the condition, skip this check */
+			error = true;
+			return false;
+		}
 
-		block.add_statement (new Loop (body, source_reference));
+		if (condition.value_type == null || !condition.value_type.compatible (context.analyzer.bool_type)) {
+			error = true;
+			Report.error (condition.source_reference, "Condition must be boolean");
+			return false;
+		}
 
-		var parent_block = (Block) parent_node;
-		parent_block.replace_statement (this, block);
+		if (!body.check (context)) {
+			error = true;
+			return false;
+		}
 
-		return block.check (context);
+		return !error;
 	}
 }
diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala
index af4066a..4736a5c 100644
--- a/vala/valaflowanalyzer.vala
+++ b/vala/valaflowanalyzer.vala
@@ -784,6 +784,54 @@ public class Vala.FlowAnalyzer : CodeVisitor {
 		jump_stack.remove_at (jump_stack.size - 1);
 	}
 
+	public override void visit_do_statement (DoStatement stmt) {
+		if (unreachable (stmt)) {
+			return;
+		}
+
+		var body_block = new BasicBlock ();
+		current_block.connect (body_block);
+		current_block = body_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));
+
+		// body
+		stmt.body.accept (this);
+
+		// end of loop block reachable?
+		if (current_block != null) {
+			current_block.connect (loop_block);
+		}
+
+		// condition
+		current_block = loop_block;
+		loop_block.add_node (stmt.condition);
+		handle_errors (stmt.condition);
+
+		if (!always_false (stmt.condition)) {
+			loop_block.connect (body_block);
+		}
+
+		if (!always_true (stmt.condition)) {
+			loop_block.connect (after_loop_block);
+		}
+
+		// after loop block reachable?
+		if (after_loop_block.get_predecessors ().size == 0) {
+			// after loop block not reachable
+			mark_unreachable ();
+		} else {
+			// after loop block reachable
+			current_block = after_loop_block;
+		}
+
+		jump_stack.remove_at (jump_stack.size - 1);
+		jump_stack.remove_at (jump_stack.size - 1);
+	}
+
 	public override void visit_foreach_statement (ForeachStatement stmt) {
 		if (unreachable (stmt)) {
 			return;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]