aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/parser/qqmljsast.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-03-25 16:36:45 +0200
committerLars Knoll <lars.knoll@qt.io>2018-04-27 08:11:50 +0000
commitcdbe4754bdd073dd464cc9224609cbfcd736bd49 (patch)
tree0d338865e0e06c91a217f801a9168df219b6e5ca /src/qml/parser/qqmljsast.cpp
parent00b47c45097d7183ac7f3655aa4b2e6e74359e3f (diff)
Support destructuring assignments
Not everything works yet, but basic destructuring assignments do. Change-Id: I5f74691fd6458092ecfde9d1a8a802f99fc57b9e Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/parser/qqmljsast.cpp')
-rw-r--r--src/qml/parser/qqmljsast.cpp179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index a9fd2e9278..762eb9536a 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -79,6 +79,16 @@ UiObjectMember *Node::uiObjectMemberCast()
return nullptr;
}
+LeftHandSideExpression *Node::leftHandSideExpressionCast()
+{
+ return nullptr;
+}
+
+Pattern *Node::patternCast()
+{
+ return nullptr;
+}
+
ExpressionNode *ExpressionNode::expressionCast()
{
return this;
@@ -221,6 +231,165 @@ void ObjectPattern::accept0(Visitor *visitor)
visitor->endVisit(this);
}
+/*
+ This is the grammar for AssignmentPattern that we need to convert the literal to:
+
+ AssignmentPattern:
+ ObjectAssignmentPattern
+ ArrayAssignmentPattern
+ ArrayAssignmentPattern:
+ [ ElisionOpt AssignmentRestElementOpt ]
+ [ AssignmentElementList ]
+ [ AssignmentElementList , ElisionOpt AssignmentRestElementOpt ]
+ AssignmentElementList:
+ AssignmentElisionElement
+ AssignmentElementList , AssignmentElisionElement
+ AssignmentElisionElement:
+ ElisionOpt AssignmentElement
+ AssignmentRestElement:
+ ... DestructuringAssignmentTarget
+
+ ObjectAssignmentPattern:
+ {}
+ { AssignmentPropertyList }
+ { AssignmentPropertyList, }
+ AssignmentPropertyList:
+ AssignmentProperty
+ AssignmentPropertyList , AssignmentProperty
+ AssignmentProperty:
+ IdentifierReference InitializerOpt_In
+ PropertyName:
+ AssignmentElement
+
+ AssignmentElement:
+ DestructuringAssignmentTarget InitializerOpt_In
+ DestructuringAssignmentTarget:
+ LeftHandSideExpression
+
+ It was originally parsed with the following grammar:
+
+ArrayLiteral:
+ [ ElisionOpt ]
+ [ ElementList ]
+ [ ElementList , ElisionOpt ]
+ElementList:
+ ElisionOpt AssignmentExpression_In
+ ElisionOpt SpreadElement
+ ElementList , ElisionOpt AssignmentExpression_In
+ ElementList , Elisionopt SpreadElement
+SpreadElement:
+ ... AssignmentExpression_In
+ObjectLiteral:
+ {}
+ { PropertyDefinitionList }
+ { PropertyDefinitionList , }
+PropertyDefinitionList:
+ PropertyDefinition
+ PropertyDefinitionList , PropertyDefinition
+PropertyDefinition:
+ IdentifierReference
+ CoverInitializedName
+ PropertyName : AssignmentExpression_In
+ MethodDefinition
+PropertyName:
+ LiteralPropertyName
+ ComputedPropertyName
+
+*/
+bool ArrayPattern::convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage)
+{
+ for (auto *it = elements; it; it = it->next) {
+ if (it->element->type == PatternElement::SpreadElement && it->next) {
+ *errorLocation = it->element->firstSourceLocation();
+ *errorMessage = QString::fromLatin1("'...' can only appear as last element in a destructuring list.");
+ return false;
+ }
+ if (!it->element->convertLiteralToAssignmentPattern(pool, errorLocation, errorMessage))
+ return false;
+ }
+ return true;
+}
+
+bool ObjectPattern::convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage)
+{
+ for (auto *it = properties; it; it = it->next) {
+ if (!it->property->convertLiteralToAssignmentPattern(pool, errorLocation, errorMessage))
+ return false;
+ }
+ return true;
+}
+
+bool PatternElement::convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage)
+{
+ Q_ASSERT(type == Literal || type == SpreadElement);
+ Q_ASSERT(bindingIdentifier.isNull());
+ Q_ASSERT(bindingPattern == nullptr);
+ Q_ASSERT(bindingPattern == nullptr);
+ Q_ASSERT(initializer);
+ ExpressionNode *init = initializer;
+
+ initializer = nullptr;
+ LeftHandSideExpression *lhs = init->leftHandSideExpressionCast();
+ if (type == SpreadElement) {
+ if (!lhs) {
+ *errorLocation = init->firstSourceLocation();
+ *errorMessage = QString::fromLatin1("Invalid lhs expression after '...' in destructuring expression.");
+ return false;
+ }
+ // ### Should be binding
+ initializer = lhs;
+ return true;
+ }
+ type = PatternElement::Binding;
+
+ if (BinaryExpression *b = init->binaryExpressionCast()) {
+ if (b->op != QSOperator::Assign) {
+ *errorLocation = b->operatorToken;
+ *errorMessage = QString::fromLatin1("Invalid assignment operation in destructuring expression");
+ return false;
+ }
+ lhs = b->left->leftHandSideExpressionCast();
+ initializer = b->right;
+ Q_ASSERT(lhs);
+ } else {
+ lhs = init->leftHandSideExpressionCast();
+ }
+ if (!lhs) {
+ *errorLocation = init->firstSourceLocation();
+ *errorMessage = QString::fromLatin1("Destructuring target is not a left hand side expression.");
+ return false;
+ }
+
+ if (auto *p = lhs->patternCast()) {
+ bindingPattern = p;
+ if (!p->convertLiteralToAssignmentPattern(pool, errorLocation, errorMessage))
+ return false;
+ return true;
+ }
+ if (auto *i = cast<IdentifierExpression *>(lhs)) {
+ bindingIdentifier = i->name.toString();
+ return true;
+ }
+ *errorLocation = lastSourceLocation();
+ *errorMessage = QLatin1String("Unimplemented!");
+ return false;
+}
+
+bool PatternProperty::convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage)
+{
+ Q_ASSERT(type != SpreadElement);
+ if (type == Binding)
+ return true;
+ if (type == Getter || type == Setter) {
+ *errorLocation = firstSourceLocation();
+ *errorMessage = QString::fromLatin1("Invalid getter/setter in destructuring expression.");
+ return false;
+ }
+ Q_ASSERT(type == Literal);
+ return PatternElement::convertLiteralToAssignmentPattern(pool, errorLocation, errorMessage);
+}
+
+
void Elision::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
@@ -1100,6 +1269,16 @@ ClassElementList *ClassElementList::finish()
return front;
}
+Pattern *Pattern::patternCast()
+{
+ return this;
+}
+
+LeftHandSideExpression *LeftHandSideExpression::leftHandSideExpressionCast()
+{
+ return this;
+}
+
} } // namespace QQmlJS::AST
QT_QML_END_NAMESPACE