Modules | Files | Inheritance Tree | Inheritance Graph | Name Index | Config
File: Synopsis/Parser/C++/syn/builder.cc
    1| // Synopsis C++ Parser: builder.cc source file
    2| // Implementation of the Builder class
    3| 
    4| // $Id: builder.cc,v 1.44 2003/01/27 06:53:37 chalky Exp $
    5| //
    6| // This file is a part of Synopsis.
    7| // Copyright (C) 2002 Stephen Davies
    8| //
    9| // Synopsis is free software; you can redistribute it and/or modify it
   10| // under the terms of the GNU General Public License as published by
   11| // the Free Software Foundation; either version 2 of the License, or
   12| // (at your option) any later version.
   13| //
   14| // This program is distributed in the hope that it will be useful,
   15| // but WITHOUT ANY WARRANTY; without even the implied warranty of
   16| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   17| // General Public License for more details.
   18| //
   19| // You should have received a copy of the GNU General Public License
   20| // along with this program; if not, write to the Free Software
   21| // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   22| // 02111-1307, USA.
   23| 
   24| // $Log: builder.cc,v $
   25| // Revision 1.44  2003/01/27 06:53:37  chalky
   26| // Added macro support for C++.
   27| //
   28| // Revision 1.43  2003/01/16 10:19:03  chalky
   29| // Prevent true, false and null appearing in output
   30| //
   31| // Revision 1.42  2002/12/12 17:25:34  chalky
   32| // Implemented Include support for C++ parser. A few other minor fixes.
   33| //
   34| // Revision 1.41  2002/12/09 08:27:34  chalky
   35| // initialise m_file
   36| //
   37| // Revision 1.40  2002/12/09 04:01:00  chalky
   38| // Added multiple file support to parsers, changed AST datastructure to handle
   39| // new information, added a demo to demo/C++. AST Declarations now have a
   40| // reference to a SourceFile (which includes a filename) instead of a filename.
   41| //
   42| // Revision 1.39  2002/11/17 12:11:43  chalky
   43| // Reformatted all files with astyle --style=ansi, renamed fakegc.hh
   44| //
   45| //
   46| 
   47| #include <map>
   48| #include <typeinfo>
   49| #include <sstream>
   50| #include <algorithm>
   51| 
   52| #include "builder.hh"
   53| #include "type.hh"
   54| #include "dict.hh"
   55| #include "swalker.hh"
   56| #include "scopeinfo.hh"
   57| #include "lookup.hh"
   58| #include "typeinfo.hh"
   59| 
   60| // for debugging
   61| #include "dumper.hh"
   62| #include "strace.hh"
   63| 
   64| //. Simplify names. Typically only used for accessing vectors and iterators
   65| using namespace Types;
   66| using namespace AST;
   67| 
   68| //. Utility method
   69| ScopedName extend(const ScopedName& name, const std::string& str)
   70| {
   71|     ScopedName ret = name;
   72|     ret.push_back(str);
   73|     return ret;
   74| }
   75| 
   76| 
   77| /////// FIXME: wtf is this doing here??
   78| namespace
   79| {
   80| //. This class is very similar to ostream_iterator, except that it works on
   81| //. pointers to types
   82| template <typename T>
   83| class ostream_ptr_iterator
   84| {
   85|     std::ostreamout;
   86|     const charsep;
   87| public:
   88|     ostream_ptr_iterator(std::ostream& o, const char* s) : out(&o), sep(s)
   89|     {}
   90|     ostream_ptr_iterator<T>& operator =(const T* value)
   91|     {
   92|         *out << *value;
   93|         if (sep)
   94|             *out << sep;
   95|         return *this;
   96|     }
   97|     ostream_ptr_iterator<T>& operator *()
   98|     {
   99|         return *this;
  100|     }
  101|     ostream_ptr_iterator<T>& operator ++()
  102|     {
  103|         return *this;
  104|     }
  105|     ostream_ptr_iterator<T>& operator ++(int)
  106|     {
  107|         return *this;
  108|     }
  109| };
  110| }
  111| 
  112| //. Formats a vector<string> to the output, joining the strings with ::'s.
  113| //. This operator is prototyped in builder.hh and can be used from other
  114| //. modules
  115| std::ostreamoperator <<(std::ostream& out, const ScopedName& vec)
  116| {
  117|     return out << join(vec"::");
  118| }
  119| 
  120| //
  121| // Struct Builder::Private
  122| //
  123| 
  124| struct Builder::Private
  125| {
  126|     typedef std::map<AST::Scope*, ScopeInfo*> ScopeMap;
  127|     ScopeMap map;
  128| 
  129|     //. A map of name references
  130|     typedef std::map<ScopedName, std::vector<AST::Reference> > RefMap;
  131|     RefMap refs;
  132| 
  133|     //. A list of builtin declarations
  134|     Declaration::vector builtin_decls;
  135| };
  136| 
  137| //
  138| // Class Builder
  139| //
  140| 
  141| Builder::Builder(AST::SourceFile* file)
  142| {
  143|     m_file = NULL;
  144|     m_unique = 1;
  145|     m = new Private;
  146|     ScopedName name;
  147|     m_scope = m_global = new AST::Namespace(file, 0, "global", name);
  148|     ScopeInfoglobal = find_info(m_global);
  149|     m_scopes.push_back(global);
  150|     // Insert the global base types
  151|     Types::Baset_bool, *t_null;
  152|     AST::Declarationdecl;
  153|     global->dict->insert(create_base("char"));
  154|     global->dict->insert(t_bool = create_base("bool"));
  155|     global->dict->insert(create_base("short"));
  156|     global->dict->insert(create_base("int"));
  157|     global->dict->insert(create_base("long"));
  158|     global->dict->insert(create_base("unsigned"));
  159|     global->dict->insert(create_base("unsigned long"));
  160|     global->dict->insert(create_base("float"));
  161|     global->dict->insert(create_base("double"));
  162|     global->dict->insert(create_base("void"));
  163|     global->dict->insert(create_base("..."));
  164|     global->dict->insert(create_base("long long"));
  165|     global->dict->insert(create_base("long double"));
  166|     global->dict->insert(t_null = create_base("__null_t"));
  167|     // Add a variables for true
  168|     name.clear();
  169|     name.push_back("true");
  170|     decl = new AST::Variable(file, -1, "variable", name, t_bool, false);
  171|     global->dict->insert(decl);
  172|     m->builtin_decls.push_back(decl);
  173|     // Add a variable for false
  174|     name.clear();
  175|     name.push_back("false");
  176|     decl = new AST::Variable(file, -1, "variable", name, t_bool, false);
  177|     global->dict->insert(decl);
  178|     m->builtin_decls.push_back(decl);
  179|     // Add a variable for null pointer types (g++ #defines NULL to __null)
  180|     name.clear();
  181|     name.push_back("__null");
  182|     decl = new AST::Variable(file, -1, "variable", name, t_null, false);
  183|     global->dict->insert(decl);
  184|     m->builtin_decls.push_back(decl);
  185| 
  186|     // Create the Lookup helper
  187|     m_lookup = new Lookup(this);
  188| }
  189| 
  190| Builder::~Builder()
  191| {
  192|     // TODO Delete all ...
  193|     delete m_lookup;
  194|     delete m;
  195| }
  196| 
  197| //. Finds or creates a cached Scope
  198| ScopeInfoBuilder::find_info(AST::Scope* decl)
  199| {
  200|     Private::ScopeMap::iterator iter = m->map.find(decl);
  201|     if (iter == m->map.end())
  202|     {
  203|         ScopeInfoscope = new ScopeInfo(decl);
  204|         m->map.insert(Private::ScopeMap::value_type(declscope));
  205|         return scope;
  206|     }
  207|     return iter->second;
  208| }
  209| 
  210| void Builder::set_access(AST::Access axs)
  211| {
  212|     m_scopes.back()->access = axs;
  213| }
  214| 
  215| void Builder::set_file(AST::SourceFile* file)
  216| {
  217|     m_file = file;
  218| }
  219| 
  220| const Declaration::vector& Builder::builtin_decls() const
  221| {
  222|     return m->builtin_decls;
  223| }
  224| 
  225| //
  226| // AST Methods
  227| //
  228| 
  229| void Builder::add(AST::Declaration* decl, bool is_template)
  230| {
  231|     ScopeInfoscopeinfo;
  232|     AST::Declaration::vectordecls;
  233|     if (is_template)
  234|     {
  235|         scopeinfo = m_scopes[m_scopes.size()-2];
  236|         decls = &scopeinfo->scope_decl->declarations();
  237|     }
  238|     else
  239|     {
  240|         scopeinfo = m_scopes.back();
  241|         decls = &m_scope->declarations();
  242|     }
  243|     // Set access
  244|     decl->set_access(scopeinfo->access);
  245|     // Add to name dictionary
  246|     scopeinfo->dict->insert(decl);
  247| 
  248|     const std::stringscope_type = scopeinfo->scope_decl->type();
  249|     if (scope_type != "local" && scope_type != "function")
  250|     {
  251|         // Add declaration
  252|         decls->push_back(decl);
  253|         // Add to SourceFile
  254|         decl->file()->declarations().push_back(decl);
  255|     }
  256| }
  257| 
  258| void Builder::add(Types::Named* type)
  259| {
  260|     // Add to name dictionary
  261|     m_scopes.back()->dict->insert(type);
  262| }
  263| 
  264| void Builder::add_macros(const std::vector<AST::Macro*>& macros)
  265| {
  266|     std::vector<AST::Macro*>::const_iterator iter;
  267|     for (iter = macros.begin(); iter != macros.end(); iter++)
  268|         m_global->declarations().push_back(*iter);
  269| 
  270| }
  271| 
  272| AST::NamespaceBuilder::start_namespace(const std::string& n, NamespaceType nstype)
  273| {
  274|     std::string name = ntype_str;
  275|     AST::Namespacens = 0;
  276|     bool generated = false;
  277|     // Decide what to do based on the given namespace type
  278|     switch (nstype)
  279|     {
  280|     case NamespaceNamed:
  281|         type_str = "namespace";
  282|         // Check if namespace already exists
  283|             Dictionarydict = scopeinfo()->dict;
  284|             if (dict->has_key(name))
  285|                 try
  286|                 {
  287|                     ns = Types::declared_cast<AST::Namespace>(dict->lookup(name));
  288|                 }
  289|                 catch (const Types::wrong_type_cast&)
  290|                 { }
  291|         }
  292|         break;
  293|     case NamespaceAnon:
  294|         type_str = "module";
  295|         // name is the filename. Wrap it in {}'s. only keep after last /
  296|             size_t slash_at = name.rfind('/');
  297|             if (slash_at != std::string::npos)
  298|                 name.erase(0slash_at + 1);
  299|             name = "{" + name + "}";
  300|         }
  301|         break;
  302|     case NamespaceUnique:
  303|         type_str = "local";
  304|         { // name is empty or the type. Encode it with a unique number
  305|             if (!name.size())
  306|                 name = "ns";
  307|             int count = m_scopes.back()->getCount(name);
  308|             std::ostringstream buf;
  309|             buf << '`' << name;
  310|             if (count > 1)
  311|                 buf << count;
  312|             name = buf.str();
  313|         }
  314|         break;
  315|     case NamespaceTemplate:
  316|         type_str = "template";
  317|         { // name is empty or the type. Encode it with a unique number
  318|             if (!name.size())
  319|                 name = "template";
  320|             int count = m_scopes.back()->getCount(name);
  321|             std::ostringstream buf;
  322|             buf << '`' << name << count;
  323|             name = buf.str();
  324|         }
  325|         break;
  326|     }
  327|     // Create a new namespace object unless we already found one
  328|     if (ns == NULL)
  329|     {
  330|         generated = true;
  331|         // Create the namspace
  332|         if (nstype == NamespaceTemplate)
  333|             ns = new AST::Namespace(m_file, 0, type_str, m_scope->name());
  334|         else
  335|         {
  336|             // Generate a nested name
  337|             ScopedName ns_name = extend(m_scope->name(), name);
  338|             ns = new AST::Namespace(m_file, 0, type_str, ns_name);
  339|             add(ns);
  340|         }
  341|     }
  342|     // Create ScopeInfo object. Search is this NS plus enclosing NS's search
  343|     ScopeInfons_info = find_info(ns);
  344|     ScopeInfocurrent = m_scopes.back();
  345|     // For anon namespaces, we insert the anon ns into the parent search
  346|     if (nstype == NamespaceAnon && generated)
  347|         current->search.push_back(ns_info);
  348|     // Initialize search to same as parent scope if we generated a new NS
  349|     if (generated)
  350|         std::copy(current->search.begin(), current->search.end(),
  351|                   std::back_inserter(ns_info->search));
  352| 
  353|     // Push stack
  354|     m_scopes.push_back(ns_info);
  355|     m_scope = ns;
  356|     return ns;
  357| }
  358| 
  359| void Builder::end_namespace()
  360| {
  361|     // TODO: Check if it is a namespace...
  362|     m_scopes.pop_back();
  363|     m_scope = m_scopes.back()->scope_decl;
  364| }
  365| 
  366| // Utility class to recursively add base classes to given search
  367| void Builder::add_class_bases(AST::Class* clas, ScopeSearch& search)
  368| {
  369|     AST::Inheritance::vector::iterator inh_iter = clas->parents().begin();
  370|     while (inh_iter != clas->parents().end())
  371|     {
  372|         AST::Inheritanceinh = *inh_iter++;
  373|         Types::Typetype = inh->parent();
  374|         try
  375|         {
  376|             AST::Classbase = Types::declared_cast<AST::Class>(type);
  377|             // Found a base class, so look it up
  378|             ScopeInfoscope = find_info(base);
  379|             search.push_back(scope);
  380|             // Recursively add..
  381|             add_class_bases(basesearch);
  382|         }
  383|         catch (const Types::wrong_type_cast&)
  384|         /* TODO: handle typedefs and parameterized types */
  385|         }
  386|     }
  387| }
  388| 
  389| void Builder::update_class_base_search()
  390| {
  391|     ScopeInfoscope = m_scopes.back();
  392|     AST::Classclas = dynamic_cast<AST::Class*>(scope->scope_decl);
  393|     if (!clas)
  394|         return;
  395|     ScopeSearch search = scope->search;
  396|     ScopeSearch::iterator iter = search.begin();
  397|     scope->search.clear();
  398|     // Add the scope itself
  399|     scope->search.push_back(*iter++);
  400|     // Add base classes
  401|     add_class_bases(classcope->search);
  402|     // Add containing scopes, stored in search
  403|     while (iter != search.end())
  404|         scope->search.push_back(*iter++);
  405| }
  406| 
  407| AST::ClassBuilder::start_class(int lineno, const std::string& type, const std::string& name, AST::Parameter::vector* templ_params)
  408| {
  409|     // Generate the name
  410|     ScopedName class_name;
  411|     if (templ_params)
  412|         class_name = extend(m_scopes[m_scopes.size()-2]->scope_decl->name(), name);
  413|     else
  414|         class_name = extend(m_scope->name(), name);
  415|     // Create the Class
  416|     AST::Classns = new AST::Class(m_file, lineno, type, class_name);
  417|     // Create template type
  418|     if (templ_params)
  419|     {
  420|         Types::Templatetempl = new Types::Template(class_name, ns, *templ_params);
  421|         ns->set_template_type(templ);
  422|         add(nstrue);
  423|     }
  424|     else
  425|         add(ns);
  426|     // Push stack. Search is this Class plus base Classes plus enclosing NS's search
  427|     ScopeInfons_info = find_info(ns);
  428|     ns_info->access = (type == "struct" ? AST::Public : AST::Private);
  429|     std::copy(scopeinfo()->search.begin(), scopeinfo()->search.end(),
  430|               std::back_inserter(ns_info->search));
  431|     m_scopes.push_back(ns_info);
  432|     m_scope = ns;
  433|     return ns;
  434| }
  435| 
  436| // Declaration of a previously forward declared class (ie: must find and
  437| // replace previous forward declaration in the appropriate place)
  438| AST::ClassBuilder::start_class(int lineno, const std::string& type, const ScopedName& names)
  439| {
  440|     // Find the forward declaration of this class
  441|     Types::Namednamed = m_lookup->lookupType(names);
  442|     // Must be either unknown or declared->forward
  443|     Types::Unknownunknown = dynamic_cast<Types::Unknown*>(named);
  444|     if (!unknown)
  445|     {
  446|         Types::Declareddeclared = dynamic_cast<Types::Declared*>(named);
  447|         if (!declared)
  448|         {
  449|             std::cerr << "Fatal: Qualified class name did not reference a declared type." << std::endl;
  450|             exit(1);
  451|         }
  452|         AST::Forwardforward = dynamic_cast<AST::Forward*>(declared->declaration());
  453|         if (!forward)
  454|         {
  455|             std::cerr << "Fatal: Qualified class name did not reference a forward declaration." << std::endl;
  456|             exit(1);
  457|         }
  458|     }
  459|     // Create the Class
  460|     AST::Classns = new AST::Class(m_file, lineno, type, named->name());
  461|     // Add to container scope
  462|     ScopedName scope_name = names;
  463|     scope_name.pop_back();
  464|     Types::Declaredscope_type = dynamic_cast<Types::Declared*>(m_lookup->lookupType(scope_name));
  465|     if (!scope_type)
  466|     {
  467|         std::cerr << "Fatal: Qualified class name was not in a declaration." << std::endl;
  468|         exit(1);
  469|     }
  470|     AST::Scopescope = dynamic_cast<AST::Scope*>(scope_type->declaration());
  471|     if (!scope)
  472|     {
  473|         std::cerr << "Fatal: Qualified class name was not in a scope." << std::endl;
  474|         exit(1);
  475|     }
  476|     // Set access
  477|     //decl->setAccess(m_scopes.back()->access);
  478|     // Add declaration
  479|     scope->declarations().push_back(ns);
  480|     // Add to name dictionary
  481|     ScopeInfoscope_info = find_info(scope);
  482|     scope_info->dict->insert(ns);
  483|     // Push stack. Search is this Class plus enclosing scopes. bases added later
  484|     ScopeInfons_info = find_info(ns);
  485|     ns_info->access = (type == "struct" ? AST::Public : AST::Private);
  486|     std::copy(scope_info->search.begin(), scope_info->search.end(),
  487|               std::back_inserter(ns_info->search));
  488|     m_scopes.push_back(ns_info);
  489|     m_scope = ns;
  490|     return ns;
  491| }
  492| 
  493| void Builder::end_class()
  494| {
  495|     // Check if it is a class...
  496|     m_scopes.pop_back();
  497|     m_scope = m_scopes.back()->scope_decl;
  498| }
  499| 
  500| AST::NamespaceBuilder::start_template()
  501| {
  502|     return start_namespace(""NamespaceTemplate);
  503| }
  504| 
  505| void Builder::end_template()
  506| {
  507|     end_namespace();
  508| }
  509| 
  510| 
  511| //. Start function impl scope
  512| void Builder::start_function_impl(const ScopedName& name)
  513| {
  514|     STrace trace("Builder::start_function_impl");
  515|     // Create the Namespace
  516|     AST::Namespacens = new AST::Namespace(m_file, 0, "function", name);
  517|     ScopeInfons_info = find_info(ns);
  518|     ScopeInfoscope_info;
  519|     if (name.size() > 1)
  520|     {
  521|         // Find container scope
  522|         std::vector<std::stringscope_name = name;
  523|         scope_name.pop_back();
  524|         scope_name.insert(scope_name.begin(), ""); // force lookup from global, not current scope, since name is fully qualified
  525|         Types::Declaredscope_type = dynamic_cast<Types::Declared*>(m_lookup->lookupType(scope_name));
  526|         if (!scope_type)
  527|         {
  528|             throw ERROR("Warning: Qualified func name was not in a declaration. Parent scope is:" << scope_name);
  529|         }
  530|         AST::Scopescope = dynamic_cast<AST::Scope*>(scope_type->declaration());
  531|         if (!scope)
  532|         {
  533|             throw ERROR("Warning: Qualified func name was not in a scope.");
  534|         }
  535|         scope_info = find_info(scope);
  536|     }
  537|     else
  538|     {
  539|         scope_info = find_info(m_global);
  540|     }
  541|     // Add to name dictionary TODO: this is for debugging only!
  542|     scope_info->dict->insert(ns);
  543|     // Push stack. Search is this Class plus enclosing scopes. bases added later
  544|     std::copy(scope_info->search.begin(), scope_info->search.end(),
  545|               std::back_inserter(ns_info->search));
  546| 
  547|     m_scopes.push_back(ns_info);
  548|     m_scope = ns;
  549| }
  550| 
  551| //. End function impl scope
  552| void Builder::end_function_impl()
  553| {
  554|     m_scopes.pop_back();
  555|     m_scope = m_scopes.back()->scope_decl;
  556| }
  557| 
  558| //. Add an function
  559| AST::FunctionBuilder::add_function(int line, const std::string& name,
  560|                                      const std::vector<std::string>& premod, Types::Type* ret,
  561|                                      const std::string& realname, AST::Parameter::vector* templ_params)
  562| {
  563|     // Find the parent scope, depending on whether this is a template or not
  564|     AST::Scopeparent_scope;
  565|     if (templ_params)
  566|         parent_scope = m_scopes[m_scopes.size()-2]->scope_decl;
  567|     else
  568|         parent_scope = m_scope;
  569| 
  570|     // Determine the new scoped name
  571|     ScopedName func_name = extend(parent_scope->name(), name);
  572| 
  573|     // Decide whether this is a member function (aka operation) or just a
  574|     // function
  575|     AST::Functionfunc;
  576|     if (dynamic_cast<AST::Class*>(parent_scope))
  577|         func = new AST::Operation(m_file, line, "member function", func_name, premod, ret, realname);
  578|     else
  579|         func = new AST::Function(m_file, line, "function", func_name, premod, ret, realname);
  580| 
  581|     // Create template type
  582|     if (templ_params)
  583|     {
  584|         Types::Templatetempl = new Types::Template(func_name, func, *templ_params);
  585|         func->set_template_type(templ);
  586|         add(functrue);
  587|     }
  588|     else
  589|         add(func);
  590|     return func;
  591| }
  592| 
  593| //. Add a variable
  594| AST::VariableBuilder::add_variable(int line, const std::string& name, Types::Type* vtype, bool constr, const std::string& type)
  595| {
  596|     // Generate the name
  597|     ScopedName scope = m_scope->name();
  598|     scope.push_back(name);
  599|     AST::Variablevar = new AST::Variable(m_file, line, type, scope, vtype, constr);
  600|     add(var);
  601|     return var;
  602| }
  603| 
  604| void Builder::add_this_variable()
  605| {
  606|     // First find out if we are in a method
  607|     AST::Scopefunc_ns = m_scope;
  608|     ScopedName name = func_ns->name();
  609|     name.pop_back();
  610|     name.insert(name.begin(), std::string());
  611|     Types::Namedclas_named = m_lookup->lookupType(namefalse);
  612|     AST::Classclas;
  613|     try
  614|     {
  615|         clas = Types::declared_cast<AST::Class>(clas_named);
  616|     }
  617|     catch (const Types::wrong_type_cast& )
  618|         // Not in a method -- so dont add a 'this'
  619|     {
  620|         return;
  621|     }
  622| 
  623|     // clas is now the AST::Class of the enclosing class
  624|     Types::Type::Mods prepost;
  625|     post.push_back("*");
  626|     Types::Modifiert_this = new Types::Modifier(clas->declared(), pre, post);
  627|     add_variable(-1"this"t_thisfalse"this");
  628| }
  629| 
  630| //. Add a typedef
  631| AST::TypedefBuilder::add_typedef(int line, const std::string& name, Types::Type* alias, bool constr)
  632| {
  633|     // Generate the name
  634|     ScopedName scoped_name = extend(m_scope->name(), name);
  635|     // Create the object
  636|     AST::Typedeftdef = new AST::Typedef(m_file, line, "typedef", scoped_name, alias, constr);
  637|     add(tdef);
  638|     return tdef;
  639| }
  640| 
  641| //. Add an enumerator
  642| AST::EnumeratorBuilder::add_enumerator(int line, const std::string& name, const std::string& value)
  643| {
  644|     ScopedName scoped_name = extend(m_scope->name(), name);
  645|     AST::Enumeratorenumor = new AST::Enumerator(m_file, line, "enumerator", scoped_name, value);
  646|     add(enumor->declared());
  647|     return enumor;
  648| }
  649| 
  650| //. Add an enum
  651| AST::Enum* Builder::add_enum(int line, const std::string& name, const std::vector<AST::Enumerator*>& enumors)
  652| {
  653|     ScopedName scoped_name = extend(m_scope->name(), name);
  654|     AST::Enum* theEnum = new AST::Enum(m_file, line, "enum", scoped_name);
  655|     theEnum->enumerators() = enumors;
  656|     add(theEnum);
  657|     return theEnum;
  658| }
  659| 
  660| //. Add tail comment
  661| AST::DeclarationBuilder::add_tail_comment(int line)
  662| {
  663|     ScopedName name;
  664|     name.push_back("dummy");
  665|     AST::Declarationdecl = new AST::Declaration(m_file, line, "dummy", name);
  666|     add(decl);
  667|     return decl;
  668| }
  669| 
  670| // A functor that adds only inheritances which are class objects to a given
  671| // list
  672| class InheritanceAdder
  673| {
  674|     std::list<AST::Class*>& open_list;
  675| public:
  676|     InheritanceAdder(std::list<AST::Class*>& l) : open_list(l)
  677|     {}
  678|     InheritanceAdder(const InheritanceAdder& i) : open_list(i.open_list)
  679|     {}
  680|     void operator() (AST::Inheritance* i)
  681|     {
  682|         try
  683|         {
  684|             open_list.push_back(Types::declared_cast<AST::Class>(i->parent()));
  685|         }
  686|         catch (const Types::wrong_type_cast&)
  687|         /* ?? ignore for now */
  688|         }
  689|     }
  690| };
  691| 
  692| 
  693| //. Maps a scoped name into a vector of scopes and the final type. Returns
  694| //. true on success.
  695| bool Builder::mapName(const ScopedName& names, std::vector<AST::Scope*>& o_scopes, Types::Named*& o_type)
  696| {
  697|     STrace trace("Builder::mapName");
  698|     AST::Scopeast_scope = m_global;
  699|     ScopedName::const_iterator iter = names.begin();
  700|     ScopedName::const_iterator last = names.end();
  701|     last--;
  702|     ScopedName scoped_name;
  703| 
  704|     // Start scope name at global level
  705|     scoped_name.push_back("");
  706| 
  707|     // Sanity check
  708|     if (iter == names.end())
  709|         return false;
  710| 
  711|     // Loop through all containing scopes
  712|     while (iter != last)
  713|     {
  714|         //const std::string& name = *iter++;
  715|         scoped_name.push_back(*iter++);
  716|         Types::Namedtype = m_lookup->lookupType(scoped_name);
  717|         if (!type)
  718|         {
  719|             LOG("Warning: failed to lookup " << scoped_name << " in global scope");
  720|             return false;
  721|         }
  722|         try
  723|         {
  724|             ast_scope = Types::declared_cast<AST::Scope>(type);
  725|         }
  726|         catch (const Types::wrong_type_cast&)
  727|         {
  728|             LOG("Warning: looked up scope wasnt a scope!" << scoped_name);
  729|             return false;
  730|         }
  731|         o_scopes.push_back(ast_scope);
  732|     }
  733| 
  734|     // iter now == last, which can be any type
  735|     scoped_name.push_back(*iter);
  736|     Types::Namedtype = m_lookup->lookupType(scoped_nametrue);
  737|     if (!type)
  738|     {
  739|         //find_info(ast_scope)->dict->dump();
  740|         LOG("\nWarning: final type lookup wasn't found!" << *iter);
  741|         return false;
  742|     }
  743| 
  744|     o_type = type;
  745|     return true;
  746| }
  747| 
  748| 
  749| Types::UnknownBuilder::create_unknown(const std::string& name)
  750| {
  751|     // Generate the name
  752|     ScopedName u_name = extend(m_scope->name(), name);
  753|     Types::Unknownunknown = new Types::Unknown(u_name);
  754|     return unknown;
  755| }
  756| 
  757| Types::UnknownBuilder::add_unknown(const std::string& name)
  758| {
  759|     if (m_scopes.back()->dict->has_key(name) == false)
  760|         add(create_unknown(name));
  761|     return NULL;
  762| }
  763| 
  764| AST::ForwardBuilder::add_forward(int lineno, const std::string& name, AST::Parameter::vector* templ_params)
  765| {
  766|     if (!templ_params)
  767|     {
  768|         add_unknown(name);
  769|         return NULL;
  770|     }
  771|     // Must find the scope above the template scope
  772|     ScopeInfoparent_scope = m_scopes[m_scopes.size()-2];
  773|     ScopedName scoped_name = extend(parent_scope->scope_decl->name(), name);
  774|     if (parent_scope->dict->has_key(name) == true)
  775|         return NULL;
  776|     AST::Forwardforward = new AST::Forward(m_file, lineno, "forward", scoped_name);
  777|     Types::Templatetempl = new Types::Template(scoped_name, NULL, *templ_params);
  778|     forward->set_template_type(templ);
  779|     add(forwardtrue);
  780|     return NULL;
  781| }
  782| 
  783| Types::BaseBuilder::create_base(const std::string& name)
  784| {
  785|     return new Types::Base(extend(m_scope->name(), name));
  786| }
  787| 
  788| Types::DependentBuilder::create_dependent(const std::string& name)
  789| {
  790|     return new Types::Dependent(extend(m_scope->name(), name));
  791| }
  792| 
  793| std::string Builder::dump_search(ScopeInfo* scope)
  794| {
  795|     ScopeSearchsearch = scope->search;
  796|     std::ostringstream buf;
  797|     buf << "Search for ";
  798|     if (scope->scope_decl->name().size() == 0)
  799|         buf << "global";
  800|     else
  801|         buf << m_scope->name();
  802|     buf << " is now: ";
  803|     ScopeSearch::iterator iter = search.begin();
  804|     while (iter != search.end())
  805|     {
  806|         buf << (iter==search.begin() ? "" : ", ");
  807|         const ScopedNamename = (*iter)->scope_decl->name();
  808|         if (name.size())
  809|             if ( (*iter)->is_using )
  810|                 buf << "(" << name << ")";
  811|             else
  812|                 buf << name;
  813|         else
  814|             buf << "global";
  815|         ++iter;
  816|     }
  817|     //buf << std::ends;
  818|     return buf.str();
  819| }
  820| 
  821| // A comparator which compares declaration pointers of ScopeInfo objects
  822| class Builder::EqualScope
  823| {
  824|     AST::Scopetarget;
  825| public:
  826|     EqualScope(ScopeInfo* t)
  827|     {
  828|         target = t->scope_decl;
  829|     }
  830|     bool operator()(ScopeInfo* s)
  831|     {
  832|         return s->scope_decl == target;
  833|     }
  834| };
  835| 
  836| void Builder::do_add_using_namespace(ScopeInfo* target, ScopeInfo* scope)
  837| {
  838|     STrace trace("Builder::addUsingNamespace");
  839| 
  840|     // Check if 'scope' already has 'target' in its using list
  841|     ScopeSearchuses = scope->using_scopes;
  842|     if (std::find_if(uses.begin(), uses.end(), EqualScope(target)) != uses.end())
  843|         // Already using
  844|         return;
  845|     // Else add it
  846|     scope->using_scopes.push_back(target);
  847|     target->used_by.push_back(scope);
  848| 
  849|     ScopedNametarget_name = target->scope_decl->name();
  850| 
  851|     // Find where to insert 'scope' into top()'s search list
  852|     // "closest enclosing namespace that contains both using directive and
  853|     //  target namespace" -- C++ Standard
  854|     ScopeSearchsearch = scope->search;
  855|     LOG(dump_search(scope));
  856|     ScopeSearch::iterator iter = search.end();
  857|     // Skip global scope.. cant check something with no name
  858|     --iter;
  859|     while (iter != search.begin())
  860|     {
  861|         // Move to next scope to check
  862|         --iter;
  863|         ScopedNamesearch_name = (*iter)->scope_decl->name();
  864|         if (target_name.size() < search_name.size())
  865|             // Search is more nested than the target
  866|             break;
  867|         if (search_name.size() < 1)
  868|             // Global NS..
  869|             continue;
  870|         if (target_name[search_name.size()-1] != search_name.back())
  871|             // Different scope path taken
  872|             break;
  873|     }
  874|     // Move back to last which was common, so we can insert before it
  875|     if (*iter != search.back() && iter != search.begin())
  876|         iter++;
  877| 
  878|     // Create a dummy ScopeInfo which is just an alias to the original. This
  879|     // is needed to cumulate using namespaces in the lookups
  880|     ScopeInfonew_scope = new ScopeInfo(target);
  881|     search.insert(iternew_scope);
  882| 
  883|     LOG(dump_search(scope));
  884| 
  885|     // Add target to all used_by scopes
  886|     ScopeSearch used_by_copy = scope->used_by;
  887|     iter = used_by_copy.begin();
  888|     while (iter != used_by_copy.end())
  889|         do_add_using_namespace(target, *iter++);
  890| }
  891| 
  892| // Add a namespace using declaration.
  893| void Builder::add_using_namespace(Types::Named* type)
  894| {
  895|     STrace trace("Builder::usingNamespace");
  896|     AST::Scopeast_scope = Types::declared_cast<AST::Scope>(type);
  897|     ScopeInfotarget = find_info(ast_scope);
  898|     do_add_using_namespace(targetm_scopes.back());
  899| }
  900| 
  901| 
  902| // Add a namespace alias using declaration.
  903| void Builder::add_aliased_using_namespace(Types::Named* type, const std::string& alias)
  904| {
  905|     STrace trace("Builder::usingNamespace");
  906| 
  907|     // Retrieve the 'Namespace' it points to
  908|     AST::Namespacens = Types::declared_cast<AST::Namespace>(type);
  909| 
  910|     // Create a new declared type with a different name
  911|     ScopedName new_name = extend(m_scope->name(), alias);
  912|     Types::Declareddeclared = new Types::Declared(new_name, ns);
  913| 
  914|     // Add to current scope
  915|     add(declared);
  916| }
  917| 
  918| // Add a using declaration.
  919| void Builder::add_using_declaration(Types::Named* type)
  920| {
  921|     // Add it to the current scope
  922|     add(type);
  923| }
  924| 
  925| // vim: set ts=8 sts=4 sw=4 et: