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
20 * Jürg Billeter <j@bitron.ch>
26 * Represents a source code block.
28 public class Vala
.Block
: Symbol
, Statement
{
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
> ();
42 * Creates a new block.
44 * @param source_reference reference to source code
46 public Block (SourceReference? source_reference
) {
47 base (null, source_reference
);
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
);
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
));
86 * Add a local variable to this block.
88 * @param local 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
));
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
));
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
) {
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
;
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
;
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
;
211 } else if (statement_list
[i
] == old_stmt
) {
212 statement_list
[i
] = new_stmt
;
213 new_stmt
.parent_node
= this
;