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
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <rasa@gmx.ch>
27 * Code visitor building the symbol tree.
29 public class Vala
.SymbolBuilder
: CodeVisitor
{
32 Symbol current_symbol
;
33 SourceFile current_source_file
;
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) {
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
) {
73 if (current_symbol
.lookup (name
) != null) {
75 Report
.error (node
.source_reference
, "`%s' already contains a definition for `%s'".printf (current_symbol
.get_full_name (), name
));
79 node
.symbol
= new
Symbol (node
);
81 current_symbol
.add (name
, node
.symbol
);
83 node
.symbol
.parent_symbol
= current_symbol
;
89 public override void visit_class (Class
! cl
) {
91 /* skip classes with errors */
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
);
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) {
119 Report
.error (cl
.constructor
.source_reference
, "`%s' already contains a constructor".printf (current_symbol
.get_full_name ()));
122 main_class
.constructor
= cl
.constructor
;
124 if (cl
.destructor
!= null) {
125 if (main_class
.destructor
!= null) {
127 Report
.error (cl
.destructor
.source_reference
, "`%s' already contains a destructor".printf (current_symbol
.get_full_name ()));
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
) {
148 /* skip structs with errors */
152 if (add_symbol (st
.name
, st
) == null) {
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
) {
165 /* skip interfaces with errors */
169 if (add_symbol (iface
.name
, iface
) == null) {
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
) {
182 /* skip enums with errors */
186 if (add_symbol (en
.name
, en
) == null) {
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
) {
204 /* skip flags with errors */
208 if (add_symbol (fl
.name
, fl
) == null) {
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
) {
226 /* skip enums with errors */
230 if (add_symbol (cb
.name
, cb
) == null) {
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) {
255 if (!(m
.symbol
.parent_symbol
.node is DataType
)) {
256 Report
.error (m
.source_reference
, "instance methods not allowed outside of data types");
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) {
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");
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
) {
305 add_symbol (p
.name
, p
);
309 public override void visit_property (Property
! prop
) {
311 /* skip properties with errors */
315 if (add_symbol (prop
.name
, prop
) == null) {
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
) {
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
;
358 var block
= new
Block ();
360 block
.add_statement (new
ReturnStatement (new MemberAccess
.simple ("_%s".printf (prop
.name
))));
362 block
.add_statement (new
ExpressionStatement (new
Assignment (new MemberAccess
.simple ("_%s".printf (prop
.name
)), new MemberAccess
.simple ("value"))));
367 acc
.accept_children (this
);
369 current_symbol
= current_symbol
.parent_symbol
;
372 public override void visit_signal (Signal
! sig
) {
374 /* skip signals with errors */
378 if (add_symbol (sig
.name
, sig
) == null) {
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
);