codegen: Limit scope of locals freed on errors thrown from catch clauses
[vala-lang.git] / vala / valablock.vala
blobde8a62ab3d8fb73d6169b7daebf725c5615cd867
1 /* valablock.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 source code block.
28 public class Vala.Block : Symbol, Statement {
29 /**
30 * Specifies whether this block contains a jump statement. This
31 * information can be used to remove unreachable block cleanup code.
33 public bool contains_jump_statement { get; set; }
35 public bool captured { get; set; }
37 private List<Statement> statement_list = new ArrayList<Statement> ();
38 private List<LocalVariable> local_variables = new ArrayList<LocalVariable> ();
39 private List<Constant> local_constants = new ArrayList<Constant> ();
41 /**
42 * Creates a new block.
44 * @param source reference to source code
46 public Block (SourceReference? source_reference) {
47 base (null, source_reference);
50 /**
51 * Append a statement to this block.
53 * @param stmt a statement
55 public void add_statement (Statement stmt) {
56 stmt.parent_node = this;
57 statement_list.add (stmt);
60 public void insert_statement (int index, Statement stmt) {
61 stmt.parent_node = this;
62 statement_list.insert (index, stmt);
65 /**
66 * Returns a copy of the list of statements.
68 * @return statement list
70 public List<Statement> get_statements () {
71 var list = new ArrayList<Statement> ();
72 foreach (Statement stmt in statement_list) {
73 var stmt_list = stmt as StatementList;
74 if (stmt_list != null) {
75 for (int i = 0; i < stmt_list.length; i++) {
76 list.add (stmt_list.get (i));
78 } else {
79 list.add (stmt);
82 return list;
85 /**
86 * Add a local variable to this block.
88 * @param decl a variable declarator
90 public void add_local_variable (LocalVariable local) {
91 var parent_block = parent_symbol;
92 while (parent_block is Block || parent_block is Method || parent_block is PropertyAccessor) {
93 if (parent_block.scope.lookup (local.name) != null) {
94 Report.error (local.source_reference, "Local variable `%s' conflicts with a local variable or constant declared in a parent scope".printf (local.name));
95 break;
97 parent_block = parent_block.parent_symbol;
99 local_variables.add (local);
102 public void remove_local_variable (LocalVariable local) {
103 local_variables.remove (local);
107 * Returns a copy of the list of local variables.
109 * @return variable declarator list
111 public List<LocalVariable> get_local_variables () {
112 return local_variables;
115 public void add_local_constant (Constant constant) {
116 var parent_block = parent_symbol;
117 while (parent_block is Block || parent_block is Method || parent_block is PropertyAccessor) {
118 if (parent_block.scope.lookup (constant.name) != null) {
119 Report.error (constant.source_reference, "Local constant `%s' conflicts with a local variable or constant declared in a parent scope".printf (constant.name));
120 break;
122 parent_block = parent_block.parent_symbol;
124 local_constants.add (constant);
125 scope.add (constant.name, constant);
128 public override void accept (CodeVisitor visitor) {
129 visitor.visit_block (this);
132 public override void accept_children (CodeVisitor visitor) {
133 foreach (Statement stmt in statement_list) {
134 stmt.accept (visitor);
138 public override bool check (CodeContext context) {
139 if (checked) {
140 return !error;
143 checked = true;
145 owner = context.analyzer.current_symbol.scope;
147 var old_symbol = context.analyzer.current_symbol;
148 var old_insert_block = context.analyzer.insert_block;
149 context.analyzer.current_symbol = this;
150 context.analyzer.insert_block = this;
152 for (int i = 0; i < statement_list.size; i++) {
153 statement_list[i].check (context);
156 foreach (LocalVariable local in get_local_variables ()) {
157 local.active = false;
160 foreach (Constant constant in local_constants) {
161 constant.active = false;
164 // use get_statements () instead of statement_list to not miss errors within StatementList objects
165 foreach (Statement stmt in get_statements ()) {
166 add_error_types (stmt.get_error_types ());
169 context.analyzer.current_symbol = old_symbol;
170 context.analyzer.insert_block = old_insert_block;
172 return !error;
175 public override void emit (CodeGenerator codegen) {
176 codegen.visit_block (this);
179 public void insert_before (Statement stmt, Statement new_stmt) {
180 for (int i = 0; i < statement_list.size; i++) {
181 var stmt_list = statement_list[i] as StatementList;
182 if (stmt_list != null) {
183 for (int j = 0; j < stmt_list.length; j++) {
184 if (stmt_list.get (j) == stmt) {
185 stmt_list.insert (j, new_stmt);
186 new_stmt.parent_node = this;
187 break;
190 } else if (statement_list[i] == stmt) {
191 stmt_list = new StatementList (source_reference);
192 stmt_list.add (new_stmt);
193 stmt_list.add (stmt);
194 statement_list[i] = stmt_list;
195 new_stmt.parent_node = this;
200 public void replace_statement (Statement old_stmt, Statement new_stmt) {
201 for (int i = 0; i < statement_list.size; i++) {
202 var stmt_list = statement_list[i] as StatementList;
203 if (stmt_list != null) {
204 for (int j = 0; j < stmt_list.length; j++) {
205 if (stmt_list.get (j) == old_stmt) {
206 stmt_list.set (j, new_stmt);
207 new_stmt.parent_node = this;
208 break;
211 } else if (statement_list[i] == old_stmt) {
212 statement_list[i] = new_stmt;
213 new_stmt.parent_node = this;
214 break;