Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativerewrite.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
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 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
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 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qdeclarativerewrite_p.h"
43
44 #include "private/qdeclarativeglobal_p.h"
45
46 #include <QtCore/qdebug.h>
47
48 QT_BEGIN_NAMESPACE
49
50 DEFINE_BOOL_CONFIG_OPTION(rewriteDump, QML_REWRITE_DUMP);
51
52 namespace QDeclarativeRewrite {
53
54 bool SharedBindingTester::isSharable(const QString &code)
55 {
56     Engine engine;
57     NodePool pool(QString(), &engine);
58     Lexer lexer(&engine);
59     Parser parser(&engine);
60     lexer.setCode(code, 0);
61     parser.parseStatement();
62     if (!parser.statement()) 
63         return false;
64
65     return isSharable(parser.statement());
66 }
67
68 bool SharedBindingTester::isSharable(AST::Node *node)
69 {
70     _sharable = true;
71     AST::Node::acceptChild(node, this);
72     return _sharable;
73 }
74
75 QString RewriteBinding::operator()(const QString &code, bool *ok, bool *sharable)
76 {
77     Engine engine;
78     NodePool pool(QString(), &engine);
79     Lexer lexer(&engine);
80     Parser parser(&engine);
81     lexer.setCode(code, 0);
82     parser.parseStatement();
83     if (!parser.statement()) {
84         if (ok) *ok = false;
85         return QString();
86     } else {
87         if (ok) *ok = true;
88         if (sharable) {
89             SharedBindingTester tester;
90             *sharable = tester.isSharable(parser.statement());
91         }
92     }
93     return rewrite(code, 0, parser.statement());
94 }
95
96 QString RewriteBinding::operator()(QDeclarativeJS::AST::Node *node, const QString &code, bool *sharable)
97 {
98     if (!node)
99         return code;
100
101     if (sharable) {
102         SharedBindingTester tester;
103         *sharable = tester.isSharable(node);
104     }
105
106     QDeclarativeJS::AST::ExpressionNode *expression = node->expressionCast();
107     QDeclarativeJS::AST::Statement *statement = node->statementCast();
108     if(!expression && !statement)
109         return code;
110
111     TextWriter w;
112     _writer = &w;
113     _position = expression ? expression->firstSourceLocation().begin() : statement->firstSourceLocation().begin();
114     _inLoop = 0;
115
116     accept(node);
117
118     unsigned startOfStatement = 0;
119     unsigned endOfStatement = (expression ? expression->lastSourceLocation().end() : statement->lastSourceLocation().end()) - _position;
120
121     QString startString = QLatin1String("(function ") + QString::fromUtf8(_name) + QLatin1String("() { ");
122     if (expression)
123         startString += QLatin1String("return ");
124     _writer->replace(startOfStatement, 0, startString);
125     _writer->replace(endOfStatement, 0, QLatin1String(" })"));
126
127     if (rewriteDump()) {
128         qWarning() << "=============================================================";
129         qWarning() << "Rewrote:";
130         qWarning() << qPrintable(code);
131     }
132
133     QString codeCopy = code;
134     w.write(&codeCopy);
135
136     if (rewriteDump()) {
137         qWarning() << "To:";
138         qWarning() << qPrintable(code);
139         qWarning() << "=============================================================";
140     }
141
142     return codeCopy;
143 }
144
145 void RewriteBinding::accept(AST::Node *node)
146 {
147     AST::Node::acceptChild(node, this);
148 }
149
150 QString RewriteBinding::rewrite(QString code, unsigned position,
151                                 AST::Statement *node)
152 {
153     TextWriter w;
154     _writer = &w;
155     _position = position;
156     _inLoop = 0;
157
158     accept(node);
159
160     unsigned startOfStatement = node->firstSourceLocation().begin() - _position;
161     unsigned endOfStatement = node->lastSourceLocation().end() - _position;
162
163     _writer->replace(startOfStatement, 0, QLatin1String("(function ") + QString::fromUtf8(_name) + QLatin1String("() { "));
164     _writer->replace(endOfStatement, 0, QLatin1String(" })"));
165
166     if (rewriteDump()) {
167         qWarning() << "=============================================================";
168         qWarning() << "Rewrote:";
169         qWarning() << qPrintable(code);
170     }
171
172     w.write(&code);
173
174     if (rewriteDump()) {
175         qWarning() << "To:";
176         qWarning() << qPrintable(code);
177         qWarning() << "=============================================================";
178     }
179
180     return code;
181 }
182
183 bool RewriteBinding::visit(AST::Block *ast)
184 {
185     for (AST::StatementList *it = ast->statements; it; it = it->next) {
186         if (! it->next) {
187             // we need to rewrite only the last statement of a block.
188             accept(it->statement);
189         }
190     }
191
192     return false;
193 }
194
195 bool RewriteBinding::visit(AST::ExpressionStatement *ast)
196 {
197     if (! _inLoop) {
198         unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position;
199         _writer->replace(startOfExpressionStatement, 0, QLatin1String("return "));
200     }
201
202     return false;
203 }
204
205 bool RewriteBinding::visit(AST::DoWhileStatement *)
206 {
207     ++_inLoop;
208     return true;
209 }
210
211 void RewriteBinding::endVisit(AST::DoWhileStatement *)
212 {
213     --_inLoop;
214 }
215
216 bool RewriteBinding::visit(AST::WhileStatement *)
217 {
218     ++_inLoop;
219     return true;
220 }
221
222 void RewriteBinding::endVisit(AST::WhileStatement *)
223 {
224     --_inLoop;
225 }
226
227 bool RewriteBinding::visit(AST::ForStatement *)
228 {
229     ++_inLoop;
230     return true;
231 }
232
233 void RewriteBinding::endVisit(AST::ForStatement *)
234 {
235     --_inLoop;
236 }
237
238 bool RewriteBinding::visit(AST::LocalForStatement *)
239 {
240     ++_inLoop;
241     return true;
242 }
243
244 void RewriteBinding::endVisit(AST::LocalForStatement *)
245 {
246     --_inLoop;
247 }
248
249 bool RewriteBinding::visit(AST::ForEachStatement *)
250 {
251     ++_inLoop;
252     return true;
253 }
254
255 void RewriteBinding::endVisit(AST::ForEachStatement *)
256 {
257     --_inLoop;
258 }
259
260 bool RewriteBinding::visit(AST::LocalForEachStatement *)
261 {
262     ++_inLoop;
263     return true;
264 }
265
266 void RewriteBinding::endVisit(AST::LocalForEachStatement *)
267 {
268     --_inLoop;
269 }
270
271 } // namespace QDeclarativeRewrite
272
273 QT_END_NAMESPACE