aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/parser')
-rw-r--r--src/qml/parser/qqmljs.g707
-rw-r--r--src/qml/parser/qqmljsast.cpp156
-rw-r--r--src/qml/parser/qqmljsast_p.h383
-rw-r--r--src/qml/parser/qqmljsastfwd_p.h43
-rw-r--r--src/qml/parser/qqmljsastvisitor.cpp40
-rw-r--r--src/qml/parser/qqmljsastvisitor_p.h849
-rw-r--r--src/qml/parser/qqmljsengine_p.cpp157
-rw-r--r--src/qml/parser/qqmljsengine_p.h90
-rw-r--r--src/qml/parser/qqmljsglobal_p.h47
-rw-r--r--src/qml/parser/qqmljskeywords_p.h40
-rw-r--r--src/qml/parser/qqmljslexer.cpp1057
-rw-r--r--src/qml/parser/qqmljslexer_p.h226
12 files changed, 1662 insertions, 2133 deletions
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index f10bde5ff1..57954d7d1a 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -1,41 +1,5 @@
-----------------------------------------------------------------------------
---
-- Copyright (C) 2016 The Qt Company Ltd.
--- Contact: http://www.qt.io/licensing/
---
--- This file is part of the QtQml module of the Qt Toolkit.
---
--- $QT_BEGIN_LICENSE:LGPL$
--- Commercial License Usage
--- Licensees holding valid commercial Qt licenses may use this file in
--- accordance with the commercial license agreement provided with the
--- Software or, alternatively, in accordance with the terms contained in
--- a written agreement between you and The Qt Company. For licensing terms
--- and conditions see https://www.qt.io/terms-conditions. For further
--- information use the contact form at https://www.qt.io/contact-us.
---
--- GNU Lesser General Public License Usage
--- Alternatively, this file may be used under the terms of the GNU Lesser
--- General Public License version 3 as published by the Free Software
--- Foundation and appearing in the file LICENSE.LGPL3 included in the
--- packaging of this file. Please review the following information to
--- ensure the GNU Lesser General Public License version 3 requirements
--- will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
---
--- GNU General Public License Usage
--- Alternatively, this file may be used under the terms of the GNU
--- General Public License version 2.0 or (at your option) the GNU General
--- Public license version 3 or any later version approved by the KDE Free
--- Qt Foundation. The licenses are as published by the Free Software
--- Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
--- included in the packaging of this file. Please review the following
--- information to ensure the GNU General Public License requirements will
--- be met: https://www.gnu.org/licenses/gpl-2.0.html and
--- https://www.gnu.org/licenses/gpl-3.0.html.
---
--- $QT_END_LICENSE$
---
-----------------------------------------------------------------------------
+-- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
%parser QQmlJSGrammar
%decl qqmljsparser_p.h
@@ -81,6 +45,7 @@
%token T_COMPATIBILITY_SEMICOLON
%token T_ARROW "=>"
%token T_QUESTION_QUESTION "??"
+%token T_QUESTION_DOT "?."
%token T_ENUM "enum"
%token T_ELLIPSIS "..."
%token T_YIELD "yield"
@@ -108,8 +73,19 @@
%token T_GET "get"
%token T_SET "set"
+-- token representing no token
+%token T_NONE
+
%token T_ERROR
+-- states for line by line parsing
+%token T_EOL
+%token T_PARTIAL_COMMENT "non closed multiline comment"
+%token T_PARTIAL_SINGLE_QUOTE_STRING_LITERAL "multiline single quote string literal"
+%token T_PARTIAL_DOUBLE_QUOTE_STRING_LITERAL "multiline double quote string literal"
+%token T_PARTIAL_TEMPLATE_HEAD "(template head)"
+%token T_PARTIAL_TEMPLATE_MIDDLE "(template middle)"
+
--- feed tokens
%token T_FEED_UI_PROGRAM
%token T_FEED_UI_OBJECT_MEMBER
@@ -131,44 +107,9 @@
%start TopLevel
-/./****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+/.// Copyright (C) 2016 The Qt Company Ltd.
+// Contact: https://www.qt.io/licensing/
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmljsengine_p.h>
#include <private/qqmljslexer_p.h>
@@ -182,44 +123,9 @@
./
-/:/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+/:// Copyright (C) 2016 The Qt Company Ltd.
+// Contact: https://www.qt.io/licensing/
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
@@ -306,14 +212,15 @@ public:
AST::ExportClause *ExportClause;
AST::ExportDeclaration *ExportDeclaration;
AST::TypeAnnotation *TypeAnnotation;
- AST::TypeArgumentList *TypeArgumentList;
AST::Type *Type;
AST::UiProgram *UiProgram;
AST::UiHeaderItemList *UiHeaderItemList;
+ AST::UiPragmaValueList *UiPragmaValueList;
AST::UiPragma *UiPragma;
AST::UiImport *UiImport;
AST::UiParameterList *UiParameterList;
+ AST::UiPropertyAttributes *UiPropertyAttributes;
AST::UiPublicMember *UiPublicMember;
AST::UiObjectDefinition *UiObjectDefinition;
AST::UiObjectInitializer *UiObjectInitializer;
@@ -395,6 +302,18 @@ public:
inline int errorColumnNumber() const
{ return diagnosticMessage().loc.startColumn; }
+ inline bool identifierInsertionEnabled() const
+ { return m_identifierInsertionEnabled; }
+
+ inline void setIdentifierInsertionEnabled(bool enable)
+ { m_identifierInsertionEnabled = enable; }
+
+ inline bool incompleteBindingsEnabled() const
+ { return m_incompleteBindingsEnabled; }
+
+ inline void setIncompleteBindingsEnabled(bool enable)
+ { m_incompleteBindingsEnabled = enable; }
+
protected:
bool parse(int startToken);
@@ -415,6 +334,7 @@ protected:
AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
void pushToken(int token);
+ void pushTokenWithEmptyLocation(int token);
int lookaheadToken(Lexer *lexer);
static DiagnosticMessage compileError(const SourceLocation &location,
@@ -444,8 +364,8 @@ protected:
Value *sym_stack = nullptr;
int *state_stack = nullptr;
SourceLocation *location_stack = nullptr;
- QList<QStringView> string_stack;
- QList<QStringView> rawString_stack;
+ std::vector<QStringView> string_stack;
+ std::vector<QStringView> rawString_stack;
AST::Node *program = nullptr;
@@ -466,12 +386,14 @@ protected:
QStringView yytokenraw;
SourceLocation yylloc;
SourceLocation yyprevlloc;
+ int yyprevtoken = -1;
SavedToken token_buffer[TOKEN_BUFFER_SIZE];
SavedToken *first_token = nullptr;
SavedToken *last_token = nullptr;
int functionNestingLevel = 0;
+ int classNestingLevel = 0;
enum CoverExpressionType {
CE_Invalid,
@@ -482,6 +404,8 @@ protected:
CoverExpressionType coverExpressionType = CE_Invalid;
QList<DiagnosticMessage> diagnostic_messages;
+ bool m_identifierInsertionEnabled = false;
+ bool m_incompleteBindingsEnabled = false;
};
} // end of namespace QQmlJS
@@ -557,11 +481,13 @@ AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
{
QVarLengthArray<QStringView, 4> nameIds;
QVarLengthArray<SourceLocation, 4> locations;
+ QVarLengthArray<SourceLocation, 4> dotLocations;
AST::ExpressionNode *it = expr;
while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) {
nameIds.append(m->name);
locations.append(m->identifierToken);
+ dotLocations.append(m->dotToken);
it = m->base;
}
@@ -573,6 +499,7 @@ AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
for (int i = nameIds.size() - 1; i != -1; --i) {
currentId = new (pool) AST::UiQualifiedId(currentId, nameIds[i]);
currentId->identifierToken = locations[i];
+ currentId->dotToken = dotLocations[i];
}
return currentId->finish();
@@ -594,9 +521,19 @@ void Parser::pushToken(int token)
yytoken = token;
}
+void Parser::pushTokenWithEmptyLocation(int token)
+{
+ pushToken(token);
+ yylloc = yyprevlloc;
+ yylloc.offset += yylloc.length;
+ yylloc.startColumn += yylloc.length;
+ yylloc.length = 0;
+}
+
int Parser::lookaheadToken(Lexer *lexer)
{
if (yytoken < 0) {
+ yyprevtoken = yytoken;
yytoken = lexer->lex();
yylval = lexer->tokenValue();
yytokenspell = lexer->tokenSpell();
@@ -692,6 +629,7 @@ bool Parser::parse(int startToken)
#endif
if (action > 0) {
if (action != ACCEPT_STATE) {
+ yyprevtoken = yytoken;
yytoken = -1;
sym(1).dval = yylval;
stringRef(1) = yytokenspell;
@@ -809,20 +747,56 @@ UiHeaderItemList: UiHeaderItemList UiImport;
./
PragmaId: JsIdentifier;
+PragmaValue: JsIdentifier
+ | T_STRING_LITERAL;
Semicolon: T_AUTOMATIC_SEMICOLON;
Semicolon: T_SEMICOLON;
+UiPragmaValueList: PragmaValue;
+/.
+ case $rule_number: {
+ AST::UiPragmaValueList *list
+ = new (pool) AST::UiPragmaValueList(stringRef(1));
+ list->location = loc(1);
+ sym(1).Node = list;
+ } break;
+./
+
+UiPragmaValueList: UiPragmaValueList T_COMMA PragmaValue;
+/.
+ case $rule_number: {
+ AST::UiPragmaValueList *list
+ = new (pool) AST::UiPragmaValueList(sym(1).UiPragmaValueList, stringRef(3));
+ list->location = loc(3);
+ sym(1).Node = list;
+ } break;
+./
+
UiPragma: T_PRAGMA PragmaId Semicolon;
/.
case $rule_number: {
AST::UiPragma *pragma = new (pool) AST::UiPragma(stringRef(2));
pragma->pragmaToken = loc(1);
+ pragma->pragmaIdToken = loc(2);
pragma->semicolonToken = loc(3);
sym(1).Node = pragma;
} break;
./
+UiPragma: T_PRAGMA PragmaId T_COLON UiPragmaValueList Semicolon;
+/.
+ case $rule_number: {
+ AST::UiPragma *pragma = new (pool) AST::UiPragma(
+ stringRef(2), sym(4).UiPragmaValueList->finish());
+ pragma->pragmaToken = loc(1);
+ pragma->pragmaIdToken = loc(2);
+ pragma->colonToken = loc(3);
+ pragma->semicolonToken = loc(5);
+ sym(1).Node = pragma;
+ } break;
+./
+
ImportId: MemberExpression;
UiImport: UiImportHead Semicolon;
@@ -1177,6 +1151,20 @@ case $rule_number:
} break;
./
+UiObjectMember: UiQualifiedId Semicolon;
+/.
+ case $rule_number: {
+ if (!m_incompleteBindingsEnabled) {
+ diagnostic_messages.append(compileError(loc(1), QLatin1String("Incomplete binding, expected token `:` or `{`")));
+ return false;
+ }
+ AST::EmptyStatement *statement = new (pool) AST::EmptyStatement;
+ statement->semicolonToken = loc(2);
+ AST::UiScriptBinding *node = new (pool) AST::UiScriptBinding(sym(1).UiQualifiedId, statement);
+ sym(1).Node = node;
+ } break;
+./
+
UiPropertyType: T_VAR;
/. case $rule_number: Q_FALLTHROUGH(); ./
UiPropertyType: T_RESERVED_WORD;
@@ -1213,10 +1201,10 @@ UiParameterListOpt: UiParameterList;
} break;
./
-UiParameterList: QmlIdentifier T_COLON UiPropertyType;
+UiParameterList: QmlIdentifier T_COLON Type;
/.
case $rule_number: {
- AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(3).UiQualifiedId->finish(), stringRef(1));
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(3).Type, stringRef(1));
node->identifierToken = loc(1);
node->colonToken = loc(2);
node->propertyTypeToken = loc(3);
@@ -1224,20 +1212,20 @@ UiParameterList: QmlIdentifier T_COLON UiPropertyType;
} break;
./
-UiParameterList: UiPropertyType QmlIdentifier;
+UiParameterList: Type QmlIdentifier;
/.
case $rule_number: {
- AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiQualifiedId->finish(), stringRef(2));
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).Type, stringRef(2));
node->propertyTypeToken = loc(1);
node->identifierToken = loc(2);
sym(1).Node = node;
} break;
./
-UiParameterList: UiParameterList T_COMMA QmlIdentifier T_COLON UiPropertyType;
+UiParameterList: UiParameterList T_COMMA QmlIdentifier T_COLON Type;
/.
case $rule_number: {
- AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(5).UiQualifiedId->finish(), stringRef(3));
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(5).Type, stringRef(3));
node->propertyTypeToken = loc(5);
node->commaToken = loc(2);
node->identifierToken = loc(3);
@@ -1246,10 +1234,10 @@ UiParameterList: UiParameterList T_COMMA QmlIdentifier T_COLON UiPropertyType;
} break;
./
-UiParameterList: UiParameterList T_COMMA UiPropertyType QmlIdentifier;
+UiParameterList: UiParameterList T_COMMA Type QmlIdentifier;
/.
case $rule_number: {
- AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(3).UiQualifiedId->finish(), stringRef(4));
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(3).Type, stringRef(4));
node->propertyTypeToken = loc(3);
node->commaToken = loc(2);
node->identifierToken = loc(4);
@@ -1262,7 +1250,7 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN Semic
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
node->type = AST::UiPublicMember::Signal;
- node->propertyToken = loc(1);
+ node->setPropertyToken(loc(1));
node->typeToken = loc(2);
node->identifierToken = loc(2);
node->parameters = sym(4).UiParameterList;
@@ -1276,7 +1264,7 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER Semicolon;
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
node->type = AST::UiPublicMember::Signal;
- node->propertyToken = loc(1);
+ node->setPropertyToken(loc(1));
node->typeToken = loc(2);
node->identifierToken = loc(2);
node->semicolonToken = loc(3);
@@ -1284,126 +1272,97 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER Semicolon;
} break;
./
-UiObjectMemberListPropertyNoInitialiser: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
-/.
- case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
- node->typeModifier = stringRef(2);
- node->propertyToken = loc(1);
- node->typeModifierToken = loc(2);
- node->typeToken = loc(4);
- node->identifierToken = loc(6);
- node->semicolonToken = loc(7);
- sym(1).Node = node;
- } break;
-./
+-------------------------------------------------------------------------------
+-- There is some ambiguity in whether required default property should be parsed
+-- as required (default (property)) or as ((required (default)) property)
+-- by reducing after each attribute modifier, we ensure that T_PROPERTY (which
+-- is always available is used as the base case (so we only have to allocate the
+-- node in the T_PROPERY case, and all other rules can assume that the node is
+-- already available).
+--------------------------------------------------------------------------------
-UiObjectMember: UiObjectMemberListPropertyNoInitialiser;
+AttrRequired: T_REQUIRED %prec REDUCE_HERE;
+AttrReadonly: T_READONLY %prec REDUCE_HERE;
+AttrDefault: T_DEFAULT %prec REDUCE_HERE;
-UiObjectMember: T_READONLY UiObjectMemberListPropertyNoInitialiser;
+UiPropertyAttributes: AttrRequired UiPropertyAttributes;
/.
case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isReadonlyMember = true;
- node->readonlyToken = loc(1);
- sym(1).Node = node;
+ AST::UiPropertyAttributes *node = sym(2).UiPropertyAttributes;
+ if (node->isRequired())
+ diagnostic_messages.append(compileError(node->requiredToken(), QLatin1String("Duplicated 'required' attribute is not allowed."), QtCriticalMsg));
+ node->m_requiredToken = loc(1);
+ sym(1).UiPropertyAttributes = node;
} break;
./
-UiObjectMemberPropertyNoInitialiser: T_PROPERTY UiPropertyType QmlIdentifier Semicolon;
+UiPropertyAttributes: AttrDefault UiPropertyAttributes;
/.
case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
- node->propertyToken = loc(1);
- node->typeToken = loc(2);
- node->identifierToken = loc(3);
- node->semicolonToken = loc(4);
- sym(1).Node = node;
+ AST::UiPropertyAttributes *node = sym(2).UiPropertyAttributes;
+ if (node->isDefaultMember())
+ diagnostic_messages.append(compileError(node->requiredToken(), QLatin1String("Duplicated 'default' attribute is not allowed."), QtCriticalMsg));
+ node->m_defaultToken = loc(1);
+ sym(1).UiPropertyAttributes = node;
} break;
./
-
-UiObjectMember: UiObjectMemberPropertyNoInitialiser;
-
-UiObjectMember: T_DEFAULT UiObjectMemberPropertyNoInitialiser;
+UiPropertyAttributes: AttrReadonly UiPropertyAttributes;
/.
case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
- sym(1).Node = node;
+ AST::UiPropertyAttributes *node = sym(2).UiPropertyAttributes;
+ if (node->isReadonly())
+ diagnostic_messages.append(compileError(node->requiredToken(), QLatin1String("Duplicated 'readonly' attribute is not allowed."), QtCriticalMsg));
+ node->m_readonlyToken = loc(1);
+ sym(1).UiPropertyAttributes = node;
} break;
./
-
-UiObjectMember: T_REQUIRED UiObjectMemberListPropertyNoInitialiser;
+UiPropertyAttributes: T_PROPERTY;
/.
case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isRequired = true;
- node->requiredToken = loc(1);
- sym(1).Node = node;
+ AST::UiPropertyAttributes *node = new (pool) AST::UiPropertyAttributes();
+ node->m_propertyToken = loc(1);
+ sym(1).UiPropertyAttributes = node;
} break;
./
-UiObjectMember: T_DEFAULT T_REQUIRED UiObjectMemberListPropertyNoInitialiser;
+UiObjectMemberListPropertyNoInitialiser: UiPropertyAttributes T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
/.
case $rule_number: {
- AST::UiPublicMember *node = sym(3).UiPublicMember;
- node->isRequired = true;
- node->requiredToken = loc(2);
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
- sym(1).Node = node;
- } break;
-./
-
-UiObjectMember: T_REQUIRED T_DEFAULT UiObjectMemberListPropertyNoInitialiser;
-/.
- case $rule_number: {
- AST::UiPublicMember *node = sym(3).UiPublicMember;
- node->isRequired = true;
- node->requiredToken = loc(1);
- node->isDefaultMember = true;
- node->defaultToken = loc(2);
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
+ auto attributes = sym(1).UiPropertyAttributes;
+ node->setAttributes(attributes);
+ if (attributes->isReadonly())
+ diagnostic_messages.append(compileError(attributes->readonlyToken(), QLatin1String("Read-only properties require an initializer."), QtWarningMsg));
+ node->typeModifier = stringRef(2);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7);
sym(1).Node = node;
} break;
./
-UiObjectMember: T_DEFAULT UiObjectMemberListPropertyNoInitialiser;
-/.
- case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
- sym(1).Node = node;
- } break;
-./
+UiObjectMember: UiObjectMemberListPropertyNoInitialiser;
-UiObjectMember: T_DEFAULT T_REQUIRED UiObjectMemberPropertyNoInitialiser;
+UiObjectMemberPropertyNoInitialiser: UiPropertyAttributes UiPropertyType QmlIdentifier Semicolon;
/.
case $rule_number: {
- AST::UiPublicMember *node = sym(3).UiPublicMember;
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
- node->isRequired = true;
- node->requiredToken = loc(2);
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
+ auto attributes = sym(1).UiPropertyAttributes;
+ if (attributes->isReadonly())
+ diagnostic_messages.append(compileError(attributes->readonlyToken(), QLatin1String("Read-only properties require an initializer."), QtCriticalMsg));
+ node->setAttributes(attributes);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4);
sym(1).Node = node;
} break;
./
-UiObjectMember: T_REQUIRED T_DEFAULT UiObjectMemberPropertyNoInitialiser;
-/.
- case $rule_number: {
- AST::UiPublicMember *node = sym(3).UiPublicMember;
- node->isDefaultMember = true;
- node->defaultToken = loc(2);
- node->isRequired = true;
- node->requiredToken = loc(1);
- sym(1).Node = node;
- } break;
-./
+UiObjectMember: UiObjectMemberPropertyNoInitialiser;
OptionalSemicolon: | Semicolon;
/.
@@ -1423,21 +1382,14 @@ UiRequired: T_REQUIRED QmlIdentifier Semicolon;
UiObjectMember: UiRequired;
-UiObjectMember: T_REQUIRED UiObjectMemberPropertyNoInitialiser;
-/.
- case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->requiredToken = loc(1);
- node->isRequired = true;
- sym(1).Node = node;
- } break;
-./
-
-UiObjectMemberWithScriptStatement: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
+UiObjectMemberWithScriptStatement: UiPropertyAttributes UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3), sym(5).Statement);
- node->propertyToken = loc(1);
+ auto attributes = sym(1).UiPropertyAttributes;
+ if (attributes->isRequired())
+ diagnostic_messages.append(compileError(attributes->requiredToken(), QLatin1String("Required properties with initializer do not make sense."), QtCriticalMsg));
+ node->setAttributes(attributes);
node->typeToken = loc(2);
node->identifierToken = loc(3);
node->colonToken = loc(4);
@@ -1445,47 +1397,48 @@ UiObjectMemberWithScriptStatement: T_PROPERTY UiPropertyType QmlIdentifier T_COL
} break;
./
-UiObjectMember: UiObjectMemberWithScriptStatement;
-
-UiObjectMember: T_READONLY UiObjectMemberWithScriptStatement;
+UiObjectMemberWithScriptStatement: UiPropertyAttributes T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isReadonlyMember = true;
- node->readonlyToken = loc(1);
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6), sym(8).Statement);
+ node->typeModifier = stringRef(2);
+ auto attributes = sym(1).UiPropertyAttributes;
+ if (attributes->isRequired())
+ diagnostic_messages.append(compileError(attributes->requiredToken(), QLatin1String("Required properties with initializer do not make sense."), QtCriticalMsg));
+ node->setAttributes(attributes);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->colonToken = loc(7);
sym(1).Node = node;
} break;
./
-UiObjectMember: T_DEFAULT UiObjectMemberWithScriptStatement;
-/.
- case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
- sym(1).Node = node;
- } break;
-./
+UiObjectMember: UiObjectMemberWithScriptStatement;
-UiObjectMemberWithArray: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
+UiObjectMemberWithArray: UiPropertyAttributes T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON ExpressionStatementLookahead T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
+ auto attributes = sym(1).UiPropertyAttributes;
+ if (attributes->isRequired())
+ diagnostic_messages.append(compileError(attributes->requiredToken(), QLatin1String("Required properties with initializer do not make sense."), QtCriticalMsg));
+ node->setAttributes(attributes);
node->typeModifier = stringRef(2);
- node->propertyToken = loc(1);
node->typeModifierToken = loc(2);
node->typeToken = loc(4);
node->identifierToken = loc(6);
node->semicolonToken = loc(7); // insert a fake ';' before ':'
+ node->colonToken = loc(7);
AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(6));
propertyName->identifierToken = loc(6);
- propertyName->next = 0;
+ propertyName->next = nullptr;
- AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(propertyName, sym(9).UiArrayMemberList->finish());
+ AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(propertyName, sym(10).UiArrayMemberList->finish());
binding->colonToken = loc(7);
- binding->lbracketToken = loc(8);
- binding->rbracketToken = loc(10);
+ binding->lbracketToken = loc(9);
+ binding->rbracketToken = loc(11);
node->binding = binding;
@@ -1495,28 +1448,22 @@ UiObjectMemberWithArray: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIde
UiObjectMember: UiObjectMemberWithArray;
-UiObjectMember: T_READONLY UiObjectMemberWithArray;
-/.
- case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isReadonlyMember = true;
- node->readonlyToken = loc(1);
- sym(1).Node = node;
- } break;
-./
-
-UiObjectMemberExpressionStatementLookahead: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
+UiObjectMemberExpressionStatementLookahead: UiPropertyAttributes UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
- node->propertyToken = loc(1);
+ auto attributes = sym(1).UiPropertyAttributes;
+ if (attributes->isRequired())
+ diagnostic_messages.append(compileError(attributes->requiredToken(), QLatin1String("Required properties with initializer do not make sense."), QtWarningMsg));
+ node->setAttributes(attributes);
node->typeToken = loc(2);
node->identifierToken = loc(3);
node->semicolonToken = loc(4); // insert a fake ';' before ':'
+ node->colonToken = loc(4);
AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(3));
propertyName->identifierToken = loc(3);
- propertyName->next = 0;
+ propertyName->next = nullptr;
AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding(
propertyName, sym(6).UiQualifiedId, sym(7).UiObjectInitializer);
@@ -1530,16 +1477,6 @@ UiObjectMemberExpressionStatementLookahead: T_PROPERTY UiPropertyType QmlIdentif
UiObjectMember: UiObjectMemberExpressionStatementLookahead;
-UiObjectMember: T_READONLY UiObjectMemberExpressionStatementLookahead;
-/.
- case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isReadonlyMember = true;
- node->readonlyToken = loc(1);
- sym(1).Node = node;
- } break;
-./
-
UiObjectMember: GeneratorDeclaration;
/.
case $rule_number: {
@@ -1590,6 +1527,8 @@ UiObjectMember: T_ENUM T_IDENTIFIER T_LBRACE EnumMemberList T_RBRACE;
case $rule_number: {
AST::UiEnumDeclaration *enumDeclaration = new (pool) AST::UiEnumDeclaration(stringRef(2), sym(4).UiEnumMemberList->finish());
enumDeclaration->enumToken = loc(1);
+ enumDeclaration->identifierToken = loc(2);
+ enumDeclaration->lbraceToken = loc(3);
enumDeclaration->rbraceToken = loc(5);
sym(1).Node = enumDeclaration;
break;
@@ -1605,6 +1544,7 @@ UiObjectMember: T_COMPONENT T_IDENTIFIER T_COLON UiObjectDefinition;
}
auto inlineComponent = new (pool) AST::UiInlineComponent(stringRef(2), sym(4).UiObjectDefinition);
inlineComponent->componentToken = loc(1);
+ inlineComponent->identifierToken = loc(2);
sym(1).Node = inlineComponent;
} break;
./
@@ -1630,6 +1570,18 @@ EnumMemberList: T_IDENTIFIER T_EQ T_NUMERIC_LITERAL;
}
./
+
+EnumMemberList: T_IDENTIFIER T_EQ T_MINUS T_NUMERIC_LITERAL;
+/.
+ case $rule_number: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(stringRef(1), -sym(4).dval);
+ node->memberToken = loc(1);
+ node->valueToken = combine(loc(3), loc(4));
+ sym(1).Node = node;
+ break;
+ }
+./
+
EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER;
/.
case $rule_number: {
@@ -1651,6 +1603,18 @@ EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER T_EQ T_NUMERIC_LITERAL;
}
./
+
+EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER T_EQ T_MINUS T_NUMERIC_LITERAL;
+/.
+ case $rule_number: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(sym(1).UiEnumMemberList, stringRef(3), -sym(6).dval);
+ node->memberToken = loc(3);
+ node->valueToken = combine(loc(5), loc(6));
+ sym(1).Node = node;
+ break;
+ }
+./
+
QmlIdentifier: T_IDENTIFIER
| T_PROPERTY
| T_SIGNAL
@@ -1684,28 +1648,35 @@ BindingIdentifier: IdentifierReference;
-- Types
--------------------------------------------------------------------------------------------------------
-TypeArguments: Type;
+Type: UiQualifiedId T_LT SimpleType T_GT;
/.
case $rule_number: {
- sym(1).TypeArgumentList = new (pool) AST::TypeArgumentList(sym(1).Type);
+ sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId, sym(3).Type);
} break;
./
-TypeArguments: TypeArguments T_COMMA Type;
+Type: SimpleType;
+
+SimpleType: T_RESERVED_WORD;
/.
case $rule_number: {
- sym(1).TypeArgumentList = new (pool) AST::TypeArgumentList(sym(1).TypeArgumentList, sym(3).Type);
+ AST::UiQualifiedId *id = new (pool) AST::UiQualifiedId(stringRef(1));
+ id->identifierToken = loc(1);
+ sym(1).Type = new (pool) AST::Type(id->finish());
} break;
./
-Type: UiQualifiedId T_LT TypeArguments T_GT;
+SimpleType: UiQualifiedId;
/.
case $rule_number: {
- sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId, sym(3).TypeArgumentList->finish());
+ sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId);
} break;
./
-Type: T_RESERVED_WORD;
+SimpleType: T_VAR;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+
+SimpleType: T_VOID;
/.
case $rule_number: {
AST::UiQualifiedId *id = new (pool) AST::UiQualifiedId(stringRef(1));
@@ -1714,13 +1685,6 @@ Type: T_RESERVED_WORD;
} break;
./
-Type: UiQualifiedId;
-/.
- case $rule_number: {
- sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId);
- } break;
-./
-
TypeAnnotation: T_COLON Type;
/.
case $rule_number: {
@@ -1729,14 +1693,6 @@ TypeAnnotation: T_COLON Type;
} break;
./
-
-TypeExpression: Type;
-/.
- case $rule_number: {
- sym(1).Expression = new (pool) AST::TypeExpression(sym(1).Type);
- } break;
-./
-
TypeAnnotationOpt: TypeAnnotation;
TypeAnnotationOpt: ;
/.
@@ -2100,7 +2056,6 @@ PropertyDefinition: IdentifierReference;
AST::IdentifierExpression *expr = new (pool) AST::IdentifierExpression(stringRef(1));
expr->identifierToken = loc(1);
AST::PatternProperty *node = new (pool) AST::PatternProperty(name, expr);
- node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
@@ -2121,8 +2076,8 @@ CoverInitializedName: IdentifierReference Initializer_In;
if (auto *c = asAnonymousClassDefinition(sym(2).Expression))
c->name = stringRef(1);
AST::BinaryExpression *assignment = new (pool) AST::BinaryExpression(left, QSOperator::Assign, sym(2).Expression);
+ assignment->operatorToken = loc(2);
AST::PatternProperty *node = new (pool) AST::PatternProperty(name, assignment);
- node->colonToken = loc(1);
sym(1).Node = node;
} break;
@@ -2235,7 +2190,9 @@ Initializer: T_EQ AssignmentExpression;
Initializer_In: T_EQ AssignmentExpression_In;
/.
case $rule_number: {
- sym(1) = sym(2);
+ auto node = new (pool) AST::InitializerExpression(sym(2).Expression);
+ node->equalToken = loc(1);
+ sym(1).Expression = node;
} break;
./
@@ -2253,7 +2210,14 @@ InitializerOpt: Initializer;
InitializerOpt_In: Initializer_In;
TemplateLiteral: T_NO_SUBSTITUTION_TEMPLATE;
-/. case $rule_number: Q_FALLTHROUGH(); ./
+/.
+ case $rule_number: {
+ AST::TemplateLiteral *node = new (pool) AST::TemplateLiteral(stringRef(1), rawStringRef(1), nullptr);
+ node->literalToken = loc(1);
+ node->hasNoSubstitution = true;
+ sym(1).Node = node;
+ } break;
+./
TemplateSpans: T_TEMPLATE_TAIL;
/.
@@ -2301,7 +2265,16 @@ MemberExpression: MemberExpression T_LBRACKET Expression_In T_RBRACKET;
sym(1).Node = node;
} break;
./
-
+MemberExpression: MemberExpression T_QUESTION_DOT T_LBRACKET Expression_In T_RBRACKET;
+/.
+ case $rule_number: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(4).Expression);
+ node->lbracketToken = loc(3);
+ node->rbracketToken = loc(5);
+ node->isOptional = true;
+ sym(1).Node = node;
+ } break;
+./
-- the identifier has to be "target", catched at codegen time
NewTarget: T_NEW T_DOT T_IDENTIFIER;
@@ -2324,6 +2297,17 @@ MemberExpression: MemberExpression T_DOT IdentifierName;
} break;
./
+MemberExpression: MemberExpression T_QUESTION_DOT IdentifierName;
+/.
+ case $rule_number: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ node->isOptional = true;
+ sym(1).Node = node;
+ } break;
+./
+
MemberExpression: MetaProperty;
MemberExpression: T_NEW MemberExpression T_LPAREN Arguments T_RPAREN;
@@ -2372,6 +2356,17 @@ CallExpression: MemberExpression T_LPAREN Arguments T_RPAREN;
} break;
./
+CallExpression: MemberExpression T_QUESTION_DOT T_LPAREN Arguments T_RPAREN;
+/.
+ case $rule_number: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(4).ArgumentList);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->isOptional = true;
+ sym(1).Node = node;
+ } break;
+./
+
CallExpression: Super T_LPAREN Arguments T_RPAREN;
/. case $rule_number: Q_FALLTHROUGH(); ./
CallExpression: CallExpression T_LPAREN Arguments T_RPAREN;
@@ -2384,6 +2379,18 @@ CallExpression: CallExpression T_LPAREN Arguments T_RPAREN;
} break;
./
+CallExpression: CallExpression T_QUESTION_DOT T_LPAREN Arguments T_RPAREN;
+/.
+ case $rule_number: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(4).ArgumentList);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->isOptional = true;
+ sym(1).Node = node;
+ } break;
+./
+
+
CallExpression: CallExpression T_LBRACKET Expression_In T_RBRACKET;
/.
case $rule_number: {
@@ -2394,6 +2401,17 @@ CallExpression: CallExpression T_LBRACKET Expression_In T_RBRACKET;
} break;
./
+CallExpression: CallExpression T_QUESTION_DOT T_LBRACKET Expression_In T_RBRACKET;
+/.
+ case $rule_number: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(4).Expression);
+ node->lbracketToken = loc(3);
+ node->rbracketToken = loc(5);
+ node->isOptional = true;
+ sym(1).Node = node;
+ } break;
+./
+
CallExpression: CallExpression T_DOT IdentifierName;
/.
case $rule_number: {
@@ -2404,6 +2422,17 @@ CallExpression: CallExpression T_DOT IdentifierName;
} break;
./
+CallExpression: CallExpression T_QUESTION_DOT IdentifierName;
+/.
+ case $rule_number: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ node->isOptional = true;
+ sym(1).Node = node;
+ } break;
+./
+
Arguments: ;
/.
case $rule_number: {
@@ -2697,30 +2726,22 @@ RelationalOperator: T_INSTANCEOF;
sym(1).ival = QSOperator::InstanceOf;
} break;
./
-
-RelationalExpression_In: RelationalExpression_In T_IN ShiftExpression;
+RelationalOperator: T_AS;
/.
case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::In, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
+ sym(1).ival = QSOperator::As;
} break;
./
-TypeAssertExpression_In: RelationalExpression_In T_AS TypeExpression;
-/. case $rule_number: Q_FALLTHROUGH(); ./
-TypeAssertExpression: RelationalExpression T_AS TypeExpression;
+RelationalExpression_In: RelationalExpression_In T_IN ShiftExpression;
/.
case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::As, sym(3).Expression);
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::In, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
./
-RelationalExpression_In: TypeAssertExpression_In;
-RelationalExpression: TypeAssertExpression;
-
EqualityExpression_In: RelationalExpression_In;
EqualityExpression: RelationalExpression;
@@ -2897,6 +2918,9 @@ AssignmentExpression: LeftHandSideExpression T_EQ AssignmentExpression;
AssignmentExpression_In: LeftHandSideExpression T_EQ AssignmentExpression_In;
/.
case $rule_number: {
+ if (sym(1).Expression->containsOptionalChain()) {
+ syntaxError(loc(1), QStringLiteral("Optional chains are not permitted on the left-hand-side in assignments"));
+ }
// need to convert the LHS to an AssignmentPattern if it was an Array/ObjectLiteral
if (AST::Pattern *p = sym(1).Expression->patternCast()) {
SourceLocation errorLoc;
@@ -2927,6 +2951,9 @@ AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpres
AssignmentExpression_In: LeftHandSideExpression AssignmentOperator AssignmentExpression_In;
/.
case $rule_number: {
+ if (sym(1).Expression->containsOptionalChain()) {
+ syntaxError(loc(1), QStringLiteral("Optional chains are not permitted on the left-hand-side in assignments"));
+ }
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
@@ -3355,14 +3382,15 @@ BindingElisionElement: ElisionOpt BindingElement;
BindingProperty: BindingIdentifier InitializerOpt_In;
/.
case $rule_number: {
- AST::StringLiteralPropertyName *name = new (pool) AST::StringLiteralPropertyName(stringRef(1));
+ AST::IdentifierPropertyName *name = new (pool) AST::IdentifierPropertyName(stringRef(1));
name->propertyNameToken = loc(1);
// if initializer is an anonymous function expression, we need to assign identifierref as it's name
if (auto *f = asAnonymousFunctionDefinition(sym(2).Expression))
f->name = stringRef(1);
if (auto *c = asAnonymousClassDefinition(sym(2).Expression))
c->name = stringRef(1);
- sym(1).Node = new (pool) AST::PatternProperty(name, stringRef(1), sym(2).Expression);
+ AST::PatternProperty *node = new (pool) AST::PatternProperty(name, stringRef(1), sym(2).Expression);
+ sym(1).Node = node;
} break;
./
@@ -3370,6 +3398,7 @@ BindingProperty: PropertyName T_COLON BindingIdentifier InitializerOpt_In;
/.
case $rule_number: {
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, stringRef(3), sym(4).Expression);
+ node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
@@ -3378,6 +3407,7 @@ BindingProperty: PropertyName T_COLON BindingPattern InitializerOpt_In;
/.
case $rule_number: {
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, sym(3).Pattern, sym(4).Expression);
+ node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
@@ -4043,14 +4073,14 @@ ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead AssignmentExpress
/.
case $rule_number: {
AST::ReturnStatement *ret = new (pool) AST::ReturnStatement(sym(4).Expression);
- ret->returnToken = sym(4).Node->firstSourceLocation();
- ret->semicolonToken = sym(4).Node->lastSourceLocation();
+ ret->returnToken = sym(4).Node->firstSourceLocation().startZeroLengthLocation();
+ ret->semicolonToken = sym(4).Node->lastSourceLocation().endZeroLengthLocation(driver->code());
AST::StatementList *statements = (new (pool) AST::StatementList(ret))->finish();
AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringView(), sym(1).FormalParameterList, statements);
f->isArrowFunction = true;
- f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation() : loc(1);
- f->lbraceToken = sym(4).Node->firstSourceLocation();
- f->rbraceToken = sym(4).Node->lastSourceLocation();
+ f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation().startZeroLengthLocation() : loc(1).startZeroLengthLocation();
+ f->lbraceToken = sym(4).Node->firstSourceLocation().startZeroLengthLocation();
+ f->rbraceToken = sym(4).Node->lastSourceLocation().endZeroLengthLocation(driver->code());
sym(1).Node = f;
} break;
./
@@ -4062,8 +4092,8 @@ ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead T_FORCE_BLOCK Fun
case $rule_number: {
AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringView(), sym(1).FormalParameterList, sym(6).StatementList);
f->isArrowFunction = true;
- f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation() : loc(1);
- f->lbraceToken = loc(6);
+ f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation().startZeroLengthLocation() : loc(1).startZeroLengthLocation();
+ f->lbraceToken = loc(5);
f->rbraceToken = loc(7);
sym(1).Node = f;
} break;
@@ -4136,7 +4166,6 @@ MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_R
f->rbraceToken = loc(9);
f->isGenerator = true;
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Method);
- node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
@@ -4154,7 +4183,6 @@ MethodDefinition: T_GET PropertyName T_LPAREN T_RPAREN TypeAnnotationOpt Functio
f->lbraceToken = loc(6);
f->rbraceToken = loc(8);
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Getter);
- node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
@@ -4171,7 +4199,6 @@ MethodDefinition: T_SET PropertyName T_LPAREN PropertySetParameterList T_RPAREN
f->lbraceToken = loc(7);
f->rbraceToken = loc(9);
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Setter);
- node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
@@ -4350,16 +4377,16 @@ ClassDeclaration_Default: ClassDeclaration;
ClassLBrace: T_LBRACE;
/.
case $rule_number: {
- lexer->setStaticIsKeyword(true);
+ if (++classNestingLevel == 1)
+ lexer->setStaticIsKeyword(true);
} break;
./
ClassRBrace: T_RBRACE;
-/. case $rule_number: ./
-ClassStaticQualifier: T_STATIC;
/.
case $rule_number: {
- lexer->setStaticIsKeyword(false);
+ if (--classNestingLevel == 0)
+ lexer->setStaticIsKeyword(false);
} break;
./
@@ -4414,10 +4441,9 @@ ClassElement: MethodDefinition;
} break;
./
-ClassElement: ClassStaticQualifier MethodDefinition;
+ClassElement: T_STATIC MethodDefinition;
/.
case $rule_number: {
- lexer->setStaticIsKeyword(true);
AST::ClassElementList *node = new (pool) AST::ClassElementList(sym(2).PatternProperty, true);
sym(1).Node = node;
} break;
@@ -4802,35 +4828,26 @@ ExportSpecifier: IdentifierName T_AS IdentifierName;
if (first_token == last_token) {
const int errorState = state_stack[tos];
+ // automatic insertion of missing identifiers after dots
+ if (yytoken != -1 && m_identifierInsertionEnabled && t_action(errorState, T_IDENTIFIER) && yyprevtoken == T_DOT) {
+#ifdef PARSER_DEBUG
+ qDebug() << "Inserting missing identifier between" << spell[yyprevtoken] << "and"
+ << spell[yytoken];
+#endif
+ pushTokenWithEmptyLocation(T_IDENTIFIER);
+ action = errorState;
+ goto _Lcheck_token;
+ }
+
+
// automatic insertion of `;'
if (yytoken != -1 && ((t_action(errorState, T_AUTOMATIC_SEMICOLON) && lexer->canInsertAutomaticSemicolon(yytoken))
|| t_action(errorState, T_COMPATIBILITY_SEMICOLON))) {
#ifdef PARSER_DEBUG
qDebug() << "Inserting automatic semicolon.";
#endif
- SavedToken &tk = token_buffer[0];
- tk.token = yytoken;
- tk.dval = yylval;
- tk.spell = yytokenspell;
- tk.raw = yytokenraw;
- tk.loc = yylloc;
-
- yylloc = yyprevlloc;
- yylloc.offset += yylloc.length;
- yylloc.startColumn += yylloc.length;
- yylloc.length = 0;
-
- //const QString msg = QCoreApplication::translate("QQmlParser", "Missing `;'");
- //diagnostic_messages.append(compileError(yyloc, msg, QtWarningMsg));
-
- first_token = &token_buffer[0];
- last_token = &token_buffer[1];
-
- yytoken = T_SEMICOLON;
- yylval = 0;
-
+ pushTokenWithEmptyLocation(T_SEMICOLON);
action = errorState;
-
goto _Lcheck_token;
}
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index 4b5d866662..8f13ad193e 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -1,48 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include <QString>
#include <QLocale>
+#include "common/qqmljssourcelocation_p.h"
#include "qqmljsast_p.h"
#include "qqmljsastvisitor_p.h"
#include <qlocale.h>
+#include <algorithm>
+#include <array>
+
QT_BEGIN_NAMESPACE
namespace QQmlJS { namespace AST {
@@ -118,6 +87,44 @@ ExpressionNode *ExpressionNode::expressionCast()
return this;
}
+bool ExpressionNode::containsOptionalChain() const
+{
+ for (const Node *node = this;;) {
+ switch (node->kind) {
+ case Kind_FieldMemberExpression: {
+ const auto *fme = AST::cast<const FieldMemberExpression*>(node);
+ if (fme->isOptional)
+ return true;
+ node = fme->base;
+ break;
+ }
+ case Kind_ArrayMemberExpression: {
+ const auto *ame = AST::cast<const ArrayMemberExpression*>(node);
+ if (ame->isOptional)
+ return true;
+ node = ame->base;
+ break;
+ }
+ case Kind_CallExpression: {
+ const auto *ce = AST::cast<const CallExpression*>(node);
+ if (ce->isOptional)
+ return true;
+ node = ce->base;
+ break;
+ }
+ case Kind_NestedExpression: {
+ const auto *ne = AST::cast<const NestedExpression*>(node);
+ node = ne->expression;
+ break;
+ }
+ default:
+ // These unhandled nodes lead to invalid lvalues anyway, so they do not need to be handled here.
+ return false;
+ }
+ }
+ return false;
+}
+
FormalParameterList *ExpressionNode::reparseAsFormalParameterList(MemoryPool *pool)
{
AST::ExpressionNode *expr = this;
@@ -1009,13 +1016,9 @@ BoundNames FormalParameterList::formals() const
// change the name of the earlier argument to enforce the lookup semantics from the spec
formals[duplicateIndex].id += QLatin1String("#") + QString::number(i);
}
- formals += {
- name,
- it->element->typeAnnotation,
- it->element->isInjectedSignalParameter
- ? BoundName::Injected
- : BoundName::Declared
- };
+ formals += { name, it->element->firstSourceLocation(), it->element->typeAnnotation,
+ it->element->isInjectedSignalParameter ? BoundName::Injected
+ : BoundName::Declared };
}
++i;
}
@@ -1043,17 +1046,10 @@ void FormalParameterList::accept0(BaseVisitor *visitor)
}
}
-FormalParameterList *FormalParameterList::finish(QQmlJS::MemoryPool *pool)
+FormalParameterList *FormalParameterList::finish(QQmlJS::MemoryPool *)
{
FormalParameterList *front = next;
next = nullptr;
-
- int i = 0;
- for (const FormalParameterList *it = this; it; it = it->next) {
- if (it->element && it->element->bindingIdentifier.isEmpty())
- it->element->bindingIdentifier = pool->newString(QLatin1String("arg#") + QString::number(i));
- ++i;
- }
return front;
}
@@ -1162,8 +1158,8 @@ void ExportClause::accept0(BaseVisitor *visitor)
void ExportDeclaration::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
- accept(fromClause, visitor);
accept(exportClause, visitor);
+ accept(fromClause, visitor);
accept(variableStatementOrDeclaration, visitor);
}
@@ -1305,41 +1301,40 @@ void Type::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(typeId, visitor);
- accept(typeArguments, visitor);
+ accept(typeArgument, visitor);
}
visitor->endVisit(this);
}
-void TypeArgumentList::accept0(BaseVisitor *visitor)
+void TypeAnnotation::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
- for (TypeArgumentList *it = this; it; it = it->next)
- accept(it->typeId, visitor);
+ accept(type, visitor);
}
visitor->endVisit(this);
}
-void TypeAnnotation::accept0(BaseVisitor *visitor)
+void UiImport::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
- accept(type, visitor);
+ accept(importUri, visitor);
+ // accept(version, visitor); // accept manually in visit if interested
}
visitor->endVisit(this);
}
-void UiImport::accept0(BaseVisitor *visitor)
+void UiPragmaValueList::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
- accept(importUri, visitor);
- // accept(version, visitor); // accept manually in visit if interested
}
visitor->endVisit(this);
}
+
void UiPragma::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
@@ -1399,6 +1394,11 @@ void TaggedTemplate::accept0(BaseVisitor *visitor)
visitor->endVisit(this);
}
+void InitializerExpression::accept0(BaseVisitor *visitor)
+{
+ expression->accept0(visitor);
+}
+
void PatternElement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
@@ -1418,8 +1418,8 @@ void PatternElement::boundNames(BoundNames *names)
else if (PatternPropertyList *p = propertyList())
p->boundNames(names);
} else {
- names->append({bindingIdentifier.toString(), typeAnnotation,
- isInjectedSignalParameter ? BoundName::Injected : BoundName::Declared});
+ names->append({ bindingIdentifier.toString(), firstSourceLocation(), typeAnnotation,
+ isInjectedSignalParameter ? BoundName::Injected : BoundName::Declared });
}
}
@@ -1557,17 +1557,11 @@ QString Type::toString() const
void Type::toString(QString *out) const
{
- for (QQmlJS::AST::UiQualifiedId *it = typeId; it; it = it->next) {
- out->append(it->name);
+ typeId->toString(out);
- if (it->next)
- out->append(QLatin1Char('.'));
- }
-
- if (typeArguments) {
+ if (typeArgument) {
out->append(QLatin1Char('<'));
- if (auto subType = static_cast<TypeArgumentList*>(typeArguments)->typeId)
- subType->toString(out);
+ typeArgument->toString(out);
out->append(QLatin1Char('>'));
};
}
@@ -1610,6 +1604,20 @@ void UiAnnotation::accept0(BaseVisitor *visitor)
visitor->endVisit(this);
}
+SourceLocation UiPropertyAttributes::firstSourceLocation() const
+{
+ std::array<const SourceLocation *, 4> tokens {&m_propertyToken, &m_defaultToken, &m_readonlyToken, &m_requiredToken};
+ const auto it = std::min_element(tokens.begin(), tokens.end(), compareLocationsByBegin<true>);
+ return **it;
+}
+
+SourceLocation UiPropertyAttributes::lastSourceLocation() const
+{
+ std::array<const SourceLocation *, 4> tokens {&m_propertyToken, &m_defaultToken, &m_readonlyToken, &m_requiredToken};
+ const auto it = std::max_element(tokens.begin(), tokens.end(), compareLocationsByBegin<false>);
+ return **it;
+}
+
} } // namespace QQmlJS::AST
QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index cb6d5fa3ee..2bb9b3f001 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSAST_P_H
#define QQMLJSAST_P_H
@@ -56,11 +20,19 @@
#include <private/qqmljsmemorypool_p.h>
-#include <QtCore/qstring.h>
+#include <QtCore/qtaggedpointer.h>
#include <QtCore/qversionnumber.h>
+#include <type_traits>
+
QT_BEGIN_NAMESPACE
+class QString;
+
+namespace QQmlJS {
+ class Parser;
+}
+
#define QQMLJS_DECLARE_AST_NODE(name) \
enum { K = Kind_##name };
@@ -126,10 +98,10 @@ enum class VariableScope {
template <typename T1, typename T2>
T1 cast(T2 *ast)
{
- if (ast && ast->kind == static_cast<T1>(0)->K)
+ if (ast && ast->kind == std::remove_pointer_t<T1>::K)
return static_cast<T1>(ast);
- return 0;
+ return nullptr;
}
FunctionExpression *asAnonymousFunctionDefinition(AST::Node *n);
@@ -177,6 +149,7 @@ public:
Kind_ClassDeclaration,
Kind_IdentifierExpression,
Kind_IdentifierPropertyName,
+ Kind_InitializerExpression,
Kind_ComputedPropertyName,
Kind_IfStatement,
Kind_LabelledStatement,
@@ -239,7 +212,7 @@ public:
Kind_PatternProperty,
Kind_PatternPropertyList,
Kind_Type,
- Kind_TypeArgumentList,
+ Kind_TypeArgument,
Kind_TypeAnnotation,
Kind_UiArrayBinding,
@@ -250,9 +223,11 @@ public:
Kind_UiObjectInitializer,
Kind_UiObjectMemberList,
Kind_UiArrayMemberList,
+ Kind_UiPragmaValueList,
Kind_UiPragma,
Kind_UiProgram,
Kind_UiParameterList,
+ Kind_UiPropertyAttributes,
Kind_UiPublicMember,
Kind_UiQualifiedId,
Kind_UiScriptBinding,
@@ -307,12 +282,6 @@ public:
node->accept(visitor);
}
- // ### Remove when we can. This is part of the qmldevtools library, though.
- inline static void acceptChild(Node *node, BaseVisitor *visitor)
- {
- return accept(node, visitor);
- }
-
virtual void accept0(BaseVisitor *visitor) = 0;
virtual SourceLocation firstSourceLocation() const = 0;
virtual SourceLocation lastSourceLocation() const = 0;
@@ -360,12 +329,33 @@ public:
{ return identifierToken; }
SourceLocation lastSourceLocation() const override
- { return lastListElement(this)->identifierToken; }
+ {
+ return lastListElement(this)->lastOwnSourceLocation();
+ }
+
+ SourceLocation lastOwnSourceLocation() const { return identifierToken; }
+
+ QString toString() const
+ {
+ QString result;
+ toString(&result);
+ return result;
+ }
+
+ void toString(QString *out) const
+ {
+ for (const UiQualifiedId *it = this; it; it = it->next) {
+ out->append(it->name);
+ if (it->next)
+ out->append(QLatin1Char('.'));
+ }
+ }
// attributes
UiQualifiedId *next;
QStringView name;
SourceLocation identifierToken;
+ SourceLocation dotToken;
};
class QML_PARSER_EXPORT Type: public Node
@@ -373,9 +363,9 @@ class QML_PARSER_EXPORT Type: public Node
public:
QQMLJS_DECLARE_AST_NODE(Type)
- Type(UiQualifiedId *typeId, Node *typeArguments = nullptr)
+ Type(UiQualifiedId *typeId, Type *typeArgument = nullptr)
: typeId(typeId)
- , typeArguments(typeArguments)
+ , typeArgument(typeArgument ? typeArgument->typeId : nullptr)
{ kind = K; }
void accept0(BaseVisitor *visitor) override;
@@ -384,53 +374,14 @@ public:
{ return typeId->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return typeArguments ? typeArguments->lastSourceLocation() : typeId->lastSourceLocation(); }
+ { return typeArgument ? typeArgument->lastSourceLocation() : typeId->lastSourceLocation(); }
QString toString() const;
void toString(QString *out) const;
// attributes
UiQualifiedId *typeId;
- Node *typeArguments; // TypeArgumentList
-};
-
-
-class QML_PARSER_EXPORT TypeArgumentList: public Node
-{
-public:
- QQMLJS_DECLARE_AST_NODE(TypeArgumentList)
-
- TypeArgumentList(Type *typeId)
- : typeId(typeId)
- , next(nullptr)
- { kind = K; }
-
- TypeArgumentList(TypeArgumentList *previous, Type *typeId)
- : typeId(typeId)
- {
- kind = K;
- next = previous->next;
- previous->next = this;
- }
-
- void accept0(BaseVisitor *visitor) override;
-
- SourceLocation firstSourceLocation() const override
- { return typeId->firstSourceLocation(); }
-
- SourceLocation lastSourceLocation() const override
- { return lastListElement(this)->typeId->lastSourceLocation(); }
-
- inline TypeArgumentList *finish()
- {
- TypeArgumentList *front = next;
- next = nullptr;
- return front;
- }
-
-// attributes
- Type *typeId;
- TypeArgumentList *next;
+ UiQualifiedId *typeArgument;
};
class QML_PARSER_EXPORT TypeAnnotation: public Node
@@ -460,6 +411,7 @@ public:
ExpressionNode() {}
ExpressionNode *expressionCast() override;
+ bool containsOptionalChain() const;
AST::FormalParameterList *reparseAsFormalParameterList(MemoryPool *pool);
@@ -734,6 +686,7 @@ public:
void accept0(BaseVisitor *visitor) override;
+ bool hasNoSubstitution = false;
QStringView value;
QStringView rawValue;
ExpressionNode *expression;
@@ -893,12 +846,14 @@ struct QML_PARSER_EXPORT BoundName
};
QString id;
+ QQmlJS::SourceLocation location;
QTaggedPointer<TypeAnnotation, Type> typeAnnotation;
- BoundName(const QString &id, TypeAnnotation *typeAnnotation, Type type = Declared)
- : id(id), typeAnnotation(typeAnnotation, type)
+ BoundName(const QString &id, const QQmlJS::SourceLocation &location,
+ TypeAnnotation *typeAnnotation, Type type = Declared)
+ : id(id), location(location), typeAnnotation(typeAnnotation, type)
{}
BoundName() = default;
- QString typeName() const { return typeAnnotation ? typeAnnotation->type->toString() : QString(); }
+
bool isInjected() const { return typeAnnotation.tag() == Injected; }
};
@@ -919,6 +874,39 @@ struct BoundNames : public QVector<BoundName>
}
};
+/*!
+\internal
+This class is needed to pass the information about the equalToken in the parser, and is only needed
+during AST construction. It behaves exactly like the expression it contains: that avoids changing
+all the usages in qqmljs.g from ExpressionNode to InitializerExpression for every rule expecting a
+InitializerOpt_In or InitializerOpt.
+*/
+class QML_PARSER_EXPORT InitializerExpression : public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(InitializerExpression)
+
+ InitializerExpression(ExpressionNode *e) : expression(e) { kind = K; }
+
+ void accept0(BaseVisitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return equalToken; }
+
+ SourceLocation lastSourceLocation() const override { return expression->lastSourceLocation(); }
+
+ FunctionExpression *asFunctionDefinition() override
+ {
+ return expression->asFunctionDefinition();
+ }
+
+ ClassExpression *asClassDefinition() override { return expression->asClassDefinition(); }
+
+ // attributes
+ ExpressionNode *expression;
+ SourceLocation equalToken;
+};
+
class QML_PARSER_EXPORT PatternElement : public Node
{
public:
@@ -939,9 +927,28 @@ public:
Binding,
};
+private:
+ /*!
+ \internal
+ Hide InitializerExpression from the AST. InitializerExpression is only needed during parsing for
+ the AST construction, and it is not possible for the parser to directly embed the location of
+ equal tokens inside the PatternElement without the InitializerExpression.
+ */
+ void unwrapInitializer()
+ {
+ if (auto unwrapped = AST::cast<InitializerExpression *>(initializer)) {
+ equalToken = unwrapped->equalToken;
+ initializer = unwrapped->expression;
+ }
+ }
+public:
+
PatternElement(ExpressionNode *i = nullptr, Type t = Literal)
: initializer(i), type(t)
- { kind = K; }
+ {
+ kind = K;
+ unwrapInitializer();
+ }
PatternElement(QStringView n, TypeAnnotation *typeAnnotation = nullptr, ExpressionNode *i = nullptr, Type t = Binding)
: bindingIdentifier(n), initializer(i), type(t)
@@ -949,6 +956,7 @@ public:
{
Q_ASSERT(t >= RestElement);
kind = K;
+ unwrapInitializer();
}
PatternElement(Pattern *pattern, ExpressionNode *i = nullptr, Type t = Binding)
@@ -956,6 +964,7 @@ public:
{
Q_ASSERT(t >= RestElement);
kind = K;
+ unwrapInitializer();
}
void accept0(BaseVisitor *visitor) override;
@@ -979,6 +988,7 @@ public:
// attributes
SourceLocation identifierToken;
+ SourceLocation equalToken;
QStringView bindingIdentifier;
ExpressionNode *bindingTarget = nullptr;
ExpressionNode *initializer = nullptr;
@@ -1198,6 +1208,7 @@ public:
ExpressionNode *expression;
SourceLocation lbracketToken;
SourceLocation rbracketToken;
+ bool isOptional = false;
};
class QML_PARSER_EXPORT FieldMemberExpression: public LeftHandSideExpression
@@ -1222,6 +1233,7 @@ public:
QStringView name;
SourceLocation dotToken;
SourceLocation identifierToken;
+ bool isOptional = false;
};
class QML_PARSER_EXPORT TaggedTemplate : public LeftHandSideExpression
@@ -1314,6 +1326,7 @@ public:
ArgumentList *arguments;
SourceLocation lparenToken;
SourceLocation rparenToken;
+ bool isOptional = false;
};
class QML_PARSER_EXPORT ArgumentList: public Node
@@ -2957,7 +2970,6 @@ public:
ExportDeclaration(FromClause *fromClause)
: fromClause(fromClause)
{
- exportAll = true;
kind = K;
}
@@ -2980,6 +2992,11 @@ public:
kind = K;
}
+ bool exportsAll() const
+ {
+ return fromClause && !exportClause;
+ }
+
void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
@@ -2989,7 +3006,6 @@ public:
// attributes
SourceLocation exportToken;
- bool exportAll = false;
ExportClause *exportClause = nullptr;
FromClause *fromClause = nullptr;
Node *variableStatementOrDeclaration = nullptr;
@@ -3122,13 +3138,53 @@ public:
UiObjectMember *member;
};
+class QML_PARSER_EXPORT UiPragmaValueList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiPragmaValueList)
+
+ UiPragmaValueList(QStringView value)
+ : value(value)
+ , next(this)
+ {
+ kind = K;
+ }
+
+ UiPragmaValueList(UiPragmaValueList *previous, QStringView value)
+ : value(value)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ void accept0(BaseVisitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return location; }
+
+ SourceLocation lastSourceLocation() const override
+ { return lastListElement(this)->location; }
+
+ UiPragmaValueList *finish()
+ {
+ UiPragmaValueList *head = next;
+ next = nullptr;
+ return head;
+ }
+
+ QStringView value;
+ UiPragmaValueList *next;
+ SourceLocation location;
+};
+
class QML_PARSER_EXPORT UiPragma: public Node
{
public:
QQMLJS_DECLARE_AST_NODE(UiPragma)
- UiPragma(QStringView name)
- : name(name)
+ UiPragma(QStringView name, UiPragmaValueList *values = nullptr)
+ : name(name), values(values)
{ kind = K; }
void accept0(BaseVisitor *visitor) override;
@@ -3141,7 +3197,10 @@ public:
// attributes
QStringView name;
+ UiPragmaValueList *values;
SourceLocation pragmaToken;
+ SourceLocation pragmaIdToken;
+ SourceLocation colonToken;
SourceLocation semicolonToken;
};
@@ -3316,11 +3375,11 @@ class QML_PARSER_EXPORT UiParameterList: public Node
public:
QQMLJS_DECLARE_AST_NODE(UiParameterList)
- UiParameterList(UiQualifiedId *t, QStringView n):
+ UiParameterList(Type *t, QStringView n):
type (t), name (n), next (this)
{ kind = K; }
- UiParameterList(UiParameterList *previous, UiQualifiedId *t, QStringView n):
+ UiParameterList(UiParameterList *previous, Type *t, QStringView n):
type (t), name (n)
{
kind = K;
@@ -3336,7 +3395,12 @@ public:
SourceLocation lastSourceLocation() const override
{
auto last = lastListElement(this);
- return (last->colonToken.isValid() ? last->propertyTypeToken : last->identifierToken);
+ return last->lastOwnSourceLocation();
+ }
+
+ SourceLocation lastOwnSourceLocation() const
+ {
+ return (colonToken.isValid() ? propertyTypeToken : identifierToken);
}
inline UiParameterList *finish ()
@@ -3347,7 +3411,7 @@ public:
}
// attributes
- UiQualifiedId *type;
+ Type *type;
QStringView name;
UiParameterList *next;
SourceLocation commaToken;
@@ -3356,6 +3420,46 @@ public:
SourceLocation colonToken;
};
+class QML_PARSER_EXPORT UiPropertyAttributes : public Node
+{
+ QQMLJS_DECLARE_AST_NODE(UiPropertyAttributes)
+public:
+ UiPropertyAttributes() { kind = K; }
+
+ SourceLocation defaultToken() const { return m_defaultToken; }
+ bool isDefaultMember() const { return defaultToken().isValid(); }
+ SourceLocation requiredToken() const { return m_requiredToken; }
+ bool isRequired() const { return requiredToken().isValid(); }
+ SourceLocation readonlyToken() const { return m_readonlyToken; }
+ bool isReadonly() const { return readonlyToken().isValid(); }
+
+ SourceLocation propertyToken() const { return m_propertyToken; }
+
+ template <bool InvalidIsLargest = true>
+ static bool compareLocationsByBegin(const SourceLocation *& lhs, const SourceLocation *& rhs)
+ {
+ if (lhs->isValid() && rhs->isValid())
+ return lhs->begin() < rhs->begin();
+ else if (lhs->isValid())
+ return InvalidIsLargest;
+ else
+ return !InvalidIsLargest;
+ }
+
+ void accept0(BaseVisitor *) override {} // intentionally do nothing
+
+ SourceLocation firstSourceLocation() const override;
+
+ SourceLocation lastSourceLocation() const override;
+
+private:
+ friend class QQmlJS::Parser;
+ SourceLocation m_defaultToken;
+ SourceLocation m_readonlyToken;
+ SourceLocation m_requiredToken;
+ SourceLocation m_propertyToken;
+};
+
class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember
{
public:
@@ -3363,27 +3467,23 @@ public:
UiPublicMember(UiQualifiedId *memberType,
QStringView name)
- : type(Property), memberType(memberType), name(name), statement(nullptr), binding(nullptr), isDefaultMember(false), isReadonlyMember(false), parameters(nullptr)
+ : type(Property), memberType(memberType), name(name), statement(nullptr), binding(nullptr), parameters(nullptr)
{ kind = K; }
UiPublicMember(UiQualifiedId *memberType,
QStringView name,
Statement *statement)
- : type(Property), memberType(memberType), name(name), statement(statement), binding(nullptr), isDefaultMember(false), isReadonlyMember(false), parameters(nullptr)
+ : type(Property), memberType(memberType), name(name), statement(statement), binding(nullptr), parameters(nullptr)
{ kind = K; }
void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{
- if (defaultToken.isValid())
- return defaultToken;
- else if (readonlyToken.isValid())
- return readonlyToken;
- else if (requiredToken.isValid())
- return requiredToken;
-
- return propertyToken;
+ if (hasAttributes)
+ return m_attributes->firstSourceLocation();
+ else
+ return m_propertyToken;
}
SourceLocation lastSourceLocation() const override
@@ -3396,27 +3496,61 @@ public:
return semicolonToken;
}
+ SourceLocation defaultToken() const
+ {
+ return hasAttributes ? m_attributes->defaultToken() : SourceLocation {};
+ }
+ bool isDefaultMember() const { return defaultToken().isValid(); }
+
+ SourceLocation requiredToken() const
+ {
+ return hasAttributes ? m_attributes->requiredToken() : SourceLocation {};
+ }
+ bool isRequired() const { return requiredToken().isValid(); }
+
+ SourceLocation readonlyToken() const
+ {
+ return hasAttributes ? m_attributes->readonlyToken() : SourceLocation {};
+ }
+ bool isReadonly() const { return readonlyToken().isValid(); }
+
+ void setAttributes(UiPropertyAttributes *attributes)
+ {
+ m_attributes = attributes;
+ hasAttributes = true;
+ }
+
+ SourceLocation propertyToken() const
+ {
+ return hasAttributes ? m_attributes->propertyToken() : m_propertyToken;
+ }
+
+ void setPropertyToken(SourceLocation token)
+ {
+ m_propertyToken = token;
+ hasAttributes = false;
+ }
+
// attributes
- enum { Signal, Property } type;
+ enum : bool { Signal, Property } type;
+ bool hasAttributes = false;
QStringView typeModifier;
UiQualifiedId *memberType;
QStringView name;
Statement *statement; // initialized with a JS expression
UiObjectMember *binding; // initialized with a QML object or array.
- bool isDefaultMember;
- bool isReadonlyMember;
- bool isRequired = false;
UiParameterList *parameters;
// TODO: merge source locations
- SourceLocation defaultToken;
- SourceLocation readonlyToken;
- SourceLocation propertyToken;
- SourceLocation requiredToken;
SourceLocation typeModifierToken;
SourceLocation typeToken;
SourceLocation identifierToken;
SourceLocation colonToken;
SourceLocation semicolonToken;
+private:
+ union {
+ SourceLocation m_propertyToken = SourceLocation {};
+ UiPropertyAttributes *m_attributes;
+ };
};
class QML_PARSER_EXPORT UiObjectDefinition: public UiObjectMember
@@ -3463,6 +3597,7 @@ public:
QStringView name;
UiObjectDefinition* component;
SourceLocation componentToken;
+ SourceLocation identifierToken;
};
class QML_PARSER_EXPORT UiSourceElement: public UiObjectMember
@@ -3574,7 +3709,7 @@ public:
{ kind = K; }
SourceLocation firstSourceLocation() const override
- { return qualifiedId->identifierToken; }
+ { Q_ASSERT(qualifiedId); return qualifiedId->identifierToken; }
SourceLocation lastSourceLocation() const override
{ return rbracketToken; }
@@ -3661,6 +3796,8 @@ public:
// attributes
SourceLocation enumToken;
+ SourceLocation identifierToken;
+ SourceLocation lbraceToken;
SourceLocation rbraceToken;
QStringView name;
UiEnumMemberList *members;
diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h
index c3a9b5aa83..c87f67c67e 100644
--- a/src/qml/parser/qqmljsastfwd_p.h
+++ b/src/qml/parser/qqmljsastfwd_p.h
@@ -1,46 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSAST_FWD_P_H
#define QQMLJSAST_FWD_P_H
-#include "qqmljsglobal_p.h"
#include <private/qqmljssourcelocation_p.h>
#include <QtCore/qglobal.h>
@@ -159,12 +122,12 @@ class NestedExpression;
class ClassExpression;
class ClassDeclaration;
class ClassElementList;
-class TypeArgumentList;
class Type;
class TypeAnnotation;
// ui elements
class UiProgram;
+class UiPragmaValueList;
class UiPragma;
class UiImport;
class UiPublicMember;
diff --git a/src/qml/parser/qqmljsastvisitor.cpp b/src/qml/parser/qqmljsastvisitor.cpp
index 7388eccebb..21a9e92e2c 100644
--- a/src/qml/parser/qqmljsastvisitor.cpp
+++ b/src/qml/parser/qqmljsastvisitor.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmljsastvisitor_p.h"
diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h
index 1e4c78c0d4..540d21d725 100644
--- a/src/qml/parser/qqmljsastvisitor_p.h
+++ b/src/qml/parser/qqmljsastvisitor_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSASTVISITOR_P_H
#define QQMLJSASTVISITOR_P_H
@@ -56,6 +20,129 @@
QT_BEGIN_NAMESPACE
+// as done in https://en.wikipedia.org/wiki/X_Macro
+
+#define QQmlJSASTUiClassListToVisit \
+ X(UiProgram) \
+ X(UiHeaderItemList) \
+ X(UiPragmaValueList) \
+ X(UiPragma) \
+ X(UiImport) \
+ X(UiPublicMember) \
+ X(UiSourceElement) \
+ X(UiObjectDefinition) \
+ X(UiObjectInitializer) \
+ X(UiObjectBinding) \
+ X(UiScriptBinding) \
+ X(UiArrayBinding) \
+ X(UiParameterList) \
+ X(UiObjectMemberList) \
+ X(UiArrayMemberList) \
+ X(UiQualifiedId) \
+ X(UiEnumDeclaration) \
+ X(UiEnumMemberList) \
+ X(UiVersionSpecifier) \
+ X(UiInlineComponent) \
+ X(UiAnnotation) \
+ X(UiAnnotationList) \
+ X(UiRequired)
+
+#define QQmlJSASTQQmlJSClassListToVisit \
+ X(TypeExpression) \
+ X(ThisExpression) \
+ X(IdentifierExpression) \
+ X(NullExpression) \
+ X(TrueLiteral) \
+ X(FalseLiteral) \
+ X(SuperLiteral) \
+ X(StringLiteral) \
+ X(TemplateLiteral) \
+ X(NumericLiteral) \
+ X(RegExpLiteral) \
+ X(ArrayPattern) \
+ X(ObjectPattern) \
+ X(PatternElementList) \
+ X(PatternPropertyList) \
+ X(PatternElement) \
+ X(PatternProperty) \
+ X(Elision) \
+ X(NestedExpression) \
+ X(IdentifierPropertyName) \
+ X(StringLiteralPropertyName) \
+ X(NumericLiteralPropertyName) \
+ X(ComputedPropertyName) \
+ X(ArrayMemberExpression) \
+ X(FieldMemberExpression) \
+ X(TaggedTemplate) \
+ X(NewMemberExpression) \
+ X(NewExpression) \
+ X(CallExpression) \
+ X(ArgumentList) \
+ X(PostIncrementExpression) \
+ X(PostDecrementExpression) \
+ X(DeleteExpression) \
+ X(VoidExpression) \
+ X(TypeOfExpression) \
+ X(PreIncrementExpression) \
+ X(PreDecrementExpression) \
+ X(UnaryPlusExpression) \
+ X(UnaryMinusExpression) \
+ X(TildeExpression) \
+ X(NotExpression) \
+ X(BinaryExpression) \
+ X(ConditionalExpression) \
+ X(Expression) \
+ X(Block) \
+ X(StatementList) \
+ X(VariableStatement) \
+ X(VariableDeclarationList) \
+ X(EmptyStatement) \
+ X(ExpressionStatement) \
+ X(IfStatement) \
+ X(DoWhileStatement) \
+ X(WhileStatement) \
+ X(ForStatement) \
+ X(ForEachStatement) \
+ X(ContinueStatement) \
+ X(BreakStatement) \
+ X(ReturnStatement) \
+ X(YieldExpression) \
+ X(WithStatement) \
+ X(SwitchStatement) \
+ X(CaseBlock) \
+ X(CaseClauses) \
+ X(CaseClause) \
+ X(DefaultClause) \
+ X(LabelledStatement) \
+ X(ThrowStatement) \
+ X(TryStatement) \
+ X(Catch) \
+ X(Finally) \
+ X(FunctionDeclaration) \
+ X(FunctionExpression) \
+ X(FormalParameterList) \
+ X(ClassExpression) \
+ X(ClassDeclaration) \
+ X(ClassElementList) \
+ X(Program) \
+ X(NameSpaceImport) \
+ X(ImportSpecifier) \
+ X(ImportsList) \
+ X(NamedImports) \
+ X(FromClause) \
+ X(ImportClause) \
+ X(ImportDeclaration) \
+ X(ExportSpecifier) \
+ X(ExportsList) \
+ X(ExportClause) \
+ X(ExportDeclaration) \
+ X(ESModule) \
+ X(DebuggerStatement) \
+ X(Type) \
+ X(TypeAnnotation)
+
+#define QQmlJSASTClassListToVisit QQmlJSASTUiClassListToVisit QQmlJSASTQQmlJSClassListToVisit
+
namespace QQmlJS { namespace AST {
class QML_PARSER_EXPORT BaseVisitor
@@ -93,332 +180,11 @@ public:
virtual bool preVisit(Node *) = 0;
virtual void postVisit(Node *) = 0;
- // Ui
- virtual bool visit(UiProgram *) = 0;
- virtual bool visit(UiHeaderItemList *) = 0;
- virtual bool visit(UiPragma *) = 0;
- virtual bool visit(UiImport *) = 0;
- virtual bool visit(UiPublicMember *) = 0;
- virtual bool visit(UiSourceElement *) = 0;
- virtual bool visit(UiObjectDefinition *) = 0;
- virtual bool visit(UiObjectInitializer *) = 0;
- virtual bool visit(UiObjectBinding *) = 0;
- virtual bool visit(UiScriptBinding *) = 0;
- virtual bool visit(UiArrayBinding *) = 0;
- virtual bool visit(UiParameterList *) = 0;
- virtual bool visit(UiObjectMemberList *) = 0;
- virtual bool visit(UiArrayMemberList *) = 0;
- virtual bool visit(UiQualifiedId *) = 0;
- virtual bool visit(UiEnumDeclaration *) = 0;
- virtual bool visit(UiEnumMemberList *) = 0;
- virtual bool visit(UiVersionSpecifier *) = 0;
- virtual bool visit(UiInlineComponent *) = 0;
- virtual bool visit(UiAnnotation *) = 0;
- virtual bool visit(UiAnnotationList *) = 0;
- virtual bool visit(UiRequired *) = 0;
-
- virtual void endVisit(UiProgram *) = 0;
- virtual void endVisit(UiImport *) = 0;
- virtual void endVisit(UiHeaderItemList *) = 0;
- virtual void endVisit(UiPragma *) = 0;
- virtual void endVisit(UiPublicMember *) = 0;
- virtual void endVisit(UiSourceElement *) = 0;
- virtual void endVisit(UiObjectDefinition *) = 0;
- virtual void endVisit(UiObjectInitializer *) = 0;
- virtual void endVisit(UiObjectBinding *) = 0;
- virtual void endVisit(UiScriptBinding *) = 0;
- virtual void endVisit(UiArrayBinding *) = 0;
- virtual void endVisit(UiParameterList *) = 0;
- virtual void endVisit(UiObjectMemberList *) = 0;
- virtual void endVisit(UiArrayMemberList *) = 0;
- virtual void endVisit(UiQualifiedId *) = 0;
- virtual void endVisit(UiEnumDeclaration *) = 0;
- virtual void endVisit(UiEnumMemberList *) = 0;
- virtual void endVisit(UiVersionSpecifier *) = 0;
- virtual void endVisit(UiInlineComponent *) = 0;
- virtual void endVisit(UiAnnotation *) = 0;
- virtual void endVisit(UiAnnotationList *) = 0;
- virtual void endVisit(UiRequired *) = 0;
-
- // QQmlJS
- virtual bool visit(TypeExpression *) = 0;
- virtual void endVisit(TypeExpression *) = 0;
-
- virtual bool visit(ThisExpression *) = 0;
- virtual void endVisit(ThisExpression *) = 0;
-
- virtual bool visit(IdentifierExpression *) = 0;
- virtual void endVisit(IdentifierExpression *) = 0;
-
- virtual bool visit(NullExpression *) = 0;
- virtual void endVisit(NullExpression *) = 0;
-
- virtual bool visit(TrueLiteral *) = 0;
- virtual void endVisit(TrueLiteral *) = 0;
-
- virtual bool visit(FalseLiteral *) = 0;
- virtual void endVisit(FalseLiteral *) = 0;
-
- virtual bool visit(SuperLiteral *) = 0;
- virtual void endVisit(SuperLiteral *) = 0;
-
- virtual bool visit(StringLiteral *) = 0;
- virtual void endVisit(StringLiteral *) = 0;
-
- virtual bool visit(TemplateLiteral *) = 0;
- virtual void endVisit(TemplateLiteral *) = 0;
-
- virtual bool visit(NumericLiteral *) = 0;
- virtual void endVisit(NumericLiteral *) = 0;
-
- virtual bool visit(RegExpLiteral *) = 0;
- virtual void endVisit(RegExpLiteral *) = 0;
-
- virtual bool visit(ArrayPattern *) = 0;
- virtual void endVisit(ArrayPattern *) = 0;
-
- virtual bool visit(ObjectPattern *) = 0;
- virtual void endVisit(ObjectPattern *) = 0;
-
- virtual bool visit(PatternElementList *) = 0;
- virtual void endVisit(PatternElementList *) = 0;
-
- virtual bool visit(PatternPropertyList *) = 0;
- virtual void endVisit(PatternPropertyList *) = 0;
-
- virtual bool visit(PatternElement *) = 0;
- virtual void endVisit(PatternElement *) = 0;
-
- virtual bool visit(PatternProperty *) = 0;
- virtual void endVisit(PatternProperty *) = 0;
-
- virtual bool visit(Elision *) = 0;
- virtual void endVisit(Elision *) = 0;
-
- virtual bool visit(NestedExpression *) = 0;
- virtual void endVisit(NestedExpression *) = 0;
-
- virtual bool visit(IdentifierPropertyName *) = 0;
- virtual void endVisit(IdentifierPropertyName *) = 0;
-
- virtual bool visit(StringLiteralPropertyName *) = 0;
- virtual void endVisit(StringLiteralPropertyName *) = 0;
-
- virtual bool visit(NumericLiteralPropertyName *) = 0;
- virtual void endVisit(NumericLiteralPropertyName *) = 0;
-
- virtual bool visit(ComputedPropertyName *) = 0;
- virtual void endVisit(ComputedPropertyName *) = 0;
-
- virtual bool visit(ArrayMemberExpression *) = 0;
- virtual void endVisit(ArrayMemberExpression *) = 0;
-
- virtual bool visit(FieldMemberExpression *) = 0;
- virtual void endVisit(FieldMemberExpression *) = 0;
-
- virtual bool visit(TaggedTemplate *) = 0;
- virtual void endVisit(TaggedTemplate *) = 0;
-
- virtual bool visit(NewMemberExpression *) = 0;
- virtual void endVisit(NewMemberExpression *) = 0;
-
- virtual bool visit(NewExpression *) = 0;
- virtual void endVisit(NewExpression *) = 0;
-
- virtual bool visit(CallExpression *) = 0;
- virtual void endVisit(CallExpression *) = 0;
-
- virtual bool visit(ArgumentList *) = 0;
- virtual void endVisit(ArgumentList *) = 0;
-
- virtual bool visit(PostIncrementExpression *) = 0;
- virtual void endVisit(PostIncrementExpression *) = 0;
-
- virtual bool visit(PostDecrementExpression *) = 0;
- virtual void endVisit(PostDecrementExpression *) = 0;
-
- virtual bool visit(DeleteExpression *) = 0;
- virtual void endVisit(DeleteExpression *) = 0;
-
- virtual bool visit(VoidExpression *) = 0;
- virtual void endVisit(VoidExpression *) = 0;
-
- virtual bool visit(TypeOfExpression *) = 0;
- virtual void endVisit(TypeOfExpression *) = 0;
-
- virtual bool visit(PreIncrementExpression *) = 0;
- virtual void endVisit(PreIncrementExpression *) = 0;
-
- virtual bool visit(PreDecrementExpression *) = 0;
- virtual void endVisit(PreDecrementExpression *) = 0;
-
- virtual bool visit(UnaryPlusExpression *) = 0;
- virtual void endVisit(UnaryPlusExpression *) = 0;
-
- virtual bool visit(UnaryMinusExpression *) = 0;
- virtual void endVisit(UnaryMinusExpression *) = 0;
-
- virtual bool visit(TildeExpression *) = 0;
- virtual void endVisit(TildeExpression *) = 0;
-
- virtual bool visit(NotExpression *) = 0;
- virtual void endVisit(NotExpression *) = 0;
-
- virtual bool visit(BinaryExpression *) = 0;
- virtual void endVisit(BinaryExpression *) = 0;
-
- virtual bool visit(ConditionalExpression *) = 0;
- virtual void endVisit(ConditionalExpression *) = 0;
-
- virtual bool visit(Expression *) = 0;
- virtual void endVisit(Expression *) = 0;
-
- virtual bool visit(Block *) = 0;
- virtual void endVisit(Block *) = 0;
-
- virtual bool visit(StatementList *) = 0;
- virtual void endVisit(StatementList *) = 0;
-
- virtual bool visit(VariableStatement *) = 0;
- virtual void endVisit(VariableStatement *) = 0;
-
- virtual bool visit(VariableDeclarationList *) = 0;
- virtual void endVisit(VariableDeclarationList *) = 0;
-
- virtual bool visit(EmptyStatement *) = 0;
- virtual void endVisit(EmptyStatement *) = 0;
-
- virtual bool visit(ExpressionStatement *) = 0;
- virtual void endVisit(ExpressionStatement *) = 0;
-
- virtual bool visit(IfStatement *) = 0;
- virtual void endVisit(IfStatement *) = 0;
-
- virtual bool visit(DoWhileStatement *) = 0;
- virtual void endVisit(DoWhileStatement *) = 0;
-
- virtual bool visit(WhileStatement *) = 0;
- virtual void endVisit(WhileStatement *) = 0;
-
- virtual bool visit(ForStatement *) = 0;
- virtual void endVisit(ForStatement *) = 0;
-
- virtual bool visit(ForEachStatement *) = 0;
- virtual void endVisit(ForEachStatement *) = 0;
-
- virtual bool visit(ContinueStatement *) = 0;
- virtual void endVisit(ContinueStatement *) = 0;
-
- virtual bool visit(BreakStatement *) = 0;
- virtual void endVisit(BreakStatement *) = 0;
-
- virtual bool visit(ReturnStatement *) = 0;
- virtual void endVisit(ReturnStatement *) = 0;
-
- virtual bool visit(YieldExpression *) = 0;
- virtual void endVisit(YieldExpression *) = 0;
-
- virtual bool visit(WithStatement *) = 0;
- virtual void endVisit(WithStatement *) = 0;
-
- virtual bool visit(SwitchStatement *) = 0;
- virtual void endVisit(SwitchStatement *) = 0;
-
- virtual bool visit(CaseBlock *) = 0;
- virtual void endVisit(CaseBlock *) = 0;
-
- virtual bool visit(CaseClauses *) = 0;
- virtual void endVisit(CaseClauses *) = 0;
-
- virtual bool visit(CaseClause *) = 0;
- virtual void endVisit(CaseClause *) = 0;
-
- virtual bool visit(DefaultClause *) = 0;
- virtual void endVisit(DefaultClause *) = 0;
-
- virtual bool visit(LabelledStatement *) = 0;
- virtual void endVisit(LabelledStatement *) = 0;
-
- virtual bool visit(ThrowStatement *) = 0;
- virtual void endVisit(ThrowStatement *) = 0;
-
- virtual bool visit(TryStatement *) = 0;
- virtual void endVisit(TryStatement *) = 0;
-
- virtual bool visit(Catch *) = 0;
- virtual void endVisit(Catch *) = 0;
-
- virtual bool visit(Finally *) = 0;
- virtual void endVisit(Finally *) = 0;
-
- virtual bool visit(FunctionDeclaration *) = 0;
- virtual void endVisit(FunctionDeclaration *) = 0;
-
- virtual bool visit(FunctionExpression *) = 0;
- virtual void endVisit(FunctionExpression *) = 0;
-
- virtual bool visit(FormalParameterList *) = 0;
- virtual void endVisit(FormalParameterList *) = 0;
-
- virtual bool visit(ClassExpression *) = 0;
- virtual void endVisit(ClassExpression *) = 0;
-
- virtual bool visit(ClassDeclaration *) = 0;
- virtual void endVisit(ClassDeclaration *) = 0;
-
- virtual bool visit(ClassElementList *) = 0;
- virtual void endVisit(ClassElementList *) = 0;
-
- virtual bool visit(Program *) = 0;
- virtual void endVisit(Program *) = 0;
-
- virtual bool visit(NameSpaceImport *) = 0;
- virtual void endVisit(NameSpaceImport *) = 0;
-
- virtual bool visit(ImportSpecifier *) = 0;
- virtual void endVisit(ImportSpecifier *) = 0;
-
- virtual bool visit(ImportsList *) = 0;
- virtual void endVisit(ImportsList *) = 0;
-
- virtual bool visit(NamedImports *) = 0;
- virtual void endVisit(NamedImports *) = 0;
-
- virtual bool visit(FromClause *) = 0;
- virtual void endVisit(FromClause *) = 0;
-
- virtual bool visit(ImportClause *) = 0;
- virtual void endVisit(ImportClause *) = 0;
-
- virtual bool visit(ImportDeclaration *) = 0;
- virtual void endVisit(ImportDeclaration *) = 0;
-
- virtual bool visit(ExportSpecifier *) = 0;
- virtual void endVisit(ExportSpecifier *) = 0;
-
- virtual bool visit(ExportsList *) = 0;
- virtual void endVisit(ExportsList *) = 0;
-
- virtual bool visit(ExportClause *) = 0;
- virtual void endVisit(ExportClause *) = 0;
-
- virtual bool visit(ExportDeclaration *) = 0;
- virtual void endVisit(ExportDeclaration *) = 0;
-
- virtual bool visit(ESModule *) = 0;
- virtual void endVisit(ESModule *) = 0;
-
- virtual bool visit(DebuggerStatement *) = 0;
- virtual void endVisit(DebuggerStatement *) = 0;
-
- virtual bool visit(Type *) = 0;
- virtual void endVisit(Type *) = 0;
-
- virtual bool visit(TypeArgumentList *) = 0;
- virtual void endVisit(TypeArgumentList *) = 0;
-
- virtual bool visit(TypeAnnotation *) = 0;
- virtual void endVisit(TypeAnnotation *) = 0;
+#define X(name) \
+ virtual bool visit(name *) = 0; \
+ virtual void endVisit(name *) = 0;
+ QQmlJSASTClassListToVisit
+#undef X
virtual void throwRecursionDepthError() = 0;
@@ -437,334 +203,37 @@ public:
bool preVisit(Node *) override { return true; }
void postVisit(Node *) override {}
- // Ui
- bool visit(UiProgram *) override { return true; }
- bool visit(UiHeaderItemList *) override { return true; }
- bool visit(UiPragma *) override { return true; }
- bool visit(UiImport *) override { return true; }
- bool visit(UiPublicMember *) override { return true; }
- bool visit(UiSourceElement *) override { return true; }
- bool visit(UiObjectDefinition *) override { return true; }
- bool visit(UiObjectInitializer *) override { return true; }
- bool visit(UiObjectBinding *) override { return true; }
- bool visit(UiScriptBinding *) override { return true; }
- bool visit(UiArrayBinding *) override { return true; }
- bool visit(UiParameterList *) override { return true; }
- bool visit(UiObjectMemberList *) override { return true; }
- bool visit(UiArrayMemberList *) override { return true; }
- bool visit(UiQualifiedId *) override { return true; }
- bool visit(UiEnumDeclaration *) override { return true; }
- bool visit(UiEnumMemberList *) override { return true; }
- bool visit(UiVersionSpecifier *) override { return true; }
- bool visit(UiInlineComponent *) override { return true; }
- bool visit(UiAnnotation *) override { return true; }
- bool visit(UiAnnotationList *) override { return true; }
- bool visit(UiRequired *) override { return true; }
-
- void endVisit(UiProgram *) override {}
- void endVisit(UiImport *) override {}
- void endVisit(UiHeaderItemList *) override {}
- void endVisit(UiPragma *) override {}
- void endVisit(UiPublicMember *) override {}
- void endVisit(UiSourceElement *) override {}
- void endVisit(UiObjectDefinition *) override {}
- void endVisit(UiObjectInitializer *) override {}
- void endVisit(UiObjectBinding *) override {}
- void endVisit(UiScriptBinding *) override {}
- void endVisit(UiArrayBinding *) override {}
- void endVisit(UiParameterList *) override {}
- void endVisit(UiObjectMemberList *) override {}
- void endVisit(UiArrayMemberList *) override {}
- void endVisit(UiQualifiedId *) override {}
- void endVisit(UiEnumDeclaration *) override {}
- void endVisit(UiEnumMemberList *) override {}
- void endVisit(UiVersionSpecifier *) override {}
- void endVisit(UiInlineComponent *) override {}
- void endVisit(UiAnnotation *) override {}
- void endVisit(UiAnnotationList *) override {}
- void endVisit(UiRequired *) override {}
-
- // QQmlJS
- bool visit(TypeExpression *) override { return true; }
- void endVisit(TypeExpression *) override {}
-
- bool visit(ThisExpression *) override { return true; }
- void endVisit(ThisExpression *) override {}
-
- bool visit(IdentifierExpression *) override { return true; }
- void endVisit(IdentifierExpression *) override {}
-
- bool visit(NullExpression *) override { return true; }
- void endVisit(NullExpression *) override {}
-
- bool visit(TrueLiteral *) override { return true; }
- void endVisit(TrueLiteral *) override {}
-
- bool visit(FalseLiteral *) override { return true; }
- void endVisit(FalseLiteral *) override {}
-
- bool visit(SuperLiteral *) override { return true; }
- void endVisit(SuperLiteral *) override {}
-
- bool visit(StringLiteral *) override { return true; }
- void endVisit(StringLiteral *) override {}
-
- bool visit(TemplateLiteral *) override { return true; }
- void endVisit(TemplateLiteral *) override {}
-
- bool visit(NumericLiteral *) override { return true; }
- void endVisit(NumericLiteral *) override {}
-
- bool visit(RegExpLiteral *) override { return true; }
- void endVisit(RegExpLiteral *) override {}
-
- bool visit(ArrayPattern *) override { return true; }
- void endVisit(ArrayPattern *) override {}
-
- bool visit(ObjectPattern *) override { return true; }
- void endVisit(ObjectPattern *) override {}
-
- bool visit(PatternElementList *) override { return true; }
- void endVisit(PatternElementList *) override {}
-
- bool visit(PatternPropertyList *) override { return true; }
- void endVisit(PatternPropertyList *) override {}
-
- bool visit(PatternElement *) override { return true; }
- void endVisit(PatternElement *) override {}
-
- bool visit(PatternProperty *) override { return true; }
- void endVisit(PatternProperty *) override {}
-
- bool visit(Elision *) override { return true; }
- void endVisit(Elision *) override {}
-
- bool visit(NestedExpression *) override { return true; }
- void endVisit(NestedExpression *) override {}
-
- bool visit(IdentifierPropertyName *) override { return true; }
- void endVisit(IdentifierPropertyName *) override {}
-
- bool visit(StringLiteralPropertyName *) override { return true; }
- void endVisit(StringLiteralPropertyName *) override {}
-
- bool visit(NumericLiteralPropertyName *) override { return true; }
- void endVisit(NumericLiteralPropertyName *) override {}
-
- bool visit(ComputedPropertyName *) override { return true; }
- void endVisit(ComputedPropertyName *) override {}
-
- bool visit(ArrayMemberExpression *) override { return true; }
- void endVisit(ArrayMemberExpression *) override {}
-
- bool visit(FieldMemberExpression *) override { return true; }
- void endVisit(FieldMemberExpression *) override {}
-
- bool visit(TaggedTemplate *) override { return true; }
- void endVisit(TaggedTemplate *) override {}
-
- bool visit(NewMemberExpression *) override { return true; }
- void endVisit(NewMemberExpression *) override {}
-
- bool visit(NewExpression *) override { return true; }
- void endVisit(NewExpression *) override {}
-
- bool visit(CallExpression *) override { return true; }
- void endVisit(CallExpression *) override {}
-
- bool visit(ArgumentList *) override { return true; }
- void endVisit(ArgumentList *) override {}
-
- bool visit(PostIncrementExpression *) override { return true; }
- void endVisit(PostIncrementExpression *) override {}
-
- bool visit(PostDecrementExpression *) override { return true; }
- void endVisit(PostDecrementExpression *) override {}
-
- bool visit(DeleteExpression *) override { return true; }
- void endVisit(DeleteExpression *) override {}
-
- bool visit(VoidExpression *) override { return true; }
- void endVisit(VoidExpression *) override {}
-
- bool visit(TypeOfExpression *) override { return true; }
- void endVisit(TypeOfExpression *) override {}
-
- bool visit(PreIncrementExpression *) override { return true; }
- void endVisit(PreIncrementExpression *) override {}
-
- bool visit(PreDecrementExpression *) override { return true; }
- void endVisit(PreDecrementExpression *) override {}
-
- bool visit(UnaryPlusExpression *) override { return true; }
- void endVisit(UnaryPlusExpression *) override {}
-
- bool visit(UnaryMinusExpression *) override { return true; }
- void endVisit(UnaryMinusExpression *) override {}
-
- bool visit(TildeExpression *) override { return true; }
- void endVisit(TildeExpression *) override {}
-
- bool visit(NotExpression *) override { return true; }
- void endVisit(NotExpression *) override {}
-
- bool visit(BinaryExpression *) override { return true; }
- void endVisit(BinaryExpression *) override {}
-
- bool visit(ConditionalExpression *) override { return true; }
- void endVisit(ConditionalExpression *) override {}
-
- bool visit(Expression *) override { return true; }
- void endVisit(Expression *) override {}
-
- bool visit(Block *) override { return true; }
- void endVisit(Block *) override {}
-
- bool visit(StatementList *) override { return true; }
- void endVisit(StatementList *) override {}
-
- bool visit(VariableStatement *) override { return true; }
- void endVisit(VariableStatement *) override {}
-
- bool visit(VariableDeclarationList *) override { return true; }
- void endVisit(VariableDeclarationList *) override {}
-
- bool visit(EmptyStatement *) override { return true; }
- void endVisit(EmptyStatement *) override {}
-
- bool visit(ExpressionStatement *) override { return true; }
- void endVisit(ExpressionStatement *) override {}
-
- bool visit(IfStatement *) override { return true; }
- void endVisit(IfStatement *) override {}
-
- bool visit(DoWhileStatement *) override { return true; }
- void endVisit(DoWhileStatement *) override {}
-
- bool visit(WhileStatement *) override { return true; }
- void endVisit(WhileStatement *) override {}
-
- bool visit(ForStatement *) override { return true; }
- void endVisit(ForStatement *) override {}
-
- bool visit(ForEachStatement *) override { return true; }
- void endVisit(ForEachStatement *) override {}
-
- bool visit(ContinueStatement *) override { return true; }
- void endVisit(ContinueStatement *) override {}
-
- bool visit(BreakStatement *) override { return true; }
- void endVisit(BreakStatement *) override {}
-
- bool visit(ReturnStatement *) override { return true; }
- void endVisit(ReturnStatement *) override {}
-
- bool visit(YieldExpression *) override { return true; }
- void endVisit(YieldExpression *) override {}
-
- bool visit(WithStatement *) override { return true; }
- void endVisit(WithStatement *) override {}
-
- bool visit(SwitchStatement *) override { return true; }
- void endVisit(SwitchStatement *) override {}
-
- bool visit(CaseBlock *) override { return true; }
- void endVisit(CaseBlock *) override {}
-
- bool visit(CaseClauses *) override { return true; }
- void endVisit(CaseClauses *) override {}
-
- bool visit(CaseClause *) override { return true; }
- void endVisit(CaseClause *) override {}
-
- bool visit(DefaultClause *) override { return true; }
- void endVisit(DefaultClause *) override {}
-
- bool visit(LabelledStatement *) override { return true; }
- void endVisit(LabelledStatement *) override {}
-
- bool visit(ThrowStatement *) override { return true; }
- void endVisit(ThrowStatement *) override {}
-
- bool visit(TryStatement *) override { return true; }
- void endVisit(TryStatement *) override {}
-
- bool visit(Catch *) override { return true; }
- void endVisit(Catch *) override {}
-
- bool visit(Finally *) override { return true; }
- void endVisit(Finally *) override {}
-
- bool visit(FunctionDeclaration *) override { return true; }
- void endVisit(FunctionDeclaration *) override {}
-
- bool visit(FunctionExpression *) override { return true; }
- void endVisit(FunctionExpression *) override {}
-
- bool visit(FormalParameterList *) override { return true; }
- void endVisit(FormalParameterList *) override {}
-
- bool visit(ClassExpression *) override { return true; }
- void endVisit(ClassExpression *) override {}
-
- bool visit(ClassDeclaration *) override { return true; }
- void endVisit(ClassDeclaration *) override {}
-
- bool visit(ClassElementList *) override { return true; }
- void endVisit(ClassElementList *) override {}
-
- bool visit(Program *) override { return true; }
- void endVisit(Program *) override {}
-
- bool visit(NameSpaceImport *) override { return true; }
- void endVisit(NameSpaceImport *) override {}
-
- bool visit(ImportSpecifier *) override { return true; }
- void endVisit(ImportSpecifier *) override {}
-
- bool visit(ImportsList *) override { return true; }
- void endVisit(ImportsList *) override {}
-
- bool visit(NamedImports *) override { return true; }
- void endVisit(NamedImports *) override {}
-
- bool visit(FromClause *) override { return true; }
- void endVisit(FromClause *) override {}
-
- bool visit(ImportClause *) override { return true; }
- void endVisit(ImportClause *) override {}
-
- bool visit(ImportDeclaration *) override { return true; }
- void endVisit(ImportDeclaration *) override {}
-
- bool visit(ExportSpecifier *) override { return true; }
- void endVisit(ExportSpecifier *) override {}
-
- bool visit(ExportsList *) override { return true; }
- void endVisit(ExportsList *) override {}
-
- bool visit(ExportClause *) override { return true; }
- void endVisit(ExportClause *) override {}
-
- bool visit(ExportDeclaration *) override { return true; }
- void endVisit(ExportDeclaration *) override {}
-
- bool visit(ESModule *) override { return true; }
- void endVisit(ESModule *) override {}
-
- bool visit(DebuggerStatement *) override { return true; }
- void endVisit(DebuggerStatement *) override {}
-
- bool visit(Type *) override { return true; }
- void endVisit(Type *) override {}
-
- bool visit(TypeArgumentList *) override { return true; }
- void endVisit(TypeArgumentList *) override {}
-
- bool visit(TypeAnnotation *) override { return true; }
- void endVisit(TypeAnnotation *) override {}
+#define X(name) \
+ bool visit(name *) override { return true; } \
+ void endVisit(name *) override { }
+ QQmlJSASTClassListToVisit
+#undef X
};
+class QML_PARSER_EXPORT JSVisitor : public BaseVisitor
+{
+public:
+ JSVisitor() = default;
+
+ bool preVisit(Node *) override { return true; }
+ void postVisit(Node *) override { }
+
+#define X(name) \
+ bool visit(name *) override { return true; } \
+ void endVisit(name *) override { }
+ QQmlJSASTQQmlJSClassListToVisit
+#undef X
+
+#define X(name) \
+ bool visit(name *) override \
+ { \
+ Q_ASSERT(false); \
+ return false; \
+ } \
+ void endVisit(name *) override { }
+ QQmlJSASTUiClassListToVisit
+#undef X
+}; // namespace AST
} } // namespace AST
QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsengine_p.cpp b/src/qml/parser/qqmljsengine_p.cpp
deleted file mode 100644
index 53ad8820dd..0000000000
--- a/src/qml/parser/qqmljsengine_p.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmljsengine_p.h"
-#include "qqmljsglobal_p.h"
-
-#include <QtCore/private/qnumeric_p.h>
-#include <QtCore/qhash.h>
-#include <QtCore/qdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QQmlJS {
-
-static inline int toDigit(char c)
-{
- if ((c >= '0') && (c <= '9'))
- return c - '0';
- else if ((c >= 'a') && (c <= 'z'))
- return 10 + c - 'a';
- else if ((c >= 'A') && (c <= 'Z'))
- return 10 + c - 'A';
- return -1;
-}
-
-double integerFromString(const char *buf, int size, int radix)
-{
- if (size == 0)
- return qt_qnan();
-
- double sign = 1.0;
- int i = 0;
- if (buf[0] == '+') {
- ++i;
- } else if (buf[0] == '-') {
- sign = -1.0;
- ++i;
- }
-
- if (((size-i) >= 2) && (buf[i] == '0')) {
- if (((buf[i+1] == 'x') || (buf[i+1] == 'X'))
- && (radix < 34)) {
- if ((radix != 0) && (radix != 16))
- return 0;
- radix = 16;
- i += 2;
- } else {
- if (radix == 0) {
- radix = 8;
- ++i;
- }
- }
- } else if (radix == 0) {
- radix = 10;
- }
-
- int j = i;
- for ( ; i < size; ++i) {
- int d = toDigit(buf[i]);
- if ((d == -1) || (d >= radix))
- break;
- }
- double result;
- if (j == i) {
- if (!qstrcmp(buf, "Infinity"))
- result = qInf();
- else
- result = qt_qnan();
- } else {
- result = 0;
- double multiplier = 1;
- for (--i ; i >= j; --i, multiplier *= radix)
- result += toDigit(buf[i]) * multiplier;
- }
- result *= sign;
- return result;
-}
-
-Engine::Engine()
- : _lexer(nullptr), _directives(nullptr)
-{ }
-
-Engine::~Engine()
-{ }
-
-void Engine::setCode(const QString &code)
-{ _code = code; }
-
-void Engine::addComment(int pos, int len, int line, int col)
-{ if (len > 0) _comments.append(QQmlJS::SourceLocation(pos, len, line, col)); }
-
-QList<QQmlJS::SourceLocation> Engine::comments() const
-{ return _comments; }
-
-Lexer *Engine::lexer() const
-{ return _lexer; }
-
-void Engine::setLexer(Lexer *lexer)
-{ _lexer = lexer; }
-
-Directives *Engine::directives() const
-{ return _directives; }
-
-void Engine::setDirectives(Directives *directives)
-{ _directives = directives; }
-
-MemoryPool *Engine::pool()
-{ return &_pool; }
-
-QStringView Engine::newStringRef(const QString &text)
-{
- _extraCode.append(text);
- return QStringView{_extraCode.last()};
-}
-
-QStringView Engine::newStringRef(const QChar *chars, int size)
-{ return newStringRef(QString(chars, size)); }
-
-} // end of namespace QQmlJS
-
-QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsengine_p.h b/src/qml/parser/qqmljsengine_p.h
index b57515982b..37f78a30e1 100644
--- a/src/qml/parser/qqmljsengine_p.h
+++ b/src/qml/parser/qqmljsengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSENGINE_P_H
#define QQMLJSENGINE_P_H
@@ -92,40 +56,52 @@ public:
}
};
-class QML_PARSER_EXPORT Engine
+class Engine
{
- Lexer *_lexer;
- Directives *_directives;
+ Lexer *_lexer = nullptr;
+ Directives *_directives = nullptr;
MemoryPool _pool;
QList<SourceLocation> _comments;
QStringList _extraCode;
QString _code;
public:
- Engine();
- ~Engine();
-
- void setCode(const QString &code);
+ void setCode(const QString &code) { _code = code; }
const QString &code() const { return _code; }
- void addComment(int pos, int len, int line, int col);
- QList<SourceLocation> comments() const;
+ void addComment(int pos, int len, int line, int col)
+ {
+ Q_ASSERT(len >= 0);
+ _comments.append(QQmlJS::SourceLocation(pos, len, line, col));
+ }
- Lexer *lexer() const;
- void setLexer(Lexer *lexer);
+ QList<SourceLocation> comments() const { return _comments; }
- Directives *directives() const;
- void setDirectives(Directives *directives);
+ Lexer *lexer() const { return _lexer; }
+ void setLexer(Lexer *lexer) { _lexer = lexer; }
- MemoryPool *pool();
+ Directives *directives() const { return _directives; }
+ void setDirectives(Directives *directives) { _directives = directives; }
- inline QStringView midRef(int position, int size) { return QStringView{_code}.mid(position, size); }
+ MemoryPool *pool() { return &_pool; }
+ const MemoryPool *pool() const { return &_pool; }
- QStringView newStringRef(const QString &s);
- QStringView newStringRef(const QChar *chars, int size);
-};
+ QStringView midRef(int position, int size)
+ {
+ return QStringView{_code}.mid(position, size);
+ }
-double integerFromString(const char *buf, int size, int radix);
+ QStringView newStringRef(const QString &text)
+ {
+ _extraCode.append(text);
+ return QStringView{_extraCode.last()};
+ }
+
+ QStringView newStringRef(const QChar *chars, int size)
+ {
+ return newStringRef(QString(chars, size));
+ }
+};
} // end of namespace QQmlJS
diff --git a/src/qml/parser/qqmljsglobal_p.h b/src/qml/parser/qqmljsglobal_p.h
index e7937ebc3b..1ca98b2041 100644
--- a/src/qml/parser/qqmljsglobal_p.h
+++ b/src/qml/parser/qqmljsglobal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSGLOBAL_P_H
#define QQMLJSGLOBAL_P_H
@@ -50,13 +14,10 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#ifndef QT_STATIC
-# if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
- // QmlDevTools is a static library
-# define QML_PARSER_EXPORT
-# elif defined(QT_BUILD_QML_LIB)
+# if defined(QT_BUILD_QML_LIB)
# define QML_PARSER_EXPORT Q_DECL_EXPORT
# else
# define QML_PARSER_EXPORT Q_DECL_IMPORT
diff --git a/src/qml/parser/qqmljskeywords_p.h b/src/qml/parser/qqmljskeywords_p.h
index 5f08cc4353..72be5822a7 100644
--- a/src/qml/parser/qqmljskeywords_p.h
+++ b/src/qml/parser/qqmljskeywords_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSKEYWORDS_P_H
#define QQMLJSKEYWORDS_P_H
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index 5f0276da8f..704c7eb00d 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmljslexer_p.h"
#include "qqmljsengine_p.h"
@@ -51,6 +15,9 @@
#include <QtCore/qdebug.h>
#include <QtCore/QScopedValueRollback>
+#include <optional>
+
+QT_BEGIN_NAMESPACE
using namespace QQmlJS;
static inline int regExpFlagFromChar(const QChar &ch)
@@ -80,31 +47,8 @@ static inline QChar convertHex(QChar c1, QChar c2)
return QChar((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
}
-Lexer::Lexer(Engine *engine)
- : _engine(engine)
- , _codePtr(nullptr)
- , _endPtr(nullptr)
- , _tokenStartPtr(nullptr)
- , _char(u'\n')
- , _errorCode(NoError)
- , _currentLineNumber(0)
- , _currentColumnNumber(0)
- , _tokenValue(0)
- , _parenthesesState(IgnoreParentheses)
- , _parenthesesCount(0)
- , _stackToken(-1)
- , _patternFlags(0)
- , _tokenKind(0)
- , _tokenLength(0)
- , _tokenLine(0)
- , _tokenColumn(0)
- , _validTokenText(false)
- , _prohibitAutomaticSemicolon(false)
- , _restrictedKeyword(false)
- , _terminator(false)
- , _followsClosingBrace(false)
- , _delimited(true)
- , _qmlMode(true)
+Lexer::Lexer(Engine *engine, LexMode lexMode)
+ : _engine(engine), _lexMode(lexMode), _endPtr(nullptr), _qmlMode(true)
{
if (engine)
engine->setLexer(this);
@@ -120,13 +64,20 @@ QString Lexer::code() const
return _code;
}
-void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
+void Lexer::setCode(const QString &code, int lineno, bool qmlMode,
+ Lexer::CodeContinuation codeContinuation)
{
+ if (codeContinuation == Lexer::CodeContinuation::Continue)
+ _currentOffset += _code.size();
+ else
+ _currentOffset = 0;
if (_engine)
_engine->setCode(code);
_qmlMode = qmlMode;
_code = code;
+ _skipLinefeed = false;
+
_tokenText.clear();
_tokenText.reserve(1024);
_errorMessage.clear();
@@ -134,33 +85,18 @@ void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
_rawString = QStringView();
_codePtr = code.unicode();
- _endPtr = _codePtr + code.length();
+ _endPtr = _codePtr + code.size();
_tokenStartPtr = _codePtr;
- _char = u'\n';
- _errorCode = NoError;
-
- _currentLineNumber = lineno;
+ if (lineno >= 0)
+ _currentLineNumber = lineno;
_currentColumnNumber = 0;
- _tokenValue = 0;
-
- // parentheses state
- _parenthesesState = IgnoreParentheses;
- _parenthesesCount = 0;
-
- _stackToken = -1;
-
- _patternFlags = 0;
- _tokenLength = 0;
- _tokenLine = lineno;
+ _tokenLine = _currentLineNumber;
_tokenColumn = 0;
+ _tokenLength = 0;
- _validTokenText = false;
- _prohibitAutomaticSemicolon = false;
- _restrictedKeyword = false;
- _terminator = false;
- _followsClosingBrace = false;
- _delimited = true;
+ if (codeContinuation == Lexer::CodeContinuation::Reset)
+ _state = State {};
}
void Lexer::scanChar()
@@ -170,20 +106,28 @@ void Lexer::scanChar()
++_codePtr;
_skipLinefeed = false;
}
- _char = *_codePtr++;
+ _state.currentChar = *_codePtr++;
++_currentColumnNumber;
if (isLineTerminator()) {
- if (_char == u'\r') {
+ if (_state.currentChar == u'\r') {
if (_codePtr < _endPtr && *_codePtr == u'\n')
_skipLinefeed = true;
- _char = u'\n';
+ _state.currentChar = u'\n';
}
++_currentLineNumber;
_currentColumnNumber = 0;
}
}
+QChar Lexer::peekChar()
+{
+ auto peekPtr = _codePtr;
+ if (peekPtr < _endPtr)
+ return *peekPtr;
+ return QChar();
+}
+
namespace {
inline bool isBinop(int tok)
{
@@ -251,107 +195,184 @@ int octalDigit(QChar c)
int Lexer::lex()
{
- const int previousTokenKind = _tokenKind;
+ const int previousTokenKind = _state.tokenKind;
+ int tokenKind;
+ bool firstPass = true;
again:
- _tokenSpell = QStringView();
- _rawString = QStringView();
- _tokenKind = scanToken();
- _tokenLength = _codePtr - _tokenStartPtr - 1;
-
- _delimited = false;
- _restrictedKeyword = false;
- _followsClosingBrace = (previousTokenKind == T_RBRACE);
-
- // update the flags
- switch (_tokenKind) {
- case T_LBRACE:
- if (_bracesCount > 0)
- ++_bracesCount;
- Q_FALLTHROUGH();
- case T_SEMICOLON:
- _importState = ImportState::NoQmlImport;
- Q_FALLTHROUGH();
- case T_QUESTION:
- case T_COLON:
- case T_TILDE:
- _delimited = true;
- break;
- case T_AUTOMATIC_SEMICOLON:
- case T_AS:
- _importState = ImportState::NoQmlImport;
- Q_FALLTHROUGH();
- default:
- if (isBinop(_tokenKind))
- _delimited = true;
- break;
-
- case T_IMPORT:
- if (qmlMode() || (_handlingDirectives && previousTokenKind == T_DOT))
- _importState = ImportState::SawImport;
- if (isBinop(_tokenKind))
- _delimited = true;
- break;
-
- case T_IF:
- case T_FOR:
- case T_WHILE:
- case T_WITH:
- _parenthesesState = CountParentheses;
- _parenthesesCount = 0;
- break;
-
- case T_ELSE:
- case T_DO:
- _parenthesesState = BalancedParentheses;
- break;
-
- case T_CONTINUE:
- case T_BREAK:
- case T_RETURN:
- case T_YIELD:
- case T_THROW:
- _restrictedKeyword = true;
- break;
- case T_RBRACE:
- if (_bracesCount > 0)
- --_bracesCount;
- if (_bracesCount == 0)
- goto again;
- } // switch
+ tokenKind = T_ERROR;
+ _tokenSpell = QStringView();
+ _rawString = QStringView();
+ if (firstPass && _state.stackToken == -1) {
+ firstPass = false;
+ if (_codePtr > _endPtr && _lexMode == LexMode::LineByLine && !_code.isEmpty())
+ return T_EOL;
+
+ if (_state.comments == CommentState::InMultilineComment) {
+ scanChar();
+ _tokenStartPtr = _codePtr - 1;
+ _tokenLine = _currentLineNumber;
+ _tokenColumn = _currentColumnNumber;
+ while (_codePtr <= _endPtr) {
+ if (_state.currentChar == u'*') {
+ scanChar();
+ if (_state.currentChar == u'/') {
+ scanChar();
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2,
+ _codePtr - _tokenStartPtr - 1 - 4,
+ tokenStartLine(), tokenStartColumn() + 2);
+ }
+ tokenKind = T_COMMENT;
+ break;
+ }
+ } else {
+ scanChar();
+ }
+ }
+ if (tokenKind == T_ERROR)
+ tokenKind = T_PARTIAL_COMMENT;
+ } else {
+ // handle multiline continuation
+ std::optional<ScanStringMode> scanMode;
+ switch (previousTokenKind) {
+ case T_PARTIAL_SINGLE_QUOTE_STRING_LITERAL:
+ scanMode = ScanStringMode::SingleQuote;
+ break;
+ case T_PARTIAL_DOUBLE_QUOTE_STRING_LITERAL:
+ scanMode = ScanStringMode::DoubleQuote;
+ break;
+ case T_PARTIAL_TEMPLATE_HEAD:
+ scanMode = ScanStringMode::TemplateHead;
+ break;
+ case T_PARTIAL_TEMPLATE_MIDDLE:
+ scanMode = ScanStringMode::TemplateContinuation;
+ break;
+ default:
+ break;
+ }
+ if (scanMode) {
+ scanChar();
+ _tokenStartPtr = _codePtr - 1;
+ _tokenLine = _currentLineNumber;
+ _tokenColumn = _currentColumnNumber;
+ tokenKind = scanString(*scanMode);
+ }
+ }
+ }
+ if (tokenKind == T_ERROR)
+ tokenKind = scanToken();
+ _tokenLength = _codePtr - _tokenStartPtr - 1;
+ switch (tokenKind) {
+ // end of line and comments should not "overwrite" the old token type...
+ case T_EOL:
+ return tokenKind;
+ case T_COMMENT:
+ _state.comments = CommentState::HadComment;
+ return tokenKind;
+ case T_PARTIAL_COMMENT:
+ _state.comments = CommentState::InMultilineComment;
+ return tokenKind;
+ default:
+ _state.comments = CommentState::NoComment;
+ break;
+ }
+ _state.tokenKind = tokenKind;
+
+ _state.delimited = false;
+ _state.restrictedKeyword = false;
+ _state.followsClosingBrace = (previousTokenKind == T_RBRACE);
+
+ // update the flags
+ switch (_state.tokenKind) {
+ case T_LBRACE:
+ if (_state.bracesCount > 0)
+ ++_state.bracesCount;
+ Q_FALLTHROUGH();
+ case T_SEMICOLON:
+ _state.importState = ImportState::NoQmlImport;
+ Q_FALLTHROUGH();
+ case T_QUESTION:
+ case T_COLON:
+ case T_TILDE:
+ _state.delimited = true;
+ break;
+ case T_AUTOMATIC_SEMICOLON:
+ case T_AS:
+ _state.importState = ImportState::NoQmlImport;
+ Q_FALLTHROUGH();
+ default:
+ if (isBinop(_state.tokenKind))
+ _state.delimited = true;
+ break;
+
+ case T_IMPORT:
+ if (qmlMode() || (_state.handlingDirectives && previousTokenKind == T_DOT))
+ _state.importState = ImportState::SawImport;
+ if (isBinop(_state.tokenKind))
+ _state.delimited = true;
+ break;
+
+ case T_IF:
+ case T_FOR:
+ case T_WHILE:
+ case T_WITH:
+ _state.parenthesesState = CountParentheses;
+ _state.parenthesesCount = 0;
+ break;
+
+ case T_ELSE:
+ case T_DO:
+ _state.parenthesesState = BalancedParentheses;
+ break;
+
+ case T_CONTINUE:
+ case T_BREAK:
+ case T_RETURN:
+ case T_YIELD:
+ case T_THROW:
+ _state.restrictedKeyword = true;
+ break;
+ case T_RBRACE:
+ if (_state.bracesCount > 0)
+ --_state.bracesCount;
+ if (_state.bracesCount == 0)
+ goto again;
+ } // switch
// update the parentheses state
- switch (_parenthesesState) {
- case IgnoreParentheses:
- break;
-
- case CountParentheses:
- if (_tokenKind == T_RPAREN) {
- --_parenthesesCount;
- if (_parenthesesCount == 0)
- _parenthesesState = BalancedParentheses;
- } else if (_tokenKind == T_LPAREN) {
- ++_parenthesesCount;
- }
- break;
-
- case BalancedParentheses:
- if (_tokenKind != T_DO && _tokenKind != T_ELSE)
- _parenthesesState = IgnoreParentheses;
- break;
- } // switch
-
- return _tokenKind;
+ switch (_state.parenthesesState) {
+ case IgnoreParentheses:
+ break;
+
+ case CountParentheses:
+ if (_state.tokenKind == T_RPAREN) {
+ --_state.parenthesesCount;
+ if (_state.parenthesesCount == 0)
+ _state.parenthesesState = BalancedParentheses;
+ } else if (_state.tokenKind == T_LPAREN) {
+ ++_state.parenthesesCount;
+ }
+ break;
+
+ case BalancedParentheses:
+ if (_state.tokenKind != T_DO && _state.tokenKind != T_ELSE)
+ _state.parenthesesState = IgnoreParentheses;
+ break;
+ } // switch
+
+ return _state.tokenKind;
}
uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
{
- Q_ASSERT(_char == u'u');
+ Q_ASSERT(_state.currentChar == u'u');
scanChar(); // skip u
- if (_codePtr + 4 <= _endPtr && isHexDigit(_char)) {
+ constexpr int distanceFromFirstHexToLastHex = 3;
+ if (_codePtr + distanceFromFirstHexToLastHex <= _endPtr && isHexDigit(_state.currentChar)) {
uint codePoint = 0;
for (int i = 0; i < 4; ++i) {
- int digit = hexDigit(_char);
+ int digit = hexDigit(_state.currentChar);
if (digit < 0)
goto error;
codePoint *= 16;
@@ -361,15 +382,15 @@ uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
*ok = true;
return codePoint;
- } else if (_codePtr < _endPtr && _char == u'{') {
+ } else if (_codePtr < _endPtr && _state.currentChar == u'{') {
scanChar(); // skip '{'
uint codePoint = 0;
- if (!isHexDigit(_char))
+ if (!isHexDigit(_state.currentChar))
// need at least one hex digit
goto error;
while (_codePtr <= _endPtr) {
- int digit = hexDigit(_char);
+ int digit = hexDigit(_state.currentChar);
if (digit < 0)
break;
codePoint *= 16;
@@ -379,7 +400,7 @@ uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
scanChar();
}
- if (_char != u'}')
+ if (_state.currentChar != u'}')
goto error;
scanChar(); // skip '}'
@@ -389,8 +410,8 @@ uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
return codePoint;
}
- error:
- _errorCode = IllegalUnicodeEscapeSequence;
+error:
+ _state.errorCode = IllegalUnicodeEscapeSequence;
_errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
*ok = false;
@@ -402,10 +423,10 @@ QChar Lexer::decodeHexEscapeCharacter(bool *ok)
if (isHexDigit(_codePtr[0]) && isHexDigit(_codePtr[1])) {
scanChar();
- const QChar c1 = _char;
+ const QChar c1 = _state.currentChar;
scanChar();
- const QChar c2 = _char;
+ const QChar c2 = _state.currentChar;
scanChar();
if (ok)
@@ -418,6 +439,40 @@ QChar Lexer::decodeHexEscapeCharacter(bool *ok)
return QChar();
}
+namespace QQmlJS {
+QDebug operator<<(QDebug dbg, const Lexer &l)
+{
+ dbg << "{\n"
+ << " engine:" << qsizetype(l._engine) << ",\n"
+ << " lexMode:" << int(l._lexMode) << ",\n"
+ << " code.size:" << qsizetype(l._code.unicode()) << "+" << l._code.size() << ",\n"
+ << " endPtr: codePtr + " << (l._endPtr - l._codePtr) << ",\n"
+ << " qmlMode:" << l._qmlMode << ",\n"
+ << " staticIsKeyword:" << l._staticIsKeyword << ",\n"
+ << " currentLineNumber:" << l._currentLineNumber << ",\n"
+ << " currentColumnNumber:" << l._currentColumnNumber << ",\n"
+ << " currentOffset:" << l._currentOffset << ",\n"
+ << " tokenLength:" << l._tokenLength << ",\n"
+ << " tokenLine:" << l._tokenLine << ",\n"
+ << " tokenColumn:" << l._tokenColumn << ",\n"
+ << " tokenText:" << l._tokenText << ",\n"
+ << " skipLinefeed:" << l._skipLinefeed << ",\n"
+ << " errorMessage:" << l._errorMessage << ",\n"
+ << " tokenSpell:" << l._tokenSpell << ",\n"
+ << " rawString:" << l._rawString << ",\n";
+ if (l._codePtr)
+ dbg << " codePtr: code.unicode()+" << (l._codePtr - l._code.unicode()) << ",\n";
+ else
+ dbg << " codePtr: *null*,\n";
+ if (l._tokenStartPtr)
+ dbg << " tokenStartPtr: codePtr " << (l._tokenStartPtr - l._codePtr) << ",\n";
+ else
+ dbg << " tokenStartPtr: *null*,\n";
+ dbg << " state:" << l._state << "\n}";
+ return dbg;
+}
+}
+
static inline bool isIdentifierStart(uint ch)
{
// fast path for ascii
@@ -473,71 +528,36 @@ static bool isIdentifierPart(uint ch)
int Lexer::scanToken()
{
- if (_stackToken != -1) {
- int tk = _stackToken;
- _stackToken = -1;
+ if (_state.stackToken != -1) {
+ int tk = _state.stackToken;
+ _state.stackToken = -1;
return tk;
}
- if (_bracesCount == 0) {
+ if (_state.bracesCount == 0) {
// we're inside a Template string
return scanString(TemplateContinuation);
}
-
- _terminator = false;
+ if (_state.comments == CommentState::NoComment)
+ _state.terminator = false;
again:
- _validTokenText = false;
-
- // handle comment can be called after a '/' has been read
- // and returns true if it actually encountered a comment
- auto handleComment = [this](){
- if (_char == u'*') {
- scanChar();
- while (_codePtr <= _endPtr) {
- if (_char == u'*') {
- scanChar();
- if (_char == u'/') {
- scanChar();
-
- if (_engine) {
- _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 4,
- tokenStartLine(), tokenStartColumn() + 2);
- }
-
- return true;
- }
- } else {
- scanChar();
- }
- }
- } else if (_char == u'/') {
- while (_codePtr <= _endPtr && !isLineTerminator()) {
- scanChar();
- }
- if (_engine) {
- _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2,
- tokenStartLine(), tokenStartColumn() + 2);
- }
- return true;
- }
- return false;
- };
+ _state.validTokenText = false;
-
- while (_char.isSpace()) {
+ while (_state.currentChar.isSpace()) {
if (isLineTerminator()) {
- if (_restrictedKeyword) {
+ bool isAtEnd = (_codePtr + (_skipLinefeed ? 1 : 0)) == _endPtr;
+ if (_state.restrictedKeyword) {
// automatic semicolon insertion
_tokenLine = _currentLineNumber;
_tokenColumn = _currentColumnNumber;
_tokenStartPtr = _codePtr - 1;
return T_SEMICOLON;
- } else {
- _terminator = true;
+ } else if (_lexMode == LexMode::WholeCode || !isAtEnd) {
+ _state.terminator = true;
syncProhibitAutomaticSemicolon();
- }
+ } // else we will do the previous things at the start of next line...
}
scanChar();
@@ -547,10 +567,20 @@ again:
_tokenLine = _currentLineNumber;
_tokenColumn = _currentColumnNumber;
- if (_codePtr > _endPtr)
- return EOF_SYMBOL;
+ if (_codePtr >= _endPtr) {
+ if (_lexMode == LexMode::LineByLine) {
+ if (!_code.isEmpty()) {
+ _state.currentChar = *(_codePtr - 2);
+ return T_EOL;
+ } else {
+ return EOF_SYMBOL;
+ }
+ } else if (_codePtr > _endPtr) {
+ return EOF_SYMBOL;
+ }
+ }
- const QChar ch = _char;
+ const QChar ch = _state.currentChar;
scanChar();
switch (ch.unicode()) {
@@ -558,10 +588,10 @@ again:
case u'}': return T_RBRACE;
case u'|':
- if (_char == u'|') {
+ if (_state.currentChar == u'|') {
scanChar();
return T_OR_OR;
- } else if (_char == u'=') {
+ } else if (_state.currentChar == u'=') {
scanChar();
return T_OR_EQ;
}
@@ -570,7 +600,7 @@ again:
case u'{': return T_LBRACE;
case u'^':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_XOR_EQ;
}
@@ -579,56 +609,60 @@ again:
case u']': return T_RBRACKET;
case u'[': return T_LBRACKET;
case u'?': {
- if (_char == u'?') {
+ if (_state.currentChar == u'?') {
scanChar();
return T_QUESTION_QUESTION;
}
+ if (_state.currentChar == u'.' && !peekChar().isDigit()) {
+ scanChar();
+ return T_QUESTION_DOT;
+ }
return T_QUESTION;
}
case u'>':
- if (_char == u'>') {
+ if (_state.currentChar == u'>') {
scanChar();
- if (_char == u'>') {
+ if (_state.currentChar == u'>') {
scanChar();
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_GT_GT_GT_EQ;
}
return T_GT_GT_GT;
- } else if (_char == u'=') {
+ } else if (_state.currentChar == u'=') {
scanChar();
return T_GT_GT_EQ;
}
return T_GT_GT;
- } else if (_char == u'=') {
+ } else if (_state.currentChar == u'=') {
scanChar();
return T_GE;
}
return T_GT;
case u'=':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_EQ_EQ_EQ;
}
return T_EQ_EQ;
- } else if (_char == u'>') {
+ } else if (_state.currentChar == u'>') {
scanChar();
return T_ARROW;
}
return T_EQ;
case u'<':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_LE;
- } else if (_char == u'<') {
+ } else if (_state.currentChar == u'<') {
scanChar();
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_LT_LT_EQ;
}
@@ -640,26 +674,62 @@ again:
case u':': return T_COLON;
case u'/':
- if (handleComment())
- goto again;
- else if (_char == u'=') {
+ switch (_state.currentChar.unicode()) {
+ case u'*':
+ scanChar();
+ while (_codePtr <= _endPtr) {
+ if (_state.currentChar == u'*') {
+ scanChar();
+ if (_state.currentChar == u'/') {
+ scanChar();
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2,
+ _codePtr - _tokenStartPtr - 1 - 4, tokenStartLine(),
+ tokenStartColumn() + 2);
+ }
+ if (_lexMode == LexMode::LineByLine)
+ return T_COMMENT;
+ else
+ goto again;
+ }
+ } else {
+ scanChar();
+ }
+ }
+ if (_lexMode == LexMode::LineByLine)
+ return T_PARTIAL_COMMENT;
+ else
+ goto again;
+ case u'/':
+ while (_codePtr <= _endPtr && !isLineTerminator()) {
+ scanChar();
+ }
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2,
+ tokenStartLine(), tokenStartColumn() + 2);
+ }
+ if (_lexMode == LexMode::LineByLine)
+ return T_COMMENT;
+ else
+ goto again;
+ case u'=':
scanChar();
return T_DIVIDE_EQ;
+ default:
+ return T_DIVIDE_;
}
- return T_DIVIDE_;
-
case u'.':
- if (_importState == ImportState::SawImport)
+ if (_state.importState == ImportState::SawImport)
return T_DOT;
- if (isDecimalDigit(_char.unicode()))
+ if (isDecimalDigit(_state.currentChar.unicode()))
return scanNumber(ch);
- if (_char == u'.') {
+ if (_state.currentChar == u'.') {
scanChar();
- if (_char == u'.') {
+ if (_state.currentChar == u'.') {
scanChar();
return T_ELLIPSIS;
} else {
- _errorCode = IllegalCharacter;
+ _state.errorCode = IllegalCharacter;
_errorMessage = QCoreApplication::translate("QQmlParser", "Unexpected token '.'");
return T_ERROR;
}
@@ -667,14 +737,15 @@ again:
return T_DOT;
case u'-':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_MINUS_EQ;
- } else if (_char == u'-') {
+ } else if (_state.currentChar == u'-') {
scanChar();
- if (_terminator && !_delimited && !_prohibitAutomaticSemicolon && _tokenKind != T_LPAREN) {
- _stackToken = T_MINUS_MINUS;
+ if (_state.terminator && !_state.delimited && !_state.prohibitAutomaticSemicolon
+ && _state.tokenKind != T_LPAREN) {
+ _state.stackToken = T_MINUS_MINUS;
return T_SEMICOLON;
}
@@ -685,14 +756,15 @@ again:
case u',': return T_COMMA;
case u'+':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_PLUS_EQ;
- } else if (_char == u'+') {
+ } else if (_state.currentChar == u'+') {
scanChar();
- if (_terminator && !_delimited && !_prohibitAutomaticSemicolon && _tokenKind != T_LPAREN) {
- _stackToken = T_PLUS_PLUS;
+ if (_state.terminator && !_state.delimited && !_state.prohibitAutomaticSemicolon
+ && _state.tokenKind != T_LPAREN) {
+ _state.stackToken = T_PLUS_PLUS;
return T_SEMICOLON;
}
@@ -701,12 +773,12 @@ again:
return T_PLUS;
case u'*':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_STAR_EQ;
- } else if (_char == u'*') {
+ } else if (_state.currentChar == u'*') {
scanChar();
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_STAR_STAR_EQ;
}
@@ -720,26 +792,26 @@ again:
case u'@': return T_AT;
case u'&':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_AND_EQ;
- } else if (_char == u'&') {
+ } else if (_state.currentChar == u'&') {
scanChar();
return T_AND_AND;
}
return T_AND;
case u'%':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_REMAINDER_EQ;
}
return T_REMAINDER;
case u'!':
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
- if (_char == u'=') {
+ if (_state.currentChar == u'=') {
scanChar();
return T_NOT_EQ_EQ;
}
@@ -748,7 +820,7 @@ again:
return T_NOT;
case u'`':
- _outerTemplateBraceCount.push(_bracesCount);
+ _state.outerTemplateBraceCount.push(_state.bracesCount);
Q_FALLTHROUGH();
case u'\'':
case u'"':
@@ -763,7 +835,7 @@ again:
case u'7':
case u'8':
case u'9':
- if (_importState == ImportState::SawImport)
+ if (_state.importState == ImportState::SawImport)
return scanVersionNumber(ch);
else
return scanNumber(ch);
@@ -775,20 +847,23 @@ again:
scanChar();
}
if (_engine) {
- _engine->addComment(tokenOffset(), _codePtr - _tokenStartPtr - 1,
- tokenStartLine(), tokenStartColumn());
+ _engine->addComment(tokenOffset(), _codePtr - _tokenStartPtr - 1, tokenStartLine(),
+ tokenStartColumn());
}
- goto again;
+ if (_lexMode == LexMode::LineByLine)
+ return T_COMMENT;
+ else
+ goto again;
}
Q_FALLTHROUGH();
default: {
uint c = ch.unicode();
bool identifierWithEscapeChars = false;
- if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_char.unicode())) {
- c = QChar::surrogateToUcs4(ushort(c), _char.unicode());
+ if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_state.currentChar.unicode())) {
+ c = QChar::surrogateToUcs4(ushort(c), _state.currentChar.unicode());
scanChar();
- } else if (c == '\\' && _char == u'u') {
+ } else if (c == '\\' && _state.currentChar == u'u') {
identifierWithEscapeChars = true;
bool ok = false;
c = decodeUnicodeEscapeCharacter(&ok);
@@ -804,19 +879,19 @@ again:
} else {
_tokenText += QChar(c);
}
- _validTokenText = true;
+ _state.validTokenText = true;
}
while (_codePtr <= _endPtr) {
- c = _char.unicode();
+ c = _state.currentChar.unicode();
if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_codePtr->unicode())) {
scanChar();
- c = QChar::surrogateToUcs4(ushort(c), _char.unicode());
- } else if (_char == u'\\' && _codePtr[0] == u'u') {
+ c = QChar::surrogateToUcs4(ushort(c), _state.currentChar.unicode());
+ } else if (_state.currentChar == u'\\' && _codePtr[0] == u'u') {
if (!identifierWithEscapeChars) {
identifierWithEscapeChars = true;
_tokenText.resize(0);
_tokenText.insert(0, _tokenStartPtr, _codePtr - _tokenStartPtr - 1);
- _validTokenText = true;
+ _state.validTokenText = true;
}
scanChar(); // skip '\\'
@@ -860,17 +935,57 @@ again:
if (kind == T_FUNCTION) {
continue_skipping:
- while (_codePtr < _endPtr && _char.isSpace())
- scanChar();
- if (_char == u'*') {
- _tokenLength = _codePtr - _tokenStartPtr - 1;
- kind = T_FUNCTION_STAR;
- scanChar();
- } else if (_char == u'/') {
- scanChar();
- if (handleComment())
- goto continue_skipping;
- }
+ while (_codePtr < _endPtr && _state.currentChar.isSpace())
+ scanChar();
+ if (_state.currentChar == u'*') {
+ _tokenLength = _codePtr - _tokenStartPtr - 1;
+ kind = T_FUNCTION_STAR;
+ scanChar();
+ } else if (_state.currentChar == u'/') {
+ scanChar();
+ switch (_state.currentChar.unicode()) {
+ case u'*':
+ scanChar();
+ while (_codePtr <= _endPtr) {
+ if (_state.currentChar == u'*') {
+ scanChar();
+ if (_state.currentChar == u'/') {
+ scanChar();
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2,
+ _codePtr - _tokenStartPtr - 1 - 4,
+ tokenStartLine(),
+ tokenStartColumn() + 2);
+ }
+ if (_lexMode == LexMode::LineByLine)
+ return T_COMMENT;
+ goto continue_skipping;
+ }
+ } else {
+ scanChar();
+ }
+ }
+ if (_lexMode == LexMode::LineByLine)
+ return T_PARTIAL_COMMENT;
+ else
+ goto continue_skipping;
+ case u'/':
+ while (_codePtr <= _endPtr && !isLineTerminator()) {
+ scanChar();
+ }
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2,
+ _codePtr - _tokenStartPtr - 1 - 2,
+ tokenStartLine(), tokenStartColumn() + 2);
+ }
+ if (_lexMode == LexMode::LineByLine)
+ return T_COMMENT;
+ else
+ goto continue_skipping;
+ default:
+ break;
+ }
+ }
}
if (_engine) {
@@ -893,6 +1008,11 @@ again:
int Lexer::scanString(ScanStringMode mode)
{
QChar quote = (mode == TemplateContinuation) ? QChar(TemplateHead) : QChar(mode);
+ // we actually use T_STRING_LITERAL also for multiline strings, should we want to
+ // change that we should set it to:
+ // _state.tokenKind == T_PARTIAL_SINGLE_QUOTE_STRING_LITERAL ||
+ // _state.tokenKind == T_PARTIAL_DOUBLE_QUOTE_STRING_LITERAL
+ // here and uncomment the multilineStringLiteral = true below.
bool multilineStringLiteral = false;
const QChar *startCode = _codePtr - 1;
@@ -909,30 +1029,33 @@ int Lexer::scanString(ScanStringMode mode)
--_currentLineNumber; // will be read again in scanChar()
break;
}
- _errorCode = IllegalCharacter;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Stray newline in string literal");
+ _state.errorCode = IllegalCharacter;
+ _errorMessage = QCoreApplication::translate("QQmlParser",
+ "Stray newline in string literal");
return T_ERROR;
- } else if (_char == u'\\') {
+ } else if (_state.currentChar == u'\\') {
break;
- } else if (_char == u'$' && quote == u'`') {
+ } else if (_state.currentChar == u'$' && quote == u'`') {
break;
- } else if (_char == quote) {
- _tokenSpell = _engine->midRef(startCode - _code.unicode(), _codePtr - startCode - 1);
+ } else if (_state.currentChar == quote) {
+ _tokenSpell =
+ _engine->midRef(startCode - _code.unicode(), _codePtr - startCode - 1);
_rawString = _tokenSpell;
scanChar();
if (quote == u'`')
- _bracesCount = _outerTemplateBraceCount.pop();
-
+ _state.bracesCount = _state.outerTemplateBraceCount.pop();
if (mode == TemplateHead)
return T_NO_SUBSTITUTION_TEMPLATE;
else if (mode == TemplateContinuation)
return T_TEMPLATE_TAIL;
+ else if (multilineStringLiteral)
+ return T_MULTILINE_STRING_LITERAL;
else
return T_STRING_LITERAL;
}
// don't use scanChar() here, that would transform \r sequences and the midRef() call would create the wrong result
- _char = *_codePtr++;
+ _state.currentChar = *_codePtr++;
++_currentColumnNumber;
first = false;
}
@@ -942,7 +1065,7 @@ int Lexer::scanString(ScanStringMode mode)
--_codePtr;
--_currentColumnNumber;
- _validTokenText = true;
+ _state.validTokenText = true;
_tokenText = QString(startCode, _codePtr - startCode);
auto setRawString = [&](const QChar *end) {
@@ -955,7 +1078,7 @@ int Lexer::scanString(ScanStringMode mode)
scanChar();
while (_codePtr <= _endPtr) {
- if (_char == quote) {
+ if (_state.currentChar == quote) {
scanChar();
if (_engine) {
@@ -965,7 +1088,7 @@ int Lexer::scanString(ScanStringMode mode)
}
if (quote == u'`')
- _bracesCount = _outerTemplateBraceCount.pop();
+ _state.bracesCount = _state.outerTemplateBraceCount.pop();
if (mode == TemplateContinuation)
return T_TEMPLATE_TAIL;
@@ -973,27 +1096,28 @@ int Lexer::scanString(ScanStringMode mode)
return T_NO_SUBSTITUTION_TEMPLATE;
return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL;
- } else if (quote == u'`' && _char == u'$' && *_codePtr == u'{') {
+ } else if (quote == u'`' && _state.currentChar == u'$' && *_codePtr == u'{') {
scanChar();
scanChar();
- _bracesCount = 1;
+ _state.bracesCount = 1;
if (_engine) {
_tokenSpell = _engine->newStringRef(_tokenText);
setRawString(_codePtr - 2);
}
return (mode == TemplateHead ? T_TEMPLATE_HEAD : T_TEMPLATE_MIDDLE);
- } else if (_char == u'\\') {
+ } else if (_state.currentChar == u'\\') {
scanChar();
if (_codePtr > _endPtr) {
- _errorCode = IllegalEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "End of file reached at escape sequence");
+ _state.errorCode = IllegalEscapeSequence;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "End of file reached at escape sequence");
return T_ERROR;
}
QChar u;
- switch (_char.unicode()) {
+ switch (_state.currentChar.unicode()) {
// unicode escape sequence
case u'u': {
bool ok = false;
@@ -1014,8 +1138,9 @@ int Lexer::scanString(ScanStringMode mode)
bool ok = false;
u = decodeHexEscapeCharacter(&ok);
if (!ok) {
- _errorCode = IllegalHexadecimalEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal hexadecimal escape sequence");
+ _state.errorCode = IllegalHexadecimalEscapeSequence;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Illegal hexadecimal escape sequence");
return T_ERROR;
}
} break;
@@ -1032,7 +1157,7 @@ int Lexer::scanString(ScanStringMode mode)
case u'v': u = u'\v'; scanChar(); break;
case u'0':
- if (! _codePtr->isDigit()) {
+ if (!_codePtr->isDigit()) {
scanChar();
u = u'\0';
break;
@@ -1047,31 +1172,42 @@ int Lexer::scanString(ScanStringMode mode)
case u'7':
case u'8':
case u'9':
- _errorCode = IllegalEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Octal escape sequences are not allowed");
+ _state.errorCode = IllegalEscapeSequence;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Octal escape sequences are not allowed");
return T_ERROR;
case u'\r':
case u'\n':
case 0x2028u:
case 0x2029u:
+ // uncomment the following to use T_MULTILINE_STRING_LITERAL
+ // multilineStringLiteral = true;
scanChar();
continue;
default:
// non escape character
- u = _char;
+ u = _state.currentChar;
scanChar();
}
_tokenText += u;
} else {
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
}
}
-
- _errorCode = UnclosedStringLiteral;
+ if (_lexMode == LexMode::LineByLine && !_code.isEmpty()) {
+ if (mode == TemplateContinuation)
+ return T_PARTIAL_TEMPLATE_MIDDLE;
+ else if (mode == TemplateHead)
+ return T_PARTIAL_TEMPLATE_HEAD;
+ else if (mode == SingleQuote)
+ return T_PARTIAL_SINGLE_QUOTE_STRING_LITERAL;
+ return T_PARTIAL_DOUBLE_QUOTE_STRING_LITERAL;
+ }
+ _state.errorCode = UnclosedStringLiteral;
_errorMessage = QCoreApplication::translate("QQmlParser", "Unclosed string at end of line");
return T_ERROR;
}
@@ -1079,21 +1215,24 @@ int Lexer::scanString(ScanStringMode mode)
int Lexer::scanNumber(QChar ch)
{
if (ch == u'0') {
- if (_char == u'x' || _char == u'X') {
- ch = _char; // remember the x or X to use it in the error message below.
+ if (_state.currentChar == u'x' || _state.currentChar == u'X') {
+ ch = _state.currentChar; // remember the x or X to use it in the error message below.
// parse hex integer literal
scanChar(); // consume 'x'
- if (!isHexDigit(_char)) {
- _errorCode = IllegalNumber;
- _errorMessage = QCoreApplication::translate("QQmlParser", "At least one hexadecimal digit is required after '0%1'").arg(ch);
+ if (!isHexDigit(_state.currentChar)) {
+ _state.errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser",
+ "At least one hexadecimal digit is required after '0%1'")
+ .arg(ch);
return T_ERROR;
}
double d = 0.;
while (1) {
- int digit = ::hexDigit(_char);
+ int digit = ::hexDigit(_state.currentChar);
if (digit < 0)
break;
d *= 16;
@@ -1101,23 +1240,26 @@ int Lexer::scanNumber(QChar ch)
scanChar();
}
- _tokenValue = d;
+ _state.tokenValue = d;
return T_NUMERIC_LITERAL;
- } else if (_char == u'o' || _char == u'O') {
- ch = _char; // remember the o or O to use it in the error message below.
+ } else if (_state.currentChar == u'o' || _state.currentChar == u'O') {
+ ch = _state.currentChar; // remember the o or O to use it in the error message below.
// parse octal integer literal
scanChar(); // consume 'o'
- if (!isOctalDigit(_char.unicode())) {
- _errorCode = IllegalNumber;
- _errorMessage = QCoreApplication::translate("QQmlParser", "At least one octal digit is required after '0%1'").arg(ch);
+ if (!isOctalDigit(_state.currentChar.unicode())) {
+ _state.errorCode = IllegalNumber;
+ _errorMessage =
+ QCoreApplication::translate(
+ "QQmlParser", "At least one octal digit is required after '0%1'")
+ .arg(ch);
return T_ERROR;
}
double d = 0.;
while (1) {
- int digit = ::octalDigit(_char);
+ int digit = ::octalDigit(_state.currentChar);
if (digit < 0)
break;
d *= 8;
@@ -1125,37 +1267,41 @@ int Lexer::scanNumber(QChar ch)
scanChar();
}
- _tokenValue = d;
+ _state.tokenValue = d;
return T_NUMERIC_LITERAL;
- } else if (_char == u'b' || _char == u'B') {
- ch = _char; // remember the b or B to use it in the error message below.
+ } else if (_state.currentChar == u'b' || _state.currentChar == u'B') {
+ ch = _state.currentChar; // remember the b or B to use it in the error message below.
// parse binary integer literal
scanChar(); // consume 'b'
- if (_char.unicode() != u'0' && _char.unicode() != u'1') {
- _errorCode = IllegalNumber;
- _errorMessage = QCoreApplication::translate("QQmlParser", "At least one binary digit is required after '0%1'").arg(ch);
+ if (_state.currentChar.unicode() != u'0' && _state.currentChar.unicode() != u'1') {
+ _state.errorCode = IllegalNumber;
+ _errorMessage =
+ QCoreApplication::translate(
+ "QQmlParser", "At least one binary digit is required after '0%1'")
+ .arg(ch);
return T_ERROR;
}
double d = 0.;
while (1) {
int digit = 0;
- if (_char.unicode() == u'1')
+ if (_state.currentChar.unicode() == u'1')
digit = 1;
- else if (_char.unicode() != u'0')
+ else if (_state.currentChar.unicode() != u'0')
break;
d *= 2;
d += digit;
scanChar();
}
- _tokenValue = d;
+ _state.tokenValue = d;
return T_NUMERIC_LITERAL;
- } else if (_char.isDigit() && !qmlMode()) {
- _errorCode = IllegalCharacter;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Decimal numbers can't start with '0'");
+ } else if (_state.currentChar.isDigit() && !qmlMode()) {
+ _state.errorCode = IllegalCharacter;
+ _errorMessage = QCoreApplication::translate("QQmlParser",
+ "Decimal numbers can't start with '0'");
return T_ERROR;
}
}
@@ -1165,36 +1311,36 @@ int Lexer::scanNumber(QChar ch)
chars.append(ch.unicode());
if (ch != u'.') {
- while (_char.isDigit()) {
- chars.append(_char.unicode());
+ while (_state.currentChar.isDigit()) {
+ chars.append(_state.currentChar.unicode());
scanChar(); // consume the digit
}
- if (_char == u'.') {
- chars.append(_char.unicode());
+ if (_state.currentChar == u'.') {
+ chars.append(_state.currentChar.unicode());
scanChar(); // consume `.'
}
}
- while (_char.isDigit()) {
- chars.append(_char.unicode());
+ while (_state.currentChar.isDigit()) {
+ chars.append(_state.currentChar.unicode());
scanChar();
}
- if (_char == u'e' || _char == u'E') {
- if (_codePtr[0].isDigit() || ((_codePtr[0] == u'+' || _codePtr[0] == u'-') &&
- _codePtr[1].isDigit())) {
+ if (_state.currentChar == u'e' || _state.currentChar == u'E') {
+ if (_codePtr[0].isDigit()
+ || ((_codePtr[0] == u'+' || _codePtr[0] == u'-') && _codePtr[1].isDigit())) {
- chars.append(_char.unicode());
+ chars.append(_state.currentChar.unicode());
scanChar(); // consume `e'
- if (_char == u'+' || _char == u'-') {
- chars.append(_char.unicode());
+ if (_state.currentChar == u'+' || _state.currentChar == u'-') {
+ chars.append(_state.currentChar.unicode());
scanChar(); // consume the sign
}
- while (_char.isDigit()) {
- chars.append(_char.unicode());
+ while (_state.currentChar.isDigit()) {
+ chars.append(_state.currentChar.unicode());
scanChar();
}
}
@@ -1204,11 +1350,12 @@ int Lexer::scanNumber(QChar ch)
const char *end = nullptr;
bool ok = false;
- _tokenValue = qstrntod(begin, chars.size(), &end, &ok);
+ _state.tokenValue = qstrntod(begin, chars.size(), &end, &ok);
if (end - begin != chars.size()) {
- _errorCode = IllegalExponentIndicator;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number");
+ _state.errorCode = IllegalExponentIndicator;
+ _errorMessage =
+ QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number");
return T_ERROR;
}
@@ -1218,47 +1365,48 @@ int Lexer::scanNumber(QChar ch)
int Lexer::scanVersionNumber(QChar ch)
{
if (ch == u'0') {
- _tokenValue = 0;
+ _state.tokenValue = 0;
return T_VERSION_NUMBER;
}
int acc = 0;
acc += ch.digitValue();
- while (_char.isDigit()) {
+ while (_state.currentChar.isDigit()) {
acc *= 10;
- acc += _char.digitValue();
+ acc += _state.currentChar.digitValue();
scanChar(); // consume the digit
}
- _tokenValue = acc;
+ _state.tokenValue = acc;
return T_VERSION_NUMBER;
}
bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
{
_tokenText.resize(0);
- _validTokenText = true;
- _patternFlags = 0;
+ _state.validTokenText = true;
+ _state.patternFlags = 0;
if (prefix == EqualPrefix)
_tokenText += u'=';
while (true) {
- switch (_char.unicode()) {
+ switch (_state.currentChar.unicode()) {
case u'/':
scanChar();
// scan the flags
- _patternFlags = 0;
- while (isIdentLetter(_char)) {
- int flag = regExpFlagFromChar(_char);
- if (flag == 0 || _patternFlags & flag) {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Invalid regular expression flag '%0'")
- .arg(QChar(_char));
+ _state.patternFlags = 0;
+ while (isIdentLetter(_state.currentChar)) {
+ int flag = regExpFlagFromChar(_state.currentChar);
+ if (flag == 0 || _state.patternFlags & flag) {
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Invalid regular expression flag '%0'")
+ .arg(QChar(_state.currentChar));
return false;
}
- _patternFlags |= flag;
+ _state.patternFlags |= flag;
scanChar();
}
@@ -1267,59 +1415,63 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
case u'\\':
// regular expression backslash sequence
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
if (_codePtr > _endPtr || isLineTerminator()) {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression backslash sequence");
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Unterminated regular expression backslash sequence");
return false;
}
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
break;
case u'[':
// regular expression class
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
- while (_codePtr <= _endPtr && ! isLineTerminator()) {
- if (_char == u']')
+ while (_codePtr <= _endPtr && !isLineTerminator()) {
+ if (_state.currentChar == u']')
break;
- else if (_char == u'\\') {
+ else if (_state.currentChar == u'\\') {
// regular expression backslash sequence
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
if (_codePtr > _endPtr || isLineTerminator()) {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression backslash sequence");
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Unterminated regular expression backslash sequence");
return false;
}
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
} else {
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
}
}
- if (_char != u']') {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression class");
+ if (_state.currentChar != u']') {
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Unterminated regular expression class");
return false;
}
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar(); // skip ]
break;
default:
if (_codePtr > _endPtr || isLineTerminator()) {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression literal");
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Unterminated regular expression literal");
return false;
} else {
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
}
} // switch
@@ -1330,7 +1482,7 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
bool Lexer::isLineTerminator() const
{
- const ushort unicode = _char.unicode();
+ const ushort unicode = _state.currentChar.unicode();
return unicode == 0x000Au
|| unicode == 0x000Du
|| unicode == 0x2028u
@@ -1339,7 +1491,7 @@ bool Lexer::isLineTerminator() const
unsigned Lexer::isLineTerminatorSequence() const
{
- switch (_char.unicode()) {
+ switch (_state.currentChar.unicode()) {
case 0x000Au:
case 0x2028u:
case 0x2029u:
@@ -1386,10 +1538,10 @@ bool Lexer::isOctalDigit(ushort c)
QString Lexer::tokenText() const
{
- if (_validTokenText)
+ if (_state.validTokenText)
return _tokenText;
- if (_tokenKind == T_STRING_LITERAL)
+ if (_state.tokenKind == T_STRING_LITERAL)
return QString(_tokenStartPtr + 1, _tokenLength - 2);
return QString(_tokenStartPtr, _tokenLength);
@@ -1397,7 +1549,7 @@ QString Lexer::tokenText() const
Lexer::Error Lexer::errorCode() const
{
- return _errorCode;
+ return _state.errorCode;
}
QString Lexer::errorMessage() const
@@ -1407,33 +1559,31 @@ QString Lexer::errorMessage() const
void Lexer::syncProhibitAutomaticSemicolon()
{
- if (_parenthesesState == BalancedParentheses) {
+ if (_state.parenthesesState == BalancedParentheses) {
// we have seen something like "if (foo)", which means we should
// never insert an automatic semicolon at this point, since it would
// then be expanded into an empty statement (ECMA-262 7.9.1)
- _prohibitAutomaticSemicolon = true;
- _parenthesesState = IgnoreParentheses;
+ _state.prohibitAutomaticSemicolon = true;
+ _state.parenthesesState = IgnoreParentheses;
} else {
- _prohibitAutomaticSemicolon = false;
+ _state.prohibitAutomaticSemicolon = false;
}
}
bool Lexer::prevTerminator() const
{
- return _terminator;
+ return _state.terminator;
}
bool Lexer::followsClosingBrace() const
{
- return _followsClosingBrace;
+ return _state.followsClosingBrace;
}
bool Lexer::canInsertAutomaticSemicolon(int token) const
{
- return token == T_RBRACE
- || token == EOF_SYMBOL
- || _terminator
- || _followsClosingBrace;
+ return token == T_RBRACE || token == EOF_SYMBOL || _state.terminator
+ || _state.followsClosingBrace;
}
static const int uriTokens[] = {
@@ -1497,12 +1647,12 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
error->loc.startColumn = tokenStartColumn();
};
- QScopedValueRollback<bool> directivesGuard(_handlingDirectives, true);
+ QScopedValueRollback<bool> directivesGuard(_state.handlingDirectives, true);
Q_ASSERT(!_qmlMode);
lex(); // fetch the first token
- if (_tokenKind != T_DOT)
+ if (_state.tokenKind != T_DOT)
return true;
do {
@@ -1511,7 +1661,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
lex(); // skip T_DOT
- if (! (_tokenKind == T_IDENTIFIER || _tokenKind == T_IMPORT))
+ if (!(_state.tokenKind == T_IDENTIFIER || _state.tokenKind == T_IMPORT))
return true; // expected a valid QML/JS directive
const QString directiveName = tokenText();
@@ -1541,7 +1691,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
QString version;
bool fileImport = false; // file or uri import
- if (_tokenKind == T_STRING_LITERAL) {
+ if (_state.tokenKind == T_STRING_LITERAL) {
// .import T_STRING_LITERAL as T_IDENTIFIER
fileImport = true;
@@ -1553,10 +1703,10 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
}
lex();
- } else if (_tokenKind == T_IDENTIFIER) {
+ } else if (_state.tokenKind == T_IDENTIFIER) {
// .import T_IDENTIFIER (. T_IDENTIFIER)* (T_VERSION_NUMBER (. T_VERSION_NUMBER)?)? as T_IDENTIFIER
while (true) {
- if (!isUriToken(_tokenKind)) {
+ if (!isUriToken(_state.tokenKind)) {
setError(QCoreApplication::translate("QQmlParser","Invalid module URI"));
return false;
}
@@ -1568,7 +1718,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
setError(QCoreApplication::translate("QQmlParser","Invalid module URI"));
return false;
}
- if (_tokenKind != QQmlJSGrammar::T_DOT)
+ if (_state.tokenKind != QQmlJSGrammar::T_DOT)
break;
pathOrUri.append(u'.');
@@ -1580,13 +1730,13 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
}
}
- if (_tokenKind == T_VERSION_NUMBER) {
+ if (_state.tokenKind == T_VERSION_NUMBER) {
version = tokenText();
lex();
- if (_tokenKind == T_DOT) {
+ if (_state.tokenKind == T_DOT) {
version += u'.';
lex();
- if (_tokenKind != T_VERSION_NUMBER) {
+ if (_state.tokenKind != T_VERSION_NUMBER) {
setError(QCoreApplication::translate(
"QQmlParser", "Incomplete version number (dot but no minor)"));
return false; // expected the module version number
@@ -1600,7 +1750,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
//
// recognize the mandatory `as' followed by the module name
//
- if (! (_tokenKind == T_AS && tokenStartLine() == lineNumber)) {
+ if (!(_state.tokenKind == T_AS && tokenStartLine() == lineNumber)) {
if (fileImport)
setError(QCoreApplication::translate("QQmlParser", "File import requires a qualifier"));
else
@@ -1639,7 +1789,56 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
// fetch the first token after the .pragma/.import directive
lex();
- } while (_tokenKind == T_DOT);
+ } while (_state.tokenKind == T_DOT);
return true;
}
+
+const Lexer::State &Lexer::state() const
+{
+ return _state;
+}
+void Lexer::setState(const Lexer::State &state)
+{
+ _state = state;
+}
+
+int Lexer::parseModeFlags() const {
+ int flags = 0;
+ if (qmlMode())
+ flags |= QmlMode|StaticIsKeyword;
+ if (yieldIsKeyWord())
+ flags |= YieldIsKeyword;
+ if (_staticIsKeyword)
+ flags |= StaticIsKeyword;
+ return flags;
+}
+
+namespace QQmlJS {
+QDebug operator<<(QDebug dbg, const Lexer::State &s)
+{
+ dbg << "{\n"
+ << " errorCode:" << int(s.errorCode) << ",\n"
+ << " currentChar:" << s.currentChar << ",\n"
+ << " tokenValue:" << s.tokenValue << ",\n"
+ << " parenthesesState:" << s.parenthesesState << ",\n"
+ << " parenthesesCount:" << s.parenthesesCount << ",\n"
+ << " outerTemplateBraceCount:" << s.outerTemplateBraceCount << ",\n"
+ << " bracesCount:" << s.bracesCount << ",\n"
+ << " stackToken:" << s.stackToken << ",\n"
+ << " patternFlags:" << s.patternFlags << ",\n"
+ << " tokenKind:" << s.tokenKind << ",\n"
+ << " importState:" << int(s.importState) << ",\n"
+ << " validTokenText:" << s.validTokenText << ",\n"
+ << " prohibitAutomaticSemicolon:" << s.prohibitAutomaticSemicolon << ",\n"
+ << " restrictedKeyword:" << s.restrictedKeyword << ",\n"
+ << " terminator:" << s.terminator << ",\n"
+ << " followsClosingBrace:" << s.followsClosingBrace << ",\n"
+ << " delimited:" << s.delimited << ",\n"
+ << " handlingDirectives:" << s.handlingDirectives << ",\n"
+ << " generatorLevel:" << s.generatorLevel << "\n}";
+ return dbg;
+}
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h
index 7b4c219506..b6144e8894 100644
--- a/src/qml/parser/qqmljslexer_p.h
+++ b/src/qml/parser/qqmljslexer_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSLEXER_P_H
#define QQMLJSLEXER_P_H
@@ -59,6 +23,8 @@
QT_BEGIN_NAMESPACE
+class QDebug;
+
namespace QQmlJS {
class Engine;
@@ -129,37 +95,31 @@ public:
NoQmlImport
};
+ enum class LexMode { WholeCode, LineByLine };
+
+ enum class CodeContinuation { Reset, Continue };
+
public:
- Lexer(Engine *engine);
-
- int parseModeFlags() const {
- int flags = 0;
- if (qmlMode())
- flags |= QmlMode|StaticIsKeyword;
- if (yieldIsKeyWord())
- flags |= YieldIsKeyword;
- if (_staticIsKeyword)
- flags |= StaticIsKeyword;
- return flags;
- }
+ Lexer(Engine *engine, LexMode lexMode = LexMode::WholeCode);
bool qmlMode() const;
- bool yieldIsKeyWord() const { return _generatorLevel != 0; }
+ bool yieldIsKeyWord() const { return _state.generatorLevel != 0; }
void setStaticIsKeyword(bool b) { _staticIsKeyword = b; }
QString code() const;
- void setCode(const QString &code, int lineno, bool qmlMode = true);
+ void setCode(const QString &code, int lineno, bool qmlMode = true,
+ CodeContinuation codeContinuation = CodeContinuation::Reset);
int lex();
bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix);
bool scanDirectives(Directives *directives, DiagnosticMessage *error);
- int regExpFlags() const { return _patternFlags; }
+ int regExpFlags() const { return _state.patternFlags; }
QString regExpPattern() const { return _tokenText; }
- int tokenKind() const { return _tokenKind; }
- int tokenOffset() const { return _tokenStartPtr - _code.unicode(); }
+ int tokenKind() const { return _state.tokenKind; }
+ int tokenOffset() const { return _currentOffset + _tokenStartPtr - _code.unicode(); }
int tokenLength() const { return _tokenLength; }
int tokenStartLine() const { return _tokenLine; }
@@ -167,14 +127,12 @@ public:
inline QStringView tokenSpell() const { return _tokenSpell; }
inline QStringView rawString() const { return _rawString; }
- double tokenValue() const { return _tokenValue; }
+ double tokenValue() const { return _state.tokenValue; }
QString tokenText() const;
Error errorCode() const;
QString errorMessage() const;
- bool prevTerminator() const;
- bool followsClosingBrace() const;
bool canInsertAutomaticSemicolon(int token) const;
enum ParenthesesState {
@@ -183,14 +141,102 @@ public:
BalancedParentheses
};
- void enterGeneratorBody() { ++_generatorLevel; }
- void leaveGeneratorBody() { --_generatorLevel; }
+ enum class CommentState { NoComment, HadComment, InMultilineComment };
+
+ void enterGeneratorBody() { ++_state.generatorLevel; }
+ void leaveGeneratorBody() { --_state.generatorLevel; }
+
+ struct State
+ {
+ Error errorCode = NoError;
+
+ QChar currentChar = u'\n';
+ double tokenValue = 0;
+
+ // parentheses state
+ ParenthesesState parenthesesState = IgnoreParentheses;
+ int parenthesesCount = 0;
+
+ // template string stack
+ QStack<int> outerTemplateBraceCount;
+ int bracesCount = -1;
+
+ int stackToken = -1;
+
+ int patternFlags = 0;
+ int tokenKind = 0;
+ ImportState importState = ImportState::NoQmlImport;
+
+ bool validTokenText = false;
+ bool prohibitAutomaticSemicolon = false;
+ bool restrictedKeyword = false;
+ bool terminator = false;
+ bool followsClosingBrace = false;
+ bool delimited = true;
+ bool handlingDirectives = false;
+ CommentState comments = CommentState::NoComment;
+ int generatorLevel = 0;
+
+ friend bool operator==(State const &s1, State const &s2)
+ {
+ if (s1.errorCode != s2.errorCode)
+ return false;
+ if (s1.currentChar != s2.currentChar)
+ return false;
+ if (s1.tokenValue != s2.tokenValue)
+ return false;
+ if (s1.parenthesesState != s2.parenthesesState)
+ return false;
+ if (s1.parenthesesCount != s2.parenthesesCount)
+ return false;
+ if (s1.outerTemplateBraceCount != s2.outerTemplateBraceCount)
+ return false;
+ if (s1.bracesCount != s2.bracesCount)
+ return false;
+ if (s1.stackToken != s2.stackToken)
+ return false;
+ if (s1.patternFlags != s2.patternFlags)
+ return false;
+ if (s1.tokenKind != s2.tokenKind)
+ return false;
+ if (s1.importState != s2.importState)
+ return false;
+ if (s1.validTokenText != s2.validTokenText)
+ return false;
+ if (s1.prohibitAutomaticSemicolon != s2.prohibitAutomaticSemicolon)
+ return false;
+ if (s1.restrictedKeyword != s2.restrictedKeyword)
+ return false;
+ if (s1.terminator != s2.terminator)
+ return false;
+ if (s1.followsClosingBrace != s2.followsClosingBrace)
+ return false;
+ if (s1.delimited != s2.delimited)
+ return false;
+ if (s1.handlingDirectives != s2.handlingDirectives)
+ return false;
+ if (s1.generatorLevel != s2.generatorLevel)
+ return false;
+ return true;
+ }
+
+ friend bool operator!=(State const &s1, State const &s2) { return !(s1 == s2); }
+
+ friend QML_PARSER_EXPORT QDebug operator<<(QDebug dbg, State const &s);
+ };
+
+ const State &state() const;
+ void setState(const State &state);
protected:
static int classify(const QChar *s, int n, int parseModeFlags);
private:
+ int parseModeFlags() const;
+ bool prevTerminator() const;
+ bool followsClosingBrace() const;
inline void scanChar();
+ inline QChar peekChar();
int scanToken();
int scanNumber(QChar ch);
int scanVersionNumber(QChar ch);
@@ -213,54 +259,36 @@ private:
uint decodeUnicodeEscapeCharacter(bool *ok);
QChar decodeHexEscapeCharacter(bool *ok);
+ friend QML_PARSER_EXPORT QDebug operator<<(QDebug dbg, const Lexer &l);
+
private:
Engine *_engine;
+ LexMode _lexMode = LexMode::WholeCode;
QString _code;
+ const QChar *_endPtr;
+ bool _qmlMode;
+ bool _staticIsKeyword = false;
+
+ bool _skipLinefeed = false;
+
+ int _currentLineNumber = 0;
+ int _currentColumnNumber = 0;
+ int _currentOffset = 0;
+
+ int _tokenLength = 0;
+ int _tokenLine = 0;
+ int _tokenColumn = 0;
+
QString _tokenText;
QString _errorMessage;
QStringView _tokenSpell;
QStringView _rawString;
- const QChar *_codePtr;
- const QChar *_endPtr;
- const QChar *_tokenStartPtr;
-
- QChar _char;
- Error _errorCode;
-
- int _currentLineNumber;
- int _currentColumnNumber;
- double _tokenValue;
-
- // parentheses state
- ParenthesesState _parenthesesState;
- int _parenthesesCount;
-
- // template string stack
- QStack<int> _outerTemplateBraceCount;
- int _bracesCount = -1;
-
- int _stackToken;
-
- int _patternFlags;
- int _tokenKind;
- int _tokenLength;
- int _tokenLine;
- int _tokenColumn;
- ImportState _importState = ImportState::NoQmlImport;
-
- bool _validTokenText;
- bool _prohibitAutomaticSemicolon;
- bool _restrictedKeyword;
- bool _terminator;
- bool _followsClosingBrace;
- bool _delimited;
- bool _qmlMode;
- bool _skipLinefeed = false;
- int _generatorLevel = 0;
- bool _staticIsKeyword = false;
- bool _handlingDirectives = false;
+ const QChar *_codePtr = nullptr;
+ const QChar *_tokenStartPtr = nullptr;
+
+ State _state;
};
} // end of namespace QQmlJS