aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-02-10 23:22:13 +0100
committerLars Knoll <lars.knoll@qt.io>2018-04-25 17:49:38 +0000
commitda5fffbd34d8be68f8ee4c649881dbb673c9c0a5 (patch)
tree2c4647732d8754f0c9b8573875cb5936639320ca /src
parente91d0091e0778ad1379f40d97daa704515bec3d4 (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.cpp11
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp6
-rw-r--r--src/qml/compiler/qv4codegen.cpp68
-rw-r--r--src/qml/compiler/qv4codegen_p.h6
-rw-r--r--src/qml/compiler/qv4compileddata.cpp15
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h5
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp40
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h1
-rw-r--r--src/qml/parser/qqmljs.g125
-rw-r--r--src/qml/parser/qqmljsast.cpp109
-rw-r--r--src/qml/parser/qqmljsast_p.h180
-rw-r--r--src/qml/parser/qqmljsastfwd_p.h5
-rw-r--r--src/qml/parser/qqmljsastvisitor_p.h12
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 &param : 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 *) {}