1/* valanamespace.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
23using GLib;
24
25/**
26 * Represents a namespace declaration in the source code.
27 */
28public class Vala.Namespace : Symbol {
29	private List<Class> classes = new ArrayList<Class> ();
30	private List<Interface> interfaces = new ArrayList<Interface> ();
31	private List<Struct> structs = new ArrayList<Struct> ();
32	private List<Enum> enums = new ArrayList<Enum> ();
33	private List<ErrorDomain> error_domains = new ArrayList<ErrorDomain> ();
34	private List<Delegate> delegates = new ArrayList<Delegate> ();
35	private List<Constant> constants = new ArrayList<Constant> ();
36	private List<Field> fields = new ArrayList<Field> ();
37	private List<Method> methods = new ArrayList<Method> ();
38
39	private List<Comment> comments = new ArrayList<Comment> ();
40
41	private List<Namespace> namespaces = new ArrayList<Namespace> ();
42
43	private List<UsingDirective> using_directives = new ArrayList<UsingDirective> ();
44
45	/**
46	 * Creates a new namespace.
47	 *
48	 * @param name             namespace name
49	 * @param source_reference reference to source code
50	 * @return                 newly created namespace
51	 */
52	public Namespace (string? name, SourceReference? source_reference = null) {
53		base (name, source_reference);
54		access = SymbolAccessibility.PUBLIC;
55	}
56
57	/**
58	 * Adds a new using directive with the specified namespace.
59	 *
60	 * @param ns reference to namespace
61	 */
62	public void add_using_directive (UsingDirective ns) {
63		using_directives.add (ns);
64	}
65
66	public void add_comment (Comment comment) {
67		comments.add (comment);
68	}
69
70	/**
71	 * Returns the list of namespaces.
72	 *
73	 * @return comment list
74	 */
75	public unowned List<Comment> get_comments () {
76		return comments;
77	}
78
79	/**
80	 * Adds the specified namespace to this source file.
81	 *
82	 * @param ns a namespace
83	 */
84	public override void add_namespace (Namespace ns) {
85		if (ns.owner == null) {
86			ns.source_reference.file.add_node (ns);
87		}
88
89		if (scope.lookup (ns.name) is Namespace) {
90			// merge if namespace already exists
91			var old_ns = (Namespace) scope.lookup (ns.name);
92			if (old_ns.external_package && !ns.external_package) {
93				old_ns.source_reference = ns.source_reference;
94			}
95
96			foreach (var using_directive in ns.using_directives) {
97				old_ns.add_using_directive (using_directive);
98			}
99			foreach (Namespace sub_ns in ns.get_namespaces ()) {
100				old_ns.add_namespace (sub_ns);
101			}
102			foreach (Class cl in ns.get_classes ()) {
103				old_ns.add_class (cl);
104			}
105			foreach (Struct st in ns.get_structs ()) {
106				old_ns.add_struct (st);
107			}
108			foreach (Interface iface in ns.get_interfaces ()) {
109				old_ns.add_interface (iface);
110			}
111			foreach (Delegate d in ns.get_delegates ()) {
112				old_ns.add_delegate (d);
113			}
114			foreach (Enum en in ns.get_enums ()) {
115				old_ns.add_enum (en);
116			}
117			foreach (ErrorDomain ed in ns.get_error_domains ()) {
118				old_ns.add_error_domain (ed);
119			}
120			foreach (Constant c in ns.get_constants ()) {
121				old_ns.add_constant (c);
122			}
123			foreach (Field f in ns.get_fields ()) {
124				old_ns.add_field (f);
125			}
126			foreach (Method m in ns.get_methods ()) {
127				old_ns.add_method (m);
128			}
129			foreach (Comment c in ns.get_comments ()) {
130				old_ns.add_comment (c);
131			}
132			foreach (Attribute a in ns.attributes) {
133				if (old_ns.get_attribute (a.name) == null) {
134					old_ns.attributes.append(a);
135				}
136			}
137		} else {
138			namespaces.add (ns);
139			scope.add (ns.name, ns);
140		}
141	}
142
143	/**
144	 * Returns the list of namespaces.
145	 *
146	 * @return namespace list
147	 */
148	public unowned List<Namespace> get_namespaces () {
149		return namespaces;
150	}
151
152	/**
153	 * Adds the specified class to this namespace.
154	 *
155	 * @param cl a class
156	 */
157	public override void add_class (Class cl) {
158		// namespaces do not support private members
159		if (cl.access == SymbolAccessibility.PRIVATE) {
160			cl.access = SymbolAccessibility.INTERNAL;
161		}
162
163		if (cl.owner == null) {
164			cl.source_reference.file.add_node (cl);
165		}
166
167		classes.add (cl);
168		scope.add (cl.name, cl);
169	}
170
171	/**
172	 * Adds the specified interface to this namespace.
173	 *
174	 * @param iface an interface
175	 */
176	public override void add_interface (Interface iface) {
177		// namespaces do not support private members
178		if (iface.access == SymbolAccessibility.PRIVATE) {
179			iface.access = SymbolAccessibility.INTERNAL;
180		}
181
182		if (iface.owner == null) {
183			iface.source_reference.file.add_node (iface);
184		}
185
186		interfaces.add (iface);
187		scope.add (iface.name, iface);
188
189	}
190
191	/**
192	 * Adds the specified struct to this namespace.
193	 *
194	 * @param st a struct
195	 */
196	public override void add_struct (Struct st) {
197		// namespaces do not support private members
198		if (st.access == SymbolAccessibility.PRIVATE) {
199			st.access = SymbolAccessibility.INTERNAL;
200		}
201
202		if (st.owner == null) {
203			st.source_reference.file.add_node (st);
204		}
205
206		structs.add (st);
207		scope.add (st.name, st);
208	}
209
210	/**
211	 * Adds the specified enum to this namespace.
212	 *
213	 * @param en an enum
214	 */
215	public override void add_enum (Enum en) {
216		// namespaces do not support private members
217		if (en.access == SymbolAccessibility.PRIVATE) {
218			en.access = SymbolAccessibility.INTERNAL;
219		}
220
221		if (en.owner == null) {
222			en.source_reference.file.add_node (en);
223		}
224
225		enums.add (en);
226		scope.add (en.name, en);
227	}
228
229	/**
230	 * Adds the specified error domain to this namespace.
231	 *
232	 * @param edomain an error domain
233	 */
234	public override void add_error_domain (ErrorDomain edomain) {
235		// namespaces do not support private members
236		if (edomain.access == SymbolAccessibility.PRIVATE) {
237			edomain.access = SymbolAccessibility.INTERNAL;
238		}
239
240		if (edomain.owner == null) {
241			edomain.source_reference.file.add_node (edomain);
242		}
243
244		error_domains.add (edomain);
245		scope.add (edomain.name, edomain);
246	}
247
248	/**
249	 * Adds the specified delegate to this namespace.
250	 *
251	 * @param d a delegate
252	 */
253	public override void add_delegate (Delegate d) {
254		// namespaces do not support private members
255		if (d.access == SymbolAccessibility.PRIVATE) {
256			d.access = SymbolAccessibility.INTERNAL;
257		}
258
259		if (d.owner == null) {
260			d.source_reference.file.add_node (d);
261		}
262
263		delegates.add (d);
264		scope.add (d.name, d);
265	}
266
267	/**
268	 * Returns the list of structs.
269	 *
270	 * @return struct list
271	 */
272	public unowned List<Struct> get_structs () {
273		return structs;
274	}
275
276	/**
277	 * Returns the list of classes.
278	 *
279	 * @return class list
280	 */
281	public unowned List<Class> get_classes () {
282		return classes;
283	}
284
285	/**
286	 * Returns the list of interfaces.
287	 *
288	 * @return interface list
289	 */
290	public unowned List<Interface> get_interfaces () {
291		return interfaces;
292	}
293
294	/**
295	 * Returns the list of enums.
296	 *
297	 * @return enum list
298	 */
299	public unowned List<Enum> get_enums () {
300		return enums;
301	}
302
303	/**
304	 * Returns the list of error domains.
305	 *
306	 * @return error domain list
307	 */
308	public unowned List<ErrorDomain> get_error_domains () {
309		return error_domains;
310	}
311
312	/**
313	 * Returns the list of fields.
314	 *
315	 * @return field list
316	 */
317	public unowned List<Field> get_fields () {
318		return fields;
319	}
320
321	/**
322	 * Returns the list of constants.
323	 *
324	 * @return constant list
325	 */
326	public unowned List<Constant> get_constants () {
327		return constants;
328	}
329
330	/**
331	 * Returns the list of delegates.
332	 *
333	 * @return delegate list
334	 */
335	public unowned List<Delegate> get_delegates () {
336		return delegates;
337	}
338
339	/**
340	 * Returns the list of methods.
341	 *
342	 * @return method list
343	 */
344	public unowned List<Method> get_methods () {
345		return methods;
346	}
347
348	/**
349	 * Adds the specified constant to this namespace.
350	 *
351	 * @param constant a constant
352	 */
353	public override void add_constant (Constant constant) {
354		// namespaces do not support private members
355		if (constant.access == SymbolAccessibility.PRIVATE) {
356			constant.access = SymbolAccessibility.INTERNAL;
357		}
358
359		if (constant.owner == null) {
360			constant.source_reference.file.add_node (constant);
361		}
362
363		constants.add (constant);
364		scope.add (constant.name, constant);
365	}
366
367	/**
368	 * Adds the specified field to this namespace.
369	 *
370	 * @param f a field
371	 */
372	public override void add_field (Field f) {
373		// namespaces do not support private members
374		if (f.access == SymbolAccessibility.PRIVATE) {
375			f.access = SymbolAccessibility.INTERNAL;
376		}
377
378		if (f.owner == null) {
379			f.source_reference.file.add_node (f);
380		}
381
382		fields.add (f);
383		scope.add (f.name, f);
384	}
385
386	/**
387	 * Adds the specified method to this namespace.
388	 *
389	 * @param m a method
390	 */
391	public override void add_method (Method m) {
392		// namespaces do not support private members
393		if (m.access == SymbolAccessibility.PRIVATE) {
394			m.access = SymbolAccessibility.INTERNAL;
395		}
396
397		if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) {
398			m.result_var = new LocalVariable (m.return_type.copy (), "result", null, m.source_reference);
399			m.result_var.is_result = true;
400		}
401
402		if (m.owner == null) {
403			m.source_reference.file.add_node (m);
404		}
405
406		methods.add (m);
407		scope.add (m.name, m);
408	}
409
410	public override void accept (CodeVisitor visitor) {
411		visitor.visit_namespace (this);
412	}
413
414	public override void accept_children (CodeVisitor visitor) {
415		foreach (UsingDirective ns_ref in using_directives) {
416			ns_ref.accept (visitor);
417		}
418
419		foreach (Namespace ns in namespaces) {
420			ns.accept (visitor);
421		}
422
423		/* process enums first to avoid order problems in C code */
424		foreach (Enum en in enums) {
425			en.accept (visitor);
426		}
427
428		foreach (ErrorDomain edomain in error_domains) {
429			edomain.accept (visitor);
430		}
431
432		foreach (Class cl in classes) {
433			cl.accept (visitor);
434		}
435
436		foreach (Interface iface in interfaces) {
437			iface.accept (visitor);
438		}
439
440		foreach (Struct st in structs) {
441			st.accept (visitor);
442		}
443
444		foreach (Delegate d in delegates) {
445			d.accept (visitor);
446		}
447
448		foreach (Constant c in constants) {
449			c.accept (visitor);
450		}
451
452		foreach (Field f in fields) {
453			f.accept (visitor);
454		}
455
456		foreach (Method m in methods) {
457			m.accept (visitor);
458		}
459	}
460
461	public override bool check (CodeContext context) {
462		if (checked) {
463			return !error;
464		}
465
466		checked = true;
467
468		var a = get_attribute ("CCode");
469		if (a != null && a.has_argument ("gir_namespace")) {
470			source_reference.file.gir_namespace = a.get_string ("gir_namespace");
471		}
472		if (a != null && a.has_argument ("gir_version")) {
473			source_reference.file.gir_version = a.get_string ("gir_version");
474		}
475
476		foreach (Field f in fields) {
477			if (f.binding == MemberBinding.INSTANCE) {
478				Report.error (f.source_reference, "instance fields are not allowed outside of data types");
479				f.error = true;
480				error = true;
481			} else if (f.binding == MemberBinding.CLASS) {
482				Report.error (f.source_reference, "class fields are not allowed outside of classes");
483				f.error = true;
484				error = true;
485			}
486		}
487
488		foreach (Method m in methods) {
489			if (m is CreationMethod) {
490				Report.error (m.source_reference, "construction methods may only be declared within classes and structs");
491				m.error = true;
492				error = true;
493			}
494			if (m.binding == MemberBinding.INSTANCE) {
495				Report.error (m.source_reference, "instance methods are not allowed outside of data types");
496				m.error = true;
497				error = true;
498			} else if (m.binding == MemberBinding.CLASS) {
499				Report.error (m.source_reference, "class methods are not allowed outside of classes");
500				m.error = true;
501				error = true;
502			}
503		}
504
505		foreach (Namespace ns in namespaces) {
506			ns.check (context);
507		}
508
509		return !error;
510	}
511
512	public override string to_string () {
513		if (name == null) {
514			return "(root namespace)";
515		} else {
516			return "namespace %s".printf (name);
517		}
518	}
519}
520