Do not free values returned via g_object_get prematurely, require
[vala-lang.git] / vala / valanamespace.vala
blob2a46ec7f72e5fc22d29cc18f769b81ac2dd7ce78
1 /* valanamespace.vala
3 * Copyright (C) 2006-2008 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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
24 using Gee;
26 /**
27 * Represents a namespace declaration in the source code.
29 public class Vala.Namespace : Symbol {
30 private Gee.List<Class> classes = new ArrayList<Class> ();
31 private Gee.List<Interface> interfaces = new ArrayList<Interface> ();
32 private Gee.List<Struct> structs = new ArrayList<Struct> ();
33 private Gee.List<Enum> enums = new ArrayList<Enum> ();
34 private Gee.List<ErrorDomain> error_domains = new ArrayList<ErrorDomain> ();
35 private Gee.List<Delegate> delegates = new ArrayList<Delegate> ();
36 private Gee.List<Constant> constants = new ArrayList<Constant> ();
37 private Gee.List<Field> fields = new ArrayList<Field> ();
38 private Gee.List<Method> methods = new ArrayList<Method> ();
40 private Gee.List<string> cprefixes = new ArrayList<string> ();
41 private string lower_case_cprefix;
43 private Gee.List<string> cheader_filenames = new ArrayList<string> ();
45 private Gee.List<Namespace> namespaces = new ArrayList<Namespace> ();
47 /**
48 * Creates a new namespace.
50 * @param name namespace name
51 * @param source_reference reference to source code
52 * @return newly created namespace
54 public Namespace (string? name, SourceReference? source_reference = null) {
55 base (name, source_reference);
56 access = SymbolAccessibility.PUBLIC;
59 /**
60 * Adds the specified namespace to this source file.
62 * @param ns a namespace
64 public void add_namespace (Namespace ns) {
65 if (scope.lookup (ns.name) is Namespace) {
66 // merge if namespace already exists
67 var old_ns = (Namespace) scope.lookup (ns.name);
68 if (old_ns.external_package && !ns.external_package) {
69 old_ns.source_reference = ns.source_reference;
71 foreach (Namespace sub_ns in ns.get_namespaces ()) {
72 old_ns.add_namespace (sub_ns);
74 foreach (Class cl in ns.get_classes ()) {
75 old_ns.add_class (cl);
77 foreach (Struct st in ns.get_structs ()) {
78 old_ns.add_struct (st);
80 foreach (Interface iface in ns.get_interfaces ()) {
81 old_ns.add_interface (iface);
83 foreach (Delegate d in ns.get_delegates ()) {
84 old_ns.add_delegate (d);
86 foreach (Enum en in ns.get_enums ()) {
87 old_ns.add_enum (en);
89 foreach (ErrorDomain ed in ns.get_error_types ()) {
90 old_ns.add_error_domain (ed);
92 foreach (Constant c in ns.get_constants ()) {
93 old_ns.add_constant (c);
95 foreach (Field f in ns.get_fields ()) {
96 old_ns.add_field (f);
98 foreach (Method m in ns.get_methods ()) {
99 old_ns.add_method (m);
101 } else {
102 namespaces.add (ns);
103 scope.add (ns.name, ns);
108 * Returns a copy of the list of namespaces.
110 * @return namespace list
112 public Gee.List<Namespace> get_namespaces () {
113 return new ReadOnlyList<Namespace> (namespaces);
117 * Adds the specified class to this namespace.
119 * @param cl a class
121 public void add_class (Class cl) {
122 if (scope.lookup (cl.name) is Class) {
123 // merge
124 var old_class = (Class) scope.lookup (cl.name);
125 foreach (DataType base_type in cl.get_base_types ()) {
126 old_class.add_base_type (base_type);
128 foreach (Field f in cl.get_fields ()) {
129 old_class.add_field (f);
131 foreach (Method m in cl.get_methods ()) {
132 if (m == cl.default_construction_method && old_class.default_construction_method != null) {
133 // ignore secondary default creation method
134 continue;
136 old_class.add_method (m);
138 if (cl.constructor != null) {
139 old_class.constructor = cl.constructor;
141 cl.source_reference.file.remove_node (cl);
142 } else {
143 classes.add (cl);
144 scope.add (cl.name, cl);
149 * Adds the specified interface to this namespace.
151 * @param iface an interface
153 public void add_interface (Interface iface) {
154 interfaces.add (iface);
155 scope.add (iface.name, iface);
159 * Adds the specified struct to this namespace.
161 * @param st a struct
163 public void add_struct (Struct st) {
164 structs.add (st);
165 scope.add (st.name, st);
169 * Removes the specified struct from this namespace.
171 * @param st a struct
173 public void remove_struct (Struct st) {
174 structs.remove (st);
175 scope.remove (st.name);
179 * Adds the specified enum to this namespace.
181 * @param en an enum
183 public void add_enum (Enum en) {
184 enums.add (en);
185 scope.add (en.name, en);
189 * Adds the specified error domain to this namespace.
191 * @param edomain an error domain
193 public void add_error_domain (ErrorDomain edomain) {
194 error_domains.add (edomain);
195 scope.add (edomain.name, edomain);
199 * Adds the specified delegate to this namespace.
201 * @param d a delegate
203 public void add_delegate (Delegate d) {
204 delegates.add (d);
205 scope.add (d.name, d);
209 * Returns a copy of the list of structs.
211 * @return struct list
213 public Gee.List<Struct> get_structs () {
214 return new ReadOnlyList<Struct> (structs);
218 * Returns a copy of the list of classes.
220 * @return class list
222 public Gee.List<Class> get_classes () {
223 return new ReadOnlyList<Class> (classes);
227 * Returns a copy of the list of interfaces.
229 * @return interface list
231 public Gee.List<Interface> get_interfaces () {
232 return new ReadOnlyList<Interface> (interfaces);
236 * Returns a copy of the list of enums.
238 * @return enum list
240 public Gee.List<Enum> get_enums () {
241 return new ReadOnlyList<Enum> (enums);
245 * Returns a copy of the list of error domains.
247 * @return error domain list
249 public Gee.List<ErrorDomain> get_error_types () {
250 return new ReadOnlyList<ErrorDomain> (error_domains);
254 * Returns a copy of the list of fields.
256 * @return field list
258 public Gee.List<Field> get_fields () {
259 return new ReadOnlyList<Field> (fields);
263 * Returns a copy of the list of constants.
265 * @return constant list
267 public Gee.List<Constant> get_constants () {
268 return new ReadOnlyList<Constant> (constants);
272 * Returns a copy of the list of delegates.
274 * @return delegate list
276 public Gee.List<Delegate> get_delegates () {
277 return new ReadOnlyList<Delegate> (delegates);
281 * Returns a copy of the list of methods.
283 * @return method list
285 public Gee.List<Method> get_methods () {
286 return new ReadOnlyList<Method> (methods);
290 * Adds the specified constant to this namespace.
292 * @param constant a constant
294 public void add_constant (Constant constant) {
295 constants.add (constant);
296 scope.add (constant.name, constant);
300 * Adds the specified field to this namespace.
302 * @param f a field
304 public void add_field (Field f) {
305 if (f.binding == MemberBinding.INSTANCE) {
306 Report.error (f.source_reference, "instance members are not allowed outside of data types");
307 f.error = true;
308 return;
309 } else if (f.binding == MemberBinding.CLASS) {
310 Report.error (f.source_reference, "class members are not allowed outside of classes");
311 f.error = true;
312 return;
315 fields.add (f);
316 scope.add (f.name, f);
320 * Adds the specified method to this namespace.
322 * @param m a method
324 public void add_method (Method m) {
325 if (m is CreationMethod) {
326 Report.error (m.source_reference, "construction methods may only be declared within classes and structs");
327 m.error = true;
328 return;
330 if (m.binding == MemberBinding.INSTANCE) {
331 Report.error (m.source_reference, "instance members are not allowed outside of data types");
332 m.error = true;
333 return;
334 } else if (m.binding == MemberBinding.CLASS) {
335 Report.error (m.source_reference, "class members are not allowed outside of classes");
336 m.error = true;
337 return;
340 methods.add (m);
341 scope.add (m.name, m);
344 public override void accept (CodeVisitor visitor) {
345 visitor.visit_namespace (this);
348 public override void accept_children (CodeVisitor visitor) {
349 foreach (Namespace ns in namespaces) {
350 ns.accept (visitor);
353 /* process enums first to avoid order problems in C code */
354 foreach (Enum en in enums) {
355 en.accept (visitor);
358 foreach (ErrorDomain edomain in error_domains) {
359 edomain.accept (visitor);
362 foreach (Class cl in classes) {
363 cl.accept (visitor);
366 foreach (Interface iface in interfaces) {
367 iface.accept (visitor);
370 foreach (Struct st in structs) {
371 st.accept (visitor);
374 foreach (Delegate d in delegates) {
375 d.accept (visitor);
378 foreach (Constant c in constants) {
379 c.accept (visitor);
382 foreach (Field f in fields) {
383 f.accept (visitor);
386 foreach (Method m in methods) {
387 m.accept (visitor);
391 public override string get_cprefix () {
392 if (cprefixes.size > 0) {
393 return cprefixes[0];
394 } else if (null != name) {
395 string parent_prefix;
396 if (parent_symbol == null) {
397 parent_prefix = "";
398 } else {
399 parent_prefix = parent_symbol.get_cprefix ();
401 return parent_prefix + name;
402 } else {
403 return "";
407 public Gee.List<string> get_cprefixes () {
408 if (0 == cprefixes.size && null != name)
409 cprefixes.add (name);
411 return cprefixes;
415 * Adds a camel case string to be prepended to the name of members of
416 * this namespace when used in C code.
418 * @param cprefixes the camel case prefixes used in C code
420 public void add_cprefix (string cprefix) {
421 return_if_fail (cprefix.len() >= 1);
422 cprefixes.add (cprefix);
426 * Returns the lower case string to be prepended to the name of members
427 * of this namespace when used in C code.
429 * @return the lower case prefix to be used in C code
431 public override string get_lower_case_cprefix () {
432 if (lower_case_cprefix == null) {
433 if (name == null) {
434 lower_case_cprefix = "";
435 } else {
436 string parent_prefix;
437 if (parent_symbol == null) {
438 parent_prefix = "";
439 } else {
440 parent_prefix = parent_symbol.get_lower_case_cprefix ();
442 lower_case_cprefix = "%s%s_".printf (parent_prefix, camel_case_to_lower_case (name));
445 return lower_case_cprefix;
449 * Sets the lower case string to be prepended to the name of members of
450 * this namespace when used in C code.
452 * @param cprefix the lower case prefix to be used in C code
454 public void set_lower_case_cprefix (string cprefix) {
455 this.lower_case_cprefix = cprefix;
458 public override Gee.List<string> get_cheader_filenames () {
459 return new ReadOnlyList<string> (cheader_filenames);
463 * Returns the C header filename of this namespace.
465 * @return header filename
467 public string get_cheader_filename () {
468 var s = new StringBuilder ();
469 bool first = true;
470 foreach (string cheader_filename in get_cheader_filenames ()) {
471 if (first) {
472 first = false;
473 } else {
474 s.append_c (',');
476 s.append (cheader_filename);
478 return s.str;
482 * Sets the C header filename of this namespace to the specified
483 * filename.
485 * @param cheader_filename header filename
487 public void set_cheader_filename (string cheader_filename) {
488 cheader_filenames = new ArrayList<string> ();
489 cheader_filenames.add (cheader_filename);
492 private void process_ccode_attribute (Attribute a) {
493 if (a.has_argument ("cprefix")) {
494 foreach (string name in a.get_string ("cprefix").split (","))
495 add_cprefix (name);
497 if (a.has_argument ("lower_case_cprefix")) {
498 set_lower_case_cprefix (a.get_string ("lower_case_cprefix"));
500 if (a.has_argument ("cheader_filename")) {
501 var val = a.get_string ("cheader_filename");
502 foreach (string filename in val.split (",")) {
503 cheader_filenames.add (filename);
509 * Process all associated attributes.
511 public void process_attributes () {
512 foreach (Attribute a in attributes) {
513 if (a.name == "CCode") {
514 process_ccode_attribute (a);
519 public override bool check (SemanticAnalyzer analyzer) {
520 if (checked) {
521 return !error;
524 checked = true;
526 process_attributes ();
528 foreach (Namespace ns in namespaces) {
529 ns.check (analyzer);
532 return !error;