From: Luca Bruno Date: Wed, 31 Aug 2011 08:51:08 +0000 (+0200) Subject: Move ForStatement transformation into the CCodeTransformer X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2dfe8bcdb6283f5a7755edc4f7a1ea5f6ecbc347;p=thirdparty%2Fvala.git Move ForStatement transformation into the CCodeTransformer --- diff --git a/codegen/valaccodetransformer.vala b/codegen/valaccodetransformer.vala index 9e036ee02..4e31edcda 100644 --- a/codegen/valaccodetransformer.vala +++ b/codegen/valaccodetransformer.vala @@ -104,6 +104,38 @@ public class Vala.CCodeTransformer : CodeTransformer { end_replace_statement (); } + public override void visit_for_statement (ForStatement stmt) { + // convert to simple loop + begin_replace_statement (stmt); + + // initializer + foreach (var init_expr in stmt.get_initializer ()) { + b.add_expression (init_expr); + } + + if (stmt.condition == null || !always_false (stmt.condition)) { + b.open_loop (); + var notfirst = b.add_temp_declaration (null, expression ("false")); + b.open_if (expression (notfirst)); + foreach (var it_expr in stmt.get_iterator ()) { + b.add_expression (it_expr); + } + b.add_else (); + statements (@"$notfirst = true;"); + b.close (); + + if (stmt.condition != null && !always_true (stmt.condition)) { + statements (@"if (!$(stmt.condition)) break;"); + } + b.add_statement (stmt.body); + + b.close (); + } + + stmt.body.checked = false; + end_replace_statement (); + } + public override void visit_expression (Expression expr) { if (expr in context.analyzer.replaced_nodes) { return; diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala index 9b1489ce0..a0ad0b615 100644 --- a/vala/valaflowanalyzer.vala +++ b/vala/valaflowanalyzer.vala @@ -804,6 +804,75 @@ public class Vala.FlowAnalyzer : CodeVisitor { jump_stack.remove_at (jump_stack.size - 1); } + + public override void visit_for_statement (ForStatement stmt) { + if (unreachable (stmt)) { + return; + } + + var outer_block = new BasicBlock (); + all_basic_blocks.add (outer_block); + foreach (var init_expr in stmt.get_initializer ()) { + outer_block.add_node (init_expr); + } + + var iterator_block = new BasicBlock (); + all_basic_blocks.add (iterator_block); + foreach (var it_expr in stmt.get_iterator ()) { + iterator_block.add_node (it_expr); + } + + var loop_block = new BasicBlock (); + all_basic_blocks.add (loop_block); + + var after_loop_block = new BasicBlock (); + all_basic_blocks.add (after_loop_block); + + jump_stack.add (new JumpTarget.continue_target (iterator_block)); + jump_stack.add (new JumpTarget.break_target (after_loop_block)); + + current_block.connect (outer_block); + outer_block.connect (loop_block); + current_block = loop_block; + + // condition + if (stmt.condition != null) { + 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 (iterator_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_do_statement (DoStatement stmt) { if (unreachable (stmt)) { return; diff --git a/vala/valaforstatement.vala b/vala/valaforstatement.vala index aa70cee0b..380effcc5 100644 --- a/vala/valaforstatement.vala +++ b/vala/valaforstatement.vala @@ -154,16 +154,6 @@ public class Vala.ForStatement : CodeNode, Statement { } } - 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 bool check (CodeContext context) { if (checked) { return !error; @@ -171,48 +161,35 @@ public class Vala.ForStatement : CodeNode, Statement { checked = true; - // convert to simple loop - - var block = new Block (source_reference); - // initializer foreach (var init_expr in initializer) { - block.add_statement (new ExpressionStatement (init_expr, init_expr.source_reference)); + if (!init_expr.check (context)) { + error = true; + } } - // do not generate if block if condition is always true - if (condition == null || always_true (condition)) { - } 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 { - // 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); + // condition + if (condition != null) { + condition.target_type = context.analyzer.bool_type.copy (); + if (!condition.check (context)) { + error = true; + } + + if (condition.value_type == null || !condition.value_type.compatible (context.analyzer.bool_type)) { + error = true; + Report.error (condition.source_reference, "Condition must be boolean"); + } } // iterator - 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)); - - var iterator_block = new Block (source_reference); foreach (var it_expr in iterator) { - iterator_block.add_statement (new ExpressionStatement (it_expr, it_expr.source_reference)); + if (!it_expr.check (context)) { + error = true; + } } - var first_if = new IfStatement (new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, new MemberAccess.simple (first_local.name, source_reference), source_reference), iterator_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)); - - block.add_statement (new Loop (body, source_reference)); - - var parent_block = (Block) parent_node; - parent_block.replace_statement (this, block); - - if (!block.check (context)) { + // body + if (!body.check (context)) { error = true; }