diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-02-10 23:22:13 +0100 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-04-25 17:49:38 +0000 |
commit | da5fffbd34d8be68f8ee4c649881dbb673c9c0a5 (patch) | |
tree | 2c4647732d8754f0c9b8573875cb5936639320ca /src | |
parent | e91d0091e0778ad1379f40d97daa704515bec3d4 (diff) |
Partially support binding patterns
Destructuring objects works, but arrays are not
yet supported.
Change-Id: I61e917e1964e3c719f71b8f11d194e09dfe288c2
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 11 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 68 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata.cpp | 15 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilercontext_p.h | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilerscanfunctions.cpp | 40 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilerscanfunctions_p.h | 1 | ||||
-rw-r--r-- | src/qml/parser/qqmljs.g | 125 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast.cpp | 109 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast_p.h | 180 | ||||
-rw-r--r-- | src/qml/parser/qqmljsastfwd_p.h | 5 | ||||
-rw-r--r-- | src/qml/parser/qqmljsastvisitor_p.h | 12 |
13 files changed, 486 insertions, 97 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 524acff424..4774095a38 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -983,14 +983,15 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node) f->index = index; f->nameIndex = registerString(funDecl->name.toString()); - int formalsCount = 0; - for (QQmlJS::AST::FormalParameterList *it = funDecl->formals; it; it = it->next) - ++formalsCount; + const QStringList formals = funDecl->formals->formals(); + int formalsCount = formals.size(); f->formals.allocate(pool, formalsCount); int i = 0; - for (QQmlJS::AST::FormalParameterList *it = funDecl->formals; it; it = it->next, ++i) - f->formals[i] = registerString(it->name.toString()); + for (const QString &arg : formals) { + f->formals[i] = registerString(arg); + ++i; + } _object->appendFunction(f); } else { diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index a896745b3f..7c8bf05ce5 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -466,10 +466,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio for (const QString ¶m : qAsConst(parameters)) { QStringRef paramNameRef = compiler->newStringRef(param); - if (paramList) - paramList = new (pool) QQmlJS::AST::FormalParameterList(paramList, paramNameRef); - else - paramList = new (pool) QQmlJS::AST::FormalParameterList(paramNameRef); + QQmlJS::AST::BindingElement *b = new (pool) QQmlJS::AST::BindingElement(paramNameRef, nullptr); + paramList = new (pool) QQmlJS::AST::FormalParameterList(paramList, b); } if (paramList) diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 76cf29bf35..973d5cd992 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -427,6 +427,56 @@ void Codegen::variableDeclarationList(VariableDeclarationList *ast) } } +void Codegen::initializeAndDestructureBindingElement(AST::BindingElement *e, const Codegen::Reference &baseRef) +{ + RegisterScope scope(this); + Reference varToStore = referenceForName(e->name, true); + if (e->initializer && baseRef == varToStore) { + baseRef.loadInAccumulator(); + BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined(); + expression(e->initializer).loadInAccumulator(); + varToStore.storeConsumeAccumulator(); + jump.link(); + } else if (e->initializer) { + baseRef.loadInAccumulator(); + BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined(); + expression(e->initializer).loadInAccumulator(); + jump.link(); + varToStore.storeConsumeAccumulator(); + } else if (baseRef != varToStore) { + baseRef.loadInAccumulator(); + varToStore.storeConsumeAccumulator(); + } + if (BindingElementList *l = e->elementList()) { + destructureElementList(varToStore, l); + } else if (BindingPropertyList *p = e->propertyList()) { + destructurePropertyList(varToStore, p); + } +} + +void Codegen::destructurePropertyList(const Codegen::Reference &object, BindingPropertyList *bindingList) +{ + Q_UNUSED(object); + Q_UNUSED(bindingList); + + RegisterScope scope(this); + + for (BindingPropertyList *p = bindingList; p; p = p->next) { + RegisterScope scope(this); + QString propertyName = p->propertyName->asString(); + Reference property = Reference::fromMember(object, propertyName); + initializeAndDestructureBindingElement(p->binding, property); + } + +} + +void Codegen::destructureElementList(const Codegen::Reference &array, BindingElementList *bindingList) +{ + Q_UNUSED(array); + // #### implement me + throwSyntaxError(bindingList->firstSourceLocation(), QString::fromLatin1("Support for binding element lists not implemented!")); +} + bool Codegen::visit(ArgumentList *) { @@ -2334,22 +2384,18 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, int argc = 0; while (formals) { - if (formals->isRest) { + if (AST::BindingRestElement *r = formals->bindingRestElement()) { Q_ASSERT(!formals->next); Instruction::CreateRestParameter rest; rest.argIndex = argc; bytecodeGenerator->addInstruction(rest); - Reference f = referenceForName(formals->name.toString(), true); + Reference f = referenceForName(r->name.toString(), true); f.storeConsumeAccumulator(); - } - if (formals->initializer) { - RegisterScope scope(this); - Reference f = referenceForName(formals->name.toString(), true); - f.loadInAccumulator(); - BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined(); - expression(formals->initializer).loadInAccumulator(); - f.storeConsumeAccumulator(); - jump.link(); + } else if (BindingElement *e = formals->bindingElement()) { + Reference arg = referenceForName(e->name, true); + initializeAndDestructureBindingElement(e, arg); + } else { + Q_UNREACHABLE(); } formals = formals->next; ++argc; diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 560dc48a63..e708d56478 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -197,6 +197,8 @@ public: Reference &operator =(const Reference &other); bool operator==(const Reference &other) const; + bool operator!=(const Reference &other) const + { return !(*this == other); } bool isValid() const { return type != Invalid; } bool loadTriggersSideEffect() const { @@ -512,6 +514,10 @@ protected: void variableDeclaration(AST::VariableDeclaration *ast); void variableDeclarationList(AST::VariableDeclarationList *ast); + void initializeAndDestructureBindingElement(AST::BindingElement *e, const Reference &baseRef); + void destructurePropertyList(const Reference &object, AST::BindingPropertyList *bindingList); + void destructureElementList(const Reference &array, AST::BindingElementList *bindingList); + Reference referenceForName(const QString &name, bool lhs); void loadClosure(int index); diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 005263e582..a17ee43446 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -492,8 +492,9 @@ Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument) QQmlJS::AST::FormalParameterList *parameters = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(foe->node)->formals; changedSignalParameters << parameters; - for (; parameters; parameters = parameters->next) - stringTable.registerString(parameters->name.toString()); + const QStringList formals = parameters->formals(); + for (const QString &arg : formals) + stringTable.registerString(arg); } } @@ -516,11 +517,11 @@ Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument) function->formalsOffset = signalParameterNameTableOffset - jsUnit->functionOffsetTable()[functionIndex]; - for (QQmlJS::AST::FormalParameterList *parameters = changedSignalParameters.at(i); - parameters; parameters = parameters->next) { - signalParameterNameTable.append(stringTable.getStringId(parameters->name.toString())); - function->nFormals = function->nFormals + 1; - } + const QStringList formals = changedSignalParameters.at(i)->formals(); + for (const QString &arg : formals) + signalParameterNameTable.append(stringTable.getStringId(arg)); + + function->nFormals = formals.size(); // Hack to ensure an activation is created. function->flags |= QV4::CompiledData::Function::HasCatchOrWith | QV4::CompiledData::Function::HasDirectEval; diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h index 455a76c729..fef2b56055 100644 --- a/src/qml/compiler/qv4compilercontext_p.h +++ b/src/qml/compiler/qv4compilercontext_p.h @@ -263,9 +263,8 @@ struct Context { return true; if (type != FunctionDefinition) { - for (QQmlJS::AST::FormalParameterList *it = formals; it; it = it->next) - if (it->name == name) - return (scope == QQmlJS::AST::VariableDeclaration::FunctionScope); + if (formals->containsName(name)) + return (scope == QQmlJS::AST::VariableDeclaration::FunctionScope); } MemberMap::iterator it = members.find(name); if (it != members.end()) { diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp index 8824a47def..c732e60b34 100644 --- a/src/qml/compiler/qv4compilerscanfunctions.cpp +++ b/src/qml/compiler/qv4compilerscanfunctions.cpp @@ -138,16 +138,6 @@ void ScanFunctions::checkName(const QStringRef &name, const SourceLocation &loc) } } -bool ScanFunctions::formalsContainName(AST::FormalParameterList *parameters, const QString &name) -{ - while (parameters) { - if (parameters->name == name) - return true; - parameters = parameters->next; - } - return false; -} - bool ScanFunctions::visit(Program *ast) { enterEnvironment(ast, defaultProgramMode); @@ -420,11 +410,11 @@ void ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete outerContext->usesArgumentsObject = Context::ArgumentsObjectNotUsed; } - if (formalsContainName(formals, QStringLiteral("arguments"))) + if (formals->containsName(QStringLiteral("arguments"))) _context->usesArgumentsObject = Context::ArgumentsObjectNotUsed; - if (!name.isEmpty() && !formalsContainName(formals, name)) + if (!name.isEmpty() && !formals->containsName(name)) _context->addLocalVar(name, Context::ThisFunctionName, QQmlJS::AST::VariableDeclaration::FunctionScope); _context->formals = formals; @@ -433,28 +423,26 @@ void ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete bool isSimpleParameterList = formals->isSimpleParameterList(); - for (FormalParameterList *it = formals; it; it = it->next) { - QString arg = it->name.toString(); - int duplicateIndex = _context->arguments.indexOf(arg); - if (duplicateIndex != -1) { - if (_context->isStrict || !isSimpleParameterList) { - _cg->throwSyntaxError(it->identifierToken, QStringLiteral("Duplicate parameter name '%1' is not allowed.").arg(arg)); + _context->arguments = formals->formals(); + + const QStringList boundNames = formals->boundNames(); + for (int i = 0; i < boundNames.size(); ++i) { + const QString &arg = boundNames.at(i); + if (_context->isStrict || !isSimpleParameterList) { + bool duplicate = (boundNames.indexOf(arg, i + 1) != -1); + if (duplicate) { + _cg->throwSyntaxError(formals->firstSourceLocation(), QStringLiteral("Duplicate parameter name '%1' is not allowed.").arg(arg)); return; - } else { - // change the name of the earlier argument to enforce the specified lookup semantics - QString modified = arg; - while (_context->arguments.contains(modified)) - modified += QString(0xfffe); - _context->arguments[duplicateIndex] = modified; } } if (_context->isStrict) { if (arg == QLatin1String("eval") || arg == QLatin1String("arguments")) { - _cg->throwSyntaxError(it->identifierToken, QStringLiteral("'%1' cannot be used as parameter name in strict mode").arg(arg)); + _cg->throwSyntaxError(formals->firstSourceLocation(), QStringLiteral("'%1' cannot be used as parameter name in strict mode").arg(arg)); return; } } - _context->arguments += arg; + if (!_context->arguments.contains(arg)) + _context->addLocalVar(arg, Context::VariableDefinition, QQmlJS::AST::VariableDeclaration::FunctionScope); } } diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h index 0494a3248d..0767b25094 100644 --- a/src/qml/compiler/qv4compilerscanfunctions_p.h +++ b/src/qml/compiler/qv4compilerscanfunctions_p.h @@ -98,7 +98,6 @@ protected: void checkDirectivePrologue(AST::SourceElements *ast); void checkName(const QStringRef &name, const AST::SourceLocation &loc); - bool formalsContainName(AST::FormalParameterList *parameters, const QString &name); bool visit(AST::Program *ast) override; void endVisit(AST::Program *) override; diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index 801e9bc5f9..376edb9f85 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -273,6 +273,8 @@ public: AST::Block *Block; AST::VariableDeclaration *VariableDeclaration; AST::VariableDeclarationList *VariableDeclarationList; + AST::BindingElement *BindingElement; + AST::BindingPropertyList *BindingPropertyList; AST::UiProgram *UiProgram; AST::UiHeaderItemList *UiHeaderItemList; @@ -1598,6 +1600,15 @@ case $rule_number: { } break; ./ +ElisionOpt: ; +/. +case $rule_number: { + sym(1).Node = nullptr; +} break; +./ + +ElisionOpt: Elision ; + PropertyAssignment: PropertyName T_COLON AssignmentExpression ; /. case $rule_number: { @@ -2669,6 +2680,8 @@ case $rule_number: { } break; ./ +-- VariableDeclaration: BindingPattern InitializerOpt ; + VariableDeclarationNotIn: JsIdentifier InitializerNotInOpt ; /. case $rule_number: { @@ -2679,6 +2692,8 @@ case $rule_number: { } break; ./ +-- VariableDeclarationNotIn: BindingPattern InitializerNotInOpt ; + Initializer: T_EQ AssignmentExpression ; /. case $rule_number: { @@ -3128,51 +3143,123 @@ case $rule_number: { } break; ./ -FormalParameterList: FunctionRestParameter ; +FormalsList: BindingElement ; +/. case $rule_number: ./ -FormalParameterList: FormalsList ; +FormalParameterList: BindingRestElement ; +/. +case $rule_number: { + AST::FormalParameterList *node = new (pool) AST::FormalParameterList(nullptr, sym(1).Node); + sym(1).Node = node; +} break; +./ -FormalsList: FormalParameter ; +FormalParameterList: FormalsList ; -FormalParameterList: FormalsList T_COMMA FunctionRestParameter ; +FormalParameterList: FormalsList T_COMMA BindingRestElement ; /. case $rule_number: ./ -FormalsList: FormalsList T_COMMA FormalParameter ; +FormalsList: FormalsList T_COMMA BindingElement ; /. case $rule_number: { - sym(1).FormalParameterList = sym(1).FormalParameterList->append(sym(3).FormalParameterList); + AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, sym(3).Node); + sym(1).Node = node; } break; ./ -FunctionRestParameter: BindingRestElement ; -FormalParameter: BindingElement ; - BindingRestElement: T_ELLIPSIS BindingIdentifier ; /. case $rule_number: { - AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(2)); + AST::BindingRestElement *node = new (pool) AST::BindingRestElement(stringRef(2)); node->identifierToken = loc(2); - node->isRest = true; sym(1).Node = node; } break; ./ -BindingElement: SingleNameBinding ; --- BindingElement: BindingPattern InitializerOpt ; +BindingRestElementOpt: ; +BindingRestElementOpt: BindingRestElement ; --- BindingPattern: ObjectBindingPattern ; --- BindingPattern: ArrayBindingPattern ; - -SingleNameBinding: BindingIdentifier InitializerOpt ; +BindingElement: BindingIdentifier InitializerOpt ; /. case $rule_number: { - AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1)); + AST::BindingElement *node = new (pool) AST::BindingElement(stringRef(1), sym(2).Expression); node->identifierToken = loc(1); - node->initializer = sym(2).Expression; sym(1).Node = node; } break; ./ +BindingElement: BindingPattern InitializerOpt ; +/. +case $rule_number: { + AST::BindingElement *node = new (pool) AST::BindingElement(sym(1).Node, sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; +./ + +BindingPattern: ObjectBindingPattern ; + +BindingPattern: ArrayBindingPattern ; +/. +case $rule_number: { + AST::BindingElementList *node = new (pool) AST::BindingElementList(); + node->loc = loc(1); + sym(1).Node = node; +} break; +./ + +ObjectBindingPattern: T_LBRACE T_RBRACE ; +/. +case $rule_number: { + sym(1).Node = nullptr; +} break; +./ + +ObjectBindingPattern: T_LBRACE BindingPropertyList T_RBRACE ; +/. case $rule_number: ./ +ObjectBindingPattern: T_LBRACE BindingPropertyList T_COMMA T_RBRACE ; +/. +case $rule_number: { + sym(1).Node = sym(2).BindingPropertyList->finish(); +} break; +./ + +ArrayBindingPattern: T_LBRACKET ElisionOpt BindingRestElementOpt T_RBRACKET ; +ArrayBindingPattern: T_LBRACKET BindingElementList T_RBRACKET ; +ArrayBindingPattern: T_LBRACKET BindingElementList T_COMMA ElisionOpt BindingRestElementOpt T_RBRACKET ; + +BindingPropertyList: BindingProperty ; + +BindingPropertyList: BindingPropertyList T_COMMA BindingProperty ; +/. +case $rule_number: { + sym(1).Node = sym(1).BindingPropertyList->append(sym(3).BindingPropertyList); +} break; +./ + +BindingElementList: BindingElisionElement ; +BindingElementList: BindingElementList T_COMMA BindingElisionElement ; + +BindingElisionElement: ElisionOpt BindingElement ; + +BindingProperty: BindingIdentifier InitializerOpt ; +/. +case $rule_number: { + AST::StringLiteralPropertyName *name = new (pool) AST::StringLiteralPropertyName(stringRef(1)); + AST::BindingElement *e = new (pool) AST::BindingElement(stringRef(1), sym(2).Expression); + AST::BindingPropertyList *node = new (pool) AST::BindingPropertyList(name, e); + sym(1).Node = node; +} break; +./ + +BindingProperty: PropertyName T_COLON BindingElement ; +/. +case $rule_number: { + AST::BindingPropertyList *node = new (pool) AST::BindingPropertyList(sym(1).PropertyName, sym(3).BindingElement); + sym(1).Node = node; +} break; +./ + BindingIdentifier: JsIdentifier; FunctionBodyOpt: ; diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index b29450c1df..60064319c9 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -762,6 +762,41 @@ void FunctionExpression::accept0(Visitor *visitor) visitor->endVisit(this); } +QStringList FormalParameterList::formals() const +{ + QStringList formals; + int i = 0; + for (const FormalParameterList *it = this; it; it = it->next) { + QString name; + if (QQmlJS::AST::BindingElement *b = it->bindingElement()) { + name = b->name; + } else if (QQmlJS::AST::BindingRestElement *r = it->bindingRestElement()) { + name = r->name.toString(); + } + int duplicateIndex = formals.indexOf(name); + if (duplicateIndex >= 0) { + // change the name of the earlier argument to enforce the lookup semantics from the spec + formals[duplicateIndex] += QLatin1String("#") + QString::number(i); + } + formals += name; + ++i; + } + return formals; +} + +QStringList FormalParameterList::boundNames() const +{ + QStringList names; + for (const FormalParameterList *it = this; it; it = it->next) { + if (QQmlJS::AST::BindingElement *b = it->bindingElement()) { + b->boundNames(&names); + } else if (QQmlJS::AST::BindingRestElement *r = it->bindingRestElement()) { + names += r->name.toString(); + } + } + return names; +} + void FormalParameterList::accept0(Visitor *visitor) { if (visitor->visit(this)) { @@ -771,6 +806,23 @@ void FormalParameterList::accept0(Visitor *visitor) visitor->endVisit(this); } +FormalParameterList *FormalParameterList::finish() +{ + FormalParameterList *front = next; + next = nullptr; + + int i = 0; + for (const FormalParameterList *it = this; it; it = it->next) { + QString name; + if (QQmlJS::AST::BindingElement *b = it->bindingElement()) { + if (b->name.isEmpty()) + name = QLatin1String("arg#") + QString::number(i); + } + ++i; + } + return front; +} + void FunctionBody::accept0(Visitor *visitor) { if (visitor->visit(this)) { @@ -1003,6 +1055,63 @@ void TaggedTemplate::accept0(Visitor *visitor) visitor->endVisit(this); } +void BindingRestElement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void BindingElement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(initializer, visitor); + } + + visitor->endVisit(this); +} + +void BindingElement::boundNames(QStringList *names) +{ + if (binding) { + if (BindingElementList *e = elementList()) + e->boundNames(names); + else if (BindingPropertyList *p = propertyList()) + p->boundNames(names); + } else + names->append(name); +} + +void BindingElementList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void BindingElementList::boundNames(QStringList *names) +{ + // ### + Q_UNUSED(names); + +} + +void BindingPropertyList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void BindingPropertyList::boundNames(QStringList *names) +{ + for (BindingPropertyList *it = this; it; it = it->next) + it->binding->boundNames(names); +} + } } // namespace QQmlJS::AST QT_QML_END_NAMESPACE diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index 36eabec82e..6142b00712 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -205,6 +205,10 @@ public: Kind_WhileStatement, Kind_WithStatement, Kind_NestedExpression, + Kind_BindingElement, + Kind_BindingElementList, + Kind_BindingPropertyList, + Kind_BindingRestElement, Kind_UiArrayBinding, Kind_UiImport, @@ -2064,6 +2068,119 @@ public: SourceLocation rbraceToken; }; +class QML_PARSER_EXPORT BindingRestElement : public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(BindingRestElement) + + BindingRestElement(const QStringRef &n) + : name(n) + { kind = K; } + + void accept0(Visitor *visitor) override; + + SourceLocation firstSourceLocation() const override + { return identifierToken; } + + SourceLocation lastSourceLocation() const override + { return identifierToken; } + +// attributes + SourceLocation identifierToken; + QStringRef name; +}; + +class QML_PARSER_EXPORT BindingElement : public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(BindingElement) + + BindingElement(const QStringRef &n, ExpressionNode *i = nullptr) + : name(n.toString()), initializer(i) + { kind = K; } + + BindingElement(Node *binding, ExpressionNode *i = nullptr) + : binding(binding), initializer(i) + { kind = K; } + + void accept0(Visitor *visitor) override; + + SourceLocation firstSourceLocation() const override + { return identifierToken; } + + SourceLocation lastSourceLocation() const override + { return initializer ? initializer->lastSourceLocation() : (binding ? binding->lastSourceLocation() : identifierToken); } + + BindingElementList *elementList() const { return cast<BindingElementList *>(binding); } + BindingPropertyList *propertyList() const { return cast<BindingPropertyList *>(binding); } + + void boundNames(QStringList *names); + +// attributes + SourceLocation identifierToken; + Node *binding = nullptr; + QString name; + ExpressionNode *initializer = nullptr; +}; + +class QML_PARSER_EXPORT BindingElementList : public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(BindingElementList) + + BindingElementList() + { kind = K; } + + void accept0(Visitor *visitor) override; + + void boundNames(QStringList *names); + + SourceLocation firstSourceLocation() const override + { return loc; } + + SourceLocation lastSourceLocation() const override + { return loc; } + + SourceLocation loc; +}; + +class QML_PARSER_EXPORT BindingPropertyList : public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(BindingPropertyList) + + BindingPropertyList(PropertyName *n, BindingElement *e) + : propertyName(n), binding(e), next(this) + { kind = K; } + + void accept0(Visitor *visitor) override; + + void boundNames(QStringList *names); + + BindingPropertyList *append(BindingPropertyList *n) { + n->next = next; + next = n; + return n; + } + + inline BindingPropertyList *finish () + { + BindingPropertyList *front = next; + next = 0; + return front; + } + + SourceLocation firstSourceLocation() const override + { return propertyName->firstSourceLocation(); } + + SourceLocation lastSourceLocation() const override + { return next ? next->lastSourceLocation() : binding->lastSourceLocation(); } + + PropertyName *propertyName; + BindingElement *binding; + BindingPropertyList *next; +}; + class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression { public: @@ -2081,16 +2198,16 @@ class QML_PARSER_EXPORT FormalParameterList: public Node public: QQMLJS_DECLARE_AST_NODE(FormalParameterList) - FormalParameterList(const QStringRef &n) - : name(n), next(this) - { kind = K; } - - FormalParameterList(FormalParameterList *previous, const QStringRef &n): - name (n) + FormalParameterList(FormalParameterList *previous, Node *p) + : param(p) { kind = K; - next = previous->next; - previous->next = this; + if (previous) { + next = previous->next; + previous->next = this; + } else { + next = this; + } } FormalParameterList *append(FormalParameterList *n) { @@ -2099,39 +2216,60 @@ public: return n; } + BindingRestElement *bindingRestElement() const { + return cast<BindingRestElement *>(param); + } + + BindingElement *bindingElement() const { + return cast<BindingElement *>(param); + } + bool isSimpleParameterList() { AST::FormalParameterList *formals = this; while (formals) { - if (formals->isRest || formals->initializer) + if (formals->bindingRestElement()) + return false; + BindingElement *e = formals->bindingElement(); + Q_ASSERT(e); + if (e->initializer || e->binding) return false; formals = formals->next; } return true; } + bool containsName(const QString &name) const { + for (const FormalParameterList *it = this; it; it = it->next) { + if (QQmlJS::AST::BindingElement *b = it->bindingElement()) { + // ### handle binding patterns + if (b->name == name) + return true; + } else if (QQmlJS::AST::BindingRestElement *r = it->bindingRestElement()) { + if (r->name == name) + return true; + } + } + return false; + } + + QStringList formals() const; + + QStringList boundNames() const; void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override - { return identifierToken; } + { return param->firstSourceLocation(); } SourceLocation lastSourceLocation() const override - { return next ? next->lastSourceLocation() : identifierToken; } + { return next ? next->lastSourceLocation() : param->lastSourceLocation(); } - inline FormalParameterList *finish () - { - FormalParameterList *front = next; - next = nullptr; - return front; - } + FormalParameterList *finish(); // attributes - QStringRef name; - bool isRest = false; - ExpressionNode *initializer = nullptr; + Node *param = nullptr; FormalParameterList *next; - SourceLocation identifierToken; }; class QML_PARSER_EXPORT SourceElement: public Node diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h index 1aa285697f..7a8bdf1b63 100644 --- a/src/qml/parser/qqmljsastfwd_p.h +++ b/src/qml/parser/qqmljsastfwd_p.h @@ -164,6 +164,11 @@ class FunctionSourceElement; class StatementSourceElement; class DebuggerStatement; class NestedExpression; +class BindingElement; +class BindingElementList; +class BindingPropertyList; +class BindingElement; +class BindingRestElement; // ui elements class UiProgram; diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index 534cc9bd6d..d0b9cc24bc 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -320,6 +320,18 @@ public: virtual bool visit(FunctionExpression *) { return true; } virtual void endVisit(FunctionExpression *) {} + virtual bool visit(BindingElement *) { return true; } + virtual void endVisit(BindingElement *) {} + + virtual bool visit(BindingElementList *) { return true; } + virtual void endVisit(BindingElementList *) {} + + virtual bool visit(BindingPropertyList *) { return true; } + virtual void endVisit(BindingPropertyList *) {} + + virtual bool visit(BindingRestElement *) { return true; } + virtual void endVisit(BindingRestElement *) {} + virtual bool visit(FormalParameterList *) { return true; } virtual void endVisit(FormalParameterList *) {} |