move iteration of throw statements, try statements, and catch clauses from
[vala-lang.git] / vala / valasymbolbuilder.vala
blob33893246c6d34696c0712acf5f086ec7e6f9f4af
1 /* valasymbolbuilder.vala
3 * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
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 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>
21 * Raffaele Sandrini <rasa@gmx.ch>
24 using GLib;
26 /**
27 * Code visitor building the symbol tree.
29 public class Vala.SymbolBuilder : CodeVisitor {
30 Symbol root;
31 Symbol current_type;
32 Symbol current_symbol;
33 SourceFile current_source_file;
35 /**
36 * Build the symbol tree for the specified code context.
38 * @param context a code context
40 public void build (CodeContext! context) {
41 root = context.get_root ();
42 context.accept (this);
45 public override void visit_source_file (SourceFile! file) {
46 current_source_file = file;
48 file.accept_children (this);
51 public override void visit_namespace (Namespace! ns) {
52 if (ns.name == null) {
53 ns.symbol = root;
56 if (ns.symbol == null) {
57 ns.symbol = root.lookup (ns.name);
59 if (ns.symbol == null) {
60 ns.symbol = new Symbol (ns);
61 root.add (ns.name, ns.symbol);
64 current_symbol = ns.symbol;
66 ns.accept_children (this);
68 current_symbol = current_symbol.parent_symbol;
71 private weak Symbol add_symbol (string name, CodeNode! node) {
72 if (name != null) {
73 if (current_symbol.lookup (name) != null) {
74 node.error = true;
75 Report.error (node.source_reference, "`%s' already contains a definition for `%s'".printf (current_symbol.get_full_name (), name));
76 return null;
79 node.symbol = new Symbol (node);
80 if (name != null) {
81 current_symbol.add (name, node.symbol);
82 } else {
83 node.symbol.parent_symbol = current_symbol;
86 return node.symbol;
89 public override void visit_class (Class! cl) {
90 if (cl.error) {
91 /* skip classes with errors */
92 return;
95 var class_symbol = current_symbol.lookup (cl.name);
96 if (class_symbol == null || !(class_symbol.node is Class)) {
97 class_symbol = add_symbol (cl.name, cl);
98 } else {
99 /* merge this class declaration with existing class symbol */
100 var main_class = (Class) class_symbol.node;
101 foreach (TypeReference base_type in cl.get_base_types ()) {
102 main_class.add_base_type (base_type);
104 foreach (Field f in cl.get_fields ()) {
105 main_class.add_field (f);
107 foreach (Method m in cl.get_methods ()) {
108 main_class.add_method (m);
110 foreach (Property prop in cl.get_properties ()) {
111 main_class.add_property (prop, true);
113 foreach (Signal sig in cl.get_signals ()) {
114 main_class.add_signal (sig);
116 if (cl.constructor != null) {
117 if (main_class.constructor != null) {
118 cl.error = true;
119 Report.error (cl.constructor.source_reference, "`%s' already contains a constructor".printf (current_symbol.get_full_name ()));
120 return;
122 main_class.constructor = cl.constructor;
124 if (cl.destructor != null) {
125 if (main_class.destructor != null) {
126 cl.error = true;
127 Report.error (cl.destructor.source_reference, "`%s' already contains a destructor".printf (current_symbol.get_full_name ()));
128 return;
130 main_class.destructor = cl.destructor;
134 current_symbol = class_symbol;
136 cl.accept_children (this);
138 current_symbol = current_symbol.parent_symbol;
140 if (cl.symbol == null) {
141 /* remove merged class */
142 cl.@namespace.remove_class (cl);
146 public override void visit_struct (Struct! st) {
147 if (st.error) {
148 /* skip structs with errors */
149 return;
152 if (add_symbol (st.name, st) == null) {
153 return;
156 current_symbol = st.symbol;
158 st.accept_children (this);
160 current_symbol = current_symbol.parent_symbol;
163 public override void visit_interface (Interface! iface) {
164 if (iface.error) {
165 /* skip interfaces with errors */
166 return;
169 if (add_symbol (iface.name, iface) == null) {
170 return;
173 current_symbol = iface.symbol;
175 iface.accept_children (this);
177 current_symbol = current_symbol.parent_symbol;
180 public override void visit_enum (Enum! en) {
181 if (en.error) {
182 /* skip enums with errors */
183 return;
186 if (add_symbol (en.name, en) == null) {
187 return;
190 current_symbol = en.symbol;
192 en.accept_children (this);
194 current_symbol = current_symbol.parent_symbol;
197 public override void visit_enum_value (EnumValue! ev) {
198 ev.symbol = new Symbol (ev);
199 current_symbol.add (ev.name, ev.symbol);
202 public override void visit_flags (Flags! fl) {
203 if (fl.error) {
204 /* skip flags with errors */
205 return;
208 if (add_symbol (fl.name, fl) == null) {
209 return;
212 current_symbol = fl.symbol;
214 fl.accept_children (this);
216 current_symbol = current_symbol.parent_symbol;
219 public override void visit_flags_value (FlagsValue! fv) {
220 fv.symbol = new Symbol (fv);
221 current_symbol.add (fv.name, fv.symbol);
224 public override void visit_callback (Callback! cb) {
225 if (cb.error) {
226 /* skip enums with errors */
227 return;
230 if (add_symbol (cb.name, cb) == null) {
231 return;
234 current_symbol = cb.symbol;
236 cb.accept_children (this);
238 current_symbol = current_symbol.parent_symbol;
241 public override void visit_constant (Constant! c) {
242 add_symbol (c.name, c);
245 public override void visit_field (Field! f) {
246 add_symbol (f.name, f);
249 public override void visit_method (Method! m) {
250 if (add_symbol (m.name, m) == null) {
251 return;
254 if (m.instance) {
255 if (!(m.symbol.parent_symbol.node is DataType)) {
256 Report.error (m.source_reference, "instance methods not allowed outside of data types");
258 m.error = true;
259 return;
262 m.this_parameter = new FormalParameter ("this", new TypeReference ());
263 m.this_parameter.type_reference.data_type = (DataType) m.symbol.parent_symbol.node;
264 m.this_parameter.symbol = new Symbol (m.this_parameter);
265 current_symbol.add (m.this_parameter.name, m.this_parameter.symbol);
268 current_symbol = m.symbol;
270 m.accept_children (this);
272 current_symbol = current_symbol.parent_symbol;
275 public override void visit_creation_method (CreationMethod! m) {
276 if (add_symbol (m.name, m) == null) {
277 return;
280 var type_node = m.symbol.parent_symbol.node;
281 if (!(type_node is Class || type_node is Struct)) {
282 Report.error (m.source_reference, "construction methods may only be declared within classes and structs");
284 m.error = true;
285 return;
288 if (m.name == null) {
289 if (type_node is Class) {
290 ((Class) type_node).default_construction_method = m;
291 } else if (type_node is Struct) {
292 ((Struct) type_node).default_construction_method = m;
296 current_symbol = m.symbol;
298 m.accept_children (this);
300 current_symbol = current_symbol.parent_symbol;
303 public override void visit_formal_parameter (FormalParameter! p) {
304 if (!p.ellipsis) {
305 add_symbol (p.name, p);
309 public override void visit_property (Property! prop) {
310 if (prop.error) {
311 /* skip properties with errors */
312 return;
315 if (add_symbol (prop.name, prop) == null) {
316 return;
319 current_symbol = prop.symbol;
321 prop.this_parameter = new FormalParameter ("this", new TypeReference ());
322 prop.this_parameter.type_reference.data_type = (DataType) prop.symbol.parent_symbol.node;
323 prop.this_parameter.symbol = new Symbol (prop.this_parameter);
324 current_symbol.add (prop.this_parameter.name, prop.this_parameter.symbol);
326 prop.accept_children (this);
328 current_symbol = current_symbol.parent_symbol;
331 public override void visit_property_accessor (PropertyAccessor! acc) {
332 acc.symbol = new Symbol (acc);
333 acc.symbol.parent_symbol = current_symbol;
335 if (current_source_file.pkg) {
336 return;
339 current_symbol = acc.symbol;
341 if (acc.writable || acc.construction) {
342 acc.value_parameter = new FormalParameter ("value", ((Property) current_symbol.parent_symbol.node).type_reference);
343 acc.value_parameter.symbol = new Symbol (acc.value_parameter);
345 current_symbol.add (acc.value_parameter.name, acc.value_parameter.symbol);
348 if (acc.body == null) {
349 /* no accessor body specified, insert default body */
351 var prop = (Property) acc.symbol.parent_symbol.node;
353 if (prop.interface_only || prop.is_abstract) {
354 current_symbol = current_symbol.parent_symbol;
355 return;
358 var block = new Block ();
359 if (acc.readable) {
360 block.add_statement (new ReturnStatement (new MemberAccess.simple ("_%s".printf (prop.name))));
361 } else {
362 block.add_statement (new ExpressionStatement (new Assignment (new MemberAccess.simple ("_%s".printf (prop.name)), new MemberAccess.simple ("value"))));
364 acc.body = block;
367 acc.accept_children (this);
369 current_symbol = current_symbol.parent_symbol;
372 public override void visit_signal (Signal! sig) {
373 if (sig.error) {
374 /* skip signals with errors */
375 return;
378 if (add_symbol (sig.name, sig) == null) {
379 return;
382 current_symbol = sig.symbol;
384 sig.accept_children (this);
386 current_symbol = current_symbol.parent_symbol;
389 public override void visit_constructor (Constructor! c) {
390 c.symbol = new Symbol (c);
391 c.symbol.parent_symbol = current_symbol;
392 current_symbol = c.symbol;
394 c.accept_children (this);
396 current_symbol = current_symbol.parent_symbol;
399 public override void visit_destructor (Destructor! d) {
400 d.symbol = new Symbol (d);
401 d.symbol.parent_symbol = current_symbol;
402 current_symbol = d.symbol;
404 d.accept_children (this);
406 current_symbol = current_symbol.parent_symbol;
409 public override void visit_try_statement (TryStatement! stmt) {
410 stmt.accept_children (this);
413 public override void visit_catch_clause (CatchClause! clause) {
414 clause.accept_children (this);
417 public override void visit_begin_block (Block! b) {
418 b.symbol = new Symbol (b);
419 b.symbol.parent_symbol = current_symbol;
420 current_symbol = b.symbol;
423 public override void visit_end_block (Block! b) {
424 current_symbol = current_symbol.parent_symbol;
427 public override void visit_type_parameter (TypeParameter! p) {
428 add_symbol (p.name, p);