aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler
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/qml/compiler
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/qml/compiler')
-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
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 &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;