OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / tests / tools / qml-ast2dot / main.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 (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include <qmljs/parser/qmljsast_p.h>
34 #include <qmljs/parser/qmljsastvisitor_p.h>
35 #include <qmljs/qmljsdocument.h>
36
37 #include <QFile>
38 #include <QList>
39 #include <QCoreApplication>
40 #include <QStringList>
41 #include <QFileInfo>
42 #include <QTime>
43 #include <QtDebug>
44
45 #include <cstdio>
46 #include <cstdlib>
47 #include <fstream>
48 #include <iostream>
49 #ifdef __GNUC__
50 #  include <cxxabi.h>
51 #endif
52
53 using namespace QmlJS;
54 using namespace QmlJS::AST;
55 using namespace std;
56
57 class ASTDump: protected Visitor
58 {
59 public:
60     void operator()(const QString &fileName, const QByteArray &src, Node *ast) {
61         _src = src;
62         QString basename = fileName;
63         int dotIdx = basename.lastIndexOf('.');
64         if (dotIdx != -1)
65             basename.truncate(dotIdx);
66         basename.append(QLatin1String(".ast.dot"));
67         out.open(basename.toUtf8().constData());
68
69         out << "digraph AST { ordering=out;" << endl;
70         // cout << "rankdir = \"LR\";" << endl;
71         Node::accept(ast, this);
72
73         typedef QPair<QByteArray, QByteArray> Pair;
74
75         foreach (const Pair &conn, _connections)
76             out << conn.first.constData() << " -> " << conn.second.constData() << endl;
77
78         alignTerminals();
79
80         out << "}" << endl;
81         out.close();
82         cout << qPrintable(basename) << endl;
83     }
84
85 protected:
86     void alignTerminals() {
87         out<<"{ rank=same;" << endl;
88         foreach (const QByteArray &terminalShape, _terminalShapes) {
89             out << "  " << string(terminalShape) << ";" << endl;
90         }
91         out<<"}"<<endl;
92     }
93
94     static QByteArray name(Node *ast) {
95 #ifdef __GNUC__
96         QByteArray name = abi::__cxa_demangle(typeid(*ast).name(), 0, 0, 0) + 12;
97 #else
98         QByteArray name = typeid(*ast).name();
99 #endif
100         return name;
101     }
102
103     QString spell(const SourceLocation &token) {
104         return _src.mid(token.offset, token.length).replace('\'', "\\\\").replace('"', "\\\"");
105     }
106
107     void terminal(const SourceLocation &token) {
108         if (!token.isValid())
109             return;
110
111         static int count = 1;
112         QByteArray id = 't' + QByteArray::number(count++);
113         Node *node = _stack.last();
114         _connections.append(qMakePair(_id[node], id));
115
116         QByteArray t;
117         t.append(id);
118         t.append(" [label = \"");
119         t.append(spell(token).toUtf8());
120         t.append("\" shape=rect]");
121         _terminalShapes.append(t);
122     }
123
124     virtual void nonterminal(Node *ast) {
125         Node::accept(ast, this);
126     }
127
128     virtual void node(Node *ast) {
129         out << _id[ast].constData() << " [label=\"" << name(ast).constData() << "\"];" << endl;
130     }
131
132     virtual bool preVisit(Node *ast) {
133         static int count = 1;
134         const QByteArray id = 'n' + QByteArray::number(count++);
135         _id[ast] = id;
136
137
138         if (! _stack.isEmpty())
139             _connections.append(qMakePair(_id[_stack.last()], id));
140
141         _stack.append(ast);
142
143         node(ast);
144
145         return true;
146     }
147
148     virtual void postVisit(Node *) {
149         _stack.removeLast();
150     }
151
152 protected: // visiting methods:
153     virtual bool visit(UiImport *ast) {
154         terminal(ast->importToken);
155
156         if (ast->importUri)
157             nonterminal(ast->importUri);
158         else
159             terminal(ast->fileNameToken);
160
161         terminal(ast->versionToken);
162         terminal(ast->asToken);
163         terminal(ast->importIdToken);
164         terminal(ast->semicolonToken);
165         return false;
166     }
167
168     virtual bool visit(UiObjectBinding *ast) {
169         if (ast->hasOnToken) {
170             nonterminal(ast->qualifiedTypeNameId);
171             terminal(ast->colonToken);
172             nonterminal(ast->qualifiedId);
173         } else {
174             nonterminal(ast->qualifiedId);
175             terminal(ast->colonToken);
176             nonterminal(ast->qualifiedTypeNameId);
177         }
178         nonterminal(ast->initializer);
179         return false;
180     }
181
182     virtual bool visit(UiObjectDefinition *ast) {
183         nonterminal(ast->qualifiedTypeNameId);
184         nonterminal(ast->initializer);
185         return false;
186     }
187
188     virtual bool visit(UiObjectInitializer *ast) {
189         terminal(ast->lbraceToken);
190         nonterminal(ast->members);
191         terminal(ast->rbraceToken);
192         return false;
193     }
194
195     virtual bool visit(UiScriptBinding *ast) {
196         nonterminal(ast->qualifiedId);
197         terminal(ast->colonToken);
198         nonterminal(ast->statement);
199         return false;
200     }
201
202     virtual bool visit(UiArrayBinding *ast) {
203         nonterminal(ast->qualifiedId);
204         terminal(ast->colonToken);
205         terminal(ast->lbracketToken);
206         nonterminal(ast->members);
207         terminal(ast->rbracketToken);
208         return false;
209     }
210
211     virtual bool visit(UiArrayMemberList *ast) {
212         terminal(ast->commaToken);
213         nonterminal(ast->member);
214         nonterminal(ast->next);
215         return false;
216     }
217
218     virtual bool visit(UiQualifiedId *ast) {
219         terminal(ast->identifierToken);
220         nonterminal(ast->next);
221         return false;
222     }
223
224     virtual bool visit(UiPublicMember *ast) {
225         // TODO: place the parameters...
226 //        UiParameterList *parameters;
227
228         terminal(ast->defaultToken);
229         terminal(ast->readonlyToken);
230         terminal(ast->propertyToken);
231         terminal(ast->typeModifierToken);
232         terminal(ast->typeToken);
233         terminal(ast->identifierToken);
234         terminal(ast->colonToken);
235         nonterminal(ast->expression);
236         nonterminal(ast->binding);
237         terminal(ast->semicolonToken);
238         return false;
239     }
240
241     virtual bool visit(UiFormal *ast) { terminal(ast->identifierToken); terminal(ast->asToken); terminal(ast->aliasToken); return false; }
242     virtual bool visit(UiSignature *ast) { terminal(ast->lparenToken); nonterminal(ast->formals); terminal(ast->rparenToken); return false; }
243
244     virtual bool visit(StringLiteral *ast) { terminal(ast->literalToken); return false; }
245     virtual bool visit(NumericLiteral *ast) { terminal(ast->literalToken); return false; }
246     virtual bool visit(TrueLiteral *ast) { terminal(ast->trueToken); return false; }
247     virtual bool visit(FalseLiteral *ast) { terminal(ast->falseToken); return false; }
248     virtual bool visit(IdentifierExpression *ast) { terminal(ast->identifierToken); return false; }
249     virtual bool visit(FieldMemberExpression *ast) { nonterminal(ast->base); terminal(ast->dotToken); terminal(ast->identifierToken); return false; }
250     virtual bool visit(BinaryExpression *ast) { nonterminal(ast->left); terminal(ast->operatorToken); nonterminal(ast->right); return false; }
251     virtual bool visit(UnaryPlusExpression *ast) { terminal(ast->plusToken); nonterminal(ast->expression); return false; }
252     virtual bool visit(UnaryMinusExpression *ast) { terminal(ast->minusToken); nonterminal(ast->expression); return false; }
253     virtual bool visit(NestedExpression *ast) { terminal(ast->lparenToken); nonterminal(ast->expression); terminal(ast->rparenToken); return false; }
254     virtual bool visit(ThisExpression *ast) { terminal(ast->thisToken); return false; }
255     virtual bool visit(NullExpression *ast) { terminal(ast->nullToken); return false; }
256     virtual bool visit(RegExpLiteral *ast) { terminal(ast->literalToken); return false; }
257     virtual bool visit(ArrayLiteral *ast) { terminal(ast->lbracketToken); nonterminal(ast->elements); terminal(ast->commaToken); nonterminal(ast->elision); terminal(ast->rbracketToken); return false; }
258     virtual bool visit(ObjectLiteral *ast) { terminal(ast->lbraceToken); nonterminal(ast->properties); terminal(ast->rbraceToken); return false; }
259     virtual bool visit(ElementList *ast) { nonterminal(ast->next); terminal(ast->commaToken); nonterminal(ast->elision); nonterminal(ast->expression); return false; }
260     virtual bool visit(Elision *ast) { nonterminal(ast->next); terminal(ast->commaToken); return false; }
261     virtual bool visit(PropertyNameAndValueList *ast) { nonterminal(ast->name); terminal(ast->colonToken); nonterminal(ast->value); terminal(ast->commaToken); nonterminal(ast->next); return false; }
262     virtual bool visit(IdentifierPropertyName *ast) { terminal(ast->propertyNameToken); return false; }
263     virtual bool visit(StringLiteralPropertyName *ast) { terminal(ast->propertyNameToken); return false; }
264     virtual bool visit(NumericLiteralPropertyName *ast) { terminal(ast->propertyNameToken); return false; }
265     virtual bool visit(ArrayMemberExpression *ast) { nonterminal(ast->base); terminal(ast->lbracketToken); nonterminal(ast->expression); terminal(ast->rbracketToken); return false; }
266     virtual bool visit(NewMemberExpression *ast) { terminal(ast->newToken); nonterminal(ast->base); terminal(ast->lparenToken); nonterminal(ast->arguments); terminal(ast->rparenToken); return false; }
267     virtual bool visit(NewExpression *ast) { terminal(ast->newToken); nonterminal(ast->expression); return false; }
268     virtual bool visit(CallExpression *ast) { nonterminal(ast->base); terminal(ast->lparenToken); nonterminal(ast->arguments); terminal(ast->rparenToken); return false; }
269     virtual bool visit(ArgumentList *ast) { nonterminal(ast->expression); terminal(ast->commaToken); nonterminal(ast->next); return false; }
270     virtual bool visit(PostIncrementExpression *ast) { nonterminal(ast->base); terminal(ast->incrementToken); return false; }
271     virtual bool visit(PostDecrementExpression *ast) { nonterminal(ast->base); terminal(ast->decrementToken); return false; }
272     virtual bool visit(DeleteExpression *ast) { terminal(ast->deleteToken); nonterminal(ast->expression); return false; }
273     virtual bool visit(VoidExpression *ast) { terminal(ast->voidToken); nonterminal(ast->expression); return false; }
274     virtual bool visit(TypeOfExpression *ast) { terminal(ast->typeofToken); nonterminal(ast->expression); return false; }
275     virtual bool visit(PreIncrementExpression *ast) { terminal(ast->incrementToken); nonterminal(ast->expression); return false; }
276     virtual bool visit(PreDecrementExpression *ast) { terminal(ast->decrementToken); nonterminal(ast->expression); return false; }
277     virtual bool visit(TildeExpression *ast) { terminal(ast->tildeToken); nonterminal(ast->expression); return false; }
278     virtual bool visit(NotExpression *ast) { terminal(ast->notToken); nonterminal(ast->expression); return false; }
279     virtual bool visit(ConditionalExpression *ast) { nonterminal(ast->expression); terminal(ast->questionToken); nonterminal(ast->ok); terminal(ast->colonToken); nonterminal(ast->ko); return false; }
280     virtual bool visit(Expression *ast) { nonterminal(ast->left); terminal(ast->commaToken); nonterminal(ast->right); return false; }
281     virtual bool visit(Block *ast) { terminal(ast->lbraceToken); nonterminal(ast->statements); terminal(ast->rbraceToken); return false; }
282     virtual bool visit(VariableStatement *ast) { terminal(ast->declarationKindToken); nonterminal(ast->declarations); terminal(ast->semicolonToken); return false; }
283     virtual bool visit(VariableDeclaration *ast) { terminal(ast->identifierToken); nonterminal(ast->expression); return false; }
284     virtual bool visit(VariableDeclarationList *ast) { nonterminal(ast->declaration); terminal(ast->commaToken); nonterminal(ast->next); return false; }
285     virtual bool visit(EmptyStatement* ast) { terminal(ast->semicolonToken); return false; }
286     virtual bool visit(ExpressionStatement *ast) { nonterminal(ast->expression); terminal(ast->semicolonToken); return false; }
287     virtual bool visit(IfStatement *ast) { terminal(ast->ifToken); terminal(ast->lparenToken); nonterminal(ast->expression); terminal(ast->rparenToken); nonterminal(ast->ok); terminal(ast->elseToken); nonterminal(ast->ko); return false; }
288     virtual bool visit(DoWhileStatement *ast) { terminal(ast->doToken); nonterminal(ast->statement); terminal(ast->whileToken); terminal(ast->lparenToken); nonterminal(ast->expression); terminal(ast->rparenToken); terminal(ast->semicolonToken); return false; }
289
290 // TODO: visitors for:
291 //    WhileStatement
292 //    ForStatement
293 //    LocalForStatement
294 //    ForEachStatement
295 //    LocalForEachStatement
296 //    ContinueStatement
297 //    BreakStatement
298 //    ReturnStatement
299 //    WithStatement
300 //    CaseBlock
301 //    SwitchStatement
302 //    CaseClause
303 //    DefaultClause
304 //    LabelledStatement
305 //    ThrowStatement
306 //    Catch
307 //    Finally
308 //    TryStatement
309 //    FunctionExpression
310 //    FunctionDeclaration
311 //    DebuggerStatement
312 //    UiParameterList
313
314 private:
315     QHash<Node *, QByteArray> _id;
316     QList<QPair<QByteArray, QByteArray> > _connections;
317     QList<Node *> _stack;
318     QList<QByteArray> _terminalShapes;
319     ofstream out;
320     QByteArray _src;
321 };
322
323 int main(int argc, char *argv[])
324 {
325     QCoreApplication app(argc, argv);
326
327     QStringList files = app.arguments();
328     files.removeFirst();
329
330     foreach (const QString &fileName, files) {
331         QFile file(fileName);
332         if (! file.open(QFile::ReadOnly)) {
333             cerr << "Cannot open \"" << qPrintable(fileName)
334                       << "\", skipping it." << endl;
335             continue;
336         }
337
338         const QByteArray source = file.readAll();
339         file.close();
340
341         Document::Ptr doc = Document::create(fileName);
342         doc->setSource(source);
343         doc->parseQml();
344
345         foreach (const DiagnosticMessage &m, doc->diagnosticMessages()) {
346             ostream *os;
347             if (m.isError()) {
348                 os = &cerr;
349                 *os << "Error:";
350             } else {
351                 os = &cout;
352                 *os << "Warning:";
353             }
354
355             if (m.loc.isValid())
356                 *os << m.loc.startLine << ':' << m.loc.startColumn << ':';
357             *os << ' ';
358             *os << qPrintable(m.message) << endl;
359         }
360
361         ASTDump dump;
362         dump(fileName, source, doc->qmlProgram());
363     }
364
365     return EXIT_SUCCESS;
366 }