/** * \file namespace.cpp * \brief Everything you ever wanted to know about namespaces. Or something like that. * \author Stefan Reuther */ INTERFACE: #include #include "symbol_table.h" #include "scope.h" class Namespace_symbol; class Function_body_queue; class Namespace_scope : public Abstract_scope { std::string prefix; Namespace_symbol* sym; Function_body_queue* fbqueue; public: }; class Namespace_symbol : public Symbol { }; IMPLEMENTATION: #include #include "except.h" #include "downcast.h" #include "expr_annotator.h" #include "source.h" #include "symbol_name.h" #include "class.h" #include "implicit_conversion.h" #include "function_body.h" #include "init_handler.h" /**************************** Namespace_symbol ***************************/ PUBLIC Namespace_symbol::Namespace_symbol() : Symbol() { set_status(st_Defined); // namespaces can't be declared or referenced } PUBLIC Symbol::Kind Namespace_symbol::get_kind() const { return k_Namespace; } PUBLIC Namespace_scope* Namespace_symbol::get_scope() { return new Namespace_scope(0, this); } /**************************** Namespace_scope ****************************/ PUBLIC Namespace_scope::Namespace_scope(Namespace_scope* parent, std::string prefix) : Abstract_scope(parent), prefix(prefix), sym(new Namespace_symbol()), fbqueue(0) { } PUBLIC Namespace_scope::Namespace_scope(Namespace_scope* parent, Namespace_symbol* sym) : Abstract_scope(parent), prefix(Symbol_name::get_mangled_scope_from_symbol(sym->get_name())), sym(sym), fbqueue(0) { } PUBLIC std::string Namespace_scope::get_unique_name(std::string name) { return Symbol_name::get_mangled_symbol_name(prefix, name); } PUBLIC Type Namespace_scope::get_this_type() const { return Type(); } /** Look up name here. */ PUBLIC Symbol_pair Namespace_scope::lookup_here(std::string name, bool for_decl) { // FIXME: should also look up in "using" if for_decl is false return Symbol_table::get_instance().get_symbol(get_unique_name(name)); } PUBLIC void Namespace_scope::add_symbol(std::string name, Symbol* sym) { Symbol_table::get_instance().add_symbol(get_unique_name(name), name.length(), sym); } /** Add a variable at namespace scope. */ PUBLIC Variable_symbol* Namespace_scope::add_variable(Storage_class_specifier storage, Type type, Ptree* name, Ptree* init, Ptree* bitsize) { Storage_class_specifier orig_storage = storage; /* 7p5: object declaration */ assert(type.get_kind() != Type::k_Function); if (!name) compile_error("unnamed objects are not allowed at namespace scope"); if (bitsize) compile_error("objects with bitsize are not allowed at namespace scope"); /* 7p6: An object declaration is a definition unless it contains "extern" and no initializer */ const bool is_declaration = (storage == s_Extern && !init); if (storage == s_None) { /* 7.1.1p6 */ if (type.is_qualified(Type::q_Const)) storage = s_Static; else storage = s_Extern; } if (storage == s_Mutable || storage == s_Auto || storage == s_Register) /* 7.1.1p2 */ compile_error("mutable/auto/register variables not allowed at namespace scope"); Symbol_name sname(name, this, false); Symbol_pair pair = sname.lookup_for_decl(); Variable_symbol* vsym; if (pair && pair.tag != pair.untag) { /* already there. */ vsym = dynamic_cast(pair.untag); if (!vsym) compile_error("`" + pair.untag->get_name() + "' already defined as a different kind of symbol"); } else { if (sname.is_qualified()) compile_error("can't declare qualified names"); if (sname.is_template()) compile_error("can't declare template vars"); /* declare variable. */ vsym = new Variable_symbol(type, storage, 0, 0, Symbol::st_Declared); add_symbol(sname.get_name(), vsym); } if (vsym->get_type() != type) compile_error("inconsistent types for `" + vsym->get_name() + "'"); if (is_declaration) { /* (re-)declaration */ assert(!init); if (!vsym->is_declared()) vsym->set_status(Symbol::st_Declared); return 0; } else { /* definition */ if (vsym->is_defined()) compile_error("duplicate definition of `" + vsym->get_name() + "'"); if (vsym->is_member_variable()) // can't happen, members are always defined compile_error("can't initialize member variable at namespace scope"); if (orig_storage != s_None && vsym->get_storage_class() != storage) compile_error("inconsistent storage class for `" + vsym->get_name() + "'"); if (init) init = Init_handler(sname.get_scope(), init, true).process_initializer(type.get_unqualified_type()); vsym->define_variable(storage, init, bitsize, Symbol::st_Defined); return vsym; } } PUBLIC Function_signature* Namespace_scope::add_function_decl(Storage_class_specifier storage, Function_specifier_set fspec, Type type, const Symbol_name& sym_name) { Function_symbol* fsym; Type this_type; if (sym_name.is_template()) compile_error("function template specialisation not supported"); if (!sym_name.is_qualified()) { /* could be declaration */ Symbol_pair pair = lookup_here(sym_name.get_name(), true); if (!pair || pair.tag == pair.untag) { fsym = new Function_symbol(this, sym_name.get_kind()); add_symbol(sym_name.get_name(), fsym); } else { fsym = dynamic_cast(pair.untag); if (!fsym) compile_error("`" + sym_name.get_name() + "' is not a function"); } } else { /* must be already declared */ Abstract_scope* scope = sym_name.get_scope(); fsym = dynamic_cast(scope->lookup_here(sym_name.get_name(), true).untag); if (!fsym) compile_error("`" + sym_name.get_name() + "' has not been declared"); /* member function? */ if (Class_scope* cs = dynamic_cast(scope)) this_type = cs->get_class_symbol()->get_type(); } if (storage == s_None || storage == s_Static || storage == s_Extern) /* accept */; else compile_error("invalid storage class for top-level function"); Function_signature* sig = fsym->add_signature(type, this_type, storage, fspec, (sym_name.is_qualified() ? Function_symbol::must_be_declared : Function_symbol::may_be_anything)); if (!sig->is_declared()) sig->set_status(Symbol::st_Declared); return sig; } PUBLIC void Namespace_scope::add_function_implementation(Function_signature* fsig, Block_scope* scope, Ptree* tree, Ptree* initializer) { if (!fbqueue) fbqueue = new Function_body_queue(); fbqueue->add_function(fsig, scope, tree, initializer); } PUBLIC void Namespace_scope::process_pending() { if (fbqueue) fbqueue->process(); }