#include "stdafx.h"
#include "CTagsModelBuilder.h"
#include <Utilities/StringTokenizer.h>
#include <Model/CTags/CTagsCppTagFactory.h>
#include <functional>
using namespace std;
namespace CTags {
template<class T>
struct has_name : public binary_function<T, string, bool>
{
bool operator()(const first_argument_type &type, const string &name) const
{ return type->getName() == name; }
};
typedef std::vector<std::string>::iterator PathIterator;
typedef std::list<smart_ptr<CppTag> > TList;
TList::value_type getTreeItem(PathIterator begin, PathIterator end, TList &tree)
{
if(distance(begin, end) == 1) {
//ok we are at the bottom of the tree
TList::iterator type = find_if(tree.begin(), tree.end(), bind2nd(has_name<TList::value_type>(), *begin));
return type != tree.end() ? *type : TList::value_type();
} else if(begin != end) {
//we need to descend more into the tree
TList::iterator type = find_if(tree.begin(), tree.end(), bind2nd(has_name<TList::value_type>(), *begin));
return type != tree.end() ? getTreeItem(++begin, end, (*type)->getInnerTags()) : TList::value_type();
}
return TList::value_type();
}
TList::value_type getParent(const CTags::Tag &ctag, TList &tree)
{
vector<string> path = StringVectorTokenizer(ctag.getScope(), "::").tokens();
smart_ptr<CppTag> parent = getTreeItem(path.begin(), path.end(), tree);
if(parent.isNull() && ctag.getScopeType() == eNamespace && !ctag.getScope().empty()) {
parent = smart_ptr<CppTag>(new Namespace(ctag.getScope()));
if(!parent->getScopeName().empty()) {
path = StringVectorTokenizer(parent->getScopeName(), "::").tokens();
smart_ptr<CppTag> grandParent = getTreeItem(path.begin(), path.end(), tree);
if(!grandParent.isNull()) {
grandParent->getInnerTags().push_back(parent);
}
} else {
tree.push_back(parent);
}
}
return parent;
}
ModelBuilder::TagList ModelBuilder::createModel(Database::TagTable& table)
{
TagList result;
map<string, list<smart_ptr<CppTag> > > innerTags;
while(!table.empty())
{
Database::TagTable::const_iterator ctag = table.begin();
string fqn = ctag->getFQN();
string nam = ctag->getName();
string sc = ctag->getScope();
CppTagType tp = ctag->getType();
const Tag &tg = *ctag;
smart_ptr<CppTag> treeItem;
smart_ptr<CppTag> parent = getParent(*ctag, result);
switch(ctag->getType()) {
//case eNamespace :
case eClass :
case eStruct:
case eUnion:
case eEnum:
case eTypedef:
{
vector<string> p = StringVectorTokenizer(ctag->getFQN(), "::").tokens();
treeItem = getTreeItem(p.begin(), p.end(), result);
bool doInsert = false;
if(treeItem.isNull()){
treeItem = TypeInfoFactory().createTag(*ctag);
doInsert = true;
}
treeItem->getInnerTags().insert(treeItem->getInnerTags().end(), innerTags[ctag->getFQN()].begin(), innerTags[ctag->getFQN()].end());
innerTags.erase(ctag->getFQN());
if(!doInsert) {
treeItem = smart_ptr<CppTag>();
}
break;
}
case eEnumMember:
{
try {
Dynamic_cast<Enum>(parent)->getValues().push_back(ctag->getName());
} catch(...){}
break;
}
case eMethod:
{
Database::TagTable::iterator buddy;
treeItem = make_smart_ptr(MethodFactory(&table).create(*ctag, buddy));
if(buddy != table.end() && buddy != table.begin()) {
table.erase(buddy);
}
break;
}
case eField:
{
treeItem = createField(*ctag);
break;
}
case eFunction:
{
Database::TagTable::iterator buddy;
treeItem = FunctionFactory(&table).create(*ctag, buddy);
if(buddy != table.end() && buddy != table.begin()) {
table.erase(buddy);
}
break;
}
case eVariable:
{
treeItem = createVariable(*ctag);
break;
}
}
if(!treeItem.isNull()) {
if(!parent.isNull()) {
parent->getInnerTags().push_back(treeItem);
} else if(ctag->getScope() == "" /*GLOBAL_NAMESPACE*/) {
result.push_back(treeItem);
} else {
innerTags[ctag->getScope()].push_back(treeItem);
}
}
table.pop_front();
}
if(innerTags.size() == 1) {
result.insert(result.end(), innerTags.begin()->second.begin(), innerTags.begin()->second.end());
} else if(innerTags.size() > 1) {
stringstream ss;
ss << "ModelBuilder::createModel()";
AfxMessageBox(ss.str().c_str());
}
return result;
}
smart_ptr<Variable> ModelBuilder::createVariable(Tag tag)
{
smart_ptr<Variable> variable( new Variable(tag.getReturnType(), tag.getName()));
variable->setDeclaration(TagLocation(tag.getFile(), tag.getLine()));
return variable;
}
smart_ptr<Field> ModelBuilder::createField(Tag tag)
{
smart_ptr<Field> field(new Field(tag.getReturnType(), tag.getName()));
field->setAccessQualifier(tag.getAccessQualifier());
field->setDeclaration(TagLocation(tag.getFile(), tag.getLine()));
return field;
}
}