OSDN Git Service

af982907250a201d23d61cfecc92a1ffac49f055
[qt-creator-jp/qt-creator-jp.git] / src / tools / gen-cpp-ast / generate-ast.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include <QCoreApplication>
35 #include <QStringList>
36 #include <QTextDocument>
37 #include <QTextCursor>
38 #include <QTextBlock>
39 #include <QDir>
40 #include <QDebug>
41
42 #include <Control.h>
43 #include <Parser.h>
44 #include <AST.h>
45 #include <ASTVisitor.h>
46 #include <Symbols.h>
47 #include <CoreTypes.h>
48 #include <Literals.h>
49 #include <CppDocument.h>
50 #include <Overview.h>
51 #include <Names.h>
52 #include <Scope.h>
53 #include <BackwardsScanner.h>
54
55 #include <utils/changeset.h>
56
57 #include <iostream>
58 #include <cstdlib>
59
60 using namespace CPlusPlus;
61
62 static const char copyrightHeader[] =
63 "/**************************************************************************\n"
64 "**\n"
65 "** This file is part of Qt Creator\n"
66 "**\n"
67 "** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).\n"
68 "**\n"
69 "** Contact: Nokia Corporation (qt-info@nokia.com)\n"
70 "**\n"
71 "** No Commercial Usage\n"
72 "**\n"
73 "** This file contains pre-release code and may not be distributed.\n"
74 "** You may use this file in accordance with the terms and conditions\n"
75 "** contained in the Technology Preview License Agreement accompanying\n"
76 "** this package.\n"
77 "**\n"
78 "** GNU Lesser General Public License Usage\n"
79 "**\n"
80 "** Alternatively, this file may be used under the terms of the GNU Lesser\n"
81 "** General Public License version 2.1 as published by the Free Software\n"
82 "** Foundation and appearing in the file LICENSE.LGPL included in the\n"
83 "** packaging of this file.  Please review the following information to\n"
84 "** ensure the GNU Lesser General Public License version 2.1 requirements\n"
85 "** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\n"
86 "**\n"
87 "** In addition, as a special exception, Nokia gives you certain additional\n"
88 "** rights.  These rights are described in the Nokia Qt LGPL Exception\n"
89 "** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.\n"
90 "**\n"
91 "** If you have questions regarding the use of this file, please contact\n"
92 "** Nokia at qt-info@nokia.com.\n"
93 "**\n"
94 "**************************************************************************/\n"
95 ;
96
97 static const char generatedHeader[] =
98 "\n"
99 "//\n"
100 "//  W A R N I N G\n"
101 "//  -------------\n"
102 "//\n"
103 "// This file is automatically generated.\n"
104 "// Changes will be lost.\n"
105 "//\n"
106 "\n"
107 ;
108
109 class ASTNodes
110 {
111 public:
112     ASTNodes(): base(0) {}
113
114     ClassSpecifierAST *base; // points to "class AST"
115     QList<ClassSpecifierAST *> deriveds; // n where n extends AST
116     QList<QTextCursor> endOfPublicClassSpecifiers;
117 };
118
119 static Document::Ptr AST_h_document;
120 static ASTNodes astNodes;
121
122 static QTextCursor createCursor(TranslationUnit *unit, AST *ast, QTextDocument *document)
123 {
124     unsigned startLine, startColumn, endLine, endColumn;
125     unit->getTokenStartPosition(ast->firstToken(), &startLine, &startColumn);
126     unit->getTokenEndPosition(ast->lastToken() - 1, &endLine, &endColumn);
127
128     QTextCursor tc(document);
129     tc.setPosition(document->findBlockByNumber(startLine - 1).position());
130     tc.setPosition(document->findBlockByNumber(endLine - 1).position() + endColumn - 1,
131                    QTextCursor::KeepAnchor);
132
133     int charsToSkip = 0;
134     forever {
135         QChar ch = document->characterAt(tc.position() + charsToSkip);
136
137         if (! ch.isSpace())
138             break;
139
140         ++charsToSkip;
141
142         if (ch == QChar::ParagraphSeparator)
143             break;
144     }
145
146     tc.setPosition(tc.position() + charsToSkip, QTextCursor::KeepAnchor);
147     return tc;
148 }
149
150 class FindASTNodes: protected ASTVisitor
151 {
152 public:
153     FindASTNodes(Document::Ptr doc, QTextDocument *document)
154         : ASTVisitor(doc->translationUnit()), document(document)
155     {
156     }
157
158     ASTNodes operator()(AST *ast)
159     {
160         accept(ast);
161         return _nodes;
162     }
163
164 protected:
165     virtual bool visit(ClassSpecifierAST *ast)
166     {
167         Class *klass = ast->symbol;
168         Q_ASSERT(klass != 0);
169
170         const QString className = oo(klass->name());
171
172         if (className.endsWith("AST")) {
173             if (className == QLatin1String("AST"))
174                 _nodes.base = ast;
175             else {
176                 _nodes.deriveds.append(ast);
177
178                 AccessDeclarationAST *accessDeclaration = 0;
179                 for (DeclarationListAST *it = ast->member_specifier_list; it; it = it->next) {
180                     if (AccessDeclarationAST *decl = it->value->asAccessDeclaration()) {
181                         if (tokenKind(decl->access_specifier_token) == T_PUBLIC)
182                             accessDeclaration = decl;
183                     }
184                 }
185
186                 if (! accessDeclaration)
187                     qDebug() << "no access declaration for class:" << className;
188
189                 Q_ASSERT(accessDeclaration != 0);
190
191                 QTextCursor tc = createCursor(translationUnit(), accessDeclaration, document);
192                 tc.setPosition(tc.position());
193
194                 _nodes.endOfPublicClassSpecifiers.append(tc);
195             }
196         }
197
198         return true;
199     }
200
201 private:
202     QTextDocument *document;
203     ASTNodes _nodes;
204     Overview oo;
205 };
206
207 class Accept0CG: protected ASTVisitor
208 {
209     QDir _cplusplusDir;
210     QTextStream *out;
211
212 public:
213     Accept0CG(const QDir &cplusplusDir, TranslationUnit *unit)
214         : ASTVisitor(unit), _cplusplusDir(cplusplusDir), out(0)
215     { }
216
217     void operator()(AST *ast)
218     {
219         QFileInfo fileInfo(_cplusplusDir, QLatin1String("ASTVisit.cpp"));
220
221         QFile file(fileInfo.absoluteFilePath());
222         if (! file.open(QFile::WriteOnly))
223             return;
224
225         QTextStream output(&file);
226         out = &output;
227
228         *out << copyrightHeader << generatedHeader <<
229             "\n"
230             "#include \"AST.h\"\n"
231             "#include \"ASTVisitor.h\"\n"
232             "\n"
233             "using namespace CPlusPlus;\n" << endl;
234
235         accept(ast);
236     }
237
238 protected:
239     using ASTVisitor::visit;
240
241     QMap<QByteArray, ClassSpecifierAST *> classMap;
242
243     QByteArray id_cast(NameAST *name)
244     {
245         if (! name)
246             return QByteArray();
247
248         const Identifier *id = identifier(name->asSimpleName()->identifier_token);
249
250         return QByteArray::fromRawData(id->chars(), id->size());
251     }
252
253     void visitMembers(Class *klass)
254     {
255         // *out << "        // visit " << className.constData() << endl;
256         for (unsigned i = 0; i < klass->memberCount(); ++i) {
257             Symbol *member = klass->memberAt(i);
258             if (! member->name())
259                 continue;
260
261             const Identifier *id = member->name()->identifier();
262
263             if (! id)
264                 continue;
265
266             const QByteArray memberName = QByteArray::fromRawData(id->chars(), id->size());
267             if (member->type().isUnsigned() && memberName.endsWith("_token")) {
268                 // nothing to do. The member is a token.
269
270             } else if (PointerType *ptrTy = member->type()->asPointerType()) {
271
272                 if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
273                     QByteArray typeName = namedTy->name()->identifier()->chars();
274
275                     if (typeName.endsWith("AST") && memberName != "next") {
276                         *out << "        accept(" << memberName.constData() << ", visitor);" << endl;
277                     }
278                 }
279             }
280         }
281
282         for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
283             const QByteArray baseClassName = klass->baseClassAt(i)->identifier()->chars();
284
285             if (ClassSpecifierAST *baseClassSpec = classMap.value(baseClassName, 0)) {
286                 visitMembers(baseClassSpec->symbol);
287             }
288         }
289     }
290
291     bool checkMethod(Symbol *accept0Method) const
292     {
293         Declaration *decl = accept0Method->asDeclaration();
294         if (! decl)
295             return false;
296
297         Function *funTy = decl->type()->asFunctionType();
298         if (! funTy)
299             return false;
300
301         else if (funTy->isPureVirtual())
302             return false;
303
304         return true;
305     }
306
307     virtual bool visit(ClassSpecifierAST *ast)
308     {
309         Class *klass = ast->symbol;
310         const QByteArray className = id_cast(ast->name);
311
312         const Identifier *visit_id = control()->identifier("accept0");
313         Symbol *accept0Method = klass->find(visit_id);
314         for (; accept0Method; accept0Method = accept0Method->next()) {
315             if (accept0Method->identifier() != visit_id)
316                 continue;
317
318             if (checkMethod(accept0Method))
319                 break;
320         }
321
322         if (! accept0Method)
323             return true;
324
325         classMap.insert(className, ast);
326
327         *out
328                 << "void " << className.constData() << "::accept0(ASTVisitor *visitor)" << endl
329                 << "{" << endl
330                 << "    if (visitor->visit(this)) {" << endl;
331
332         visitMembers(klass);
333
334         *out
335                 << "    }" << endl
336                 << "    visitor->endVisit(this);" << endl
337                 << "}" << endl
338                 << endl;
339
340         return true;
341     }
342 };
343
344 class Match0CG: protected ASTVisitor
345 {
346     QDir _cplusplusDir;
347     QTextStream *out;
348
349 public:
350     Match0CG(const QDir &cplusplusDir, TranslationUnit *unit)
351         : ASTVisitor(unit), _cplusplusDir(cplusplusDir), out(0)
352     { }
353
354     void operator()(AST *ast)
355     {
356         QFileInfo fileInfo(_cplusplusDir, QLatin1String("ASTMatch0.cpp"));
357
358         QFile file(fileInfo.absoluteFilePath());
359         if (! file.open(QFile::WriteOnly))
360             return;
361
362         QTextStream output(&file);
363         out = &output;
364
365         *out << copyrightHeader << generatedHeader <<
366             "\n"
367             "#include \"AST.h\"\n"
368             "#include \"ASTMatcher.h\"\n"
369             "\n"
370             "using namespace CPlusPlus;\n" << endl;
371
372         accept(ast);
373     }
374
375 protected:
376     using ASTVisitor::visit;
377
378     QMap<QByteArray, ClassSpecifierAST *> classMap;
379
380     QByteArray id_cast(NameAST *name)
381     {
382         if (! name)
383             return QByteArray();
384
385         const Identifier *id = identifier(name->asSimpleName()->identifier_token);
386
387         return QByteArray::fromRawData(id->chars(), id->size());
388     }
389
390     void visitMembers(Class *klass)
391     {
392         Overview oo;
393         const QString className = oo(klass->name());
394
395         *out << "    if (" << className << " *_other = pattern->as" << className.left(className.length() - 3) << "())" << endl;
396
397         *out << "        return matcher->match(this, _other);" << endl;
398
399         *out << endl;
400     }
401
402     bool checkMethod(Symbol *accept0Method) const
403     {
404         Declaration *decl = accept0Method->asDeclaration();
405         if (! decl)
406             return false;
407
408         Function *funTy = decl->type()->asFunctionType();
409         if (! funTy)
410             return false;
411
412         else if (funTy->isPureVirtual())
413             return false;
414
415         return true;
416     }
417
418     virtual bool visit(ClassSpecifierAST *ast)
419     {
420         Class *klass = ast->symbol;
421         const QByteArray className = id_cast(ast->name);
422
423         const Identifier *match0_id = control()->identifier("match0");
424         Symbol *accept0Method = klass->find(match0_id);
425         for (; accept0Method; accept0Method = accept0Method->next()) {
426             if (accept0Method->identifier() != match0_id)
427                 continue;
428
429             if (checkMethod(accept0Method))
430                 break;
431         }
432
433         if (! accept0Method)
434             return true;
435
436         classMap.insert(className, ast);
437
438         *out
439                 << "bool " << className.constData() << "::match0(AST *pattern, ASTMatcher *matcher)" << endl
440                 << "{" << endl;
441
442         visitMembers(klass);
443
444         *out
445                 << "    return false;" << endl
446                 << "}" << endl
447                 << endl;
448
449         return true;
450     }
451 };
452
453
454 class MatcherCPPCG: protected ASTVisitor
455 {
456     QDir _cplusplusDir;
457     QTextStream *out;
458
459 public:
460     MatcherCPPCG(const QDir &cplusplusDir, TranslationUnit *unit)
461         : ASTVisitor(unit), _cplusplusDir(cplusplusDir), out(0)
462     { }
463
464     void operator()(AST *ast)
465     {
466         QFileInfo fileInfo(_cplusplusDir, QLatin1String("ASTMatcher.cpp"));
467
468         QFile file(fileInfo.absoluteFilePath());
469         if (! file.open(QFile::WriteOnly))
470             return;
471
472         QTextStream output(&file);
473         out = &output;
474
475         *out << copyrightHeader << endl
476                 << generatedHeader
477                 << "#include \"AST.h\"" << endl
478                 << "#include \"ASTMatcher.h\"" << endl
479                 << endl
480                 << "using namespace CPlusPlus;" << endl
481                 << endl
482                 << "ASTMatcher::ASTMatcher()" << endl
483                 << "{ }" << endl
484                 << endl
485                 << "ASTMatcher::~ASTMatcher()" << endl
486                 << "{ }" << endl
487                 << endl;
488
489         accept(ast);
490     }
491
492 protected:
493     using ASTVisitor::visit;
494
495     QMap<QByteArray, ClassSpecifierAST *> classMap;
496
497     QByteArray id_cast(NameAST *name)
498     {
499         if (! name)
500             return QByteArray();
501
502         const Identifier *id = identifier(name->asSimpleName()->identifier_token);
503
504         return QByteArray::fromRawData(id->chars(), id->size());
505     }
506
507     void visitMembers(Class *klass)
508     {
509         for (unsigned i = 0; i < klass->memberCount(); ++i) {
510             Symbol *member = klass->memberAt(i);
511             if (! member->name())
512                 continue;
513
514             const Identifier *id = member->name()->identifier();
515
516             if (! id)
517                 continue;
518
519             const QByteArray memberName = QByteArray::fromRawData(id->chars(), id->size());
520             if (member->type().isUnsigned() && memberName.endsWith("_token")) {
521
522                 *out
523                         << "    pattern->" << memberName << " = node->" << memberName << ";" << endl
524                         << endl;
525
526             } else if (PointerType *ptrTy = member->type()->asPointerType()) {
527
528                 if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
529                     QByteArray typeName = namedTy->name()->identifier()->chars();
530
531                     if (typeName.endsWith("AST")) {
532                         *out
533                                 << "    if (! pattern->" << memberName << ")" << endl
534                                 << "        pattern->" << memberName << " = node->" << memberName << ";" << endl
535                                 << "    else if (! AST::match(node->" << memberName << ", pattern->" << memberName << ", this))" << endl
536                                 << "        return false;" << endl
537                                 << endl;
538                     }
539                 }
540             }
541         }
542
543         for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
544             const QByteArray baseClassName = klass->baseClassAt(i)->identifier()->chars();
545
546             if (ClassSpecifierAST *baseClassSpec = classMap.value(baseClassName, 0)) {
547                 visitMembers(baseClassSpec->symbol);
548             }
549         }
550     }
551
552     bool checkMethod(Symbol *accept0Method) const
553     {
554         Declaration *decl = accept0Method->asDeclaration();
555         if (! decl)
556             return false;
557
558         Function *funTy = decl->type()->asFunctionType();
559         if (! funTy)
560             return false;
561
562         else if (funTy->isPureVirtual())
563             return false;
564
565         return true;
566     }
567
568     virtual bool visit(ClassSpecifierAST *ast)
569     {
570         Class *klass = ast->symbol;
571         const QByteArray className = id_cast(ast->name);
572
573         const Identifier *match0_id = control()->identifier("match0");
574         Symbol *match0Method = klass->find(match0_id);
575         for (; match0Method; match0Method = match0Method->next()) {
576             if (match0Method->identifier() != match0_id)
577                 continue;
578
579             if (checkMethod(match0Method))
580                 break;
581         }
582
583         if (! match0Method)
584             return true;
585
586         classMap.insert(className, ast);
587
588         *out
589                 << "bool ASTMatcher::match(" << className.constData() << " *node, " << className.constData() << " *pattern)" << endl
590                 << "{" << endl
591                 << "    (void) node;" << endl
592                 << "    (void) pattern;" << endl
593                 << endl;
594
595         visitMembers(klass);
596
597         *out
598                 << "    return true;" << endl
599                 << "}" << endl
600                 << endl;
601
602         return true;
603     }
604 };
605
606 class CloneCPPCG: protected ASTVisitor
607 {
608     QDir _cplusplusDir;
609     QTextStream *out;
610
611 public:
612     CloneCPPCG(const QDir &cplusplusDir, TranslationUnit *unit)
613         : ASTVisitor(unit), _cplusplusDir(cplusplusDir), out(0)
614     { }
615
616     void operator()(AST *ast)
617     {
618         QFileInfo fileInfo(_cplusplusDir, QLatin1String("ASTClone.cpp"));
619
620         QFile file(fileInfo.absoluteFilePath());
621         if (! file.open(QFile::WriteOnly))
622             return;
623
624         QTextStream output(&file);
625         out = &output;
626
627         *out << copyrightHeader
628                 << generatedHeader
629                 << "#include \"AST.h\"" << endl
630                 << "#include \"MemoryPool.h\"" << endl
631                 << endl
632                 << "using namespace CPlusPlus;" << endl
633                 << endl;
634
635         accept(ast);
636
637         file.close();
638     }
639
640 protected:
641     using ASTVisitor::visit;
642
643     QMap<QByteArray, ClassSpecifierAST *> classMap;
644
645     QByteArray id_cast(NameAST *name)
646     {
647         if (! name)
648             return QByteArray();
649
650         const Identifier *id = identifier(name->asSimpleName()->identifier_token);
651
652         return QByteArray::fromRawData(id->chars(), id->size());
653     }
654
655     void visitMembers(Class *klass)
656     {
657         for (unsigned i = 0; i < klass->memberCount(); ++i) {
658             Symbol *member = klass->memberAt(i);
659             if (! member->name())
660                 continue;
661
662             const Identifier *id = member->name()->identifier();
663
664             if (! id)
665                 continue;
666
667             const QByteArray memberName = QByteArray::fromRawData(id->chars(), id->size());
668             if (member->type().isUnsigned() && memberName.endsWith("_token")) {
669                 *out << "    ast->" << memberName << " = " << memberName << ";" << endl;
670             } else if (PointerType *ptrTy = member->type()->asPointerType()) {
671                 if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
672                     QByteArray typeName = namedTy->name()->identifier()->chars();
673
674                     if (typeName.endsWith("ListAST")) {
675                         *out << "    for (" << typeName << " *iter = " << memberName << ", **ast_iter = &ast->" << memberName << ";" << endl
676                              << "         iter; iter = iter->next, ast_iter = &(*ast_iter)->next)" << endl
677                              << "        *ast_iter = new (pool) " << typeName << "((iter->value) ? iter->value->clone(pool) : 0);" << endl;
678                     } else if (typeName.endsWith("AST")) {
679                         *out << "    if (" << memberName << ")" << endl
680                              << "        ast->" << memberName << " = " << memberName << "->clone(pool);" << endl;
681                     }
682                 }
683             }
684         }
685
686         for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
687             const QByteArray baseClassName = klass->baseClassAt(i)->identifier()->chars();
688
689             if (ClassSpecifierAST *baseClassSpec = classMap.value(baseClassName, 0)) {
690                 visitMembers(baseClassSpec->symbol);
691             }
692         }
693     }
694
695     bool checkMethod(Symbol *cloneMethod) const
696     {
697         Declaration *decl = cloneMethod->asDeclaration();
698         if (! decl)
699             return false;
700
701         Function *funTy = decl->type()->asFunctionType();
702         if (! funTy)
703             return false;
704
705         else if (funTy->isPureVirtual())
706             return false;
707
708         return true;
709     }
710
711     virtual bool visit(ClassSpecifierAST *ast)
712     {
713         Class *klass = ast->symbol;
714         const QByteArray className = id_cast(ast->name);
715         if (! className.endsWith("AST"))
716             return false;
717
718         const Identifier *clone_id = control()->identifier("clone");
719         Symbol *cloneMethod = klass->find(clone_id);
720         for (; cloneMethod; cloneMethod = cloneMethod->next()) {
721             if (cloneMethod->identifier() != clone_id)
722                 continue;
723
724             if (checkMethod(cloneMethod))
725                 break;
726         }
727
728         if (! cloneMethod)
729             return true;
730
731         classMap.insert(className, ast);
732
733         *out << className.constData() << " *" << className.constData() << "::" << "clone(MemoryPool *pool) const" << endl
734              << "{" << endl
735              << "    " << className.constData() << " *ast = new (pool) " << className.constData() << ";" << endl;
736
737         visitMembers(klass);
738
739         *out << "    return ast;" << endl
740              << "}" << endl << endl;
741
742         return false;
743     }
744 };
745
746 class GenerateDumpers: protected ASTVisitor
747 {
748     QTextStream out;
749
750 public:
751     GenerateDumpers(QFile *file, TranslationUnit *unit)
752         : ASTVisitor(unit), out(file)
753     { }
754
755     static void go(const QString &fileName, TranslationUnit *unit)
756     {
757         QFile file(fileName);
758         if (! file.open(QFile::WriteOnly)) {
759             std::cerr << "Cannot open dumpers file." << std::endl;
760             return;
761         }
762
763         GenerateDumpers d(&file, unit);
764         d.out << copyrightHeader
765                 << generatedHeader
766                 << endl;
767
768
769         d.accept(unit->ast());
770
771         file.close();
772     }
773
774 protected:
775     using ASTVisitor::visit;
776
777     QMap<QByteArray, ClassSpecifierAST *> classMap;
778
779     QByteArray id_cast(NameAST *name)
780     {
781         if (! name)
782             return QByteArray();
783
784         const Identifier *id = identifier(name->asSimpleName()->identifier_token);
785
786         return QByteArray::fromRawData(id->chars(), id->size());
787     }
788
789     void visitMembers(Class *klass)
790     {
791         for (unsigned i = 0; i < klass->memberCount(); ++i) {
792             Symbol *member = klass->memberAt(i);
793             if (! member->name())
794                 continue;
795
796             const Identifier *id = member->name()->identifier();
797
798             if (! id)
799                 continue;
800
801             const QByteArray memberName = QByteArray::fromRawData(id->chars(), id->size());
802             if (member->type().isUnsigned() && memberName.endsWith("_token")) {
803                 out << "    if (ast->" << memberName << ")" << endl;
804                 out << "        terminal(ast->" << memberName << ", ast);" << endl;
805             } else if (PointerType *ptrTy = member->type()->asPointerType()) {
806                 if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
807                     QByteArray typeName = namedTy->name()->identifier()->chars();
808
809                     if (typeName.endsWith("ListAST")) {
810                         out << "    for (" << typeName << " *iter = ast->" << memberName << "; iter; iter = iter->next)" << endl
811                             << "        nonterminal(iter->value);" << endl;
812                     } else if (typeName.endsWith("AST")) {
813                         out << "    nonterminal(ast->" << memberName << ");" << endl;
814                     }
815                 }
816             }
817         }
818
819         for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
820             const QByteArray baseClassName = klass->baseClassAt(i)->identifier()->chars();
821
822             if (ClassSpecifierAST *baseClassSpec = classMap.value(baseClassName, 0)) {
823                 visitMembers(baseClassSpec->symbol);
824             }
825         }
826     }
827
828     bool checkMethod(Symbol *cloneMethod) const
829     {
830         Declaration *decl = cloneMethod->asDeclaration();
831         if (! decl)
832             return false;
833
834         Function *funTy = decl->type()->asFunctionType();
835         if (! funTy)
836             return false;
837
838         else if (funTy->isPureVirtual())
839             return false;
840
841         return true;
842     }
843
844     virtual bool visit(ClassSpecifierAST *ast)
845     {
846         Class *klass = ast->symbol;
847         const QByteArray className = id_cast(ast->name);
848         if (! className.endsWith("AST"))
849             return false;
850
851         const Identifier *clone_id = control()->identifier("clone");
852         Symbol *cloneMethod = klass->find(clone_id);
853         for (; cloneMethod; cloneMethod = cloneMethod->next()) {
854             if (cloneMethod->identifier() != clone_id)
855                 continue;
856
857             if (checkMethod(cloneMethod))
858                 break;
859         }
860
861         if (! cloneMethod)
862             return true;
863
864         classMap.insert(className, ast);
865
866         out << "virtual bool visit(" << className.constData() << " *ast)" << endl
867             << "{" << endl;
868
869         visitMembers(klass);
870
871         out << "    return false;" << endl
872             << "}" << endl << endl;
873
874         return false;
875     }
876 };
877
878 class RemoveCastMethods: protected ASTVisitor
879 {
880 public:
881     RemoveCastMethods(Document::Ptr doc, QTextDocument *document)
882         : ASTVisitor(doc->translationUnit()), document(document) {}
883
884     QList<QTextCursor> operator()(AST *ast)
885     {
886         _cursors.clear();
887         accept(ast);
888         return _cursors;
889     }
890
891 protected:
892     virtual bool visit(FunctionDefinitionAST *ast)
893     {
894         Function *fun = ast->symbol;
895         const QString functionName = oo(fun->name());
896
897         if (functionName.length() > 3 && functionName.startsWith(QLatin1String("as"))
898             && functionName.at(2).isUpper()) {
899
900             QTextCursor tc = createCursor(translationUnit(), ast, document);
901
902             //qDebug() << qPrintable(tc.selectedText());
903             _cursors.append(tc);
904         }
905
906         return true;
907     }
908
909 private:
910     QTextDocument *document;
911     QList<QTextCursor> _cursors;
912     Overview oo;
913 };
914
915 static QList<QTextCursor> removeConstructors(ClassSpecifierAST *classAST,
916                                              TranslationUnit *translationUnit,
917                                              QTextDocument *document)
918 {
919     Overview oo;
920     QList<QTextCursor> cursors;
921     const QString className = oo(classAST->symbol->name());
922
923     for (DeclarationListAST *iter = classAST->member_specifier_list; iter; iter = iter->next) {
924         if (FunctionDefinitionAST *funDef = iter->value->asFunctionDefinition()) {
925             if (oo(funDef->symbol->name()) == className) {
926                 // found it:
927                 QTextCursor tc = createCursor(translationUnit, funDef, document);
928                 tc.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
929                 tc.setPosition(tc.position() + 1, QTextCursor::KeepAnchor);
930                 cursors.append(tc);
931             }
932         }
933     }
934
935     return cursors;
936 }
937
938 static QStringList collectFieldNames(ClassSpecifierAST *classAST, bool onlyTokensAndASTNodes)
939 {
940     QStringList fields;
941     Overview oo;
942     Class *clazz = classAST->symbol;
943     for (unsigned i = 0; i < clazz->memberCount(); ++i) {
944         Symbol *s = clazz->memberAt(i);
945         if (Declaration *decl = s->asDeclaration()) {
946             const QString declName = oo(decl->name());
947             const FullySpecifiedType ty = decl->type();
948             if (const PointerType *ptrTy = ty->asPointerType()) {
949                 if (onlyTokensAndASTNodes) {
950                     if (const NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
951                         if (oo(namedTy->name()).endsWith(QLatin1String("AST")))
952                             fields.append(declName);
953                     }
954                 } else {
955                     fields.append(declName);
956                 }
957             } else if (ty.isUnsigned()) {
958                 fields.append(declName);
959             }
960         }
961     }
962     return fields;
963 }
964
965 static QString createConstructor(ClassSpecifierAST *classAST)
966 {
967     Overview oo;
968     Class *clazz = classAST->symbol;
969
970     QString result(QLatin1String("    "));
971     result.append(oo(clazz->name()));
972     result.append(QLatin1String("()\n"));
973
974     QStringList classFields = collectFieldNames(classAST, false);
975     for (int i = 0; i < classFields.size(); ++i) {
976         if (i == 0) {
977             result.append(QLatin1String("        : "));
978             result.append(classFields.at(i));
979             result.append(QLatin1String("(0)\n"));
980         } else {
981             result.append(QLatin1String("        , "));
982             result.append(classFields.at(i));
983             result.append(QLatin1String("(0)\n"));
984         }
985     }
986
987     result.append(QLatin1String("    {}\n"));
988     return result;
989 }
990
991 bool checkGenerated(const QTextCursor &cursor, int *doxyStart)
992 {
993     BackwardsScanner tokens(cursor, 10, QString(), false);
994     Token prevToken = tokens.LA(1);
995     if (prevToken.kind() != T_DOXY_COMMENT && prevToken.kind() != T_CPP_DOXY_COMMENT)
996         return false;
997
998     *doxyStart = tokens.startPosition() + prevToken.begin();
999
1000     return tokens.text(tokens.startToken() - 1).contains(QLatin1String("\\generated"));
1001 }
1002
1003 struct GenInfo {
1004     GenInfo()
1005         : classAST(0)
1006         , start(0)
1007         , end(0)
1008         , firstToken(false)
1009         , lastToken(false)
1010         , remove(false)
1011     {}
1012
1013     ClassSpecifierAST *classAST;
1014     int start;
1015     int end;
1016     bool firstToken;
1017     bool lastToken;
1018     bool remove;
1019 };
1020
1021 void generateFirstToken(QTextStream &os, const QString &className, const QStringList &fields)
1022 {
1023     os << "unsigned "<< className << "::firstToken() const" << endl
1024             << "{" << endl;
1025
1026     foreach (const QString &field, fields) {
1027         os << "    if (" << field << ")" << endl;
1028
1029         if (field.endsWith(QLatin1String("_token"))) {
1030             os << "        return " << field << ";" << endl;
1031         } else {
1032             os << "        if (unsigned candidate = " << field << "->firstToken())" << endl;
1033             os << "            return candidate;" << endl;
1034         }
1035     }
1036
1037     os << "    return 0;" << endl;
1038     os << "}" << endl << endl;
1039 }
1040
1041 void generateLastToken(QTextStream &os, const QString &className, const QStringList &fields)
1042 {
1043     os << "unsigned "<< className << "::lastToken() const" << endl
1044             << "{" << endl;
1045
1046     for (int i = fields.size() - 1; i >= 0; --i) {
1047         const QString field = fields.at(i);
1048
1049         os << "    if (" << field << ")" << endl;
1050
1051         if (field.endsWith(QLatin1String("_token"))) {
1052             os << "        return " << field << " + 1;" << endl;
1053         } else {
1054             os << "        if (unsigned candidate = " << field << "->lastToken())" << endl;
1055             os << "            return candidate;" << endl;
1056         }
1057     }
1058
1059     os << "    return 1;" << endl;
1060     os << "}" << endl << endl;
1061 }
1062
1063 void generateAST_cpp(const Snapshot &snapshot, const QDir &cplusplusDir)
1064 {
1065     QFileInfo fileAST_cpp(cplusplusDir, QLatin1String("AST.cpp"));
1066     Q_ASSERT(fileAST_cpp.exists());
1067
1068     const QString fileName = fileAST_cpp.absoluteFilePath();
1069
1070     QFile file(fileName);
1071     if (! file.open(QFile::ReadOnly)) {
1072         std::cerr << "Cannot open " << fileName.toLatin1().data() << std::endl;
1073         return;
1074     }
1075
1076     const QString source = QTextStream(&file).readAll();
1077     file.close();
1078
1079     QTextDocument cpp_document;
1080     cpp_document.setPlainText(source);
1081
1082     Document::Ptr AST_cpp_document = Document::create(fileName);
1083     const QByteArray preprocessedCode = snapshot.preprocessedCode(source, fileName);
1084     AST_cpp_document->setSource(preprocessedCode);
1085     AST_cpp_document->check();
1086
1087     Overview oo;
1088     QMap<QString, ClassSpecifierAST *> classesNeedingFirstToken;
1089     QMap<QString, ClassSpecifierAST *> classesNeedingLastToken;
1090
1091     // find all classes with method declarations for firstToken/lastToken
1092     foreach (ClassSpecifierAST *classAST, astNodes.deriveds) {
1093         const QString className = oo(classAST->symbol->name());
1094         if (className.isEmpty())
1095             continue;
1096
1097         for (DeclarationListAST *declIter = classAST->member_specifier_list; declIter; declIter = declIter->next) {
1098             if (SimpleDeclarationAST *decl = declIter->value->asSimpleDeclaration()) {
1099                 if (decl->symbols && decl->symbols->value) {
1100                     if (decl->symbols->next)
1101                         std::cerr << "Found simple declaration with multiple symbols in " << className.toLatin1().data() << std::endl;
1102
1103                     Symbol *s = decl->symbols->value;
1104                     const QString funName = oo(s->name());
1105                     if (funName == QLatin1String("firstToken")) {
1106                         // found it:
1107                         classesNeedingFirstToken.insert(className, classAST);
1108                     } else if (funName == QLatin1String("lastToken")) {
1109                         // found it:
1110                         classesNeedingLastToken.insert(className, classAST);
1111                     }
1112                 }
1113             }
1114         }
1115     }
1116
1117     QList<GenInfo> todo;
1118
1119     TranslationUnitAST *xUnit = AST_cpp_document->translationUnit()->ast()->asTranslationUnit();
1120     for (DeclarationListAST *iter = xUnit->declaration_list; iter; iter = iter->next) {
1121         if (FunctionDefinitionAST *funDef = iter->value->asFunctionDefinition()) {
1122             if (const QualifiedNameId *qName = funDef->symbol->name()->asQualifiedNameId()) {
1123                 const QString className = oo(qName->base());
1124                 const QString methodName = oo(qName->name());
1125
1126                 QTextCursor cursor(&cpp_document);
1127
1128                 unsigned line = 0, column = 0;
1129                 AST_cpp_document->translationUnit()->getTokenStartPosition(funDef->firstToken(), &line, &column);
1130                 const int start = cpp_document.findBlockByNumber(line - 1).position() + column - 1;
1131                 cursor.setPosition(start);
1132                 int doxyStart = start;
1133
1134                 const bool isGenerated = checkGenerated(cursor, &doxyStart);
1135
1136                 AST_cpp_document->translationUnit()->getTokenEndPosition(funDef->lastToken() - 1, &line, &column);
1137                 int end = cpp_document.findBlockByNumber(line - 1).position() + column - 1;
1138                 while (cpp_document.characterAt(end).isSpace())
1139                     ++end;
1140
1141                 if (methodName == QLatin1String("firstToken")) {
1142                     ClassSpecifierAST *classAST = classesNeedingFirstToken.value(className, 0);
1143                     GenInfo info;
1144                     info.end = end;
1145                     if (classAST) {
1146                         info.classAST = classAST;
1147                         info.firstToken = true;
1148                         info.start = start;
1149                         classesNeedingFirstToken.remove(className);
1150                     } else {
1151                         info.start = doxyStart;
1152                         info.remove = true;
1153                     }
1154                     if (isGenerated)
1155                         todo.append(info);
1156                 } else if (methodName == QLatin1String("lastToken")) {
1157                     ClassSpecifierAST *classAST = classesNeedingLastToken.value(className, 0);
1158                     GenInfo info;
1159                     info.end = end;
1160                     if (classAST) {
1161                         info.classAST = classAST;
1162                         info.start = start;
1163                         info.lastToken = true;
1164                         classesNeedingLastToken.remove(className);
1165                     } else {
1166                         info.start = doxyStart;
1167                         info.remove = true;
1168                     }
1169                     if (isGenerated)
1170                         todo.append(info);
1171                 }
1172             }
1173         }
1174     }
1175
1176     const int documentEnd = cpp_document.lastBlock().position() + cpp_document.lastBlock().length() - 1;
1177
1178     Utils::ChangeSet changes;
1179     foreach (GenInfo info, todo) {
1180         if (info.end > documentEnd)
1181             info.end = documentEnd;
1182
1183         if (info.remove) {
1184             changes.remove(info.start, info.end);
1185             return;
1186         }
1187
1188         Overview oo;
1189
1190         const QString className = oo(info.classAST->symbol->name());
1191
1192         QString method;
1193         QTextStream os(&method);
1194         const QStringList fields = collectFieldNames(info.classAST, true);
1195
1196         if (info.firstToken) {
1197             generateFirstToken(os, className, fields);
1198         } else if (info.lastToken) {
1199             generateLastToken(os, className, fields);
1200         }
1201
1202         changes.replace(info.start, info.end, method);
1203     }
1204
1205     QTextCursor tc(&cpp_document);
1206     changes.apply(&tc);
1207
1208     QString newMethods;
1209     QTextStream os(&newMethods);
1210     foreach (const QString &className, classesNeedingFirstToken.keys()) {
1211         const QStringList fields = collectFieldNames(classesNeedingFirstToken.value(className), true);
1212         os << "/** \\generated */" << endl;
1213         generateFirstToken(os, className, fields);
1214         if (ClassSpecifierAST *classAST = classesNeedingLastToken.value(className, 0)) {
1215             const QStringList fields = collectFieldNames(classAST, true);
1216             os << "/** \\generated */" << endl;
1217             generateLastToken(os, className, fields);
1218             classesNeedingLastToken.remove(className);
1219         }
1220     }
1221     foreach (const QString &className, classesNeedingLastToken.keys()) {
1222         const QStringList fields = collectFieldNames(classesNeedingLastToken.value(className), true);
1223         os << "/** \\generated */" << endl;
1224         generateLastToken(os, className, fields);
1225     }
1226     tc.setPosition(documentEnd);
1227     tc.insertText(newMethods);
1228
1229     if (file.open(QFile::WriteOnly)) {
1230         QTextStream out(&file);
1231         out << cpp_document.toPlainText();
1232     }
1233 }
1234
1235 QStringList generateAST_H(const Snapshot &snapshot, const QDir &cplusplusDir, const QString &dumpersFile)
1236 {
1237     QStringList astDerivedClasses;
1238
1239     QFileInfo fileAST_h(cplusplusDir, QLatin1String("AST.h"));
1240     Q_ASSERT(fileAST_h.exists());
1241
1242     const QString fileName = fileAST_h.absoluteFilePath();
1243
1244     QFile file(fileName);
1245     if (! file.open(QFile::ReadOnly))
1246         return astDerivedClasses;
1247
1248     const QString source = QTextStream(&file).readAll();
1249     file.close();
1250
1251     QTextDocument document;
1252     document.setPlainText(source);
1253
1254     AST_h_document = Document::create(fileName);
1255     const QByteArray preprocessedCode = snapshot.preprocessedCode(source, fileName);
1256     AST_h_document->setSource(preprocessedCode);
1257     AST_h_document->check();
1258
1259     FindASTNodes process(AST_h_document, &document);
1260     astNodes = process(AST_h_document->translationUnit()->ast());
1261
1262     RemoveCastMethods removeCastMethods(AST_h_document, &document);
1263
1264     QList<QTextCursor> baseCastMethodCursors = removeCastMethods(astNodes.base);
1265     QMap<ClassSpecifierAST *, QList<QTextCursor> > cursors;
1266     QMap<ClassSpecifierAST *, QString> replacementCastMethods;
1267     QMap<ClassSpecifierAST *, QList<QTextCursor> > constructors;
1268     QMap<ClassSpecifierAST *, QString> replacementConstructors;
1269
1270     Overview oo;
1271
1272     QStringList castMethods;
1273     foreach (ClassSpecifierAST *classAST, astNodes.deriveds) {
1274         cursors[classAST] = removeCastMethods(classAST);
1275         const QString className = oo(classAST->symbol->name());
1276         const QString methodName = QLatin1String("as") + className.mid(0, className.length() - 3);
1277         replacementCastMethods[classAST] = QString("    virtual %1 *%2() { return this; }\n").arg(className, methodName);
1278         castMethods.append(QString("    virtual %1 *%2() { return 0; }\n").arg(className, methodName));
1279         astDerivedClasses.append(className);
1280
1281         constructors[classAST] = removeConstructors(classAST, AST_h_document->translationUnit(), &document);
1282         replacementConstructors[classAST] = createConstructor(classAST);
1283     }
1284
1285     if (! baseCastMethodCursors.isEmpty()) {
1286         castMethods.sort();
1287         for (int i = 0; i < baseCastMethodCursors.length(); ++i) {
1288             baseCastMethodCursors[i].removeSelectedText();
1289         }
1290
1291         baseCastMethodCursors.first().insertText(castMethods.join(QLatin1String("")));
1292     }
1293
1294     for (int classIndex = 0; classIndex < astNodes.deriveds.size(); ++classIndex) {
1295         ClassSpecifierAST *classAST = astNodes.deriveds.at(classIndex);
1296
1297         { // remove the cast methods.
1298             QList<QTextCursor> c = cursors.value(classAST);
1299             for (int i = 0; i < c.length(); ++i) {
1300                 c[i].removeSelectedText();
1301             }
1302         }
1303         { // remove the constructors.
1304             QList<QTextCursor> c = constructors.value(classAST);
1305             for (int i = 0; i < c.length(); ++i) {
1306                 c[i].removeSelectedText();
1307             }
1308         }
1309
1310         astNodes.endOfPublicClassSpecifiers[classIndex].insertText(
1311                 replacementConstructors.value(classAST) +
1312                 QLatin1String("\n") +
1313                 replacementCastMethods.value(classAST));
1314     }
1315
1316     if (file.open(QFile::WriteOnly)) {
1317         QTextStream out(&file);
1318         out << document.toPlainText();
1319     }
1320
1321     Accept0CG cg(cplusplusDir, AST_h_document->translationUnit());
1322     cg(AST_h_document->translationUnit()->ast());
1323
1324     Match0CG cg2(cplusplusDir, AST_h_document->translationUnit());
1325     cg2(AST_h_document->translationUnit()->ast());
1326
1327     MatcherCPPCG cg3(cplusplusDir, AST_h_document->translationUnit());
1328     cg3(AST_h_document->translationUnit()->ast());
1329
1330     CloneCPPCG cg4(cplusplusDir, AST_h_document->translationUnit());
1331     cg4(AST_h_document->translationUnit()->ast());
1332
1333     generateAST_cpp(snapshot, cplusplusDir);
1334
1335     if (!dumpersFile.isEmpty())
1336         GenerateDumpers::go(dumpersFile, AST_h_document->translationUnit());
1337
1338     return astDerivedClasses;
1339 }
1340
1341 class FindASTForwards: protected ASTVisitor
1342 {
1343 public:
1344     FindASTForwards(Document::Ptr doc, QTextDocument *document)
1345         : ASTVisitor(doc->translationUnit()), document(document)
1346     {}
1347
1348     QList<QTextCursor> operator()(AST *ast)
1349     {
1350         accept(ast);
1351         return _cursors;
1352     }
1353
1354 protected:
1355     bool visit(SimpleDeclarationAST *ast)
1356     {
1357         if (! ast->decl_specifier_list)
1358             return false;
1359
1360         if (ElaboratedTypeSpecifierAST *e = ast->decl_specifier_list->value->asElaboratedTypeSpecifier()) {
1361             if (tokenKind(e->classkey_token) == T_CLASS && !ast->declarator_list) {
1362                 QString className = oo(e->name->name);
1363
1364                 if (className.length() > 3 && className.endsWith(QLatin1String("AST"))) {
1365                     QTextCursor tc = createCursor(translationUnit(), ast, document);
1366                     _cursors.append(tc);
1367                 }
1368             }
1369         }
1370
1371         return true;
1372     }
1373
1374 private:
1375     QTextDocument *document;
1376     QList<QTextCursor> _cursors;
1377     Overview oo;
1378 };
1379
1380 void generateASTFwd_h(const Snapshot &snapshot, const QDir &cplusplusDir, const QStringList &astDerivedClasses)
1381 {
1382     QFileInfo fileASTFwd_h(cplusplusDir, QLatin1String("ASTfwd.h"));
1383     Q_ASSERT(fileASTFwd_h.exists());
1384
1385     const QString fileName = fileASTFwd_h.absoluteFilePath();
1386
1387     QFile file(fileName);
1388     if (! file.open(QFile::ReadOnly))
1389         return;
1390
1391     const QString source = QTextStream(&file).readAll();
1392     file.close();
1393
1394     QTextDocument document;
1395     document.setPlainText(source);
1396
1397     Document::Ptr doc = Document::create(fileName);
1398     const QByteArray preprocessedCode = snapshot.preprocessedCode(source, fileName);
1399     doc->setSource(preprocessedCode);
1400     doc->check();
1401
1402     FindASTForwards process(doc, &document);
1403     QList<QTextCursor> cursors = process(doc->translationUnit()->ast());
1404
1405     for (int i = 0; i < cursors.length(); ++i)
1406         cursors[i].removeSelectedText();
1407
1408     QString replacement;
1409     foreach (const QString &astDerivedClass, astDerivedClasses) {
1410         replacement += QString(QLatin1String("class %1;\n")).arg(astDerivedClass);
1411     }
1412
1413     cursors.first().insertText(replacement);
1414
1415     if (file.open(QFile::WriteOnly)) {
1416         QTextStream out(&file);
1417         out << document.toPlainText();
1418     }
1419 }
1420
1421 void generateASTPatternBuilder_h(const QDir &cplusplusDir)
1422 {
1423     QFileInfo fileInfo(cplusplusDir, QLatin1String("ASTPatternBuilder.h"));
1424     QFile file(fileInfo.absoluteFilePath());
1425     if (! file.open(QFile::WriteOnly))
1426         return;
1427
1428     Overview oo;
1429     QTextStream out(&file);
1430
1431     out
1432             << copyrightHeader
1433             << generatedHeader
1434             << "#ifndef CPLUSPLUS_AST_PATTERN_BUILDER_H" << endl
1435             << "#define CPLUSPLUS_AST_PATTERN_BUILDER_H" << endl
1436             << endl
1437             << "#include \"CPlusPlusForwardDeclarations.h\"" << endl
1438             << "#include \"AST.h\"" << endl
1439             << "#include \"MemoryPool.h\"" << endl
1440             << endl
1441             << "namespace CPlusPlus {" << endl
1442             << endl
1443             << "class CPLUSPLUS_EXPORT ASTPatternBuilder" << endl
1444             << "{" << endl
1445             << "    MemoryPool pool;" << endl
1446             << endl
1447             << "public:" << endl
1448             << "    ASTPatternBuilder() {}" << endl
1449             << endl
1450             << "    void reset() { pool.reset(); }" << endl
1451             << endl;
1452
1453     Control *control = AST_h_document->control();
1454     QSet<QString> listClasses;
1455
1456     foreach (ClassSpecifierAST *classNode, astNodes.deriveds) {
1457         Class *klass = classNode->symbol;
1458
1459         const Identifier *match0_id = control->identifier("match0");
1460         Symbol *match0Method = klass->find(match0_id);
1461         for (; match0Method; match0Method = match0Method->next()) {
1462             if (match0Method->identifier() != match0_id)
1463                 continue;
1464             else break;
1465         }
1466
1467         if (! match0Method)
1468             continue;
1469
1470         const QString className = oo(klass->name());
1471
1472         if (! className.endsWith("AST"))
1473             continue;
1474
1475         const QString methodName = className.left(className.length() - 3);
1476
1477         out
1478                 << "    " << className << " *" << methodName << "(";
1479
1480         QList<QPair<QString, QString> > args;
1481
1482         bool first = true;
1483         for (unsigned index = 0; index < klass->memberCount(); ++index) {
1484             Declaration *member = klass->memberAt(index)->asDeclaration();
1485             if (! member)
1486                 continue;
1487
1488             PointerType *ptrTy = member->type()->asPointerType();
1489             if (! ptrTy)
1490                 continue;
1491
1492             const QString tyName = oo(ptrTy->elementType());
1493             if (tyName.endsWith("ListAST"))
1494                 listClasses.insert(tyName);
1495             if (tyName.endsWith("AST")) {
1496                 if (! first)
1497                     out << ", ";
1498
1499                 const QString memberName = oo(member->name());
1500
1501                 out << tyName << " *" << memberName << " = 0";
1502                 args.append(qMakePair(tyName, memberName));
1503                 first = false;
1504             }
1505         }
1506
1507         out
1508                 << ")" << endl
1509                 << "    {" << endl
1510                 << "        " << className << " *__ast = new (&pool) " << className << ";" << endl;
1511
1512
1513         QPair<QString, QString> p;
1514         foreach (p, args) {
1515             out
1516                     << "        __ast->" << p.second << " = " << p.second << ";" << endl;
1517         }
1518
1519         out
1520                 << "        return __ast;" << endl
1521                 << "    }" << endl
1522                 << endl;
1523     }
1524
1525     foreach (const QString &className, listClasses) {
1526         const QString methodName = className.left(className.length() - 3);
1527         const QString elementName = className.left(className.length() - 7) + QLatin1String("AST");
1528         out
1529                 << "    " << className << " *" << methodName << "("
1530                 << elementName << " *value, " << className << " *next = 0)" << endl
1531                 << "    {" << endl
1532                 << "        " << className << " *__list = new (&pool) " << className << ";" << endl
1533                 << "        __list->next = next;" << endl
1534                 << "        __list->value = value;" << endl
1535                 << "        return __list;" << endl
1536                 << "    }" << endl
1537                 << endl;
1538     }
1539
1540     out
1541             << "};" << endl
1542             << endl
1543             << "} // end of namespace CPlusPlus" << endl
1544             << endl
1545             << "#endif // CPLUSPLUS_AST_PATTERN_BUILDER_H" << endl;
1546 }
1547
1548 int main(int argc, char *argv[])
1549 {
1550     QCoreApplication app(argc, argv);
1551     QStringList files = app.arguments();
1552     files.removeFirst();
1553
1554     if (files.size() != 1 && files.size() != 2) {
1555         std::cerr << "Usage: cplusplus [path to C++ front-end]" << std::endl;
1556         std::cerr << "   or: cplusplus [path to C++ front-end] [dumpers file name]" << std::endl;
1557         return EXIT_FAILURE;
1558     }
1559
1560     QDir cplusplusDir(files.first());
1561     if (!QFileInfo(cplusplusDir, QLatin1String("AST.h")).exists()) {
1562         std::cerr << "Cannot find AST.h in " << qPrintable(cplusplusDir.absolutePath())
1563                 << std::endl;
1564         return EXIT_FAILURE;
1565     }
1566
1567     QString dumpersFile;
1568     if (files.size() == 2)
1569         dumpersFile = files.last();
1570
1571     Snapshot snapshot;
1572     QStringList astDerivedClasses = generateAST_H(snapshot, cplusplusDir, dumpersFile);
1573     astDerivedClasses.sort();
1574     generateASTFwd_h(snapshot, cplusplusDir, astDerivedClasses);
1575
1576     generateASTPatternBuilder_h(cplusplusDir);
1577 }