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/qml/compiler | |
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/qml/compiler')
-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 |
8 files changed, 95 insertions, 57 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; |