codegen: Limit scope of locals freed on errors thrown from catch clauses
[vala-lang.git] / vala / valaforstatement.vala
blob555dc623c9a3f0e0fa57bc8f8608f84a522e92e2
1 /* valaforstatement.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
26 * Represents a for iteration statement in the source code.
28 public class Vala.ForStatement : CodeNode, Statement {
29 /**
30 * Specifies the loop condition.
32 public Expression? condition {
33 get {
34 return _condition;
36 set {
37 _condition = value;
38 if (_condition != null) {
39 _condition.parent_node = this;
44 /**
45 * Specifies the loop body.
47 public Block body {
48 get {
49 return _body;
51 set {
52 _body = value;
53 _body.parent_node = this;
57 private List<Expression> initializer = new ArrayList<Expression> ();
58 private List<Expression> iterator = new ArrayList<Expression> ();
60 private Expression _condition;
61 private Block _body;
63 /**
64 * Creates a new for statement.
66 * @param cond loop condition
67 * @param body loop body
68 * @param source_reference reference to source code
69 * @return newly created for statement
71 public ForStatement (Expression? condition, Block body, SourceReference? source_reference = null) {
72 this.condition = condition;
73 this.body = body;
74 this.source_reference = source_reference;
77 /**
78 * Appends the specified expression to the list of initializers.
80 * @param init an initializer expression
82 public void add_initializer (Expression init) {
83 init.parent_node = this;
84 initializer.add (init);
87 /**
88 * Returns a copy of the list of initializers.
90 * @return initializer list
92 public List<Expression> get_initializer () {
93 return initializer;
96 /**
97 * Appends the specified expression to the iterator.
99 * @param iter an iterator expression
101 public void add_iterator (Expression iter) {
102 iter.parent_node = this;
103 iterator.add (iter);
107 * Returns a copy of the iterator.
109 * @return iterator
111 public List<Expression> get_iterator () {
112 return iterator;
115 public override void accept (CodeVisitor visitor) {
116 visitor.visit_for_statement (this);
119 public override void accept_children (CodeVisitor visitor) {
120 foreach (Expression init_expr in initializer) {
121 init_expr.accept (visitor);
122 visitor.visit_end_full_expression (init_expr);
125 if (condition != null) {
126 condition.accept (visitor);
128 visitor.visit_end_full_expression (condition);
131 foreach (Expression it_expr in iterator) {
132 it_expr.accept (visitor);
133 visitor.visit_end_full_expression (it_expr);
136 body.accept (visitor);
139 bool always_true (Expression condition) {
140 var literal = condition as BooleanLiteral;
141 return (literal != null && literal.value);
144 bool always_false (Expression condition) {
145 var literal = condition as BooleanLiteral;
146 return (literal != null && !literal.value);
149 public override bool check (CodeContext context) {
150 // convert to simple loop
152 var block = new Block (source_reference);
154 // initializer
155 foreach (var init_expr in initializer) {
156 block.add_statement (new ExpressionStatement (init_expr, init_expr.source_reference));
159 // do not generate if block if condition is always true
160 if (condition == null || always_true (condition)) {
161 } else if (always_false (condition)) {
162 // do not generate if block if condition is always false
163 body.insert_statement (0, new BreakStatement (condition.source_reference));
164 } else {
165 // condition
166 var if_condition = new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, condition, condition.source_reference);
167 var true_block = new Block (condition.source_reference);
168 true_block.add_statement (new BreakStatement (condition.source_reference));
169 var if_stmt = new IfStatement (if_condition, true_block, null, condition.source_reference);
170 body.insert_statement (0, if_stmt);
173 // iterator
174 var first_local = new LocalVariable (context.analyzer.bool_type.copy (), get_temp_name (), new BooleanLiteral (true, source_reference), source_reference);
175 block.add_statement (new DeclarationStatement (first_local, source_reference));
177 var iterator_block = new Block (source_reference);
178 foreach (var it_expr in iterator) {
179 iterator_block.add_statement (new ExpressionStatement (it_expr, it_expr.source_reference));
182 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);
183 body.insert_statement (0, first_if);
184 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));
186 block.add_statement (new Loop (body, source_reference));
188 var parent_block = (Block) parent_node;
189 parent_block.replace_statement (this, block);
191 return block.check (context);