Line data Source code
1 : /* valablock.vala
2 : *
3 : * Copyright (C) 2006-2010 Jürg Billeter
4 : *
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.
9 :
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.
14 :
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
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * Represents a source code block.
27 : */
28 866182 : 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.
32 : */
33 0 : public bool contains_jump_statement { get; set; }
34 :
35 : /**
36 : * Specifies whether the end of this block is unreachable.
37 : */
38 107275 : public bool unreachable_exit { get; set; }
39 :
40 72069 : public bool captured { get; set; }
41 :
42 863106 : private List<Statement> statement_list = new ArrayList<Statement> ();
43 863106 : private List<LocalVariable> local_variables = new ArrayList<LocalVariable> ();
44 863106 : private List<Constant> local_constants = new ArrayList<Constant> ();
45 :
46 : /**
47 : * Creates a new block.
48 : *
49 : * @param source_reference reference to source code
50 : */
51 430275 : public Block (SourceReference? source_reference = null) {
52 431554 : base (null, source_reference);
53 : }
54 :
55 : /**
56 : * Append a statement to this block.
57 : *
58 : * @param stmt a statement
59 : */
60 732253 : public void add_statement (Statement stmt) {
61 732253 : stmt.parent_node = this;
62 732253 : statement_list.add (stmt);
63 : }
64 :
65 23487 : public void insert_statement (int index, Statement stmt) {
66 23487 : stmt.parent_node = this;
67 23487 : statement_list.insert (index, stmt);
68 : }
69 :
70 : /**
71 : * Returns a copy of the list of statements.
72 : *
73 : * @return statement list
74 : */
75 419656 : public List<Statement> get_statements () {
76 419656 : var list = new ArrayList<Statement> ();
77 1929140 : foreach (Statement stmt in statement_list) {
78 754742 : unowned StatementList? stmt_list = stmt as StatementList;
79 713372 : if (stmt_list != null) {
80 182210 : for (int i = 0; i < stmt_list.length; i++) {
81 140840 : list.add (stmt_list.get (i));
82 : }
83 : } else {
84 713372 : list.add (stmt);
85 : }
86 : }
87 : return list;
88 : }
89 :
90 : /**
91 : * Add a local variable to this block.
92 : *
93 : * @param local a variable declarator
94 : */
95 166285 : public void add_local_variable (LocalVariable local) {
96 166285 : unowned Symbol? parent_block = parent_symbol;
97 444007 : while (parent_block is Block || parent_block is Method || parent_block is PropertyAccessor) {
98 277722 : if (parent_block.scope.lookup (local.name) != null) {
99 0 : Report.error (local.source_reference, "Local variable `%s' conflicts with a local variable or constant declared in a parent scope", local.name);
100 0 : break;
101 : }
102 277722 : parent_block = parent_block.parent_symbol;
103 : }
104 166285 : local_variables.add (local);
105 : }
106 :
107 14814 : public void remove_local_variable (LocalVariable local) {
108 14814 : local_variables.remove (local);
109 : }
110 :
111 : /**
112 : * Returns the list of local variables.
113 : *
114 : * @return variable declarator list
115 : */
116 431671 : public unowned List<LocalVariable> get_local_variables () {
117 431671 : return local_variables;
118 : }
119 :
120 24 : public void add_local_constant (Constant constant) {
121 24 : unowned Symbol? parent_block = parent_symbol;
122 24 : while (parent_block is Block || parent_block is Method || parent_block is PropertyAccessor) {
123 0 : if (parent_block.scope.lookup (constant.name) != null) {
124 0 : Report.error (constant.source_reference, "Local constant `%s' conflicts with a local variable or constant declared in a parent scope", constant.name);
125 0 : break;
126 : }
127 0 : parent_block = parent_block.parent_symbol;
128 : }
129 24 : local_constants.add (constant);
130 24 : scope.add (constant.name, constant);
131 : }
132 :
133 : /**
134 : * Returns the list of local constants.
135 : *
136 : * @return constants list
137 : */
138 0 : public unowned List<Constant> get_local_constants () {
139 0 : return local_constants;
140 : }
141 :
142 653634 : public override void accept (CodeVisitor visitor) {
143 653634 : visitor.visit_block (this);
144 : }
145 :
146 558922 : public override void accept_children (CodeVisitor visitor) {
147 2656158 : foreach (Statement stmt in statement_list) {
148 1048618 : stmt.accept (visitor);
149 : }
150 : }
151 :
152 391764 : public override bool check (CodeContext context) {
153 391764 : if (checked) {
154 88 : return !error;
155 : }
156 :
157 391676 : checked = true;
158 :
159 391676 : owner = context.analyzer.current_symbol.scope;
160 :
161 1566704 : var old_symbol = context.analyzer.current_symbol;
162 391676 : var old_insert_block = context.analyzer.insert_block;
163 391676 : context.analyzer.current_symbol = this;
164 783352 : context.analyzer.insert_block = this;
165 :
166 1087448 : for (int i = 0; i < statement_list.size; i++) {
167 695772 : if (!statement_list[i].check (context)) {
168 257 : error = true;
169 : }
170 : }
171 :
172 717768 : foreach (LocalVariable local in get_local_variables ()) {
173 163046 : local.active = false;
174 : }
175 :
176 391722 : foreach (Constant constant in local_constants) {
177 23 : constant.active = false;
178 : }
179 :
180 391676 : context.analyzer.current_symbol = old_symbol;
181 657984 : context.analyzer.insert_block = old_insert_block;
182 :
183 391676 : return !error;
184 : }
185 :
186 392383 : public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
187 : // use get_statements () instead of statement_list to not miss errors within StatementList objects
188 1971233 : foreach (Statement stmt in get_statements ()) {
189 789425 : stmt.get_error_types (collection, source_reference);
190 : }
191 : }
192 :
193 26709 : public override void emit (CodeGenerator codegen) {
194 26709 : codegen.visit_block (this);
195 : }
196 :
197 93225 : public void insert_before (Statement stmt, Statement new_stmt) {
198 832827 : for (int i = 0; i < statement_list.size; i++) {
199 369801 : var stmt_list = statement_list[i] as StatementList;
200 369801 : if (stmt_list != null) {
201 176415 : for (int j = 0; j < stmt_list.length; j++) {
202 164995 : if (stmt_list.get (j) == stmt) {
203 54299 : stmt_list.insert (j, new_stmt);
204 54299 : new_stmt.parent_node = this;
205 54299 : break;
206 : }
207 : }
208 304082 : } else if (statement_list[i] == stmt) {
209 38926 : stmt_list = new StatementList (source_reference);
210 38926 : stmt_list.add (new_stmt);
211 38926 : stmt_list.add (stmt);
212 38926 : statement_list[i] = stmt_list;
213 38926 : new_stmt.parent_node = this;
214 : }
215 : }
216 : }
217 :
218 25341 : public void replace_statement (Statement old_stmt, Statement new_stmt) {
219 83493 : for (int i = 0; i < statement_list.size; i++) {
220 54408 : var stmt_list = statement_list[i] as StatementList;
221 54408 : if (stmt_list != null) {
222 5830 : for (int j = 0; j < stmt_list.length; j++) {
223 4380 : if (stmt_list.get (j) == old_stmt) {
224 9 : stmt_list.set (j, new_stmt);
225 9 : new_stmt.parent_node = this;
226 9 : break;
227 : }
228 : }
229 52949 : } else if (statement_list[i] == old_stmt) {
230 25332 : statement_list[i] = new_stmt;
231 25332 : new_stmt.parent_node = this;
232 25332 : break;
233 : }
234 : }
235 : }
236 : }
|