QmlJS: Update QML parser using the one from qtdeclarative 5.15

We need to do this because the new "required" keyword should be
recognized by Qt Creator.

This is not a verbatim copy of the QML parser from qtdeclarative. A few
data structures have changed that would require large scale changes in
otherwise unrelated parts of the code. For example, all Visitors need to
handle recursion depth errors now and the DiagnosticMessage only has
line and column now, no longer begin and legth.

Change-Id: Iea5b04e27b07e0cba55d64b844315af9828acbf7
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Ulf Hermann
2019-10-04 16:11:02 +02:00
parent 979d14525c
commit 58d35f8a64
14 changed files with 4344 additions and 3513 deletions

View File

@@ -218,7 +218,9 @@ public:
Kind_PatternElementList,
Kind_PatternProperty,
Kind_PatternPropertyList,
Kind_Type,
Kind_TypeArgumentList,
Kind_TypeAnnotation,
Kind_UiArrayBinding,
Kind_UiImport,
@@ -236,7 +238,8 @@ public:
Kind_UiSourceElement,
Kind_UiHeaderItemList,
Kind_UiEnumDeclaration,
Kind_UiEnumMemberList
Kind_UiEnumMemberList,
Kind_UiVersionSpecifier
};
inline Node() {}
@@ -256,11 +259,35 @@ public:
virtual FunctionExpression *asFunctionDefinition();
virtual ClassExpression *asClassDefinition();
void accept(Visitor *visitor);
static void accept(Node *node, Visitor *visitor);
bool ignoreRecursionDepth() const;
inline void accept(Visitor *visitor)
{
Visitor::RecursionDepthCheck recursionCheck(visitor);
// Stack overflow is uncommon, ignoreRecursionDepth() only returns true if
// QV4_CRASH_ON_STACKOVERFLOW is set, and ignoreRecursionDepth() needs to be out of line.
// Therefore, check for ignoreRecursionDepth() _after_ calling the inline recursionCheck().
if (recursionCheck() || ignoreRecursionDepth()) {
if (visitor->preVisit(this))
accept0(visitor);
visitor->postVisit(this);
} else {
visitor->throwRecursionDepthError();
}
}
inline static void accept(Node *node, Visitor *visitor)
{
if (node)
node->accept(visitor);
}
// ### Remove when we can. This is part of the qmldevtools library, though.
inline static void acceptChild(Node *node, Visitor *visitor)
{ return accept(node, visitor); } // ### remove
{
return accept(node, visitor);
}
virtual void accept0(Visitor *visitor) = 0;
virtual SourceLocation firstSourceLocation() const = 0;
@@ -270,6 +297,139 @@ public:
int kind = Kind_Undefined;
};
template<typename T>
T lastListElement(T head)
{
auto current = head;
while (current->next)
current = current->next;
return current;
}
class QML_PARSER_EXPORT UiQualifiedId: public Node
{
public:
QMLJS_DECLARE_AST_NODE(UiQualifiedId)
UiQualifiedId(const QStringRef &name)
: next(this), name(name)
{ kind = K; }
UiQualifiedId(UiQualifiedId *previous, const QStringRef &name)
: name(name)
{
kind = K;
next = previous->next;
previous->next = this;
}
UiQualifiedId *finish()
{
UiQualifiedId *head = next;
next = nullptr;
return head;
}
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return identifierToken; }
SourceLocation lastSourceLocation() const override
{ return lastListElement(this)->identifierToken; }
// attributes
UiQualifiedId *next;
QStringRef name;
SourceLocation identifierToken;
};
class QML_PARSER_EXPORT Type: public Node
{
public:
QMLJS_DECLARE_AST_NODE(Type)
Type(UiQualifiedId *typeId, Node *typeArguments = nullptr)
: typeId(typeId)
, typeArguments(typeArguments)
{ kind = K; }
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return typeId->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
{ return typeArguments ? typeArguments->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:
QMLJS_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(Visitor *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;
};
class QML_PARSER_EXPORT TypeAnnotation: public Node
{
public:
QMLJS_DECLARE_AST_NODE(TypeAnnotation)
TypeAnnotation(Type *type)
: type(type)
{ kind = K; }
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return colonToken; }
SourceLocation lastSourceLocation() const override
{ return type->lastSourceLocation(); }
// attributes
Type *type;
SourceLocation colonToken;
};
class QML_PARSER_EXPORT ExpressionNode: public Node
{
public:
@@ -459,7 +619,30 @@ public:
SourceLocation literalToken;
};
class QML_PARSER_EXPORT StringLiteral: public LeftHandSideExpression
class QML_PARSER_EXPORT UiVersionSpecifier : public Node
{
public:
QMLJS_DECLARE_AST_NODE(UiVersionSpecifier)
UiVersionSpecifier(int majorum, int minorum) : majorVersion(majorum), minorVersion(minorum) { kind = K; }
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override { return majorToken; }
SourceLocation lastSourceLocation() const override
{
return minorToken.isValid() ? minorToken : majorToken;
}
// attributes:
int majorVersion;
int minorVersion;
SourceLocation majorToken;
SourceLocation minorToken;
};
class QML_PARSER_EXPORT StringLiteral : public LeftHandSideExpression
{
public:
QMLJS_DECLARE_AST_NODE(StringLiteral)
@@ -485,19 +668,23 @@ class QML_PARSER_EXPORT TemplateLiteral : public LeftHandSideExpression
public:
QMLJS_DECLARE_AST_NODE(TemplateLiteral)
TemplateLiteral(const QStringRef &str, ExpressionNode *e)
: value(str), expression(e), next(nullptr)
TemplateLiteral(const QStringRef &str, const QStringRef &raw, ExpressionNode *e)
: value(str), rawValue(raw), expression(e), next(nullptr)
{ kind = K; }
SourceLocation firstSourceLocation() const override
{ return literalToken; }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : (expression ? expression->lastSourceLocation() : literalToken); }
{
auto last = lastListElement(this);
return (last->expression ? last->expression->lastSourceLocation() : last->literalToken);
}
void accept0(Visitor *visitor) override;
QStringRef value;
QStringRef rawValue;
ExpressionNode *expression;
TemplateLiteral *next;
SourceLocation literalToken;
@@ -614,7 +801,7 @@ public:
{ return commaToken; }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : commaToken; }
{ return lastListElement(this)->commaToken; }
inline Elision *finish ()
{
@@ -647,6 +834,34 @@ public:
SourceLocation propertyNameToken;
};
struct QML_PARSER_EXPORT BoundName
{
QString id;
TypeAnnotation *typeAnnotation = nullptr;
BoundName(const QString &id, TypeAnnotation *typeAnnotation)
: id(id), typeAnnotation(typeAnnotation)
{}
BoundName() = default;
QString typeName() const { return typeAnnotation ? typeAnnotation->type->toString() : QString(); }
};
struct BoundNames : public QVector<BoundName>
{
int indexOf(const QString &name, int from = 0) const
{
auto found = std::find_if(constBegin() + from, constEnd(),
[name](const BoundName &it) { return it.id == name; });
if (found == constEnd())
return -1;
return found - constBegin();
}
bool contains(const QString &name) const
{
return indexOf(name) != -1;
}
};
class QML_PARSER_EXPORT PatternElement : public Node
{
public:
@@ -655,6 +870,7 @@ public:
enum Type {
// object literal types
Literal,
Method,
Getter,
Setter,
@@ -670,8 +886,9 @@ public:
: initializer(i), type(t)
{ kind = K; }
PatternElement(const QStringRef &n, ExpressionNode *i = nullptr, Type t = Binding)
PatternElement(const QStringRef &n, TypeAnnotation *typeAnnotation = nullptr, ExpressionNode *i = nullptr, Type t = Binding)
: bindingIdentifier(n), initializer(i), type(t)
, typeAnnotation(typeAnnotation)
{
Q_ASSERT(t >= RestElement);
kind = K;
@@ -691,7 +908,7 @@ public:
{ return identifierToken.isValid() ? identifierToken : (bindingTarget ? bindingTarget->firstSourceLocation() : initializer->firstSourceLocation()); }
SourceLocation lastSourceLocation() const override
{ return initializer ? initializer->lastSourceLocation() : (bindingTarget ? bindingTarget->lastSourceLocation() : identifierToken); }
{ return initializer ? initializer->lastSourceLocation() : (bindingTarget ? bindingTarget->lastSourceLocation() : (typeAnnotation ? typeAnnotation->lastSourceLocation() : identifierToken)); }
ExpressionNode *destructuringTarget() const { return bindingTarget; }
Pattern *destructuringPattern() const { return bindingTarget ? bindingTarget->patternCast() : nullptr; }
@@ -701,7 +918,7 @@ public:
bool isVariableDeclaration() const { return scope != VariableScope::NoScope; }
bool isLexicallyScoped() const { return scope == VariableScope::Let || scope == VariableScope::Const; }
virtual void boundNames(QStringList *names);
virtual void boundNames(BoundNames *names);
// attributes
SourceLocation identifierToken;
@@ -709,6 +926,7 @@ public:
ExpressionNode *bindingTarget = nullptr;
ExpressionNode *initializer = nullptr;
Type type = Literal;
TypeAnnotation *typeAnnotation = nullptr;
// when used in a VariableDeclarationList
VariableScope scope = VariableScope::NoScope;
bool isForDeclaration = false;
@@ -738,13 +956,16 @@ public:
void accept0(Visitor *visitor) override;
void boundNames(QStringList *names);
void boundNames(BoundNames *names);
SourceLocation firstSourceLocation() const override
{ return elision ? elision->firstSourceLocation() : element->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : (element ? element->lastSourceLocation() : elision->lastSourceLocation()); }
{
auto last = lastListElement(this);
return last->element ? last->element->lastSourceLocation() : last->elision->lastSourceLocation();
}
Elision *elision = nullptr;
PatternElement *element = nullptr;
@@ -761,7 +982,7 @@ public:
{ kind = K; }
PatternProperty(PropertyName *name, const QStringRef &n, ExpressionNode *i = nullptr)
: PatternElement(n, i), name(name)
: PatternElement(n, /*type annotation*/nullptr, i), name(name)
{ kind = K; }
PatternProperty(PropertyName *name, Pattern *pattern, ExpressionNode *i = nullptr)
@@ -778,7 +999,7 @@ public:
return loc.isValid() ? loc : name->lastSourceLocation();
}
void boundNames(QStringList *names) override;
void boundNames(BoundNames *names) override;
bool convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage) override;
// attributes
@@ -806,7 +1027,7 @@ public:
void accept0(Visitor *visitor) override;
void boundNames(QStringList *names);
void boundNames(BoundNames *names);
inline PatternPropertyList *finish ()
{
@@ -819,7 +1040,7 @@ public:
{ return property->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : property->lastSourceLocation(); }
{ return lastListElement(this)->property->lastSourceLocation(); }
PatternProperty *property;
PatternPropertyList *next;
@@ -1428,7 +1649,9 @@ public:
{ return statement->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : statement->lastSourceLocation(); }
{
return lastListElement(this)->statement->lastSourceLocation();
}
inline StatementList *finish ()
{
@@ -1543,7 +1766,7 @@ public:
{ return expression->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
{ return semicolonToken.isValid() ? semicolonToken : expression->lastSourceLocation(); }
{ return expression->lastSourceLocation(); }
// attributes
ExpressionNode *expression;
@@ -1921,7 +2144,9 @@ public:
{ return clause->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : clause->lastSourceLocation(); }
{
return lastListElement(this)->clause->lastSourceLocation();
}
inline CaseClauses *finish ()
{
@@ -2096,8 +2321,9 @@ class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode
public:
QMLJS_DECLARE_AST_NODE(FunctionExpression)
FunctionExpression(const QStringRef &n, FormalParameterList *f, StatementList *b):
name (n), formals (f), body (b)
FunctionExpression(const QStringRef &n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr):
name (n), formals (f), body (b),
typeAnnotation(typeAnnotation)
{ kind = K; }
void accept0(Visitor *visitor) override;
@@ -2116,6 +2342,7 @@ public:
bool isGenerator = false;
FormalParameterList *formals;
StatementList *body;
TypeAnnotation *typeAnnotation;
SourceLocation functionToken;
SourceLocation identifierToken;
SourceLocation lparenToken;
@@ -2129,8 +2356,8 @@ class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression
public:
QMLJS_DECLARE_AST_NODE(FunctionDeclaration)
FunctionDeclaration(const QStringRef &n, FormalParameterList *f, StatementList *b):
FunctionExpression(n, f, b)
FunctionDeclaration(const QStringRef &n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr):
FunctionExpression(n, f, b, typeAnnotation)
{ kind = K; }
void accept0(Visitor *visitor) override;
@@ -2200,9 +2427,9 @@ public:
return false;
}
QStringList formals() const;
BoundNames formals() const;
QStringList boundNames() const;
BoundNames boundNames() const;
void accept0(Visitor *visitor) override;
@@ -2210,7 +2437,9 @@ public:
{ return element->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : element->lastSourceLocation(); }
{
return lastListElement(this)->element->lastSourceLocation();
}
FormalParameterList *finish(MemoryPool *pool);
@@ -2387,7 +2616,9 @@ public:
{ return importSpecifierToken; }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : importSpecifierToken; }
{
return lastListElement(this)->importSpecifierToken;
}
// attributes
SourceLocation importSpecifierToken;
@@ -2624,7 +2855,7 @@ public:
SourceLocation firstSourceLocation() const override
{ return exportSpecifier->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : exportSpecifier->lastSourceLocation(); }
{ return lastListElement(this)->exportSpecifier->lastSourceLocation(); }
// attributes
ExportSpecifier *exportSpecifier;
@@ -2751,44 +2982,6 @@ public:
SourceLocation semicolonToken;
};
class QML_PARSER_EXPORT UiQualifiedId: public Node
{
public:
QMLJS_DECLARE_AST_NODE(UiQualifiedId)
UiQualifiedId(const QStringRef &name)
: next(this), name(name)
{ kind = K; }
UiQualifiedId(UiQualifiedId *previous, const QStringRef &name)
: name(name)
{
kind = K;
next = previous->next;
previous->next = this;
}
UiQualifiedId *finish()
{
UiQualifiedId *head = next;
next = nullptr;
return head;
}
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return identifierToken; }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : identifierToken; }
// attributes
UiQualifiedId *next;
QStringRef name;
SourceLocation identifierToken;
};
class QML_PARSER_EXPORT UiImport: public Node
{
public:
@@ -2820,6 +3013,7 @@ public:
SourceLocation asToken;
SourceLocation importIdToken;
SourceLocation semicolonToken;
UiVersionSpecifier *version = nullptr;
};
class QML_PARSER_EXPORT UiObjectMember: public Node
@@ -2854,7 +3048,7 @@ public:
{ return member->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : member->lastSourceLocation(); }
{ return lastListElement(this)->member->lastSourceLocation(); }
UiObjectMemberList *finish()
{
@@ -2933,7 +3127,7 @@ public:
{ return headerItem->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : headerItem->lastSourceLocation(); }
{ return lastListElement(this)->headerItem->lastSourceLocation(); }
// attributes
Node *headerItem;
@@ -2997,7 +3191,7 @@ public:
{ return member->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : member->lastSourceLocation(); }
{ return lastListElement(this)->member->lastSourceLocation(); }
UiArrayMemberList *finish()
{
@@ -3055,10 +3249,13 @@ public:
void accept0(Visitor *) override;
SourceLocation firstSourceLocation() const override
{ return propertyTypeToken; }
{ return colonToken.isValid() ? identifierToken : propertyTypeToken; }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : identifierToken; }
{
auto last = lastListElement(this);
return (last->colonToken.isValid() ? last->propertyTypeToken : last->identifierToken);
}
inline UiParameterList *finish ()
{
@@ -3074,6 +3271,7 @@ public:
SourceLocation commaToken;
SourceLocation propertyTypeToken;
SourceLocation identifierToken;
SourceLocation colonToken;
};
class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember
@@ -3100,6 +3298,8 @@ public:
return defaultToken;
else if (readonlyToken.isValid())
return readonlyToken;
else if (requiredToken.isValid())
return requiredToken;
return propertyToken;
}
@@ -3123,10 +3323,13 @@ public:
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;
@@ -3168,7 +3371,7 @@ public:
SourceLocation firstSourceLocation() const override
{
if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
if (FunctionExpression *funDecl = sourceElement->asFunctionDefinition())
return funDecl->firstSourceLocation();
else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
return varStmt->firstSourceLocation();
@@ -3178,7 +3381,7 @@ public:
SourceLocation lastSourceLocation() const override
{
if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
if (FunctionExpression *funDecl = sourceElement->asFunctionDefinition())
return funDecl->lastSourceLocation();
else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
return varStmt->lastSourceLocation();
@@ -3310,8 +3513,10 @@ public:
{ return memberToken; }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() :
valueToken.isValid() ? valueToken : memberToken; }
{
auto last = lastListElement(this);
return last->valueToken.isValid() ? last->valueToken : last->memberToken;
}
void accept0(Visitor *visitor) override;