summaryrefslogtreecommitdiff
path: root/src/tools/cplusplus/Main.cpp
diff options
context:
space:
mode:
authorRoberto Raggi <roberto.raggi@nokia.com>2009-11-12 17:35:48 +0100
committerRoberto Raggi <roberto.raggi@nokia.com>2009-11-12 18:03:05 +0100
commit5dcf449afd7755d0ab88e55638fcbd8bc98deded (patch)
tree2e9a0abdadc4474d5bbf513183ac8818dd2bbcd1 /src/tools/cplusplus/Main.cpp
parentb2f6803329126c7f8f391e97ffd50f26b98064a0 (diff)
downloadqt-creator-5dcf449afd7755d0ab88e55638fcbd8bc98deded.tar.gz
Initial work on the pattern matcher for AST nodes.
Diffstat (limited to 'src/tools/cplusplus/Main.cpp')
-rw-r--r--src/tools/cplusplus/Main.cpp203
1 files changed, 150 insertions, 53 deletions
diff --git a/src/tools/cplusplus/Main.cpp b/src/tools/cplusplus/Main.cpp
index 16c9908a13..00fc4eea00 100644
--- a/src/tools/cplusplus/Main.cpp
+++ b/src/tools/cplusplus/Main.cpp
@@ -55,66 +55,158 @@ static const char copyrightHeader[] =
"**************************************************************************/\n"
;
-class SearchListNodes: protected ASTVisitor
+class VisitCG: protected ASTVisitor
{
- QList<QByteArray> _listNodes;
+ QDir _cplusplusDir;
+ QTextStream *out;
public:
- SearchListNodes(Control *control)
- : ASTVisitor(control)
+ VisitCG(const QDir &cplusplusDir, Control *control)
+ : ASTVisitor(control), _cplusplusDir(cplusplusDir), out(0)
{ }
- QList<QByteArray> operator()(AST *ast)
+ void operator()(AST *ast)
{
- _listNodes.clear();
+ QFileInfo fileInfo(_cplusplusDir, QLatin1String("ASTVisit.cpp"));
+
+ QFile file(fileInfo.absoluteFilePath());
+ if (! file.open(QFile::WriteOnly))
+ return;
+
+ QTextStream output(&file);
+ out = &output;
+
+ *out << copyrightHeader <<
+ "\n"
+ "#include \"AST.h\"\n"
+ "#include \"ASTVisitor.h\"\n"
+ "\n"
+ "using namespace CPlusPlus;\n" << endl;
+
accept(ast);
- return _listNodes;
}
protected:
- virtual bool visit(ClassSpecifierAST *ast)
+ using ASTVisitor::visit;
+
+ QMap<QByteArray, ClassSpecifierAST *> classMap;
+
+ QByteArray id_cast(NameAST *name)
{
- const QString className = oo(ast->symbol->name());
-
- if (! (className.length() > 3 && className.endsWith(QLatin1String("AST"))))
- return true;
+ if (! name)
+ return QByteArray();
+
+ Identifier *id = identifier(name->asSimpleName()->identifier_token);
+
+ return QByteArray::fromRawData(id->chars(), id->size());
+ }
- for (unsigned i = 0; i < ast->symbol->memberCount(); ++i) {
- Symbol *member = ast->symbol->memberAt(i);
- Name *memberName = member->name();
+ void visitMembers(Class *klass)
+ {
+ const QByteArray className = klass->name()->identifier()->chars();
- if (! memberName)
+ // *out << " // visit " << className.constData() << endl;
+ for (unsigned i = 0; i < klass->memberCount(); ++i) {
+ Symbol *member = klass->memberAt(i);
+ if (! member->name())
continue;
- else if (! memberName->identifier())
+
+ Identifier *id = member->name()->identifier();
+
+ if (! id)
continue;
-
- if (! qstrcmp("next", memberName->identifier()->chars())) {
- _listNodes.append(className.toUtf8());
- break;
+
+ const QByteArray memberName = QByteArray::fromRawData(id->chars(), id->size());
+ if (member->type().isUnsigned() && memberName.endsWith("_token")) {
+ // nothing to do. The member is a token.
+
+ } else if (PointerType *ptrTy = member->type()->asPointerType()) {
+
+ if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
+ QByteArray typeName = namedTy->name()->identifier()->chars();
+
+ if (typeName.endsWith("AST") && memberName != "next") {
+ *out << " accept(" << memberName.constData() << ", visitor);" << endl;
+ }
+ }
+ }
+ }
+
+ for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
+ const QByteArray baseClassName = klass->baseClassAt(i)->identifier()->chars();
+
+ if (ClassSpecifierAST *baseClassSpec = classMap.value(baseClassName, 0)) {
+ visitMembers(baseClassSpec->symbol);
}
}
+ }
+
+ bool checkMethod(Symbol *accept0Method) const
+ {
+ Declaration *decl = accept0Method->asDeclaration();
+ if (! decl)
+ return false;
+
+ Function *funTy = decl->type()->asFunctionType();
+ if (! funTy)
+ return false;
+
+ else if (funTy->isPureVirtual())
+ return false;
return true;
}
-private:
- Overview oo;
+ virtual bool visit(ClassSpecifierAST *ast)
+ {
+ Class *klass = ast->symbol;
+ const QByteArray className = id_cast(ast->name);
+
+ Identifier *visit_id = control()->findOrInsertIdentifier("accept0");
+ Symbol *accept0Method = klass->members()->lookat(visit_id);
+ for (; accept0Method; accept0Method = accept0Method->next()) {
+ if (accept0Method->identifier() != visit_id)
+ continue;
+
+ if (checkMethod(accept0Method))
+ break;
+ }
+
+ if (! accept0Method)
+ return true;
+
+ classMap.insert(className, ast);
+
+ *out
+ << "void " << className.constData() << "::accept0(ASTVisitor *visitor)" << endl
+ << "{" << endl
+ << " if (visitor->visit(this)) {" << endl;
+
+ visitMembers(klass);
+
+ *out
+ << " }" << endl
+ << " visitor->endVisit(this);" << endl
+ << "}" << endl
+ << endl;
+
+ return true;
+ }
};
-class VisitCG: protected ASTVisitor
+class MatchCG: protected ASTVisitor
{
QDir _cplusplusDir;
- QList<QByteArray> _listNodes;
QTextStream *out;
public:
- VisitCG(const QDir &cplusplusDir, Control *control)
+ MatchCG(const QDir &cplusplusDir, Control *control)
: ASTVisitor(control), _cplusplusDir(cplusplusDir), out(0)
{ }
void operator()(AST *ast)
{
- QFileInfo fileInfo(_cplusplusDir, QLatin1String("ASTVisit.cpp"));
+ QFileInfo fileInfo(_cplusplusDir, QLatin1String("ASTMatch0.cpp"));
QFile file(fileInfo.absoluteFilePath());
if (! file.open(QFile::WriteOnly))
@@ -126,13 +218,10 @@ public:
*out << copyrightHeader <<
"\n"
"#include \"AST.h\"\n"
- "#include \"ASTVisitor.h\"\n"
+ "#include \"ASTMatcher.h\"\n"
"\n"
"using namespace CPlusPlus;\n" << endl;
- SearchListNodes listNodes(control());
- _listNodes = listNodes(ast);
-
accept(ast);
}
@@ -153,9 +242,14 @@ protected:
void visitMembers(Class *klass)
{
- const QByteArray className = klass->name()->identifier()->chars();
+ Overview oo;
+ const QString className = oo(klass->name());
+
+ *out << " if (" << className << " *_other = pattern->as" << className.left(className.length() - 3) << "()) {" << endl;
+
+ *out << " if (! matcher->match(this, _other))" << endl
+ << " return false;" << endl;
- // *out << " // visit " << className.constData() << endl;
for (unsigned i = 0; i < klass->memberCount(); ++i) {
Symbol *member = klass->memberAt(i);
if (! member->name())
@@ -168,21 +262,17 @@ protected:
const QByteArray memberName = QByteArray::fromRawData(id->chars(), id->size());
if (member->type().isUnsigned() && memberName.endsWith("_token")) {
- // nothing to do. The member is a token.
+ // nothing to do here.
} else if (PointerType *ptrTy = member->type()->asPointerType()) {
if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
QByteArray typeName = namedTy->name()->identifier()->chars();
- if (_listNodes.contains(typeName) && memberName != "next") {
- *out
- << " for (" << typeName.constData() << " *it = "
- << memberName.constData() << "; it; it = it->next)" << endl
- << " accept(it, visitor);" << endl;
+ if (typeName.endsWith("AST")) {
+ *out << " if (! match(" << memberName << ", _other->" << memberName << ", matcher))" << endl
+ << " return false;" << endl;
- } else if (typeName.endsWith("AST") && memberName != "next") {
- *out << " accept(" << memberName.constData() << ", visitor);" << endl;
}
}
}
@@ -195,6 +285,9 @@ protected:
visitMembers(baseClassSpec->symbol);
}
}
+
+ *out << " return true;" << endl;
+ *out << " }" << endl;
}
bool checkMethod(Symbol *accept0Method) const
@@ -218,10 +311,10 @@ protected:
Class *klass = ast->symbol;
const QByteArray className = id_cast(ast->name);
- Identifier *visit_id = control()->findOrInsertIdentifier("accept0");
- Symbol *accept0Method = klass->members()->lookat(visit_id);
+ Identifier *match0_id = control()->findOrInsertIdentifier("match0");
+ Symbol *accept0Method = klass->members()->lookat(match0_id);
for (; accept0Method; accept0Method = accept0Method->next()) {
- if (accept0Method->identifier() != visit_id)
+ if (accept0Method->identifier() != match0_id)
continue;
if (checkMethod(accept0Method))
@@ -234,15 +327,13 @@ protected:
classMap.insert(className, ast);
*out
- << "void " << className.constData() << "::accept0(ASTVisitor *visitor)" << endl
- << "{" << endl
- << " if (visitor->visit(this)) {" << endl;
+ << "bool " << className.constData() << "::match0(AST *pattern, ASTMatcher *matcher)" << endl
+ << "{" << endl;
visitMembers(klass);
*out
- << " }" << endl
- << " visitor->endVisit(this);" << endl
+ << " return false;" << endl
<< "}" << endl
<< endl;
@@ -317,8 +408,8 @@ protected:
_nodes.deriveds.append(ast);
AccessDeclarationAST *accessDeclaration = 0;
- for (DeclarationListAST *it = ast->member_specifiers; it; it = it->next) {
- if (AccessDeclarationAST *decl = it->declaration->asAccessDeclaration()) {
+ for (DeclarationListAST *it = ast->member_specifier_list; it; it = it->next) {
+ if (AccessDeclarationAST *decl = it->value->asAccessDeclaration()) {
if (tokenKind(decl->access_specifier_token) == T_PUBLIC)
accessDeclaration = decl;
}
@@ -457,6 +548,9 @@ QStringList generateAST_H(const Snapshot &snapshot, const QDir &cplusplusDir)
VisitCG cg(cplusplusDir, doc->control());
cg(doc->translationUnit()->ast());
+ MatchCG cg2(cplusplusDir, doc->control());
+ cg2(doc->translationUnit()->ast());
+
return astDerivedClasses;
}
@@ -476,8 +570,11 @@ public:
protected:
bool visit(SimpleDeclarationAST *ast)
{
- if (ElaboratedTypeSpecifierAST *e = ast->decl_specifier_seq->asElaboratedTypeSpecifier()) {
- if (tokenKind(e->classkey_token) == T_CLASS && !ast->declarators) {
+ if (! ast->decl_specifier_list)
+ return false;
+
+ if (ElaboratedTypeSpecifierAST *e = ast->decl_specifier_list->value->asElaboratedTypeSpecifier()) {
+ if (tokenKind(e->classkey_token) == T_CLASS && !ast->declarator_list) {
QString className = oo(e->name->name);
if (className.length() > 3 && className.endsWith(QLatin1String("AST"))) {