From 657bb225b4909a38085febbf34ce0cf4f7f21588 Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Thu, 26 Aug 2010 16:38:34 +0200
Subject: [PATCH] Added a trivial Visitor generator.

---
 src/tools/mkvisitor/conf.c++      |  15 +
 src/tools/mkvisitor/main.cpp      | 456 ++++++++++++++++++++++++++++++
 src/tools/mkvisitor/mkvisitor     |   5 +
 src/tools/mkvisitor/mkvisitor.pro |  19 ++
 4 files changed, 495 insertions(+)
 create mode 100644 src/tools/mkvisitor/conf.c++
 create mode 100644 src/tools/mkvisitor/main.cpp
 create mode 100755 src/tools/mkvisitor/mkvisitor
 create mode 100644 src/tools/mkvisitor/mkvisitor.pro

diff --git a/src/tools/mkvisitor/conf.c++ b/src/tools/mkvisitor/conf.c++
new file mode 100644
index 00000000000..69bafe0459c
--- /dev/null
+++ b/src/tools/mkvisitor/conf.c++
@@ -0,0 +1,15 @@
+#define __extension__
+#define __context__
+#define __range__
+#define __asm(a...)
+#define __asm__(a...)
+#define   restrict
+#define __restrict
+#define __restrict__
+// #define __weak
+#define __builtin_va_arg(a,b) ((b)0)
+#define __stdcall
+#define __fastcall
+#define __imag__
+#define __real__
+#define __complex__
diff --git a/src/tools/mkvisitor/main.cpp b/src/tools/mkvisitor/main.cpp
new file mode 100644
index 00000000000..7588ff2700d
--- /dev/null
+++ b/src/tools/mkvisitor/main.cpp
@@ -0,0 +1,456 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include <AST.h>
+#include <ASTVisitor.h>
+#include <ASTPatternBuilder.h>
+#include <ASTMatcher.h>
+#include <Control.h>
+#include <Scope.h>
+#include <Bind.h>
+#include <TranslationUnit.h>
+#include <Literals.h>
+#include <Symbols.h>
+#include <Names.h>
+#include <CoreTypes.h>
+#include <CppDocument.h>
+#include <SymbolVisitor.h>
+#include <Overview.h>
+#include <LookupContext.h>
+
+#include <QFile>
+#include <QList>
+#include <QCoreApplication>
+#include <QStringList>
+#include <QFileInfo>
+#include <QTime>
+#include <QtDebug>
+
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+
+using namespace CPlusPlus;
+
+class MkVisitor: protected SymbolVisitor
+{
+    const LookupContext &context;
+    Overview oo;
+    QList<ClassOrNamespace *> interfaces;
+    QList<ClassOrNamespace *> nodes;
+
+    bool isMiscNode(ClassOrNamespace *b) const
+    {
+        foreach (ClassOrNamespace *u, b->usings()) {
+            if (oo(u->symbols().first()->name()) == QLatin1String("AST"))
+                return true;
+        }
+
+        return false;
+    }
+
+    QString getAcceptFunctionName(ClassOrNamespace *b, QString *retType) const
+    {
+        Q_ASSERT(b != 0);
+
+        retType->clear();
+
+        if (interfaces.contains(b) || isMiscNode(b)) {
+            QString className = oo(b->symbols().first()->name());
+
+            if (className.endsWith("AST")) {
+                className.chop(3);
+
+                QString funcName = className;
+                if (! funcName.isEmpty())
+                    funcName[0] = funcName[0].toLower();
+
+                if (funcName == QLatin1String("operator"))
+                    funcName = QLatin1String("cppOperator");
+
+                if (interfaces.contains(b))
+                    *retType = className + QLatin1String("Ty");
+
+                return funcName;
+            }
+        }
+
+        if (! b->usings().isEmpty())
+            return getAcceptFunctionName(b->usings().first(), retType);
+
+        Q_ASSERT(!"wtf?");
+        return QString();
+    }
+
+public:
+    MkVisitor(const LookupContext &context): context(context) {
+        accept(context.thisDocument()->globalNamespace());
+
+        // declaration
+
+        std::cout << "#include <CPlusPlus.h>" << std::endl
+                  << "#include <memory>" << std::endl
+                  << "#include <cassert>" << std::endl
+                  << std::endl
+                  << "using namespace CPlusPlus;" << std::endl
+                  << std::endl;
+
+
+        std::cout << "class Semantic: protected ASTVisitor" << std::endl
+                  << "{" << std::endl
+                  << "public:" << std::endl
+                  << "    Semantic(TranslationUnit *unit): ASTVisitor(unit) { translationUnit(unit->ast()->asTranslationUnit()); }" << std::endl
+                  << std::endl;
+
+        foreach (ClassOrNamespace *b, interfaces) {
+            Q_ASSERT(! b->symbols().isEmpty());
+
+            Class *klass = 0;
+            foreach (Symbol *s, b->symbols())
+                if ((klass = s->asClass()) != 0)
+                    break;
+
+            Q_ASSERT(klass != 0);
+
+            QString className = oo(klass->name());
+            if (className == "AST")
+                continue;
+
+            QString baseClassName = className;
+            baseClassName.chop(3);
+
+            QString retTy = false;
+            QString funcName = getAcceptFunctionName(b, &retTy);
+
+            std::cout
+                    << "    typedef void *" << qPrintable(baseClassName) << "Ty;" << std::endl
+                    << "    " << qPrintable(baseClassName) << "Ty " << qPrintable(funcName)
+                    << "(" << qPrintable(className) << " *ast);" << std::endl
+                    << std::endl;
+        }
+
+        std::cout << "protected:" << std::endl;
+        std::cout << "    using ASTVisitor::translationUnit;" << std::endl
+                  << std::endl;
+
+        QHash<ClassOrNamespace *, QList<ClassOrNamespace *> > implements;
+        foreach (ClassOrNamespace *b, nodes) {
+            ClassOrNamespace *iface = 0;
+            foreach (ClassOrNamespace *u, b->usings()) {
+                if (interfaces.contains(u)) {
+                    iface = u;
+                    break;
+                }
+            }
+            Q_ASSERT(iface != 0);
+            implements[iface].append(b);
+        }
+
+        foreach (ClassOrNamespace *iface, interfaces) {
+            foreach (ClassOrNamespace *b, implements.value(iface)) {
+                if (! isMiscNode(b))
+                    continue;
+
+                Class *klass = 0;
+                foreach (Symbol *s, b->symbols())
+                    if ((klass = s->asClass()) != 0)
+                        break;
+
+                Q_ASSERT(klass != 0);
+
+                QString retTy ;
+                QString className = oo(klass->name());
+                std::cout << "    void " << qPrintable(getAcceptFunctionName(b, &retTy)) << "(" << qPrintable(className) << " *ast);" << std::endl;
+            }
+        }
+
+        std::cout << std::endl;
+
+        foreach (ClassOrNamespace *iface, interfaces) {
+            std::cout << "    // " << qPrintable(oo(iface->symbols().first()->name())) << std::endl;
+            foreach (ClassOrNamespace *b, implements.value(iface)) {
+                Class *klass = 0;
+                foreach (Symbol *s, b->symbols())
+                    if ((klass = s->asClass()) != 0)
+                        break;
+
+                Q_ASSERT(klass != 0);
+
+                QString className = oo(klass->name());
+                std::cout << "    virtual bool visit(" << qPrintable(className) << " *ast);" << std::endl;
+            }
+            std::cout << std::endl;
+        }
+
+        std::cout << "private:" << std::endl;
+        foreach (ClassOrNamespace *b, interfaces) {
+            Q_ASSERT(! b->symbols().isEmpty());
+
+            Class *klass = 0;
+            foreach (Symbol *s, b->symbols())
+                if ((klass = s->asClass()) != 0)
+                    break;
+
+            Q_ASSERT(klass != 0);
+
+            QString className = oo(klass->name());
+            if (className == "AST")
+                continue;
+
+            QString baseClassName = className;
+            baseClassName.chop(3);
+
+            QString current = "_current";
+            current += baseClassName;
+
+            std::cout << "    " << qPrintable(baseClassName) << "Ty " << qPrintable(current) << ";" << std::endl;
+        }
+
+        std::cout << "};" << std::endl
+                  << std::endl;
+
+
+        std::cout << "namespace { bool debug_todo = false; }" << std::endl
+                  << std::endl;
+
+
+        // implementation
+
+        foreach (ClassOrNamespace *b, interfaces) {
+            Q_ASSERT(! b->symbols().isEmpty());
+
+            Class *klass = 0;
+            foreach (Symbol *s, b->symbols())
+                if ((klass = s->asClass()) != 0)
+                    break;
+
+            Q_ASSERT(klass != 0);
+
+            QString className = oo(klass->name());
+            if (className == "AST")
+                continue;
+
+            QString baseClassName = className;
+            baseClassName.chop(3);
+
+            QString retTy;
+            QString funcName = getAcceptFunctionName(b, &retTy);
+
+            QString current = "_current";
+            current += baseClassName;
+
+            std::cout << "Semantic::" << qPrintable(baseClassName) << "Ty Semantic::"
+                      << qPrintable(funcName) << "(" << qPrintable(className) << " *ast)" << std::endl
+                      << "{" << std::endl
+                      << "    " << qPrintable(baseClassName) << "Ty value = " << qPrintable(baseClassName) << "Ty();" << std::endl
+                      << "    std::swap(" << qPrintable(current) << ", value);" << std::endl
+                      << "    accept(ast);" << std::endl
+                      << "    std::swap(" << qPrintable(current) << ", value);" << std::endl
+                      << "    return value;" << std::endl
+                      << "}" << std::endl
+                      << std::endl;
+        }
+
+        foreach (ClassOrNamespace *iface, interfaces) {
+            std::cout << "// " << qPrintable(oo(iface->symbols().first()->name())) << std::endl;
+            foreach (ClassOrNamespace *b, implements.value(iface)) {
+                Class *klass = 0;
+                foreach (Symbol *s, b->symbols())
+                    if ((klass = s->asClass()) != 0)
+                        break;
+
+                Q_ASSERT(klass != 0);
+
+                QString className = oo(klass->name());
+                std::cout << "bool Semantic::visit(" << qPrintable(className) << " *ast)" << std::endl
+                          << "{" << std::endl;
+
+                if (isMiscNode(b)) {
+                    std::cout << "    (void) ast;" << std::endl
+                              << "    assert(!\"unreachable\");" << std::endl
+                              << "    return false;" << std::endl
+                              << "}" << std::endl
+                              << std::endl;
+
+                    QString retTy;
+                    std::cout << "void Semantic::" << qPrintable(getAcceptFunctionName(b, &retTy)) << "(" << qPrintable(className) << " *ast)" << std::endl
+                              << "{" << std::endl
+                              << "    if (! ast)" << std::endl
+                              << "        return;" << std::endl
+                              << std::endl;
+                }
+
+                std::cout
+                        << "    if (debug_todo)" << std::endl
+                        << "        translationUnit()->warning(ast->firstToken(), \"TODO: %s\", __func__);" << std::endl;
+
+                for (unsigned i = 0; i < klass->memberCount(); ++i) {
+                    Declaration *decl = klass->memberAt(i)->asDeclaration();
+                    if (! decl)
+                        continue;
+                    if (decl->type()->isFunctionType())
+                        continue;
+                    const QString declName = oo(decl->name());
+                    if (PointerType *ptrTy = decl->type()->asPointerType()) {
+                        if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
+                            const QString eltTyName = oo(namedTy->name());
+                            if (eltTyName.endsWith("ListAST")) {
+                                QString name = eltTyName;
+                                name.chop(7);
+                                name += "AST";
+
+                                Control *control = context.thisDocument()->control();
+                                const Name *n = control->nameId(control->identifier(name.toLatin1().constData()));
+
+                                if (ClassOrNamespace *bb = context.lookupType(n, klass)) {
+                                    QString retTy;
+                                    QString funcName = getAcceptFunctionName(bb, &retTy);
+                                    Q_ASSERT(! funcName.isEmpty());
+
+                                    QString var;
+                                    if (! retTy.isEmpty())
+                                        var += retTy + QLatin1String(" value = ");
+                                    //std::cout << "    // ### accept with function " << qPrintable(getAcceptFunctionName(bb, &hasRetValue)) << std::endl;
+                                    std::cout << "    for (" << qPrintable(eltTyName) << " *it = ast->" << qPrintable(declName) << "; it; it = it->next) {" << std::endl
+                                              << "        " << qPrintable(var) << "this->" << qPrintable(funcName) << "(it->value);" << std::endl
+                                              << "    }" << std::endl;
+                                    continue;
+                                }
+
+                                std::cout << "    // ### process list of " << qPrintable(name) << std::endl;
+                                continue;
+                            }
+
+                            if (ClassOrNamespace *ty = context.lookupType(namedTy->name(), klass)) {
+                                QString className = oo(ty->symbols().first()->name());
+                                QString baseClassName = className;
+                                if (baseClassName.endsWith("AST")) {
+                                    baseClassName.chop(3);
+
+                                    QString retTy;
+                                    QString funcName = getAcceptFunctionName(ty, &retTy);
+                                    QString var;
+                                    if (! retTy.isEmpty())
+                                        var += retTy + QLatin1String(" ") + declName + QLatin1String(" = ");
+                                    std::cout << "    " << qPrintable(var) << "this->" << qPrintable(funcName) << "(ast->" << qPrintable(declName) << ");" << std::endl;
+                                    continue;
+                                }
+                            }
+                        }
+                    }
+
+                    std::cout << "    // " << qPrintable(oo.prettyType(decl->type(), declName)) << " = ast->" << qPrintable(declName) << ";" << std::endl;
+                }
+
+                if (! isMiscNode(b))
+                    std::cout << "    return false;" << std::endl;
+
+                std::cout
+                          << "}" << std::endl
+                          << std::endl;
+            }
+            std::cout << std::endl;
+        }
+
+    }
+
+protected:
+    using SymbolVisitor::visit;
+
+    QList<ClassOrNamespace *> baseClasses(ClassOrNamespace *b) {
+        QList<ClassOrNamespace *> usings = b->usings();
+        foreach (ClassOrNamespace *u, usings)
+            usings += baseClasses(u);
+        return usings;
+    }
+
+    virtual bool visit(Class *klass) {
+        const QString className = oo(klass->name());
+        if (! className.endsWith("AST"))
+            return false;
+
+        ClassOrNamespace *b = context.lookupType(klass);
+        Q_ASSERT(b != 0);
+
+        const Identifier *accept0 = context.thisDocument()->control()->identifier("accept0");
+        if (Symbol *s = klass->find(accept0)) {
+            if (Function *meth = s->type()->asFunctionType()) {
+                if (! meth->isPureVirtual()) {
+                    foreach (ClassOrNamespace *u, b->usings()) {
+                        if (interfaces.contains(u)) {
+                            // qDebug() << oo(klass->name()) << "implements" << oo(u->symbols().first()->name());
+                        } else {
+                            Q_ASSERT(!"no way");
+                        }
+                    }
+                    nodes.append(b);
+                    return false;
+                }
+            }
+        }
+
+        //qDebug() << oo(klass->name()) << "is a base ast node";
+        interfaces.append(b);
+
+        return false;
+    }
+};
+
+int main(int argc, char *argv[])
+{
+    QCoreApplication app(argc, argv);
+
+    QStringList files = app.arguments();
+    files.removeFirst();
+
+    foreach (const QString &fileName, files) {
+        QFile file(fileName);
+        if (! file.open(QFile::ReadOnly))
+            continue;
+
+        const QByteArray source = file.readAll();
+        file.close();
+
+        Document::Ptr doc = Document::create(fileName);
+        //doc->control()->setDiagnosticClient(0);
+        doc->setSource(source);
+        doc->parse();
+
+        doc->translationUnit()->blockErrors(true);
+
+        doc->check();
+        Snapshot snapshot;
+	snapshot.insert(doc);
+
+	LookupContext context(doc, snapshot);
+	MkVisitor mkVisitor(context);
+    }
+
+    return EXIT_SUCCESS;
+}
diff --git a/src/tools/mkvisitor/mkvisitor b/src/tools/mkvisitor/mkvisitor
new file mode 100755
index 00000000000..0a6f67da532
--- /dev/null
+++ b/src/tools/mkvisitor/mkvisitor
@@ -0,0 +1,5 @@
+#!/bin/sh
+me=$(dirname $0)
+${CPP-gcc} -DCPLUSPLUS_WITHOUT_QT -U__BLOCKS__ -xc++ -E -include $me/conf.c++ ../../shared/cplusplus/AST.h > $me/file.i
+$me/cplusplus0 $me/file.i
+rm -f $me/file.i
diff --git a/src/tools/mkvisitor/mkvisitor.pro b/src/tools/mkvisitor/mkvisitor.pro
new file mode 100644
index 00000000000..57c410474aa
--- /dev/null
+++ b/src/tools/mkvisitor/mkvisitor.pro
@@ -0,0 +1,19 @@
+QT = core gui
+macx:CONFIG -= app_bundle
+TARGET = cplusplus0
+
+include(../../libs/cplusplus/cplusplus-lib.pri)
+
+# Input
+SOURCES += main.cpp
+
+unix {
+    debug:OBJECTS_DIR = $${OUT_PWD}/.obj/debug-shared
+    release:OBJECTS_DIR = $${OUT_PWD}/.obj/release-shared
+
+    debug:MOC_DIR = $${OUT_PWD}/.moc/debug-shared
+    release:MOC_DIR = $${OUT_PWD}/.moc/release-shared
+
+    RCC_DIR = $${OUT_PWD}/.rcc/
+    UI_DIR = $${OUT_PWD}/.uic/
+}
-- 
GitLab