Click here to Skip to main content
15,884,836 members
Articles / Desktop Programming / MFC

Another Enum Viewer

Rate me:
Please Sign up or sign in to vote.
4.50/5 (2 votes)
22 Oct 20015 min read 82.8K   1.3K   19  
An article on the usage and design of another Enum Viewer
// CPPSymTableSpecializeClass.cpp: Templated class specialization

#include "CPPSymTable.h"
#include "CPPScope.h"
#include "CPPTypeTemplated.h"
#include "CPPTypeClass.h"
#include "CPPDecl.h"
#include "JLCast.h"
#include "CPPParserSym.h"
#include "TokenStream.h"
#include "JLTokenBuffer.h"
#include "TemplateArgumentList.h"
#include "TemplateParameterList.h"
#include "CPPScopeContainers.h"

////////////////////////////////////////////////////////////////////
// LookupClassSpecialization: Given the name of a class template
// and a list of template arguments, create a specialization 
// if one does not exist.
//
// Inputs:
//    const JLStr&             className   name of the class template
//    CPPScopeRefI             containingScope
//                                         The scope in which the class
//                                         template is declared
//    TemplateArgumentListRef  argList     list of actual template
//                                         arguments (types or values)
//    const ANTLRTokenPtr&     errTok      Token for error reporting
// Outputs:
//    JLStr&                   specializationNameReturn
//                                         If successful, filled with the
//                                         decorated template class name
//    CPPTypeRefI&             specializationTypeReturn
//                                         If successful, points to the
//                                         type entry for the class specialization.
// Return:
//    bool     true on success, false if something was wrong with
//             the specialization, in which case an error has
//             already been reported.
//
// Note:  A class specialization name contains the types of
// the arguments, for example:
//    template declaration            invocation      name
//    --------------------            ----------      ----
//    template <class T> class A{}    A<int>          A<int>
//    template <class T> class A{}    A<char***>      A<char***>
//
// Note: If one or more of the template arguments are themselves
// template placeholders (unspecified values or types), then return
// type, if successful, will be unspecialized or partially-specialized.
// For example:
//    template <class T> class A { };
//    template <class T> class A<T*> { };
//    template <class X> class B { 
//        A<X> ax;   // type of ax is unspecialized template "A"
//        A<X*> ax;  // type of ax is partially-specialized template "A<$0*>"
//    };
// When template "B" is fully-specialized, then it will be reparsed 
// and ax will be given a fully-specialized type.
////////////////////////////////////////////////////////////////////
bool 
CPPSymTable::LookupClassSpecialization(
   const JLStr& className, 
   CPPScopeRefI containingScope,
   TemplateArgumentListRefI templateArgumentList, 
   const ANTLRTokenPtr& errTok,
   JLStr& specializationNameReturn,
   CPPTypeRefI& specializationTypeReturn
)
{
   // TODO: if the containing scope is a template placeholder scope,
   // then don't even bother -- return another template placeholder.

   // Look up the primary template declaration
   CPPDeclRefI primaryDecl = GetClassPrimaryTemplate(className, containingScope);
   assert(primaryDecl->GetType()->GetFlavor() == CPPType::Templated);

   // Get the primary template parameter list
   TemplateParameterListRefI primaryTemplateParameterList = 
      STATIC_CAST(CPPTypeTemplated*, primaryDecl->GetType().get())->GetParameterList();

   // TODO: Make sure that the given template argument list matches the
   // primary template parameter list, other than those that
   // have default arguments.

   // TODO: Using the primary template, fill in the default 
   // template arguments for any missing arguments.
   // This may require reparsing of the default argument values.

   // Given the completed argument list, create the 
   // specialization name for the class and scope
   specializationNameReturn = FormatClassSpecializationName(
      className,
      templateArgumentList
   );

   // Given this name, if there already exists a
   // specialization for the template under that name,
   // then return it.  Note that this may return types that are
   // themselves unspecialized templates, for example:
   //    template <class T> class A { };
   //    template <class X> class B {
   //       A<X> ax;   // ax is still unspecialized
   //    };
   //
   // Note that this also prevents recursive
   // instantiation of template classes in cases like:
   //    template <class T> class A { A<T>* foo(); };
   {
      CPPScope::DeclIterator iter;
      CPPDeclRefI tmpDecl = 
         containingScope->FindDeclByName(specializationNameReturn, iter);
      if (tmpDecl.get() != 0)
      {
         specializationTypeReturn = tmpDecl->GetType();
         return true;
      }
   }

   // Perform type deduction to choose the correct 
   // class template partial specialization.
   // TODO: This should also get the results of the type deduction.
   // TODO: This should report an error for ambiguous specializations.
   CPPTypeRefI partialSpecializationType;
   CPPDeclRefI partialSpecializationDecl;
   TemplateParameterListRefI partialSpecializationParameterList;
   if (!ChooseClassPartialSpecialization(
         className,
         containingScope,
         templateArgumentList,
         partialSpecializationType,
         partialSpecializationDecl,
         partialSpecializationParameterList
      )
   )
   {
      return false;
   }

   assert(partialSpecializationType->GetFlavor() == CPPType::Templated);

   //////////////////////////////////////////////////////////////////////
   // Save symbol table state
   //////////////////////////////////////////////////////////////////////
   CPPScopeState scopeState = SaveScope();

   //////////////////////////////////////////////////////////////////////
   // Create the right symbol table state for the template
   //////////////////////////////////////////////////////////////////////

   // Push a resolved global scope on the stack to avoid searching
   // any scopes already on the stack.
   EnterResolvedGlobalScope();

   // TODO: Push the full scope context of the template declaration

   // Push a local scope for the template arguments
   EnterLocalScope();

   // Enter the actual template arguments into the local scope
   // TODO: use the deduced arguments instead of the actual arguments
   assert(templateArgumentList->size() == partialSpecializationParameterList->size());
   TemplateParameterList::iterator parmListIter = partialSpecializationParameterList->begin();
   for (
      TemplateArgumentList::iterator argListIter = templateArgumentList->begin();
      argListIter != templateArgumentList->end();
      argListIter++, parmListIter++
   )
   {
      CPPDecl* newDecl;
      if ((*argListIter)->GetFlavor() == TemplateArgument::Type)
      {
         newDecl = new CPPDeclType(
            (*parmListIter)->GetName(),
            CPPConst::asPUBLIC,
            (*argListIter)->GetType(),
            false   // type, not typedef
         );
      } else {
         newDecl = new CPPDeclObject(
            (*parmListIter)->GetName(),
            CPPConst::asPUBLIC,
            (*parmListIter)->GetType(),
            CPPConst::scNONE,
            CPPConst::dmNONE,
            (*argListIter)->GetValue(),
            StrListRefI()
         );
      }
      GetCurrentScope()->AddDecl(newDecl);
   }

   // Set up the current access of the containing scope to be equal
   // to the access of the template declaration
   CPPConst::AccessSpecifier saveAccess = containingScope->GetCurrentAccess();
   containingScope->SetCurrentAccess(partialSpecializationDecl->GetAccessSpecifier());

   // Push the containing scope to get results of the
   // template specialization re-parsing
   PushScope(containingScope);

   // Set up a declaration-name-substituation, so that when the 
   // specialized class declaration is entered, it shows up
   // under the specialization name instead of the raw class name.
   DeclNameSubst saveDeclNameSubst = declNameSubst;
   declNameSubst.first = className;
   declNameSubst.second = specializationNameReturn;

   //////////////////////////////////////////////////////////////////////
   // Create a new parser using the current symbol table
   //////////////////////////////////////////////////////////////////////

   // Create a token stream/buffer from the template tokens
   TokenListStream templateTokenStream(
      *STATIC_CAST(CPPTypeTemplated*, partialSpecializationType.get())->GetTokens()
   );
   JLTokenBuffer templateTokenBuffer(
      &templateTokenStream, 
      CPPParser::ConstLLK
   );

	CPPParserSym subParser(
      &templateTokenBuffer,
      this,
      parser->GetOptions()
   );
   subParser.init();
   
   //////////////////////////////////////////////////////////////////////
   // Do the processing of the specialized template
   //////////////////////////////////////////////////////////////////////

   // Parse the class body.
   // Use a special rule that catches errors with exceptions
   subParser.template_specialization_reparse();

   //////////////////////////////////////////////////////////////////////
   // Restore the parser state
   //////////////////////////////////////////////////////////////////////

   // Pop the scope to the previous level
   RestoreScope(scopeState);

   // Find the specialization scope and type
   {
      CPPScope::DeclIterator declIter;
      CPPDeclRefI tmpDecl;
      tmpDecl = containingScope->FindDeclByName(specializationNameReturn, declIter);
      if (tmpDecl.get() == 0)
      {
         // something wrong with the reparse
      } else {
         specializationTypeReturn = tmpDecl->GetType();
         assert(specializationTypeReturn.get() != 0);
      }
   }

   // Restore the access of the containing scope
   containingScope->SetCurrentAccess(saveAccess);

   // Restore the declaration-name-substituation to its previous state
   declNameSubst = saveDeclNameSubst;

   return true;
}


////////////////////////////////////////////////////////////////////
// ChooseClassPartialSpecialization: Given the name of a class template
// and a list of template arguments, choose the partial specialization
// that most closely matches the arguments (or choose the primary template
// declaration if that is closest).
//
// Inputs:
//    const JLStr&              className   name of the class template
//    CPPScopeRefI              containingScope
//                                          The scope in which the class
//                                          template is declared
//    TemplateParameterListRefI primaryTemplateParameterList
//                                          The template parameter list of
//                                          the primary class template declaration.
//    TemplateArgumentListRef   templateArgumentList
//                                          list of actual template
//                                          arguments (types or values)
// Outputs: 
//    CPPTypeRefI&              partialSpecializationTypeReturn
//                                          The type of the selected partial 
//                                          specialization.
//    CPPTypeRefI&              partialSpecializationDeclReturn
//                                          The partial specialization declaration
// Return:
//    bool     true on success, false if something was wrong with
//             the specialization, in which case an error has
//             already been reported.
////////////////////////////////////////////////////////////////////
bool
CPPSymTable::ChooseClassPartialSpecialization(
   const JLStr& className,
   CPPScopeRefI containingScope,
   TemplateArgumentListRefI templateArgumentList, 
   CPPTypeRefI& partialSpecializationTypeReturn,
   CPPDeclRefI& partialSpecializationDeclReturn,
   TemplateParameterListRefI& partialSpecializationParameterListReturn
)
{
   // TODO: almost everything
   // For now, just choose the primary template and ignore all else
   CPPScope::DeclIterator declIter;
   for (
      partialSpecializationDeclReturn = containingScope->FindDeclByName(className, declIter);
      partialSpecializationDeclReturn.get() != 0;
      partialSpecializationDeclReturn = containingScope->NextDecl(declIter)
   )
   {
      // If there is a template under a name, then there should be no 
      // non-templated decl under that name.
      assert(partialSpecializationDeclReturn->GetType()->GetFlavor() == CPPType::Templated);

      // For now, just return primary template decl
      if (STATIC_CAST(CPPTypeTemplated*, partialSpecializationDeclReturn->GetType().get())->IsPrimary())
      {
         partialSpecializationTypeReturn = partialSpecializationDeclReturn->GetType();
         partialSpecializationParameterListReturn =
            STATIC_CAST(CPPTypeTemplated*, partialSpecializationTypeReturn.get())->
            GetParameterList();
         return true;
      }
   }

   assert(0);
   return false;

   
   // Given the completed argument list, select a list of candidates
   // from the primary template and any partial specializations.

   // Given the list of candidates, determine the partial ordering
   // and find the "most specialized" candidate.  If no candidate is
   // most specialized then report an ambiguity error.

   // Given the template argument list, construct a name for the 
   // (perhaps partially) specialized template class type.

   // If the specialization name exists already in the containing
   // scope, then return the associated scope and type.

   // If the specialization name does not already exist in the containing
   // scope, then create a (perhaps partial) specialization type and scope
   // by filling in the template placeholders and reparsing the template class
   // definition.
}


////////////////////////////////////////////////////////////////////
// GetClassPrimaryTemplate: Given the name of a class template,
// lookup the primary template declaration.
//
// Inputs:
//    const JLStr&    className          name of the class template
//    CPPScopeRefI    containingScope
//                                       The scope in which the class
//                                       primary template is declared
// Return:
//    CPPDeclRefI    declaration of the primary template
// Note: asserts if no declaration is found
////////////////////////////////////////////////////////////////////
CPPDeclRefI
CPPSymTable::GetClassPrimaryTemplate(
   const JLStr& className,
   CPPScopeRefI containingScope
)
{
   // Find the templated declaration under the given name that is 
   // a primary template declaration.
   CPPScope::DeclIterator iter;
   for (
      CPPDeclRefI tmpDecl = containingScope->FindDeclByName(className, iter);
      tmpDecl.get() != 0;
      tmpDecl = containingScope->NextDecl(iter)
   )
   {
      if (
         tmpDecl->GetType()->GetFlavor() == CPPType::Templated &&
         STATIC_CAST(CPPTypeTemplated*, tmpDecl->GetType().get())->IsPrimary()
      )
      {
         return tmpDecl;
      }

      if (!NameIsDecoratedName(className, containingScope->GetName()))
      {
         // Found a hiding declaration
         break;
      }

   }

   // TODO: assert here is bad
   assert(0);
   return CPPDeclRefI();
}


///////////////////////////////////////////////////////////////////
// FormatClassSpecializationName: Given the name of a templated
// class, and a non-empty list of specialization arguments,
// sythesize a name for the decl/scope that is unique compared with
// other possible specializations.
//
// This overload of the method is for template partial specializations.
//
// This constructs a name composed of the raw name combined
// with the formatted type names and values of the template arguments, with
// the exception that the template placeholder types are formatted to
// indicate their position in the template parameter list.  Some examples:
// 
//    name   template-parm-list    specialization     result
//    ====   ==================    ==============     =====================
//    A      <class M, class N>    <M,N*>             A<$0,$1*>
//    A      <class M>             <M,M*>             A<$0*,$1*>
//    A      <>                    <int,char**>       A<int,char**>
//
// For nested template declarations, the index variables have an additional
// number indicating their template nesting level in addition to parameter
// position.  For example:
//    template <class T1> class A {
//       template <class T2> class B {};
//    };
// Yields A<$0>::B<$0_1> for the name of the inner class template.
//
// Inputs:
//    const JLStr&               name
//                                     The name of the declaration
//    TemplateArgumentListRefI   specializationArgList
//                                     List of template specialization
//                                     arguments. May be empty
///////////////////////////////////////////////////////////////////
JLStr
CPPSymTable::FormatClassSpecializationName(
   const JLStr& name,
   TemplateArgumentListRefI specializationArgList
)
{
   JLStr specializedName = name;
   specializedName += "<";
   assert(specializationArgList->size() != 0);
   for (
      TemplateArgumentList::iterator iter = specializationArgList->begin();
      iter != specializationArgList->end();
      iter++
   )
   {
      if (iter != specializationArgList->begin())
      {
         specializedName += ",";
      }
      specializedName += (*iter)->Format();
   }
   specializedName += ">";
   return specializedName;
}

///////////////////////////////////////////////////////////////////
// FormatClassSpecializationName: Given the name of a primary templated
// class, and the formal template parameters,
// sythesize a name for the decl/scope that is unique compared with
// other possible specializations.
//
// This constructs a name composed of the raw name combined
// with the template placeholder types formatted to
// indicate their position in the template parameter list.  Some examples:
// 
//    name   template-parm-list    result
//    ====   ==================    ===========
//    A      <class M, class N>    A<$0,$1>
//    A      <int I, class N>      A<#0,$1>
//
// Inputs:
//    const JLStr&               name
//                                     The name of the declaration
//    TemplateParameterListRefI  templateParameterList
//                                     List of formal template parameters
///////////////////////////////////////////////////////////////////
JLStr
CPPSymTable::FormatClassSpecializationName(
   const JLStr& name,
   TemplateParameterListRefI templateParameterList
)
{
   JLStr specializedName = name;
   specializedName += "<";

   for (
      TemplateParameterList::iterator iter = templateParameterList->begin();
      iter != templateParameterList->end();
      iter++
   )
   {
      if (iter != templateParameterList->begin())
      {
         specializedName += ",";
      }
      specializedName += (*iter)->Format();
   }

   specializedName += ">";
   return specializedName;
}


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions