Commit bef4ed89 authored by Roberto Raggi's avatar Roberto Raggi
Browse files

Introduced destructive pattern matching.

parent 6ff99e05
......@@ -281,12 +281,72 @@ protected:
virtual bool match0(AST *, ASTMatcher *) = 0;
};
class CPLUSPLUS_EXPORT StatementAST: public AST
{
public:
virtual StatementAST *asStatement() { return this; }
};
class CPLUSPLUS_EXPORT ExpressionAST: public AST
{
public:
virtual ExpressionAST *asExpression() { return this; }
};
class CPLUSPLUS_EXPORT DeclarationAST: public AST
{
public:
virtual DeclarationAST *asDeclaration() { return this; }
};
class CPLUSPLUS_EXPORT NameAST: public ExpressionAST
{
public: // annotations
Name *name;
public:
virtual NameAST *asName() { return this; }
};
class CPLUSPLUS_EXPORT SpecifierAST: public AST
{
public:
virtual SpecifierAST *asSpecifier() { return this; }
};
class CPLUSPLUS_EXPORT PtrOperatorAST: public AST
{
public:
virtual PtrOperatorAST *asPtrOperator() { return this; }
};
class CPLUSPLUS_EXPORT PostfixAST: public AST
{
public:
virtual PostfixAST *asPostfix() { return this; }
};
class CPLUSPLUS_EXPORT CoreDeclaratorAST: public AST
{
public:
virtual CoreDeclaratorAST *asCoreDeclarator() { return this; }
};
class CPLUSPLUS_EXPORT PostfixDeclaratorAST: public AST
{
public:
virtual PostfixDeclaratorAST *asPostfixDeclarator() { return this; }
};
class CPLUSPLUS_EXPORT ObjCSelectorAST: public AST
{
public: // annotation
Name *selector_name;
public:
virtual ObjCSelectorAST *asObjCSelector() { return this; }
};
class CPLUSPLUS_EXPORT SimpleSpecifierAST: public SpecifierAST
{
public:
......@@ -363,36 +423,6 @@ protected:
virtual bool match0(AST *, ASTMatcher *);
};
class CPLUSPLUS_EXPORT StatementAST: public AST
{
public:
virtual StatementAST *asStatement() { return this; }
};
class CPLUSPLUS_EXPORT ExpressionAST: public AST
{
public:
virtual ExpressionAST *asExpression() { return this; }
};
class CPLUSPLUS_EXPORT DeclarationAST: public AST
{
public:
virtual DeclarationAST *asDeclaration() { return this; }
};
class CPLUSPLUS_EXPORT CoreDeclaratorAST: public AST
{
public:
virtual CoreDeclaratorAST *asCoreDeclarator() { return this; }
};
class CPLUSPLUS_EXPORT PostfixDeclaratorAST: public AST
{
public:
virtual PostfixDeclaratorAST *asPostfixDeclarator() { return this; }
};
class CPLUSPLUS_EXPORT DeclaratorAST: public AST
{
public:
......@@ -1201,16 +1231,6 @@ protected:
virtual bool match0(AST *, ASTMatcher *);
};
class CPLUSPLUS_EXPORT NameAST: public ExpressionAST
{
public: // annotations
Name *name;
public:
virtual NameAST *asName() { return this; }
};
class CPLUSPLUS_EXPORT NestedNameSpecifierAST: public AST
{
public:
......@@ -1530,12 +1550,6 @@ protected:
virtual bool match0(AST *, ASTMatcher *);
};
class CPLUSPLUS_EXPORT PostfixAST: public AST
{
public:
virtual PostfixAST *asPostfix() { return this; }
};
class CPLUSPLUS_EXPORT CallAST: public PostfixAST
{
public:
......@@ -1681,12 +1695,6 @@ protected:
virtual bool match0(AST *, ASTMatcher *);
};
class CPLUSPLUS_EXPORT PtrOperatorAST: public AST
{
public:
virtual PtrOperatorAST *asPtrOperator() { return this; }
};
class CPLUSPLUS_EXPORT PointerToMemberAST: public PtrOperatorAST
{
public:
......@@ -2386,16 +2394,6 @@ protected:
virtual bool match0(AST *, ASTMatcher *);
};
class CPLUSPLUS_EXPORT ObjCSelectorAST: public AST
{
public: // annotation
Name *selector_name;
public:
virtual ObjCSelectorAST *asObjCSelector() { return this; }
};
class CPLUSPLUS_EXPORT ObjCSelectorWithoutArgumentsAST: public ObjCSelectorAST
{
public:
......
This diff is collapsed.
......@@ -36,13 +36,10 @@ namespace CPlusPlus {
class CPLUSPLUS_EXPORT ASTMatcher
{
public:
ASTMatcher(TranslationUnit *translationUnit, TranslationUnit *patternTranslationUnit);
ASTMatcher(TranslationUnit *translationUnit);
virtual ~ASTMatcher();
TranslationUnit *translationUnit() const;
TranslationUnit *patternTranslationUnit() const;
bool matchToken(unsigned index, unsigned otherIndex) const;
virtual bool match(AccessDeclarationAST *node, AccessDeclarationAST *pattern);
virtual bool match(ArrayAccessAST *node, ArrayAccessAST *pattern);
......@@ -169,7 +166,6 @@ public:
private:
TranslationUnit *_translationUnit;
TranslationUnit *_patternTranslationUnit;
};
} // end of namespace CPlusPlus
......
......@@ -55,6 +55,103 @@ static const char copyrightHeader[] =
"**************************************************************************/\n"
;
class ASTNodes
{
public:
ASTNodes(): base(0) {}
ClassSpecifierAST *base; // points to "class AST"
QList<ClassSpecifierAST *> deriveds; // n where n extends AST
QList<QTextCursor> endOfPublicClassSpecifiers;
};
static ASTNodes astNodes;
static QTextCursor createCursor(TranslationUnit *unit, AST *ast, QTextDocument *document)
{
unsigned startLine, startColumn, endLine, endColumn;
unit->getTokenStartPosition(ast->firstToken(), &startLine, &startColumn);
unit->getTokenEndPosition(ast->lastToken() - 1, &endLine, &endColumn);
QTextCursor tc(document);
tc.setPosition(document->findBlockByNumber(startLine - 1).position());
tc.setPosition(document->findBlockByNumber(endLine - 1).position() + endColumn - 1,
QTextCursor::KeepAnchor);
int charsToSkip = 0;
forever {
QChar ch = document->characterAt(tc.position() + charsToSkip);
if (! ch.isSpace())
break;
++charsToSkip;
if (ch == QChar::ParagraphSeparator)
break;
}
tc.setPosition(tc.position() + charsToSkip, QTextCursor::KeepAnchor);
return tc;
}
class FindASTNodes: protected ASTVisitor
{
public:
FindASTNodes(Document::Ptr doc, QTextDocument *document)
: ASTVisitor(doc->control()), document(document)
{
}
ASTNodes operator()(AST *ast)
{
accept(ast);
return _nodes;
}
protected:
virtual bool visit(ClassSpecifierAST *ast)
{
Class *klass = ast->symbol;
Q_ASSERT(klass != 0);
const QString className = oo(klass->name());
if (className.endsWith("AST")) {
if (className == QLatin1String("AST"))
_nodes.base = ast;
else {
_nodes.deriveds.append(ast);
AccessDeclarationAST *accessDeclaration = 0;
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;
}
}
if (! accessDeclaration)
qDebug() << "no access declaration for class:" << className;
Q_ASSERT(accessDeclaration != 0);
QTextCursor tc = createCursor(translationUnit(), accessDeclaration, document);
tc.setPosition(tc.position());
_nodes.endOfPublicClassSpecifiers.append(tc);
}
}
return true;
}
private:
QTextDocument *document;
ASTNodes _nodes;
Overview oo;
};
class Accept0CG: protected ASTVisitor
{
QDir _cplusplusDir;
......@@ -103,8 +200,6 @@ protected:
void visitMembers(Class *klass)
{
const QByteArray className = klass->name()->identifier()->chars();
// *out << " // visit " << className.constData() << endl;
for (unsigned i = 0; i < klass->memberCount(); ++i) {
Symbol *member = klass->memberAt(i);
......@@ -328,78 +423,19 @@ public:
*out << copyrightHeader << endl
<< "#include \"AST.h\"" << endl
<< "#include \"ASTMatcher.h\"" << endl
<< "#include \"Control.h\"" << endl
<< "#include \"TranslationUnit.h\"" << endl
<< endl
<< "using namespace CPlusPlus;" << endl
<< endl
<< "ASTMatcher::ASTMatcher(Control *control)" << endl
<< " : _control(control)" << endl
<< "ASTMatcher::ASTMatcher(TranslationUnit *translationUnit)"
<< " : _translationUnit(translationUnit)" << endl
<< "{ }" << endl
<< endl
<< "ASTMatcher::~ASTMatcher()" << endl
<< "{ }" << endl
<< endl
<< "Control *ASTMatcher::control() const" << endl
<< "{ return _control; }" << endl
<< endl
<< "TranslationUnit *ASTMatcher::translationUnit() const" << endl
<< "{ return _control->translationUnit(); }" << endl
<< endl
<< "unsigned ASTMatcher::tokenCount() const" << endl
<< "{ return translationUnit()->tokenCount(); }" << endl
<< endl
<< "const Token &ASTMatcher::tokenAt(unsigned index) const" << endl
<< "{ return translationUnit()->tokenAt(index); }" << endl
<< endl
<< "int ASTMatcher::tokenKind(unsigned index) const" << endl
<< "{ return translationUnit()->tokenKind(index); }" << endl
<< endl
<< "const char *ASTMatcher::spell(unsigned index) const" << endl
<< "{ return translationUnit()->spell(index); }" << endl
<< endl
<< "Identifier *ASTMatcher::identifier(unsigned index) const" << endl
<< "{ return translationUnit()->identifier(index); }" << endl
<< endl
<< "Literal *ASTMatcher::literal(unsigned index) const" << endl
<< "{ return translationUnit()->literal(index); }" << endl
<< endl
<< "NumericLiteral *ASTMatcher::numericLiteral(unsigned index) const" << endl
<< "{ return translationUnit()->numericLiteral(index); }" << endl
<< endl
<< "StringLiteral *ASTMatcher::stringLiteral(unsigned index) const" << endl
<< "{ return translationUnit()->stringLiteral(index); }" << endl
<< endl
<< "void ASTMatcher::getPosition(unsigned offset," << endl
<< " unsigned *line," << endl
<< " unsigned *column," << endl
<< " StringLiteral **fileName) const" << endl
<< "{ translationUnit()->getPosition(offset, line, column, fileName); }" << endl
<< endl
<< "void ASTMatcher::getTokenPosition(unsigned index," << endl
<< " unsigned *line," << endl
<< " unsigned *column," << endl
<< " StringLiteral **fileName) const" << endl
<< "{ translationUnit()->getTokenPosition(index, line, column, fileName); }" << endl
<< endl
<< "void ASTMatcher::getTokenStartPosition(unsigned index, unsigned *line, unsigned *column) const" << endl
<< "{ getPosition(tokenAt(index).begin(), line, column); }" << endl
<< endl
<< "void ASTMatcher::getTokenEndPosition(unsigned index, unsigned *line, unsigned *column) const" << endl
<< "{ getPosition(tokenAt(index).end(), line, column); }" << endl
<< endl
<< "bool ASTMatcher::matchToken(unsigned index, unsigned otherIndex) const" << endl
<< "{" << endl
<< " const Token &token = tokenAt(index);" << endl
<< " const Token &otherToken = tokenAt(otherIndex);" << endl
<< " if (token.f.kind != otherToken.f.kind)" << endl
<< " return false;" << endl
<< " else if (token.is(T_IDENTIFIER)) {" << endl
<< " if (token.identifier != otherToken.identifier)" << endl
<< " return false;" << endl
<< " }" << endl
<< " return true;" << endl
<< "}" << endl
<< "{ return _translationUnit; }" << endl
<< endl;
accept(ast);
......@@ -422,8 +458,6 @@ protected:
void visitMembers(Class *klass)
{
const QByteArray className = klass->name()->identifier()->chars();
for (unsigned i = 0; i < klass->memberCount(); ++i) {
Symbol *member = klass->memberAt(i);
if (! member->name())
......@@ -436,10 +470,10 @@ 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.
*out << " if (! matchToken(node->" << memberName << ", pattern->" << memberName << "))" << endl
<< " return false;" << endl;
*out
<< " pattern->" << memberName << " = node->" << memberName << ";" << endl
<< endl;
} else if (PointerType *ptrTy = member->type()->asPointerType()) {
......@@ -447,8 +481,12 @@ protected:
QByteArray typeName = namedTy->name()->identifier()->chars();
if (typeName.endsWith("AST")) {
*out << " if (! AST::match(node->" << memberName << ", pattern->" << memberName << ", this))" << endl
<< " return false;" << endl;
*out
<< " if (! pattern->" << memberName << ")" << endl
<< " pattern->" << memberName << " = node->" << memberName << ";" << endl
<< " else if (! AST::match(node->" << memberName << ", pattern->" << memberName << ", this))" << endl
<< " return false;" << endl
<< endl;
}
}
}
......@@ -501,7 +539,10 @@ protected:
*out
<< "bool ASTMatcher::match(" << className.constData() << " *node, " << className.constData() << " *pattern)" << endl
<< "{" << endl;
<< "{" << endl
<< " (void) node;" << endl
<< " (void) pattern;" << endl
<< endl;
visitMembers(klass);
......@@ -514,103 +555,6 @@ protected:
}
};
QTextCursor createCursor(TranslationUnit *unit, AST *ast, QTextDocument *document)
{
unsigned startLine, startColumn, endLine, endColumn;
unit->getTokenStartPosition(ast->firstToken(), &startLine, &startColumn);
unit->getTokenEndPosition(ast->lastToken() - 1, &endLine, &endColumn);
QTextCursor tc(document);
tc.setPosition(document->findBlockByNumber(startLine - 1).position());
tc.setPosition(document->findBlockByNumber(endLine - 1).position() + endColumn - 1,
QTextCursor::KeepAnchor);
int charsToSkip = 0;
forever {
QChar ch = document->characterAt(tc.position() + charsToSkip);
if (! ch.isSpace())
break;
++charsToSkip;
if (ch == QChar::ParagraphSeparator)
break;
}
tc.setPosition(tc.position() + charsToSkip, QTextCursor::KeepAnchor);
return tc;
}
class ASTNodes
{
public:
ASTNodes(): base(0) {}
ClassSpecifierAST *base; // points to "class AST"
QList<ClassSpecifierAST *> deriveds; // n where n extends AST
QList<QTextCursor> endOfPublicClassSpecifiers;
};
class FindASTNodes: protected ASTVisitor
{
public:
FindASTNodes(Document::Ptr doc, QTextDocument *document)
: ASTVisitor(doc->control()), document(document)
{
}
ASTNodes operator()(AST *ast)
{
accept(ast);
return _nodes;
}
protected:
virtual bool visit(ClassSpecifierAST *ast)
{
Class *klass = ast->symbol;
Q_ASSERT(klass != 0);
const QString className = oo(klass->name());
if (className.endsWith("AST")) {
if (className == QLatin1String("AST"))
_nodes.base = ast;
else {
_nodes.deriveds.append(ast);
AccessDeclarationAST *accessDeclaration = 0;
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;
}
}
if (! accessDeclaration)
qDebug() << "no access declaration for class:" << className;
Q_ASSERT(accessDeclaration != 0);
QTextCursor tc = createCursor(translationUnit(), accessDeclaration, document);
tc.setPosition(tc.position());
_nodes.endOfPublicClassSpecifiers.append(tc);
}
}
return true;
}
private:
QTextDocument *document;
ASTNodes _nodes;
Overview oo;
};
class RemoveCastMethods: protected ASTVisitor
{
public:
......@@ -648,6 +592,7 @@ private:
Overview oo;
};
QStringList generateAST_H(const Snapshot &snapshot, const QDir &cplusplusDir)
{
QStringList astDerivedClasses;
......@@ -673,7 +618,7 @@ QStringList generateAST_H(const Snapshot &snapshot, const QDir &cplusplusDir)
doc->check();
FindASTNodes process(doc, &document);
ASTNodes astNodes = process(doc->translationUnit()->ast());
astNodes = process(doc->translationUnit()->ast());
RemoveCastMethods removeCastMethods(doc, &document);
......
......@@ -54,30 +54,90 @@
using namespace CPlusPlus;
class ForEachBinaryExpression: protected ASTVisitor
class PatternBuilder
{
public:
PatternBuilder()
: pool(new MemoryPool()) {}
~PatternBuilder()
{ delete pool; }
UnaryExpressionAST *CreateUnaryExpression(ExpressionAST *expr = 0)
{
UnaryExpressionAST *ast = new (pool) UnaryExpressionAST;
ast->expression = expr;
return ast;
}
BinaryExpressionAST *CreateBinaryExpression(ExpressionAST *left = 0, ExpressionAST *right = 0)
{
BinaryExpressionAST *ast = new (pool) BinaryExpressionAST;
ast->left_expression = left;
ast->right_expression = right;
return ast;
}
NumericLiteralAST *NumericLiteral()
{
NumericLiteralAST *ast = new (pool) NumericLiteralAST;
return ast;
}
SimpleNameAST *SimpleName()
{
SimpleNameAST *ast = new (pool) SimpleNameAST;
return ast;
}
IfStatementAST *IfStatement(ExpressionAST *cond = 0, StatementAST *iftrue = 0, StatementAST *iffalse = 0)
{
IfStatementAST *ast = new (pool) IfStatementAST;
ast->condition = cond;
ast->statement = iftrue;
ast->else_statement = iffalse;
return ast;
}
CompoundStatementAST *CompoundStatement()
{
CompoundStatementAST *ast = new (pool) CompoundStatementAST;
return ast;
}
private:
MemoryPool *pool;
};
class ForEachNode: protected ASTVisitor
{
Document::Ptr doc;