aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/qml/qdeclarativerewrite.cpp
diff options
context:
space:
mode:
authorAlan Alpert <alan.alpert@nokia.com>2012-02-01 08:07:39 +1000
committerQt by Nokia <qt-info@nokia.com>2012-02-09 01:34:24 +0100
commit5060b58fdde00ca3fa4dc29bd58b80138a271b10 (patch)
tree7b64064c463c4184e1666f6539ca60a9cac3f91e /src/declarative/qml/qdeclarativerewrite.cpp
parente8420af07158dc3aa5c6ea7ddae6f8be4976e454 (diff)
Rewrite multiline strings properly
Because the bindings rewriter works on code strings, it would leave multiline strings across multiple lines (which is illegal in ECMAScript. It now manually breaks them up when it sees them, by replacing a \n character with a literal \n. Since RewriteSignalHandler now likes to have the AST passed in too, the related method in QDeclarativeCompiler (and its customers) have been altered to use the QDeclarativeScript::Value instead of just a string. Task-number: QTBUG-23387 Change-Id: Id060de37e70590c9da2a902038ed02d948fdd70f Reviewed-by: Alan Alpert <alan.alpert@nokia.com>
Diffstat (limited to 'src/declarative/qml/qdeclarativerewrite.cpp')
-rw-r--r--src/declarative/qml/qdeclarativerewrite.cpp115
1 files changed, 113 insertions, 2 deletions
diff --git a/src/declarative/qml/qdeclarativerewrite.cpp b/src/declarative/qml/qdeclarativerewrite.cpp
index 3d73c094b7..77da943704 100644
--- a/src/declarative/qml/qdeclarativerewrite.cpp
+++ b/src/declarative/qml/qdeclarativerewrite.cpp
@@ -110,6 +110,7 @@ QString RewriteBinding::operator()(QDeclarativeJS::AST::Node *node, const QStrin
_writer = &w;
_position = expression ? expression->firstSourceLocation().begin() : statement->firstSourceLocation().begin();
_inLoop = 0;
+ _code = &code;
accept(node);
@@ -152,6 +153,7 @@ QString RewriteBinding::rewrite(QString code, unsigned position,
_writer = &w;
_position = position;
_inLoop = 0;
+ _code = &code;
accept(node);
@@ -200,6 +202,45 @@ bool RewriteBinding::visit(AST::ExpressionStatement *ast)
return false;
}
+bool RewriteBinding::visit(AST::StringLiteral *ast)
+{
+ /* When rewriting the code for bindings, we have to remove ILLEGAL JS tokens like newlines.
+ They're still in multi-line strings, because the QML parser allows them, but we have to
+ rewrite them to be JS compliant.
+
+ For performance reasons, we don't go for total correctness. \r is only replaced if a
+ \n was found (since most line endings are \n or \r\n) and QChar::LineSeparator is not
+ even considered. QTBUG-24064.
+
+ Note that rewriteSignalHandler has a function just like this one, for the same reason.
+ */
+
+ unsigned startOfString = ast->firstSourceLocation().begin() + 1 - _position;
+ unsigned stringLength = ast->firstSourceLocation().length - 2;
+
+ int lastIndex = -1;
+ bool foundNewLine = false;
+ QStringRef subStr(_code, startOfString, stringLength);
+ while (true) {
+ lastIndex = subStr.indexOf(QLatin1Char('\n'), lastIndex + 1);
+ if (lastIndex == -1)
+ break;
+ foundNewLine = true;
+ _writer->replace(startOfString+lastIndex, 1, QLatin1String("\\n"));
+ }
+
+ if (foundNewLine) {
+ while (true) {
+ lastIndex = subStr.indexOf(QLatin1Char('\r'), lastIndex + 1);
+ if (lastIndex == -1)
+ break;
+ _writer->replace(startOfString+lastIndex, 1, QLatin1String("\\r"));
+ }
+ }
+
+ return false;
+}
+
bool RewriteBinding::visit(AST::DoWhileStatement *)
{
++_inLoop;
@@ -320,9 +361,79 @@ void RewriteBinding::rewriteCaseStatements(AST::StatementList *statements, bool
}
}
-QString RewriteSignalHandler::operator()(const QString &code, const QString &name)
+void RewriteSignalHandler::accept(AST::Node *node)
+{
+ AST::Node::acceptChild(node, this);
+}
+
+bool RewriteSignalHandler::visit(AST::StringLiteral *ast)
+{
+ unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position;
+ _strStarts << startOfExpressionStatement + 1;
+ _strLens << ast->firstSourceLocation().length - 2;
+
+ return false;
+}
+
+void RewriteSignalHandler::rewriteMultilineStrings(QString &code)
+{
+ QList<int> replaceR, replaceN;
+ for (int i=0; i < _strStarts.count(); i++) {
+ QStringRef curSubstr = QStringRef(&code, _strStarts[i], _strLens[i]);
+ int lastIndex = -1;
+ while (true) {
+ lastIndex = curSubstr.indexOf(QLatin1Char('\n'), lastIndex + 1);
+ if (lastIndex == -1)
+ break;
+ replaceN << _strStarts[i]+lastIndex;
+ }
+
+ if (replaceN.count()) {
+ while (true) {
+ lastIndex = curSubstr.indexOf(QLatin1Char('\r'), lastIndex + 1);
+ if (lastIndex == -1)
+ break;
+ replaceR << _strStarts[i]+lastIndex;
+ }
+ }
+ }
+ for (int ii = replaceN.count() - 1; ii >= 0; ii--)
+ code.replace(replaceN[ii], 1, QLatin1String("\\n"));
+ if (replaceR.count())
+ for (int ii = replaceR.count() - 1; ii >= 0; ii--)
+ code.replace(replaceR[ii], 1, QLatin1String("\\r"));
+}
+
+QString RewriteSignalHandler::operator()(QDeclarativeJS::AST::Node *node, const QString &code, const QString &name)
{
- return QStringLiteral("(function ") + name + QStringLiteral("() { ") + code + QStringLiteral(" })");
+ if (rewriteDump()) {
+ qWarning() << "=============================================================";
+ qWarning() << "Rewrote:";
+ qWarning() << qPrintable(code);
+ }
+
+ QDeclarativeJS::AST::ExpressionNode *expression = node->expressionCast();
+ QDeclarativeJS::AST::Statement *statement = node->statementCast();
+ if (!expression && !statement)
+ return code;
+
+ _strStarts.clear();
+ _strLens.clear();
+ _position = expression ? expression->firstSourceLocation().begin() : statement->firstSourceLocation().begin();
+ accept(node);
+
+ QString rewritten = code;
+ rewriteMultilineStrings(rewritten);
+
+ rewritten = QStringLiteral("(function ") + name + QStringLiteral("() { ") + rewritten + QStringLiteral(" })");
+
+ if (rewriteDump()) {
+ qWarning() << "To:";
+ qWarning() << qPrintable(rewritten);
+ qWarning() << "=============================================================";
+ }
+
+ return rewritten;
}
} // namespace QDeclarativeRewrite