[vala/wip/transform: 17/107] Move ForStatement transformation into the code transformer



commit 9fe9f614ebbd6fcbc8181bfdad2bec04573e8c02
Author: Luca Bruno <lucabru src gnome org>
Date:   Wed Aug 31 10:51:08 2011 +0200

    Move ForStatement transformation into the code transformer

 vala/valacodetransformer.vala |   44 +++++++++++++++++++++++++++-
 vala/valaflowanalyzer.vala    |   64 ++++++++++++++++++++++++++++++++++++++++
 vala/valaforstatement.vala    |   65 ++++++++++++++++------------------------
 3 files changed, 133 insertions(+), 40 deletions(-)
---
diff --git a/vala/valacodetransformer.vala b/vala/valacodetransformer.vala
index 8264033..893bb18 100644
--- a/vala/valacodetransformer.vala
+++ b/vala/valacodetransformer.vala
@@ -244,7 +244,49 @@ public class Vala.CodeTransformer : CodeVisitor {
        }
 
        public override void visit_for_statement (ForStatement stmt) {
-               stmt.accept_children (this);
+               // convert to simple loop
+
+               var block = new Block (stmt.source_reference);
+
+               // initializer
+               foreach (var init_expr in stmt.get_initializer ()) {
+                       block.add_statement (new ExpressionStatement (init_expr, init_expr.source_reference));
+               }
+
+               // do not generate if block if condition is always true
+               if (stmt.condition == null || always_true (stmt.condition)) {
+               } 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 {
+                       // condition
+                       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);
+               }
+
+               // iterator
+               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 iterator_block = new Block (stmt.source_reference);
+               foreach (var it_expr in stmt.get_iterator ()) {
+                       iterator_block.add_statement (new ExpressionStatement (it_expr, 
it_expr.source_reference));
+               }
+
+               var first_if = new IfStatement (new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, new 
MemberAccess.simple (first_local.name, stmt.source_reference), stmt.source_reference), iterator_block, null, 
stmt.source_reference);
+               stmt.body.insert_statement (0, first_if);
+               stmt.body.insert_statement (1, 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));
+
+               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_foreach_statement (ForeachStatement stmt) {
diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala
index 047f201..e616a8c 100644
--- a/vala/valaflowanalyzer.vala
+++ b/vala/valaflowanalyzer.vala
@@ -778,6 +778,70 @@ 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 ();
+               foreach (var init_expr in stmt.get_initializer ()) {
+                       outer_block.add_node (init_expr);
+               }
+
+               var iterator_block = new BasicBlock ();
+               foreach (var it_expr in stmt.get_iterator ()) {
+                       iterator_block.add_node (it_expr);
+               }
+
+               var loop_block = new BasicBlock ();
+
+               var after_loop_block = new BasicBlock ();
+
+               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 ();
+                               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 ab80af5..2f4bef1 100644
--- a/vala/valaforstatement.vala
+++ b/vala/valaforstatement.vala
@@ -136,58 +136,45 @@ public class Vala.ForStatement : 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 bool check (CodeContext context) {
-               // convert to simple loop
+               if (checked) {
+                       return !error;
+               }
 
-               var block = new Block (source_reference);
+               checked = true;
 
                // 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);
+               // body
+               if (!body.check (context)) {
+                       error = true;
+               }
 
-               return block.check (context);
+               return !error;
        }
 }


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