From: Luca Bruno Date: Tue, 30 Aug 2011 10:43:41 +0000 (+0200) Subject: Move WhileStatement transformation into the code transformer X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bdacbde5c6c64fe15a90ed9ecbe5c78d1847b74d;p=thirdparty%2Fvala.git Move WhileStatement transformation into the code transformer --- diff --git a/vala/valacodetransformer.vala b/vala/valacodetransformer.vala index 1f0136d79..c9fd8079c 100644 --- a/vala/valacodetransformer.vala +++ b/vala/valacodetransformer.vala @@ -167,8 +167,39 @@ public class Vala.CodeTransformer : CodeVisitor { label.accept_children (this); } + bool always_true (Expression condition) { + var literal = condition as BooleanLiteral; + return (literal != null && literal.value); + } + + bool always_false (Expression condition) { + var literal = condition as BooleanLiteral; + return (literal != null && !literal.value); + } + public override void visit_while_statement (WhileStatement stmt) { - stmt.accept_children (this); + // convert to simple loop + + if (always_true (stmt.condition)) { + // do not generate if block if condition is always true + } else if (always_false (stmt.condition)) { + // do not generate if block if condition is always false + stmt.body.insert_statement (0, new BreakStatement (stmt.condition.source_reference)); + } else { + 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); + stmt.body.insert_statement (0, if_stmt); + } + + var loop = new Loop (stmt.body, stmt.source_reference); + + var parent_block = (Block) stmt.parent_node; + parent_block.replace_statement (stmt, loop); + + stmt.body.checked = false; + check (loop); } public override void visit_do_statement (DoStatement stmt) { diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala index dc7e471a3..6b15400ef 100644 --- a/vala/valaflowanalyzer.vala +++ b/vala/valaflowanalyzer.vala @@ -753,6 +753,57 @@ public class Vala.FlowAnalyzer : CodeVisitor { jump_stack.remove_at (jump_stack.size - 1); } + public override void visit_while_statement (WhileStatement stmt) { + if (unreachable (stmt)) { + return; + } + + var loop_block = new BasicBlock (); + all_basic_blocks.add (loop_block); + jump_stack.add (new JumpTarget.continue_target (loop_block)); + var after_loop_block = new BasicBlock (); + all_basic_blocks.add (after_loop_block); + jump_stack.add (new JumpTarget.break_target (after_loop_block)); + + current_block.connect (loop_block); + current_block = loop_block; + + // condition + loop_block.add_node (stmt.condition); + handle_errors (stmt.condition); + + if (always_false (stmt.condition)) { + mark_unreachable (); + } else { + current_block = new BasicBlock (); + all_basic_blocks.add (current_block); + loop_block.connect (current_block); + } + + if (!always_true (stmt.condition)) { + loop_block.connect (after_loop_block); + } + + // loop block + stmt.body.accept (this); + // end of loop block reachable? + if (current_block != null) { + current_block.connect (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; diff --git a/vala/valawhilestatement.vala b/vala/valawhilestatement.vala index a15b1abe8..963764bb9 100644 --- a/vala/valawhilestatement.vala +++ b/vala/valawhilestatement.vala @@ -81,16 +81,6 @@ public class Vala.WhileStatement : CodeNode, Statement { body.accept (visitor); } - bool always_true (Expression condition) { - var literal = condition as BooleanLiteral; - return (literal != null && literal.value); - } - - bool always_false (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; @@ -104,28 +94,25 @@ public class Vala.WhileStatement : CodeNode, Statement { checked = true; - // convert to simple loop - - if (always_true (condition)) { - // do not generate if block if condition is always true - } else if (always_false (condition)) { - // do not generate if block if condition is always false - body.insert_statement (0, new BreakStatement (condition.source_reference)); - } else { - 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); - } + condition.target_type = context.analyzer.bool_type.copy (); - var loop = new Loop (body, source_reference); + condition.check (context); - var parent_block = (Block) parent_node; - parent_block.replace_statement (this, loop); + if (condition.error) { + /* if there was an error in the condition, skip this check */ + error = true; + return false; + } + + 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; + } - if (!loop.check (context)) { + if (!body.check (context)) { error = true; + return false; } return !error;