/* valanamespace.vala * * Copyright (C) 2006-2010 Jürg Billeter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Author: * Jürg Billeter */ using GLib; /** * Represents a namespace declaration in the source code. */ public class Vala.Namespace : Symbol { private List classes = new ArrayList (); private List interfaces = new ArrayList (); private List structs = new ArrayList (); private List enums = new ArrayList (); private List error_domains = new ArrayList (); private List delegates = new ArrayList (); private List constants = new ArrayList (); private List fields = new ArrayList (); private List methods = new ArrayList (); private List comments = new ArrayList (); private List namespaces = new ArrayList (); private List using_directives = new ArrayList (); /** * Creates a new namespace. * * @param name namespace name * @param source_reference reference to source code * @return newly created namespace */ public Namespace (string? name, SourceReference? source_reference = null) { base (name, source_reference); access = SymbolAccessibility.PUBLIC; } /** * Adds a new using directive with the specified namespace. * * @param ns reference to namespace */ public void add_using_directive (UsingDirective ns) { using_directives.add (ns); } public void add_comment (Comment comment) { comments.add (comment); } /** * Returns the list of namespaces. * * @return comment list */ public unowned List get_comments () { return comments; } /** * Adds the specified namespace to this source file. * * @param ns a namespace */ public override void add_namespace (Namespace ns) { if (ns.owner == null) { ns.source_reference.file.add_node (ns); } if (scope.lookup (ns.name) is Namespace) { // merge if namespace already exists var old_ns = (Namespace) scope.lookup (ns.name); if (old_ns.external_package && !ns.external_package) { old_ns.source_reference = ns.source_reference; } foreach (var using_directive in ns.using_directives) { old_ns.add_using_directive (using_directive); } foreach (Namespace sub_ns in ns.get_namespaces ()) { old_ns.add_namespace (sub_ns); } foreach (Class cl in ns.get_classes ()) { old_ns.add_class (cl); } foreach (Struct st in ns.get_structs ()) { old_ns.add_struct (st); } foreach (Interface iface in ns.get_interfaces ()) { old_ns.add_interface (iface); } foreach (Delegate d in ns.get_delegates ()) { old_ns.add_delegate (d); } foreach (Enum en in ns.get_enums ()) { old_ns.add_enum (en); } foreach (ErrorDomain ed in ns.get_error_domains ()) { old_ns.add_error_domain (ed); } foreach (Constant c in ns.get_constants ()) { old_ns.add_constant (c); } foreach (Field f in ns.get_fields ()) { old_ns.add_field (f); } foreach (Method m in ns.get_methods ()) { old_ns.add_method (m); } foreach (Comment c in ns.get_comments ()) { old_ns.add_comment (c); } foreach (Attribute a in ns.attributes) { if (old_ns.get_attribute (a.name) == null) { old_ns.attributes.append(a); } } } else { namespaces.add (ns); scope.add (ns.name, ns); } } /** * Returns the list of namespaces. * * @return namespace list */ public unowned List get_namespaces () { return namespaces; } /** * Adds the specified class to this namespace. * * @param cl a class */ public override void add_class (Class cl) { // namespaces do not support private members if (cl.access == SymbolAccessibility.PRIVATE) { cl.access = SymbolAccessibility.INTERNAL; } if (cl.owner == null) { cl.source_reference.file.add_node (cl); } classes.add (cl); scope.add (cl.name, cl); } /** * Adds the specified interface to this namespace. * * @param iface an interface */ public override void add_interface (Interface iface) { // namespaces do not support private members if (iface.access == SymbolAccessibility.PRIVATE) { iface.access = SymbolAccessibility.INTERNAL; } if (iface.owner == null) { iface.source_reference.file.add_node (iface); } interfaces.add (iface); scope.add (iface.name, iface); } /** * Adds the specified struct to this namespace. * * @param st a struct */ public override void add_struct (Struct st) { // namespaces do not support private members if (st.access == SymbolAccessibility.PRIVATE) { st.access = SymbolAccessibility.INTERNAL; } if (st.owner == null) { st.source_reference.file.add_node (st); } structs.add (st); scope.add (st.name, st); } /** * Adds the specified enum to this namespace. * * @param en an enum */ public override void add_enum (Enum en) { // namespaces do not support private members if (en.access == SymbolAccessibility.PRIVATE) { en.access = SymbolAccessibility.INTERNAL; } if (en.owner == null) { en.source_reference.file.add_node (en); } enums.add (en); scope.add (en.name, en); } /** * Adds the specified error domain to this namespace. * * @param edomain an error domain */ public override void add_error_domain (ErrorDomain edomain) { // namespaces do not support private members if (edomain.access == SymbolAccessibility.PRIVATE) { edomain.access = SymbolAccessibility.INTERNAL; } if (edomain.owner == null) { edomain.source_reference.file.add_node (edomain); } error_domains.add (edomain); scope.add (edomain.name, edomain); } /** * Adds the specified delegate to this namespace. * * @param d a delegate */ public override void add_delegate (Delegate d) { // namespaces do not support private members if (d.access == SymbolAccessibility.PRIVATE) { d.access = SymbolAccessibility.INTERNAL; } if (d.owner == null) { d.source_reference.file.add_node (d); } delegates.add (d); scope.add (d.name, d); } /** * Returns the list of structs. * * @return struct list */ public unowned List get_structs () { return structs; } /** * Returns the list of classes. * * @return class list */ public unowned List get_classes () { return classes; } /** * Returns the list of interfaces. * * @return interface list */ public unowned List get_interfaces () { return interfaces; } /** * Returns the list of enums. * * @return enum list */ public unowned List get_enums () { return enums; } /** * Returns the list of error domains. * * @return error domain list */ public unowned List get_error_domains () { return error_domains; } /** * Returns the list of fields. * * @return field list */ public unowned List get_fields () { return fields; } /** * Returns the list of constants. * * @return constant list */ public unowned List get_constants () { return constants; } /** * Returns the list of delegates. * * @return delegate list */ public unowned List get_delegates () { return delegates; } /** * Returns the list of methods. * * @return method list */ public unowned List get_methods () { return methods; } /** * Adds the specified constant to this namespace. * * @param constant a constant */ public override void add_constant (Constant constant) { // namespaces do not support private members if (constant.access == SymbolAccessibility.PRIVATE) { constant.access = SymbolAccessibility.INTERNAL; } if (constant.owner == null) { constant.source_reference.file.add_node (constant); } constants.add (constant); scope.add (constant.name, constant); } /** * Adds the specified field to this namespace. * * @param f a field */ public override void add_field (Field f) { // namespaces do not support private members if (f.access == SymbolAccessibility.PRIVATE) { f.access = SymbolAccessibility.INTERNAL; } if (f.owner == null) { f.source_reference.file.add_node (f); } fields.add (f); scope.add (f.name, f); } /** * Adds the specified method to this namespace. * * @param m a method */ public override void add_method (Method m) { // namespaces do not support private members if (m.access == SymbolAccessibility.PRIVATE) { m.access = SymbolAccessibility.INTERNAL; } if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) { m.result_var = new LocalVariable (m.return_type.copy (), "result", null, m.source_reference); m.result_var.is_result = true; } if (m.owner == null) { m.source_reference.file.add_node (m); } methods.add (m); scope.add (m.name, m); } public override void accept (CodeVisitor visitor) { visitor.visit_namespace (this); } public override void accept_children (CodeVisitor visitor) { foreach (UsingDirective ns_ref in using_directives) { ns_ref.accept (visitor); } foreach (Namespace ns in namespaces) { ns.accept (visitor); } /* process enums first to avoid order problems in C code */ foreach (Enum en in enums) { en.accept (visitor); } foreach (ErrorDomain edomain in error_domains) { edomain.accept (visitor); } foreach (Class cl in classes) { cl.accept (visitor); } foreach (Interface iface in interfaces) { iface.accept (visitor); } foreach (Struct st in structs) { st.accept (visitor); } foreach (Delegate d in delegates) { d.accept (visitor); } foreach (Constant c in constants) { c.accept (visitor); } foreach (Field f in fields) { f.accept (visitor); } foreach (Method m in methods) { m.accept (visitor); } } public override bool check (CodeContext context) { if (checked) { return !error; } checked = true; var a = get_attribute ("CCode"); if (a != null && a.has_argument ("gir_namespace")) { var new_gir = a.get_string ("gir_namespace"); var old_gir = source_reference.file.gir_namespace; if (old_gir != null && old_gir != new_gir) { source_reference.file.gir_ambiguous = true; } source_reference.file.gir_namespace = new_gir; } if (a != null && a.has_argument ("gir_version")) { source_reference.file.gir_version = a.get_string ("gir_version"); } foreach (Field f in fields) { if (f.binding == MemberBinding.INSTANCE) { Report.error (f.source_reference, "instance fields are not allowed outside of data types"); f.error = true; error = true; } else if (f.binding == MemberBinding.CLASS) { Report.error (f.source_reference, "class fields are not allowed outside of classes"); f.error = true; error = true; } } foreach (Method m in methods) { if (m is CreationMethod) { Report.error (m.source_reference, "construction methods may only be declared within classes and structs"); m.error = true; error = true; } if (m.binding == MemberBinding.INSTANCE) { Report.error (m.source_reference, "instance methods are not allowed outside of data types"); m.error = true; error = true; } else if (m.binding == MemberBinding.CLASS) { Report.error (m.source_reference, "class methods are not allowed outside of classes"); m.error = true; error = true; } } foreach (Namespace ns in namespaces) { ns.check (context); } return !error; } public override string to_string () { if (name == null) { return "(root namespace)"; } else { return "namespace %s".printf (name); } } }