1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdeclarativerewrite_p.h"
44 #include "qdeclarativeglobal_p.h"
46 #include <QtCore/qdebug.h>
50 DEFINE_BOOL_CONFIG_OPTION(rewriteDump, QML_REWRITE_DUMP);
52 namespace QDeclarativeRewrite {
54 bool SharedBindingTester::isSharable(const QString &code)
58 Parser parser(&engine);
59 lexer.setCode(code, 0);
60 parser.parseStatement();
61 if (!parser.statement())
64 return isSharable(parser.statement());
67 bool SharedBindingTester::isSharable(AST::Node *node)
70 AST::Node::acceptChild(node, this);
74 QString RewriteBinding::operator()(const QString &code, bool *ok, bool *sharable)
78 Parser parser(&engine);
79 lexer.setCode(code, 0);
80 parser.parseStatement();
81 if (!parser.statement()) {
87 SharedBindingTester tester;
88 *sharable = tester.isSharable(parser.statement());
91 return rewrite(code, 0, parser.statement());
94 QString RewriteBinding::operator()(QDeclarativeJS::AST::Node *node, const QString &code, bool *sharable)
100 SharedBindingTester tester;
101 *sharable = tester.isSharable(node);
104 QDeclarativeJS::AST::ExpressionNode *expression = node->expressionCast();
105 QDeclarativeJS::AST::Statement *statement = node->statementCast();
106 if(!expression && !statement)
111 _position = expression ? expression->firstSourceLocation().begin() : statement->firstSourceLocation().begin();
117 unsigned startOfStatement = 0;
118 unsigned endOfStatement = (expression ? expression->lastSourceLocation().end() : statement->lastSourceLocation().end()) - _position;
120 QString startString = QLatin1String("(function ") + _name + QLatin1String("() { ");
122 startString += QLatin1String("return ");
123 _writer->replace(startOfStatement, 0, startString);
124 _writer->replace(endOfStatement, 0, QLatin1String(" })"));
127 qWarning() << "=============================================================";
128 qWarning() << "Rewrote:";
129 qWarning() << qPrintable(code);
132 QString codeCopy = code;
137 qWarning() << qPrintable(codeCopy);
138 qWarning() << "=============================================================";
144 void RewriteBinding::accept(AST::Node *node)
146 AST::Node::acceptChild(node, this);
149 QString RewriteBinding::rewrite(QString code, unsigned position,
150 AST::Statement *node)
154 _position = position;
160 unsigned startOfStatement = node->firstSourceLocation().begin() - _position;
161 unsigned endOfStatement = node->lastSourceLocation().end() - _position;
163 _writer->replace(startOfStatement, 0, QLatin1String("(function ") + _name + QLatin1String("() { "));
164 _writer->replace(endOfStatement, 0, QLatin1String(" })"));
167 qWarning() << "=============================================================";
168 qWarning() << "Rewrote:";
169 qWarning() << qPrintable(code);
176 qWarning() << qPrintable(code);
177 qWarning() << "=============================================================";
183 bool RewriteBinding::visit(AST::Block *ast)
185 for (AST::StatementList *it = ast->statements; it; it = it->next) {
187 // we need to rewrite only the last statement of a block.
188 accept(it->statement);
195 bool RewriteBinding::visit(AST::ExpressionStatement *ast)
198 unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position;
199 _writer->replace(startOfExpressionStatement, 0, QLatin1String("return "));
205 bool RewriteBinding::visit(AST::StringLiteral *ast)
207 /* When rewriting the code for bindings, we have to remove ILLEGAL JS tokens like newlines.
208 They're still in multi-line strings, because the QML parser allows them, but we have to
209 rewrite them to be JS compliant.
211 For performance reasons, we don't go for total correctness. \r is only replaced if a
212 \n was found (since most line endings are \n or \r\n) and QChar::LineSeparator is not
213 even considered. QTBUG-24064.
215 Note that rewriteSignalHandler has a function just like this one, for the same reason.
218 unsigned startOfString = ast->firstSourceLocation().begin() + 1 - _position;
219 unsigned stringLength = ast->firstSourceLocation().length - 2;
222 bool foundNewLine = false;
223 QStringRef subStr(_code, startOfString, stringLength);
225 lastIndex = subStr.indexOf(QLatin1Char('\n'), lastIndex + 1);
229 _writer->replace(startOfString+lastIndex, 1, QLatin1String("\\n"));
234 lastIndex = subStr.indexOf(QLatin1Char('\r'), lastIndex + 1);
237 _writer->replace(startOfString+lastIndex, 1, QLatin1String("\\r"));
244 bool RewriteBinding::visit(AST::DoWhileStatement *)
250 void RewriteBinding::endVisit(AST::DoWhileStatement *)
255 bool RewriteBinding::visit(AST::WhileStatement *)
261 void RewriteBinding::endVisit(AST::WhileStatement *)
266 bool RewriteBinding::visit(AST::ForStatement *)
272 void RewriteBinding::endVisit(AST::ForStatement *)
277 bool RewriteBinding::visit(AST::LocalForStatement *)
283 void RewriteBinding::endVisit(AST::LocalForStatement *)
288 bool RewriteBinding::visit(AST::ForEachStatement *)
294 void RewriteBinding::endVisit(AST::ForEachStatement *)
299 bool RewriteBinding::visit(AST::LocalForEachStatement *)
305 void RewriteBinding::endVisit(AST::LocalForEachStatement *)
310 bool RewriteBinding::visit(AST::CaseBlock *ast)
312 // Process the initial sequence of the case clauses.
313 for (AST::CaseClauses *it = ast->clauses; it; it = it->next) {
314 // Return the value of the last statement in the block, if this is the last `case clause'
315 // of the switch statement.
316 bool returnTheValueOfLastStatement = (it->next == 0) && (ast->defaultClause == 0) && (ast->moreClauses == 0);
318 if (AST::CaseClause *clause = it->clause) {
319 accept(clause->expression);
320 rewriteCaseStatements(clause->statements, returnTheValueOfLastStatement);
324 // Process the default case clause
325 if (ast->defaultClause) {
326 // Return the value of the last statement in the block, if this is the last `case clause'
327 // of the switch statement.
328 bool rewriteTheLastStatement = (ast->moreClauses == 0);
330 rewriteCaseStatements(ast->defaultClause->statements, rewriteTheLastStatement);
333 // Process trailing `case clauses'
334 for (AST::CaseClauses *it = ast->moreClauses; it; it = it->next) {
335 // Return the value of the last statement in the block, if this is the last `case clause'
336 // of the switch statement.
337 bool returnTheValueOfLastStatement = (it->next == 0);
339 if (AST::CaseClause *clause = it->clause) {
340 accept(clause->expression);
341 rewriteCaseStatements(clause->statements, returnTheValueOfLastStatement);
348 void RewriteBinding::rewriteCaseStatements(AST::StatementList *statements, bool rewriteTheLastStatement)
350 for (AST::StatementList *it = statements; it; it = it->next) {
351 if (it->next && AST::cast<AST::BreakStatement *>(it->next->statement) != 0) {
352 // The value of the first statement followed by a `break'.
353 accept(it->statement);
355 } else if (!it->next) {
356 if (rewriteTheLastStatement)
357 accept(it->statement);
358 else if (AST::Block *block = AST::cast<AST::Block *>(it->statement))
359 rewriteCaseStatements(block->statements, rewriteTheLastStatement);
364 void RewriteSignalHandler::accept(AST::Node *node)
366 AST::Node::acceptChild(node, this);
369 bool RewriteSignalHandler::visit(AST::StringLiteral *ast)
371 unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position;
372 _strStarts << startOfExpressionStatement + 1;
373 _strLens << ast->firstSourceLocation().length - 2;
378 void RewriteSignalHandler::rewriteMultilineStrings(QString &code)
380 QList<int> replaceR, replaceN;
381 for (int i=0; i < _strStarts.count(); i++) {
382 QStringRef curSubstr = QStringRef(&code, _strStarts[i], _strLens[i]);
385 lastIndex = curSubstr.indexOf(QLatin1Char('\n'), lastIndex + 1);
388 replaceN << _strStarts[i]+lastIndex;
391 if (replaceN.count()) {
393 lastIndex = curSubstr.indexOf(QLatin1Char('\r'), lastIndex + 1);
396 replaceR << _strStarts[i]+lastIndex;
400 for (int ii = replaceN.count() - 1; ii >= 0; ii--)
401 code.replace(replaceN[ii], 1, QLatin1String("\\n"));
402 if (replaceR.count())
403 for (int ii = replaceR.count() - 1; ii >= 0; ii--)
404 code.replace(replaceR[ii], 1, QLatin1String("\\r"));
407 QString RewriteSignalHandler::operator()(QDeclarativeJS::AST::Node *node, const QString &code, const QString &name)
410 qWarning() << "=============================================================";
411 qWarning() << "Rewrote:";
412 qWarning() << qPrintable(code);
415 QDeclarativeJS::AST::ExpressionNode *expression = node->expressionCast();
416 QDeclarativeJS::AST::Statement *statement = node->statementCast();
417 if (!expression && !statement)
422 _position = expression ? expression->firstSourceLocation().begin() : statement->firstSourceLocation().begin();
425 QString rewritten = code;
426 rewriteMultilineStrings(rewritten);
428 rewritten = QStringLiteral("(function ") + name + QStringLiteral("() { ") + rewritten + QStringLiteral(" })");
432 qWarning() << qPrintable(rewritten);
433 qWarning() << "=============================================================";
439 } // namespace QDeclarativeRewrite