diff --git a/Source/cmCableCommand.h b/Source/cmCableCommand.h index b00c19930..211b70e23 100644 --- a/Source/cmCableCommand.h +++ b/Source/cmCableCommand.h @@ -21,7 +21,15 @@ #include "cmCabilData.h" /** \class cmCabilCommand - * \brief Superclass for all CABIL_ command classes. + * \brief Superclass for all cmCabil command classes. + * + * cmCabilCommand is the superclass for all CABIL-related commands. + * The C++ Automated Bindings for Interpreted Languages (CABIL, + * pronounced "sawbill") tool is configured using an XML input file. + * The input format is quite flexible, but XML is hard for humans to + * write by hand. The CABIL commands in CMake are designed to simplify + * the interface with only a small loss in functionality. These commands + * can be used to automatically generate CABIL configuration files. */ class cmCabilCommand : public cmCommand { diff --git a/Source/cmCableDefineSetCommand.cxx b/Source/cmCableDefineSetCommand.cxx index e1f137711..725ea0e9f 100644 --- a/Source/cmCableDefineSetCommand.cxx +++ b/Source/cmCableDefineSetCommand.cxx @@ -16,6 +16,8 @@ #include "cmCabilDefineSetCommand.h" #include "cmCacheManager.h" +#include "cmRegularExpression.h" + // cmCabilDefineSetCommand bool cmCabilDefineSetCommand::Invoke(std::vector& args) @@ -34,7 +36,7 @@ bool cmCabilDefineSetCommand::Invoke(std::vector& args) // The rest of the arguments are the elements to be placed in the set. for(; arg != args.end(); ++arg) { - m_Elements.push_back(*arg); + m_Elements.push_back(Element(this->GenerateTag(*arg), *arg)); } return true; @@ -46,11 +48,109 @@ bool cmCabilDefineSetCommand::Invoke(std::vector& args) */ void cmCabilDefineSetCommand::WriteConfiguration(std::ostream& os) const { + cmRegularExpression needCdataBlock("[&<>]"); + os << " " << std::endl; for(Elements::const_iterator e = m_Elements.begin(); e != m_Elements.end(); ++e) { - os << " " << e->c_str() << "" << std::endl; + os << " first.length() > 0) + { + os << " tag=\"" << e->first.c_str() << "\""; + } + os << ">"; + if(needCdataBlock.find(e->second.c_str())) + { + os << "second.c_str() << "]]>"; + } + else + { + os << e->second.c_str(); + } + os << "" << std::endl; } os << " " << std::endl; } + + +/** + * Given the string representing a set element, automatically generate + * the CABIL element tag for it. + * + * **This function determines how the output language of all + * CABIL-generated wrappers will look!** + */ +std::string +cmCabilDefineSetCommand::GenerateTag(const std::string& element) const +{ + // Hold the regular expressions for matching against the element. + cmRegularExpression regex; + + // If the element's code begins in a $, it is referring to a set name. + // The set's elements have their own tags, so we don't need one. + regex.compile("^[ \t]*\\$"); + if(regex.find(element)) + { return ""; } + + // Test for simple integer + regex.compile("^[ \t]*([0-9]*)[ \t]*$"); + if(regex.find(element)) + { + std::string tag = "_"; + tag.append(regex.match(1)); + return tag; + } + + // Test for basic integer type + regex.compile("^[ \t]*(unsigned[ ]|signed[ ])?[ \t]*(char|short|int|long|long[ ]long)[ \t]*$"); + if(regex.find(element)) + { + std::string tag = "_"; + if(regex.match(1) == "unsigned ") + { tag.append("u"); } + if(regex.match(2) == "long long") + { tag.append("llong"); } + else + { tag.append(regex.match(2)); } + return tag; + } + + // Test for basic floating-point type + regex.compile("^[ \t]*(long[ ])?[ \t]*(float|double)[ \t]*$"); + if(regex.find(element)) + { + std::string tag = "_"; + if(regex.match(1) == "long ") + tag.append("l"); + tag.append(regex.match(2)); + return tag; + } + + // Test for basic wide-character type + regex.compile("^[ \t]*(wchar_t)[ \t]*$"); + if(regex.find(element)) + { + return "_wchar"; + } + + // Test for plain type name (without template arguments). + regex.compile("^[ \t]*([A-Za-z_][A-Za-z0-9_]*)[ \t]*$"); + if(regex.find(element)) + { + // The tag is the same as the type. + return regex.match(1); + } + + // Test for template class instance. + regex.compile("^[ \t]*([A-Za-z_][A-Za-z0-9_]*)<.*[ \t]*$"); + if(regex.find(element)) + { + // The tag is the type without arguments (the arguments may have + // their own tags). + return regex.match(1); + } + + return "NO_AUTO_TAG"; +} diff --git a/Source/cmCableDefineSetCommand.h b/Source/cmCableDefineSetCommand.h index 345ac0633..3d598b130 100644 --- a/Source/cmCableDefineSetCommand.h +++ b/Source/cmCableDefineSetCommand.h @@ -69,14 +69,22 @@ public: virtual const char* GetFullDocumentation() { return - "CABIL_DEFINE_SET(name_of_set member1 member2 ...)"; + "CABIL_DEFINE_SET(name_of_set member1 member2 ...)\n" + "Generates a Set definition in the CABIL configuration. Tags are\n" + "automatically generated. The sets are referenced in other CABIL\n" + "commands by a '$' immediately followed by the set name (ex. $SetName)."; } virtual void WriteConfiguration(std::ostream&) const; cmTypeMacro(cmCabilDefineSetCommand, cmCabilCommand); + +private: + std::string GenerateTag(const std::string&) const; + private: - typedef std::vector Elements; + typedef std::pair Element; + typedef std::vector Elements; /** * The name of the set. diff --git a/Source/cmCableInstantiateClassCommand.cxx b/Source/cmCableInstantiateClassCommand.cxx new file mode 100644 index 000000000..249163277 --- /dev/null +++ b/Source/cmCableInstantiateClassCommand.cxx @@ -0,0 +1,47 @@ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) 2000 National Library of Medicine + All rights reserved. + + See COPYRIGHT.txt for copyright details. + +=========================================================================*/ +#include "cmCabilInstantiateClassCommand.h" +#include "cmCacheManager.h" + +#include "cmRegularExpression.h" + + +/** + * Write the CABIL configuration code to define this InstantiationSet. + * This includes the "class" keyword to do class template instantiations. + */ +void cmCabilInstantiateClassCommand::WriteConfiguration(std::ostream& os) const +{ + cmRegularExpression needCdataBlock("[&<>]"); + + os << std::endl + << " " << std::endl; + for(Elements::const_iterator e = m_Elements.begin(); + e != m_Elements.end(); ++e) + { + os << " class "; + if(needCdataBlock.find(e->c_str())) + { + os << "c_str() << "]]>"; + } + else + { + os << e->c_str(); + } + os << "" << std::endl; + } + os << " " << std::endl; +} diff --git a/Source/cmCableInstantiateClassCommand.h b/Source/cmCableInstantiateClassCommand.h new file mode 100644 index 000000000..b02b28a33 --- /dev/null +++ b/Source/cmCableInstantiateClassCommand.h @@ -0,0 +1,75 @@ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) 2000 National Library of Medicine + All rights reserved. + + See COPYRIGHT.txt for copyright details. + +=========================================================================*/ +#ifndef cmCabilInstantiateClassCommand_h +#define cmCabilInstantiateClassCommand_h + +#include "cmStandardIncludes.h" +#include "cmCabilInstantiateCommand.h" + +/** \class cmCabilInstantiateClassCommand + * \brief Define a command that generates a rule for explicit template + * instantiations of classes. + * + * cmCabilInstantiateCommand is used to generate a rule in a CABIL + * configuration file to create explicit template instantiations of + * classes. + */ +class cmCabilInstantiateClassCommand : public cmCabilInstantiateCommand +{ +public: + /** + * This is a virtual constructor for the command. + */ + virtual cmCommand* Clone() + { + return new cmCabilInstantiateClassCommand; + } + + /** + * The name of the command as specified in CMakeList.txt. + */ + virtual const char* GetName() { return "CABIL_INSTANTIATE_CLASS";} + + /** + * Succinct documentation. + */ + virtual const char* GetTerseDocumentation() + { + return "Define CABIL InstantiationSet of classes."; + } + + /** + * More documentation. + */ + virtual const char* GetFullDocumentation() + { + return + "CABIL_INSTANTIATE_CLASS(cabil_config_file member1 member2 ...)\n" + "Generates an InstantiationSet in the CABIL configuration. It is\n" + "assumed that all members of the set are explicit instantiations of\n" + "template classes (not functions, operators, etc)."; + } + + virtual void WriteConfiguration(std::ostream&) const; + + cmTypeMacro(cmCabilInstantiateClassCommand, cmCabilInstantiateCommand); +protected: + typedef cmCabilInstantiateCommand::Elements Elements; +}; + + + +#endif diff --git a/Source/cmCableInstantiateCommand.cxx b/Source/cmCableInstantiateCommand.cxx index c82eabb9c..b30a1c531 100644 --- a/Source/cmCableInstantiateCommand.cxx +++ b/Source/cmCableInstantiateCommand.cxx @@ -17,6 +17,7 @@ #include "cmCacheManager.h" #include "cmCabilDefineSetCommand.h" +#include "cmRegularExpression.h" // cmCabilInstantiateCommand bool cmCabilInstantiateCommand::Invoke(std::vector& args) @@ -97,12 +98,23 @@ void cmCabilInstantiateCommand::FinalPass() */ void cmCabilInstantiateCommand::WriteConfiguration(std::ostream& os) const { + cmRegularExpression needCdataBlock("[&<>]"); + os << std::endl << " " << std::endl; for(Elements::const_iterator e = m_Elements.begin(); e != m_Elements.end(); ++e) { - os << " " << e->c_str() << "" << std::endl; + os << " "; + if(needCdataBlock.find(e->c_str())) + { + os << "c_str() << "]]>"; + } + else + { + os << e->c_str(); + } + os << "" << std::endl; } os << " " << std::endl; } diff --git a/Source/cmCableInstantiateCommand.h b/Source/cmCableInstantiateCommand.h index 477fee2e8..1bb37222d 100644 --- a/Source/cmCableInstantiateCommand.h +++ b/Source/cmCableInstantiateCommand.h @@ -65,7 +65,7 @@ public: */ virtual const char* GetTerseDocumentation() { - return "Define a rule for creating explicit template instantiations."; + return "Define CABIL InstantiationSet."; } /** @@ -74,13 +74,16 @@ public: virtual const char* GetFullDocumentation() { return - "CABIL_INSTANTIATE(cabil_config_file member1 member2 ...)"; + "CABIL_INSTANTIATE(cabil_config_file member1 member2 ...)\n" + "Generates an InstantiationSet in the CABIL configuration. It is\n" + "assumed that all members of the set are explicit instantiations of\n" + "template non-classes (functions, operators, etc)."; } virtual void WriteConfiguration(std::ostream&) const; cmTypeMacro(cmCabilInstantiateCommand, cmCabilCommand); -private: +protected: typedef std::vector Elements; /** diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index a2e6c5ab2..b693495ef 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -28,6 +28,7 @@ #include "cmCabilData.cxx" #include "cmCabilDefineSetCommand.cxx" #include "cmCabilInstantiateCommand.cxx" +#include "cmCabilInstantiateClassCommand.cxx" #include "cmFindFileCommand.cxx" #include "cmWrapTclCommand.cxx" @@ -56,6 +57,7 @@ void GetPredefinedCommands(std::list& commands) commands.push_back(new cmConfigureFileNoAutoconf); commands.push_back(new cmCabilDefineSetCommand); commands.push_back(new cmCabilInstantiateCommand); + commands.push_back(new cmCabilInstantiateClassCommand); commands.push_back(new cmFindFileCommand); commands.push_back(new cmWrapTclCommand); }