ENH: Added cable class-set expansion and tagging for alternate name generation. This should make the generated wrappers much easier to setup and use.
This commit is contained in:
parent
cb858f511e
commit
6d54c3d6f8
|
@ -62,11 +62,24 @@ void cmCableClass::AddSource(const char* source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The destructor frees all the cmCableClass instances in the set.
|
||||||
|
*/
|
||||||
|
cmCableClassSet::~cmCableClassSet()
|
||||||
|
{
|
||||||
|
for(CableClassMap::const_iterator i = m_CableClassMap.begin();
|
||||||
|
i != m_CableClassMap.end(); ++i)
|
||||||
|
{
|
||||||
|
delete i->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a class to the set.
|
* Add a class to the set.
|
||||||
*/
|
*/
|
||||||
void cmCableClassSet::AddClass(const char* name,
|
void cmCableClassSet::AddClass(const char* name,
|
||||||
const cmCableClass& cableClass)
|
cmCableClass* cableClass)
|
||||||
{
|
{
|
||||||
m_CableClassMap.insert(CableClassMap::value_type(name, cableClass));
|
m_CableClassMap.insert(CableClassMap::value_type(name, cableClass));
|
||||||
}
|
}
|
||||||
|
@ -81,10 +94,11 @@ void cmCableClassSet::AddSource(const char* name)
|
||||||
for(CableClassMap::iterator c = m_CableClassMap.begin();
|
for(CableClassMap::iterator c = m_CableClassMap.begin();
|
||||||
c != m_CableClassMap.end(); ++c)
|
c != m_CableClassMap.end(); ++c)
|
||||||
{
|
{
|
||||||
c->second.AddSource(name);
|
c->second->AddSource(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the size of the internal CableClassMap used to store the set.
|
* Get the size of the internal CableClassMap used to store the set.
|
||||||
*/
|
*/
|
||||||
|
@ -113,100 +127,638 @@ cmCableClassSet::CableClassMap::const_iterator cmCableClassSet::End() const
|
||||||
return m_CableClassMap.end();
|
return m_CableClassMap.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the given string to extract the class information specified.
|
* A utility class to generate element combinations from all possible
|
||||||
|
* substitutions of set members into a $ token.
|
||||||
|
*/
|
||||||
|
class ElementCombinationGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ElementCombinationGenerator(const char* in_element, cmMakefile* in_makefile,
|
||||||
|
cmCableClassSet* out_set):
|
||||||
|
m_Makefile(in_makefile), m_OutputSet(out_set)
|
||||||
|
{
|
||||||
|
this->ParseInputElement(in_element);
|
||||||
|
}
|
||||||
|
~ElementCombinationGenerator();
|
||||||
|
|
||||||
|
void Generate();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Represent a substitution.
|
||||||
|
*/
|
||||||
|
class Substitution
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Substitution() {}
|
||||||
|
void Bind(const std::string& in_code, const cmCableClass* in_class)
|
||||||
|
{
|
||||||
|
m_Code = in_code;
|
||||||
|
m_Class = in_class;
|
||||||
|
}
|
||||||
|
const cmCableClass* GetClass() const
|
||||||
|
{ return m_Class; }
|
||||||
|
const std::string& GetCode() const
|
||||||
|
{ return m_Code; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* The cmCableClass associated with this substitution.
|
||||||
|
*/
|
||||||
|
const cmCableClass* m_Class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The code to be used for the substitution.
|
||||||
|
*/
|
||||||
|
std::string m_Code;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to the parts of an input string of code, possibly with
|
||||||
|
* $SomeSetName tokens in it. An indivitual Portion will be either
|
||||||
|
* a StringPortion, which has no substitutions, or a ReplacePortion,
|
||||||
|
* which has only a substitution, and no hard-coded text.
|
||||||
|
*
|
||||||
|
* This is used by cmCableClassSet::GenerateElementCombinations() to
|
||||||
|
* hold the pieces of a string after the set substitution tokens
|
||||||
|
* have been extracted.
|
||||||
|
*/
|
||||||
|
class Portion
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Get the C++ code corresponding to this Portion of a string.
|
||||||
|
*/
|
||||||
|
virtual std::string GetCode() const =0;
|
||||||
|
/**
|
||||||
|
* Get the class corresponding to this Portion of a string. This is NULL
|
||||||
|
* for StringPortion, and points to a cmCableClass for ReplacePortion.
|
||||||
|
*/
|
||||||
|
virtual const cmCableClass* GetClass() const
|
||||||
|
{ return NULL; }
|
||||||
|
virtual ~Portion() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent a hard-coded part of an input string, that has no substitutions
|
||||||
|
* in it. The tag for this part of a string is always empty.
|
||||||
|
*/
|
||||||
|
class StringPortion: public Portion
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StringPortion(const std::string& in_code): m_Code(in_code) {}
|
||||||
|
virtual std::string GetCode() const
|
||||||
|
{ return m_Code; }
|
||||||
|
virtual const cmCableClass* GetClass() const
|
||||||
|
{ return NULL; }
|
||||||
|
virtual ~StringPortion() {}
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Hold this Portion's contribution to the output string.
|
||||||
|
*/
|
||||||
|
std::string m_Code;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent the "$SomeSetName" portion of an input string. This has a
|
||||||
|
* reference to the Substitution holding the real output to generate.
|
||||||
|
*/
|
||||||
|
class ReplacePortion: public Portion
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ReplacePortion(const Substitution& in_substitution):
|
||||||
|
m_Substitution(in_substitution) {}
|
||||||
|
virtual std::string GetCode() const
|
||||||
|
{ return m_Substitution.GetCode(); }
|
||||||
|
virtual const cmCableClass* GetClass() const
|
||||||
|
{ return m_Substitution.GetClass(); }
|
||||||
|
virtual ~ReplacePortion() {}
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Refer to the real Substitution for this Portion's contribution.
|
||||||
|
*/
|
||||||
|
const Substitution& m_Substitution;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::list<Portion*> Portions;
|
||||||
|
typedef std::map<const cmCableClassSet*, Substitution*> Substitutions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The makefile in which to lookup set names.
|
||||||
|
*/
|
||||||
|
cmMakefile* m_Makefile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cmCableClassSet instance to be filled with combinations.
|
||||||
|
*/
|
||||||
|
cmCableClassSet* m_OutputSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class name parsed out for this element, before set expansion.
|
||||||
|
*/
|
||||||
|
std::string m_ClassName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tag name parsed out or generated for this element.
|
||||||
|
*/
|
||||||
|
std::string m_Tag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of sources parsed out for this element.
|
||||||
|
*/
|
||||||
|
cmCableClass::Sources m_Sources;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parts of the input string after parsing of the tokens.
|
||||||
|
*/
|
||||||
|
Portions m_Portions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map from substitution's Set to actual Substitution.
|
||||||
|
*/
|
||||||
|
Substitutions m_Substitutions;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Generate(Substitutions::const_iterator);
|
||||||
|
void ParseInputElement(const char*);
|
||||||
|
void SplitClassName();
|
||||||
|
std::string ParseSetName(std::string::const_iterator&,
|
||||||
|
std::string::const_iterator) const;
|
||||||
|
void FindTagSource();
|
||||||
|
bool GenerateTag(const std::string&);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor frees portions and substitutions that were allocated by
|
||||||
|
* constructor.
|
||||||
|
*/
|
||||||
|
ElementCombinationGenerator
|
||||||
|
::~ElementCombinationGenerator()
|
||||||
|
{
|
||||||
|
// Free the string portions that were allocated.
|
||||||
|
for(Portions::iterator portion = m_Portions.begin();
|
||||||
|
portion != m_Portions.end(); ++portion)
|
||||||
|
{
|
||||||
|
delete *portion;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the substitutions that were allocated.
|
||||||
|
for(Substitutions::iterator sub = m_Substitutions.begin();
|
||||||
|
sub != m_Substitutions.end(); ++sub)
|
||||||
|
{
|
||||||
|
delete sub->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate all element combinations possible with the set of
|
||||||
|
* substitutions available. The given output set is filled with
|
||||||
|
* all the combinations.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ElementCombinationGenerator
|
||||||
|
::Generate()
|
||||||
|
{
|
||||||
|
// If there are no substitutions to be made, just generate this
|
||||||
|
// single combination.
|
||||||
|
if(m_Substitutions.empty())
|
||||||
|
{
|
||||||
|
cmCableClass* cableClass = new cmCableClass(m_Tag);
|
||||||
|
cableClass->AddSources(m_Sources);
|
||||||
|
m_OutputSet->AddClass(m_ClassName.c_str(), cableClass);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We must generate all combinations of substitutions.
|
||||||
|
// Begin the recursion with the first substitution.
|
||||||
|
this->Generate(m_Substitutions.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal helper to Generate() which generates all
|
||||||
|
* combinations in a recursive, depth-first order.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ElementCombinationGenerator
|
||||||
|
::Generate(Substitutions::const_iterator substitution)
|
||||||
|
{
|
||||||
|
// Test our position in the list of substitutions to be bound.
|
||||||
|
if(substitution == m_Substitutions.end())
|
||||||
|
{
|
||||||
|
// All substitutions have been prepared. Generate this combination.
|
||||||
|
std::string tag = m_Tag;
|
||||||
|
std::string code = "";
|
||||||
|
|
||||||
|
// The set of sources for the generated combination. It will
|
||||||
|
// always include the sources parsed from the original element
|
||||||
|
// string.
|
||||||
|
cmCableClass::Sources sources = m_Sources;
|
||||||
|
|
||||||
|
// Put together all the pieces, with substitutions.
|
||||||
|
for(Portions::const_iterator i = m_Portions.begin();
|
||||||
|
i != m_Portions.end(); ++i)
|
||||||
|
{
|
||||||
|
// See if there is a class associated with this portion.
|
||||||
|
const cmCableClass* curClassPortion = (*i)->GetClass();
|
||||||
|
if(curClassPortion)
|
||||||
|
{
|
||||||
|
// Append the tag from the class portion.
|
||||||
|
tag.append(curClassPortion->GetTag());
|
||||||
|
|
||||||
|
// Include any sources needed by the class in this combination's set.
|
||||||
|
for(cmCableClass::Sources::const_iterator
|
||||||
|
s = curClassPortion->SourcesBegin();
|
||||||
|
s != curClassPortion->SourcesEnd(); ++s)
|
||||||
|
{
|
||||||
|
sources.insert(*s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the portion's code to this combination's code.
|
||||||
|
code.append((*i)->GetCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add this combination to the output set.
|
||||||
|
cmCableClass* cableClass = new cmCableClass(tag);
|
||||||
|
cableClass->AddSources(sources);
|
||||||
|
m_OutputSet->AddClass(code.c_str(), cableClass);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Get the set for this substitution.
|
||||||
|
const cmCableClassSet* set = substitution->first;
|
||||||
|
if(set == m_OutputSet)
|
||||||
|
{
|
||||||
|
// We cannot iterate over the set currently being defined.
|
||||||
|
cmSystemTools::Error("CABLE class set self-reference!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare an iterator to the next substitution.
|
||||||
|
Substitutions::const_iterator nextSubstitution = substitution;
|
||||||
|
++nextSubstitution;
|
||||||
|
|
||||||
|
// We must iterate over all possible values for this substitution.
|
||||||
|
for(cmCableClassSet::CableClassMap::const_iterator element = set->Begin();
|
||||||
|
element != set->End(); ++element)
|
||||||
|
{
|
||||||
|
// Bind the substitution to this element.
|
||||||
|
substitution->second->Bind(element->first, element->second);
|
||||||
|
|
||||||
|
// Move on to the next substitution.
|
||||||
|
this->Generate(nextSubstitution);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called from constructor. Parses the given string to extract the
|
||||||
|
* class information specified.
|
||||||
*
|
*
|
||||||
* The format of the string is
|
* The format of the string is
|
||||||
* [tag:]class_name[;source1;source2;...]
|
* [tag:]class_name[;source1;source2;...]
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
void cmCableClassSet::ParseAndAddElement(const char* element,
|
void
|
||||||
cmMakefile* makefile)
|
ElementCombinationGenerator
|
||||||
|
::ParseInputElement(const char* in_element)
|
||||||
{
|
{
|
||||||
// A regular expression to match the tagged element specification.
|
// A regular expression to match the tagged element specification.
|
||||||
cmRegularExpression tagGiven("^([A-Za-z_0-9]*)[ \t]*:[ \t]*([^:].*|::.*)$");
|
cmRegularExpression taggedElement =
|
||||||
|
"^([A-Za-z_0-9]*)[ \t]*:[ \t]*([^:].*|::.*)$";
|
||||||
|
|
||||||
// A regular expression to match the element when more source files are given.
|
// A regular expression to match the element when more source files are given.
|
||||||
cmRegularExpression sourcesRemain("^([^;]*);(.*)$");
|
cmRegularExpression sourcesRemain("^([^;]*);(.*)$");
|
||||||
|
|
||||||
std::string tag;
|
|
||||||
std::string elementWithoutTag;
|
std::string elementWithoutTag;
|
||||||
std::string className;
|
|
||||||
std::string sourceString;
|
std::string sourceString;
|
||||||
|
bool tagGiven = false;
|
||||||
|
|
||||||
if(tagGiven.find(element))
|
// See if the element was tagged, and if so, pull off the tag.
|
||||||
|
if(taggedElement.find(in_element))
|
||||||
{
|
{
|
||||||
// A tag was given. Use it.
|
// A tag was given. Use it.
|
||||||
tag = tagGiven.match(1);
|
tagGiven = true;
|
||||||
elementWithoutTag = tagGiven.match(2);
|
m_Tag = taggedElement.match(1);
|
||||||
|
elementWithoutTag = taggedElement.match(2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No tag was given. Try to generate one.
|
// No tag was given. We will try to generate it later.
|
||||||
//if(!this->GenerateTag(element, tag))
|
elementWithoutTag = in_element;
|
||||||
// { return false; }
|
|
||||||
elementWithoutTag = element;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Separate the class name.
|
||||||
if(sourcesRemain.find(elementWithoutTag.c_str()))
|
if(sourcesRemain.find(elementWithoutTag.c_str()))
|
||||||
{
|
{
|
||||||
className = sourcesRemain.match(1);
|
m_ClassName = sourcesRemain.match(1);
|
||||||
sourceString = sourcesRemain.match(2);
|
sourceString = sourcesRemain.match(2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
className = elementWithoutTag;
|
m_ClassName = elementWithoutTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmCableClass::Sources sources;
|
// Find any source files specified with the ";source" syntax.
|
||||||
|
|
||||||
while(sourcesRemain.find(sourceString.c_str()))
|
while(sourcesRemain.find(sourceString.c_str()))
|
||||||
{
|
{
|
||||||
sources.insert(sourcesRemain.match(1));
|
m_Sources.insert(sourcesRemain.match(1));
|
||||||
sourceString = sourcesRemain.match(2);
|
sourceString = sourcesRemain.match(2);
|
||||||
}
|
}
|
||||||
if(sourceString != "")
|
if(sourceString != "")
|
||||||
{
|
{
|
||||||
sources.insert(sourceString);
|
m_Sources.insert(sourceString);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A regular expression to match a class name that is just a set.
|
// If no tag was given, try to generate one.
|
||||||
cmRegularExpression setDereference("^\\$(.*)$");
|
if(!tagGiven)
|
||||||
if(setDereference.find(className))
|
|
||||||
{
|
{
|
||||||
std::string setName = setDereference.match(1);
|
if(!this->GenerateTag(m_ClassName))
|
||||||
cmData* d = makefile->LookupData(setName.c_str());
|
{
|
||||||
|
cmSystemTools::Error("Cannot generate tag for class name: ",
|
||||||
|
m_ClassName.c_str(),
|
||||||
|
"\nPlease supply one with the \"tag:..\" syntax.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a .h with the name of the tag, add it as a source.
|
||||||
|
this->FindTagSource();
|
||||||
|
|
||||||
|
// Split the class name up into portions for the combination
|
||||||
|
// generation method.
|
||||||
|
this->SplitClassName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the class name into portions. Plain text in the string is
|
||||||
|
* held by a StringPortion, and a $ token for replacement is
|
||||||
|
* represented by a ReplacePortion.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ElementCombinationGenerator
|
||||||
|
::SplitClassName()
|
||||||
|
{
|
||||||
|
// Break the input code into blocks alternating between literal code and
|
||||||
|
// set-substitution tokens (like $SomeSetName).
|
||||||
|
std::string currentPortion = "";
|
||||||
|
for(std::string::const_iterator c=m_ClassName.begin();
|
||||||
|
c != m_ClassName.end(); ++c)
|
||||||
|
{
|
||||||
|
// Look for the '$' to mark the beginning of a token.
|
||||||
|
if(*c != '$')
|
||||||
|
{
|
||||||
|
currentPortion.insert(currentPortion.end(), *c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If there is a portion of the string, record it.
|
||||||
|
if(currentPortion.length() > 0)
|
||||||
|
{
|
||||||
|
m_Portions.push_back(new StringPortion(currentPortion));
|
||||||
|
currentPortion = "";
|
||||||
|
}
|
||||||
|
// Skip over the '$' character.
|
||||||
|
++c;
|
||||||
|
// Get element set name token.
|
||||||
|
std::string setName = this->ParseSetName(c, m_ClassName.end());
|
||||||
|
|
||||||
|
// We have a complete set name. Look it up in makefile's data
|
||||||
|
// collection.
|
||||||
|
cmData* d = m_Makefile->LookupData(setName.c_str());
|
||||||
// This should be a dynamic_cast, but we don't want to require RTTI.
|
// This should be a dynamic_cast, but we don't want to require RTTI.
|
||||||
cmCableClassSet* classSet = static_cast<cmCableClassSet*>(d);
|
cmCableClassSet* set = static_cast<cmCableClassSet*>(d);
|
||||||
if(classSet)
|
if(set)
|
||||||
{
|
{
|
||||||
this->AddCableClassSet(*classSet, sources);
|
// We have a valid set name. Prepare the substitution entry
|
||||||
|
// for it.
|
||||||
|
Substitution* sub;
|
||||||
|
if(m_Substitutions.count(set) == 0)
|
||||||
|
{
|
||||||
|
sub = new Substitution();
|
||||||
|
m_Substitutions[set] = sub;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmSystemTools::Error("Unknown CABLE class set ", setName.c_str());
|
sub = m_Substitutions[set];
|
||||||
}
|
}
|
||||||
|
m_Portions.push_back(new ReplacePortion(*sub));
|
||||||
|
setName = "";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmCableClass cableClass;
|
// Invalid set name. Complain.
|
||||||
cableClass.AddSources(sources);
|
cmSystemTools::Error("Unknown name of CABLE class set: ",
|
||||||
this->AddClass(className.c_str(), cableClass);
|
setName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let the loop look at this character again.
|
||||||
|
--c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a final portion of the string, record it.
|
||||||
|
if(currentPortion.length() > 0)
|
||||||
|
{
|
||||||
|
m_Portions.push_back(new StringPortion(currentPortion));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add all elements from the given cmCableClassSet to this set, with the given
|
* Parse out the name of a Set specified after a $ in the element's string.
|
||||||
* sources added to each element.
|
* This is called with "c" pointing to the first character after the $,
|
||||||
|
* and "end" equal to the string's end iterator.
|
||||||
|
*
|
||||||
|
* Returns the set name after parsing. "c" will point to the first
|
||||||
|
* character after the end of the set name.
|
||||||
*/
|
*/
|
||||||
void cmCableClassSet::AddCableClassSet(const cmCableClassSet& set,
|
std::string
|
||||||
const cmCableClass::Sources& sources)
|
ElementCombinationGenerator
|
||||||
|
::ParseSetName(std::string::const_iterator& c, std::string::const_iterator end) const
|
||||||
{
|
{
|
||||||
for(CableClassMap::const_iterator c = set.Begin(); c != set.End(); ++c)
|
std::string setName = "";
|
||||||
|
|
||||||
|
// Check for the $(setName) syntax.
|
||||||
|
// If the first character after the '$' is a left paren, we scan for the
|
||||||
|
// matching paren, and take everything in-between as the set name.
|
||||||
|
if((c != end) && (*c == '('))
|
||||||
{
|
{
|
||||||
cmCableClass cableClass = c->second;
|
unsigned int depth = 1;
|
||||||
cableClass.AddSources(sources);
|
++c;
|
||||||
this->AddClass(c->first.c_str(), cableClass);
|
while(c != end)
|
||||||
|
{
|
||||||
|
char ch = *c++;
|
||||||
|
if(ch == '(') { ++depth; }
|
||||||
|
else if(ch == ')') { --depth; }
|
||||||
|
if(depth == 0) { break; }
|
||||||
|
setName.insert(setName.end(), ch);
|
||||||
|
}
|
||||||
|
return setName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The $(setName) syntax was not used.
|
||||||
|
// Look for all characters that can be part of a qualified C++
|
||||||
|
// identifier.
|
||||||
|
while(c != end)
|
||||||
|
{
|
||||||
|
char ch = *c;
|
||||||
|
if(((ch >= 'a') && (ch <= 'z'))
|
||||||
|
|| ((ch >= 'A') && (ch <= 'Z'))
|
||||||
|
|| ((ch >= '0') && (ch <= '9'))
|
||||||
|
|| (ch == '_') || (ch == ':'))
|
||||||
|
{
|
||||||
|
setName.insert(setName.end(), ch);
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return setName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After the tag for an element has been determined, but before
|
||||||
|
* combination expansion is done, this is called to search for a
|
||||||
|
* header file in the makefile's include path with the name of the
|
||||||
|
* tag. This makes specifying lists of classes that are declared in
|
||||||
|
* header files with their own name very convenient.
|
||||||
|
*/
|
||||||
|
void ElementCombinationGenerator::FindTagSource()
|
||||||
|
{
|
||||||
|
// If there is no tag, don't bother with this step.
|
||||||
|
if(m_Tag == "")
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the makefile's include path.
|
||||||
|
const std::vector<std::string>& includePath =
|
||||||
|
m_Makefile->GetIncludeDirectories();
|
||||||
|
|
||||||
|
// Search the path for a file called "(m_Tag).h".
|
||||||
|
for(std::vector<std::string>::const_iterator dir = includePath.begin();
|
||||||
|
dir != includePath.end(); ++dir)
|
||||||
|
{
|
||||||
|
std::string filePath = *dir;
|
||||||
|
m_Makefile->ExpandVariablesInString(filePath);
|
||||||
|
filePath += "/"+m_Tag+".h";
|
||||||
|
if(cmSystemTools::FileExists(filePath.c_str()))
|
||||||
|
{
|
||||||
|
m_Sources.insert(m_Tag+".h");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given the string representing a set element, automatically generate
|
||||||
|
* the element tag for it. This function determines how the output
|
||||||
|
* language of all CABLE-generated wrappers will look.
|
||||||
|
*/
|
||||||
|
bool ElementCombinationGenerator::GenerateTag(const std::string& element)
|
||||||
|
{
|
||||||
|
// 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))
|
||||||
|
{ m_Tag = ""; return true; }
|
||||||
|
|
||||||
|
// Test for simple integer
|
||||||
|
regex.compile("^[ \t]*([0-9]*)[ \t]*$");
|
||||||
|
if(regex.find(element))
|
||||||
|
{
|
||||||
|
m_Tag = "_";
|
||||||
|
m_Tag.append(regex.match(1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for basic integer type
|
||||||
|
regex.compile("^[ \t]*(unsigned[ ]|signed[ ])?[ \t]*(char|short|int|long|long[ ]long)[ \t]*$");
|
||||||
|
if(regex.find(element))
|
||||||
|
{
|
||||||
|
m_Tag = "_";
|
||||||
|
if(regex.match(1) == "unsigned ")
|
||||||
|
{ m_Tag.append("u"); }
|
||||||
|
if(regex.match(2) == "long long")
|
||||||
|
{ m_Tag.append("llong"); }
|
||||||
|
else
|
||||||
|
{ m_Tag.append(regex.match(2)); }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for basic floating-point type
|
||||||
|
regex.compile("^[ \t]*(long[ ])?[ \t]*(float|double)[ \t]*$");
|
||||||
|
if(regex.find(element))
|
||||||
|
{
|
||||||
|
m_Tag = "_";
|
||||||
|
if(regex.match(1) == "long ")
|
||||||
|
m_Tag.append("l");
|
||||||
|
m_Tag.append(regex.match(2));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for basic wide-character type
|
||||||
|
regex.compile("^[ \t]*(wchar_t)[ \t]*$");
|
||||||
|
if(regex.find(element))
|
||||||
|
{
|
||||||
|
m_Tag = "_wchar";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for type name (possibly with 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. If there were template arguments,
|
||||||
|
// they are ignored since they may have their own tags.
|
||||||
|
m_Tag = regex.match(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for a name with a single namespace qualifier.
|
||||||
|
regex.compile("^[ \t]*([A-Za-z_][A-Za-z0-9_]*)::([A-Za-z_][A-Za-z0-9_]*)(<.*)?[ \t]*$");
|
||||||
|
if(regex.find(element))
|
||||||
|
{
|
||||||
|
// The tag is the same as the namespace and type concatenated together.
|
||||||
|
m_Tag = regex.match(1);
|
||||||
|
m_Tag.append(regex.match(2));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't generate a tag.
|
||||||
|
m_Tag = "";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an element in string form, parse out the information from it,
|
||||||
|
* generate the combinations of set substitutions, and add all the
|
||||||
|
* elements that result.
|
||||||
|
*/
|
||||||
|
void cmCableClassSet::ParseAndAddElement(const char* in_element,
|
||||||
|
cmMakefile* makefile)
|
||||||
|
{
|
||||||
|
// Create an object to handle the generation.
|
||||||
|
ElementCombinationGenerator combinationGenerator(in_element, makefile, this);
|
||||||
|
|
||||||
|
// Generate the combinations.
|
||||||
|
combinationGenerator.Generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,8 @@ class cmCableClass
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::set<std::string> Sources;
|
typedef std::set<std::string> Sources;
|
||||||
|
cmCableClass() {}
|
||||||
|
cmCableClass(const std::string& tag): m_Tag(tag) {}
|
||||||
|
|
||||||
void AddSources(const Sources& sources);
|
void AddSources(const Sources& sources);
|
||||||
void AddSource(const char*);
|
void AddSource(const char*);
|
||||||
|
@ -60,7 +62,14 @@ public:
|
||||||
Sources::const_iterator SourcesBegin() const { return m_Sources.begin(); }
|
Sources::const_iterator SourcesBegin() const { return m_Sources.begin(); }
|
||||||
Sources::const_iterator SourcesEnd() const { return m_Sources.end(); }
|
Sources::const_iterator SourcesEnd() const { return m_Sources.end(); }
|
||||||
|
|
||||||
|
const std::string& GetTag() const { return m_Tag; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* The tag name of this class.
|
||||||
|
*/
|
||||||
|
std::string m_Tag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store the set of source files (headers) needed to define this class.
|
* Store the set of source files (headers) needed to define this class.
|
||||||
*/
|
*/
|
||||||
|
@ -75,22 +84,21 @@ class cmCableClassSet: public cmData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cmCableClassSet(const char* name): cmData(name) {}
|
cmCableClassSet(const char* name): cmData(name) {}
|
||||||
virtual ~cmCableClassSet() {}
|
virtual ~cmCableClassSet();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The set is stored internally as a map from class name to cmCableClass
|
* The set is stored internally as a map from class name to cmCableClass
|
||||||
* instance.
|
* instance.
|
||||||
*/
|
*/
|
||||||
typedef std::map<std::string, cmCableClass> CableClassMap;
|
typedef std::map<std::string, cmCableClass*> CableClassMap;
|
||||||
|
|
||||||
void AddClass(const char*, const cmCableClass&);
|
void AddClass(const char*, cmCableClass*);
|
||||||
void AddSource(const char* name);
|
void AddSource(const char* name);
|
||||||
unsigned int Size() const;
|
unsigned int Size() const;
|
||||||
CableClassMap::const_iterator Begin() const;
|
CableClassMap::const_iterator Begin() const;
|
||||||
CableClassMap::const_iterator End() const;
|
CableClassMap::const_iterator End() const;
|
||||||
|
|
||||||
void ParseAndAddElement(const char*, cmMakefile*);
|
void ParseAndAddElement(const char*, cmMakefile*);
|
||||||
void AddCableClassSet(const cmCableClassSet&, const cmCableClass::Sources&);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -51,6 +51,13 @@ bool cmCableClassSetCommand::InitialPass(std::vector<std::string>& args)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First, we want to expand all CMAKE variables in all arguments.
|
||||||
|
for(std::vector<std::string>::iterator a = args.begin();
|
||||||
|
a != args.end(); ++a)
|
||||||
|
{
|
||||||
|
m_Makefile->ExpandVariablesInString(*a);
|
||||||
|
}
|
||||||
|
|
||||||
// The first argument is the name of the set.
|
// The first argument is the name of the set.
|
||||||
std::vector<std::string>::const_iterator arg = args.begin();
|
std::vector<std::string>::const_iterator arg = args.begin();
|
||||||
m_ClassSetName = *arg++;
|
m_ClassSetName = *arg++;
|
||||||
|
|
|
@ -68,6 +68,13 @@ bool cmCableWrapTclCommand::InitialPass(std::vector<std::string>& args)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First, we want to expand all CMAKE variables in all arguments.
|
||||||
|
for(std::vector<std::string>::iterator a = args.begin();
|
||||||
|
a != args.end(); ++a)
|
||||||
|
{
|
||||||
|
m_Makefile->ExpandVariablesInString(*a);
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare to iterate through the arguments.
|
// Prepare to iterate through the arguments.
|
||||||
std::vector<std::string>::const_iterator arg = args.begin();
|
std::vector<std::string>::const_iterator arg = args.begin();
|
||||||
|
|
||||||
|
@ -167,7 +174,7 @@ void cmCableWrapTclCommand::GenerateCableFiles() const
|
||||||
for(cmCableClassSet::CableClassMap::const_iterator
|
for(cmCableClassSet::CableClassMap::const_iterator
|
||||||
c = m_CableClassSet->Begin(); c != m_CableClassSet->End(); ++c, ++index)
|
c = m_CableClassSet->Begin(); c != m_CableClassSet->End(); ++c, ++index)
|
||||||
{
|
{
|
||||||
this->GenerateCableClassFiles(c->first.c_str(), c->second, index);
|
this->GenerateCableClassFiles(c->first.c_str(), *(c->second), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -204,7 +211,14 @@ void cmCableWrapTclCommand::GenerateCableClassFiles(const char* name,
|
||||||
" <Header name=\"" << source->c_str() << "\"/>\n";
|
" <Header name=\"" << source->c_str() << "\"/>\n";
|
||||||
}
|
}
|
||||||
classConfig <<
|
classConfig <<
|
||||||
" <Class name=\"_wrap_::wrapper::Wrapper\"/>\n"
|
" <Class name=\"_wrap_::wrapper::Wrapper\">\n";
|
||||||
|
if(c.GetTag() != "")
|
||||||
|
{
|
||||||
|
classConfig <<
|
||||||
|
" <AlternateName name=\"" << c.GetTag().c_str() << "\"/>\n";
|
||||||
|
}
|
||||||
|
classConfig <<
|
||||||
|
" </Class>\n"
|
||||||
"</CableConfiguration>\n";
|
"</CableConfiguration>\n";
|
||||||
|
|
||||||
classConfig.close();
|
classConfig.close();
|
||||||
|
|
Loading…
Reference in New Issue