diff options
Diffstat (limited to 'src/qml/parser/qqmljsast_p.h')
-rw-r--r-- | src/qml/parser/qqmljsast_p.h | 383 |
1 files changed, 260 insertions, 123 deletions
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; |