From a14ed0793ccbff3f988e4cb8d77a056035a5a960 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Tue, 31 Jul 2012 10:12:26 +0200 Subject: QmlJS: Update to latest QmlJS parser from Qt 5. Using qtdeclarative revision c9b7582a2e7ad9fcd03dd999c3b7a16b72803238 Change-Id: I9c942fa04c3fab5ef57b38e13471d0a4e2e8a2bf Reviewed-by: Roberto Raggi --- src/libs/qmljs/parser/cmd.sed | 7 +- src/libs/qmljs/parser/gen-parser.sh | 21 ++- src/libs/qmljs/parser/parser.patch | 59 +++---- src/libs/qmljs/parser/parser.pri | 4 +- src/libs/qmljs/parser/qmldirparser.cpp | 231 ++++++++++++++++----------- src/libs/qmljs/parser/qmldirparser_p.h | 62 ++++--- src/libs/qmljs/parser/qmlerror.cpp | 13 +- src/libs/qmljs/parser/qmlerror.h | 15 +- src/libs/qmljs/parser/qmljs.g | 20 +-- src/libs/qmljs/parser/qmljsast_p.h | 2 +- src/libs/qmljs/parser/qmljsastfwd_p.h | 2 +- src/libs/qmljs/parser/qmljsglobal_p.h | 2 +- src/libs/qmljs/parser/qmljsgrammar_p.h | 2 +- src/libs/qmljs/parser/qmljslexer.cpp | 231 +++++++++++++-------------- src/libs/qmljs/parser/qmljslexer_p.h | 17 +- src/libs/qmljs/parser/qmljsmemorypool_p.h | 14 +- src/libs/qmljs/parser/qmljsparser.cpp | 21 +-- src/libs/qmljs/parser/qmljsparser_p.h | 4 +- src/libs/qmljs/qmljsdocument.cpp | 2 +- src/plugins/qmljstools/qmljsmodelmanager.cpp | 3 +- 20 files changed, 397 insertions(+), 335 deletions(-) diff --git a/src/libs/qmljs/parser/cmd.sed b/src/libs/qmljs/parser/cmd.sed index d76372675d..9f8f0db22a 100644 --- a/src/libs/qmljs/parser/cmd.sed +++ b/src/libs/qmljs/parser/cmd.sed @@ -1,8 +1,9 @@ s/private\/qdeclarative/qml/g -s/qdeclarative/qml/g +s/qqml/qml/g s/QDECLARATIVE/QML/g -s/QDeclarative/Qml/g -s/Q_DECLARATIVE_EXPORT //g +s/QQml/Qml/g +s/QQMLJS/QMLJS/g +s/Q_QML_EXPORT //g # adjust pri file s/ \$\$PWD\/qmljsglobal_p.h/ $$PWD\/qmljsglobal_p.h \\\ diff --git a/src/libs/qmljs/parser/gen-parser.sh b/src/libs/qmljs/parser/gen-parser.sh index 2fcff14ba5..8aa7181f95 100755 --- a/src/libs/qmljs/parser/gen-parser.sh +++ b/src/libs/qmljs/parser/gen-parser.sh @@ -2,20 +2,29 @@ me=$(dirname $0) -for i in $QTDIR/src/declarative/qml/parser/*.{g,h,cpp,pri}; do - sed -f $me/cmd.sed $i > $me/$(echo $(basename $i) | sed s/qdeclarativejs/qmljs/) +for i in $QTDIR/src/qml/qml/parser/*.{g,h,cpp,pri}; do + sed -f $me/cmd.sed $i > $me/$(echo $(basename $i) | sed s/qqmljs/qmljs/) done -for i in $QTDIR/src/declarative/qml/qdeclarative{error.{h,cpp},dirparser{_p.h,.cpp}}; do - sed -f $me/cmd.sed $i > $me/$(echo $(basename $i) | sed s/qdeclarative/qml/) +for i in $QTDIR/src/qml/qml/qqml{error.{h,cpp},dirparser{_p.h,.cpp}}; do + sed -f $me/cmd.sed $i > $me/$(echo $(basename $i) | sed s/qqml/qml/) done # export QmlDirParser perl -p -0777 -i -e 's/QT_BEGIN_NAMESPACE\n\nclass QmlError;\nclass QmlDirParser/#include "qmljsglobal_p.h"\n\nQT_BEGIN_NAMESPACE\n\nclass QmlError;\nclass QML_PARSER_EXPORT QmlDirParser/' qmldirparser_p.h # export QmlJSGrammar perl -p -0777 -i -e 's/#include \n\nQT_BEGIN_NAMESPACE\n\nclass QmlJSGrammar\n/#include "qmljsglobal_p.h"\n#include \n\nQT_BEGIN_NAMESPACE\n\nclass QML_PARSER_EXPORT QmlJSGrammar\n/' qmljsgrammar_p.h -# replace qmlglobal_p.h include with needed declaration -perl -p -0777 -i -e 's/#include \"qmlglobal_p.h\"/bool Qml_isFileCaseCorrect(const QString &) { return true; }/' qmldirparser.cpp +# remove qmlglobal_p.h include +perl -p -0777 -i -e 's/#include \"qmlglobal_p.h\"//' qmldirparser.cpp +# remove qmlglobal_p.h include +perl -p -0777 -i -e 's/#include \//' qmldirparser.cpp +# remove QtQml/qtqmlglobal.h include +perl -p -0777 -i -e 's/#include \//' qmlerror.h +# replace private/qhashedstring_p.h include and QHashedStringRef +perl -p -0777 -i -e 's/#include \//' qmldirparser_p.h +perl -p -0777 -i -e 's/QHashedStringRef/QString/g' qmldirparser_p.h qmldirparser.cpp +# don't use the new QVarLengthArray::length() +sed -i -e 's/chars.length()/chars.size()/' $me/qmljslexer.cpp ./changeLicense.py $me/../qmljs_global.h qml*.{cpp,h} diff --git a/src/libs/qmljs/parser/parser.patch b/src/libs/qmljs/parser/parser.patch index 755aa27a93..32fc41b90d 100644 --- a/src/libs/qmljs/parser/parser.patch +++ b/src/libs/qmljs/parser/parser.patch @@ -1,19 +1,18 @@ -diff --git b/src/libs/qmljs/parser/qmljs.g a/src/libs/qmljs/parser/qmljs.g -index 6888b65..784e47f 100644 ---- b/src/libs/qmljs/parser/qmljs.g -+++ a/src/libs/qmljs/parser/qmljs.g -@@ -1,23 +1,32 @@ +diff --git a/src/libs/qmljs/parser/qmljs.g b/src/libs/qmljs/parser/qmljs.g +index 069be3c..9cbdc23 100644 +--- a/src/libs/qmljs/parser/qmljs.g ++++ b/src/libs/qmljs/parser/qmljs.g +@@ -1,23 +1,30 @@ ---------------------------------------------------------------------------- -- --- Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ---- All rights reserved. +-- This file is part of Qt Creator +-- +-- Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +-- -- Contact: http://www.qt-project.org/ -- ---- This file is part of the QtDeclarative module of the Qt Toolkit. +--- This file is part of the QtQml module of the Qt Toolkit. -- --- $QT_BEGIN_LICENSE:LGPL-ONLY$ -- GNU Lesser General Public License Usage @@ -23,7 +22,9 @@ index 6888b65..784e47f 100644 --- 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 have questions regarding the use of this file, please contact +--- us via http://www.qt-project.org/. +-- 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. @@ -43,11 +44,11 @@ index 6888b65..784e47f 100644 --- $QT_END_LICENSE$ -- ---------------------------------------------------------------------------- - -@@ -83,46 +92,37 @@ - + +@@ -83,46 +90,36 @@ + %start TopLevel - + -/./**************************************************************************** +/./************************************************************************** +** @@ -56,10 +57,9 @@ index 6888b65..784e47f 100644 +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). ** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). --** All rights reserved. ** Contact: http://www.qt-project.org/ ** --** This file is part of the QtDeclarative module of the Qt Toolkit. +-** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage @@ -95,17 +95,19 @@ index 6888b65..784e47f 100644 -** -** -** +-** -** $QT_END_LICENSE$ -** -****************************************************************************/ +**************************************************************************/ - ++ + #include #include -@@ -136,46 +136,37 @@ - +@@ -136,46 +133,36 @@ + ./ - + -/:/**************************************************************************** +/:/************************************************************************** +** @@ -114,10 +116,9 @@ index 6888b65..784e47f 100644 +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). ** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). --** All rights reserved. ** Contact: http://www.qt-project.org/ ** --** This file is part of the QtDeclarative module of the Qt Toolkit. +-** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage @@ -153,18 +154,20 @@ index 6888b65..784e47f 100644 -** -** -** +-** -** $QT_END_LICENSE$ -** -****************************************************************************/ +**************************************************************************/ - - ++ + + // diff --git b/src/libs/qmljs/parser/qmljsengine_p.cpp a/src/libs/qmljs/parser/qmljsengine_p.cpp index 5b204c9..10e39ab 100644 --- b/src/libs/qmljs/parser/qmljsengine_p.cpp +++ a/src/libs/qmljs/parser/qmljsengine_p.cpp -@@ -113,7 +113,7 @@ double integerFromString(const QString &str, int radix) +@@ -111,7 +111,7 @@ double integerFromString(const QString &str, int radix) Engine::Engine() @@ -173,7 +176,7 @@ index 5b204c9..10e39ab 100644 { } Engine::~Engine() -@@ -134,6 +134,12 @@ Lexer *Engine::lexer() const +@@ -132,6 +132,12 @@ Lexer *Engine::lexer() const void Engine::setLexer(Lexer *lexer) { _lexer = lexer; } @@ -190,7 +193,7 @@ diff --git b/src/libs/qmljs/parser/qmljsengine_p.h a/src/libs/qmljs/parser/qmljs index 5057ea0..487619e 100644 --- b/src/libs/qmljs/parser/qmljsengine_p.h +++ a/src/libs/qmljs/parser/qmljsengine_p.h -@@ -56,6 +56,7 @@ QT_QML_BEGIN_NAMESPACE +@@ -54,6 +54,7 @@ QT_QML_BEGIN_NAMESPACE namespace QmlJS { class Lexer; @@ -198,7 +201,7 @@ index 5057ea0..487619e 100644 class MemoryPool; class QML_PARSER_EXPORT DiagnosticMessage -@@ -83,6 +84,7 @@ public: +@@ -81,6 +82,7 @@ public: class QML_PARSER_EXPORT Engine { Lexer *_lexer; @@ -206,7 +209,7 @@ index 5057ea0..487619e 100644 MemoryPool _pool; QList _comments; QString _extraCode; -@@ -100,6 +102,9 @@ public: +@@ -98,6 +100,9 @@ public: Lexer *lexer() const; void setLexer(Lexer *lexer); @@ -220,7 +223,7 @@ diff --git b/src/libs/qmljs/parser/qmljsparser.cpp a/src/libs/qmljs/parser/qmljs index a731c1a..e986534 100644 --- b/src/libs/qmljs/parser/qmljsparser.cpp +++ a/src/libs/qmljs/parser/qmljsparser.cpp -@@ -138,7 +138,20 @@ bool Parser::parse(int startToken) +@@ -137,7 +137,20 @@ bool Parser::parse(int startToken) token_buffer[0].token = startToken; first_token = &token_buffer[0]; diff --git a/src/libs/qmljs/parser/parser.pri b/src/libs/qmljs/parser/parser.pri index 966570d1e3..aa1069e5c2 100644 --- a/src/libs/qmljs/parser/parser.pri +++ b/src/libs/qmljs/parser/parser.pri @@ -10,7 +10,7 @@ HEADERS += \ $$PWD/qmljsglobal_p.h \ $$PWD/qmldirparser_p.h \ $$PWD/qmlerror.h \ - $$PWD/qmljskeywords_p.h + $$PWD/qmljskeywords_p.h \ SOURCES += \ $$PWD/qmljsast.cpp \ @@ -20,4 +20,4 @@ SOURCES += \ $$PWD/qmljslexer.cpp \ $$PWD/qmljsparser.cpp \ $$PWD/qmldirparser.cpp \ - $$PWD/qmlerror.cpp + $$PWD/qmlerror.cpp \ diff --git a/src/libs/qmljs/parser/qmldirparser.cpp b/src/libs/qmljs/parser/qmldirparser.cpp index 7324abe785..17d70e00e1 100644 --- a/src/libs/qmljs/parser/qmldirparser.cpp +++ b/src/libs/qmljs/parser/qmldirparser.cpp @@ -30,132 +30,130 @@ #include "qmldirparser_p.h" #include "qmlerror.h" -bool Qml_isFileCaseCorrect(const QString &) { return true; } -#include -#include -#include -QT_BEGIN_NAMESPACE -QmlDirParser::QmlDirParser() - : _isParsed(false) -{ -} +#include -QmlDirParser::~QmlDirParser() -{ -} - -QUrl QmlDirParser::url() const -{ - return _url; -} +QT_BEGIN_NAMESPACE -void QmlDirParser::setUrl(const QUrl &url) +static int parseInt(const QStringRef &str, bool *ok) { - _url = url; + int pos = 0; + int number = 0; + while (pos < str.length() && str.at(pos).isDigit()) { + if (pos != 0) + number *= 10; + number += str.at(pos).unicode() - '0'; + ++pos; + } + if (pos != str.length()) + *ok = false; + else + *ok = true; + return number; } -QString QmlDirParser::fileSource() const +QmlDirParser::QmlDirParser() { - return _filePathSouce; } -void QmlDirParser::setFileSource(const QString &filePath) +QmlDirParser::~QmlDirParser() { - _filePathSouce = filePath; } -QString QmlDirParser::source() const -{ - return _source; +inline static void scanSpace(const QChar *&ch) { + while (ch->isSpace() && !ch->isNull() && *ch != QLatin1Char('\n')) + ++ch; } -void QmlDirParser::setSource(const QString &source) -{ - _isParsed = false; - _source = source; +inline static void scanToEnd(const QChar *&ch) { + while (*ch != QLatin1Char('\n') && !ch->isNull()) + ++ch; } -bool QmlDirParser::isParsed() const -{ - return _isParsed; +inline static void scanWord(const QChar *&ch) { + while (!ch->isSpace() && !ch->isNull()) + ++ch; } -bool QmlDirParser::parse() +/*! +\a url is used for generating errors. +*/ +bool QmlDirParser::parse(const QString &source) { - if (_isParsed) - return true; - - _isParsed = true; _errors.clear(); _plugins.clear(); _components.clear(); + _scripts.clear(); - if (_source.isEmpty() && !_filePathSouce.isEmpty()) { - QFile file(_filePathSouce); - if (!Qml_isFileCaseCorrect(_filePathSouce)) { - QmlError error; - error.setDescription(QString::fromUtf8("cannot load module \"$$URI$$\": File name case mismatch for \"%1\"").arg(_filePathSouce)); - _errors.prepend(error); - return false; - } else if (file.open(QFile::ReadOnly)) { - _source = QString::fromUtf8(file.readAll()); - } else { - QmlError error; - error.setDescription(QString::fromUtf8("module \"$$URI$$\" definition \"%1\" not readable").arg(_filePathSouce)); - _errors.prepend(error); - return false; - } - } - - QTextStream stream(&_source); int lineNumber = 0; + bool firstLine = true; - forever { + const QChar *ch = source.constData(); + while (!ch->isNull()) { ++lineNumber; - const QString line = stream.readLine(); - if (line.isNull()) + bool invalidLine = false; + const QChar *lineStart = ch; + + scanSpace(ch); + if (*ch == QLatin1Char('\n')) { + ++ch; + continue; + } + if (ch->isNull()) break; QString sections[3]; int sectionCount = 0; - int index = 0; - const int length = line.length(); - - while (index != length) { - const QChar ch = line.at(index); - - if (ch.isSpace()) { - do { ++index; } - while (index != length && line.at(index).isSpace()); - - } else if (ch == QLatin1Char('#')) { - // recognized a comment + do { + if (*ch == QLatin1Char('#')) { + scanToEnd(ch); break; - + } + const QChar *start = ch; + scanWord(ch); + if (sectionCount < 3) { + sections[sectionCount++] = source.mid(start-source.constData(), ch-start); } else { - const int start = index; - - do { ++index; } - while (index != length && !line.at(index).isSpace()); + reportError(lineNumber, start-lineStart, QLatin1String("unexpected token")); + scanToEnd(ch); + invalidLine = true; + break; + } + scanSpace(ch); + } while (*ch != QLatin1Char('\n') && !ch->isNull()); - const QString lexeme = line.mid(start, index - start); + if (!ch->isNull()) + ++ch; - if (sectionCount >= 3) { - reportError(lineNumber, start, QLatin1String("unexpected token")); + if (invalidLine) { + reportError(lineNumber, -1, + QString::fromUtf8("invalid qmldir directive contains too many tokens")); + continue; + } else if (sectionCount == 0) { + continue; // no sections, no party. - } else { - sections[sectionCount++] = lexeme; - } + } else if (sections[0] == QLatin1String("module")) { + if (sectionCount != 2) { + reportError(lineNumber, -1, + QString::fromUtf8("module directive requires one argument, but %1 were provided").arg(sectionCount - 1)); + continue; + } + if (!_typeNamespace.isEmpty()) { + reportError(lineNumber, -1, + QString::fromUtf8("only one module directive may be defined in a qmldir file")); + continue; + } + if (!firstLine) { + reportError(lineNumber, -1, + QString::fromUtf8("module directive must be the first directive in a qmldir file")); + continue; } - } - if (sectionCount == 0) { - continue; // no sections, no party. + _typeNamespace = sections[1]; } else if (sections[0] == QLatin1String("plugin")) { if (sectionCount < 2) { @@ -177,7 +175,7 @@ bool QmlDirParser::parse() } Component entry(sections[1], sections[2], -1, -1); entry.internal = true; - _components.append(entry); + _components.insertMulti(entry.typeName, entry); } else if (sections[0] == QLatin1String("typeinfo")) { if (sectionCount != 2) { reportError(lineNumber, -1, @@ -192,7 +190,7 @@ bool QmlDirParser::parse() } else if (sectionCount == 2) { // No version specified (should only be used for relative qmldir files) const Component entry(sections[0], sections[1], -1, -1); - _components.append(entry); + _components.insertMulti(entry.typeName, entry); } else if (sectionCount == 3) { const QString &version = sections[1]; const int dotIndex = version.indexOf(QLatin1Char('.')); @@ -203,15 +201,22 @@ bool QmlDirParser::parse() reportError(lineNumber, -1, QLatin1String("unexpected '.'")); } else { bool validVersionNumber = false; - const int majorVersion = version.left(dotIndex).toInt(&validVersionNumber); + const int majorVersion = parseInt(QStringRef(&version, 0, dotIndex), &validVersionNumber); if (validVersionNumber) { - const int minorVersion = version.mid(dotIndex + 1).toInt(&validVersionNumber); + const int minorVersion = parseInt(QStringRef(&version, dotIndex+1, version.length()-dotIndex-1), &validVersionNumber); if (validVersionNumber) { - const Component entry(sections[0], sections[2], majorVersion, minorVersion); - - _components.append(entry); + const QString &fileName = sections[2]; + + if (fileName.endsWith(QLatin1String(".js"))) { + // A 'js' extension indicates a namespaced script import + const Script entry(sections[0], fileName, majorVersion, minorVersion); + _scripts.append(entry); + } else { + const Component entry(sections[0], fileName, majorVersion, minorVersion); + _components.insertMulti(entry.typeName, entry); + } } } } @@ -219,6 +224,8 @@ bool QmlDirParser::parse() reportError(lineNumber, -1, QString::fromUtf8("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount)); } + + firstLine = false; } return hasError(); @@ -227,7 +234,6 @@ bool QmlDirParser::parse() void QmlDirParser::reportError(int line, int column, const QString &description) { QmlError error; - error.setUrl(_url); error.setLine(line); error.setColumn(column); error.setDescription(description); @@ -242,28 +248,51 @@ bool QmlDirParser::hasError() const return false; } +void QmlDirParser::setError(const QmlError &e) +{ + _errors.clear(); + _errors.append(e); +} + QList QmlDirParser::errors(const QString &uri) const { + QUrl url(uri); QList errors = _errors; for (int i = 0; i < errors.size(); ++i) { QmlError &e = errors[i]; QString description = e.description(); description.replace(QLatin1String("$$URI$$"), uri); e.setDescription(description); + e.setUrl(url); } return errors; } +QString QmlDirParser::typeNamespace() const +{ + return _typeNamespace; +} + +void QmlDirParser::setTypeNamespace(const QString &s) +{ + _typeNamespace = s; +} + QList QmlDirParser::plugins() const { return _plugins; } -QList QmlDirParser::components() const +QHash QmlDirParser::components() const { return _components; } +QList QmlDirParser::scripts() const +{ + return _scripts; +} + #ifdef QT_CREATOR QList QmlDirParser::typeInfos() const { @@ -271,4 +300,18 @@ QList QmlDirParser::typeInfos() const } #endif +QDebug &operator<< (QDebug &debug, const QmlDirParser::Component &component) +{ + const QString output = QString::fromLatin1("{%1 %2.%3}"). + arg(component.typeName).arg(component.majorVersion).arg(component.minorVersion); + return debug << qPrintable(output); +} + +QDebug &operator<< (QDebug &debug, const QmlDirParser::Script &script) +{ + const QString output = QString::fromLatin1("{%1 %2.%3}"). + arg(script.nameSpace).arg(script.majorVersion).arg(script.minorVersion); + return debug << qPrintable(output); +} + QT_END_NAMESPACE diff --git a/src/libs/qmljs/parser/qmldirparser_p.h b/src/libs/qmljs/parser/qmldirparser_p.h index ca8dd57df7..6cf381c1d7 100644 --- a/src/libs/qmljs/parser/qmldirparser_p.h +++ b/src/libs/qmljs/parser/qmldirparser_p.h @@ -28,8 +28,8 @@ ** **************************************************************************/ -#ifndef QMLDIRPARSER_P_H -#define QMLDIRPARSER_P_H +#ifndef QQMLDIRPARSER_P_H +#define QQMLDIRPARSER_P_H // // W A R N I N G @@ -42,15 +42,16 @@ // We mean it. // -#include -#include +#include +#include +#include -#include "qmljsglobal_p.h" QT_BEGIN_NAMESPACE class QmlError; -class QML_PARSER_EXPORT QmlDirParser +class QmlEngine; +class Q_AUTOTEST_EXPORT QmlDirParser { Q_DISABLE_COPY(QmlDirParser) @@ -58,21 +59,15 @@ public: QmlDirParser(); ~QmlDirParser(); - QUrl url() const; - void setUrl(const QUrl &url); - - QString fileSource() const; - void setFileSource(const QString &filePath); - - QString source() const; - void setSource(const QString &source); - - bool isParsed() const; - bool parse(); + bool parse(const QString &source); bool hasError() const; + void setError(const QmlError &); QList errors(const QString &uri) const; + QString typeNamespace() const; + void setTypeNamespace(const QString &s); + struct Plugin { Plugin() {} @@ -100,7 +95,22 @@ public: bool internal; }; - QList components() const; + struct Script + { + Script() + : majorVersion(0), minorVersion(0) {} + + Script(const QString &nameSpace, const QString &fileName, int majorVersion, int minorVersion) + : nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion) {} + + QString nameSpace; + QString fileName; + int majorVersion; + int minorVersion; + }; + + QHash components() const; + QList