aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-06-06 13:55:10 +0200
committerLars Knoll <lars.knoll@qt.io>2018-06-21 19:43:16 +0000
commit0363f0f4f8870db20c630cd2af94e0b05255d036 (patch)
tree9ab1a3e3abcf349b232f947907c17efaaa19d977 /src
parent73fdeb9c1c70079e54104c93811b5d7ff9e4ee0b (diff)
Add support for spread expressions in Array literals
Change-Id: I613d853dbb34d86ebedd871e9676d3206f1e3349 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/compiler/qv4codegen.cpp170
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp5
2 files changed, 140 insertions, 35 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index b3b522e661..e39bb61688 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -831,53 +831,155 @@ bool Codegen::visit(ArrayPattern *ast)
if (hasError)
return false;
- RegisterScope scope(this);
+ PatternElementList *it = ast->elements;
int argc = 0;
- int args = -1;
- auto push = [this, &argc, &args](AST::ExpressionNode *arg) {
- int temp = bytecodeGenerator->newRegister();
- if (args == -1)
- args = temp;
- if (!arg) {
- auto c = Reference::fromConst(this, Primitive::emptyValue().asReturnedValue());
- (void) c.storeOnStack(temp);
- } else {
- RegisterScope scope(this);
- Reference r = expression(arg);
+ {
+ RegisterScope scope(this);
+
+ int args = -1;
+ auto push = [this, &argc, &args](AST::ExpressionNode *arg) {
+ int temp = bytecodeGenerator->newRegister();
+ if (args == -1)
+ args = temp;
+ if (!arg) {
+ auto c = Reference::fromConst(this, Primitive::emptyValue().asReturnedValue());
+ (void) c.storeOnStack(temp);
+ } else {
+ RegisterScope scope(this);
+ Reference r = expression(arg);
+ if (hasError)
+ return;
+ (void) r.storeOnStack(temp);
+ }
+ ++argc;
+ };
+
+ for (; it; it = it->next) {
+ PatternElement *e = it->element;
+ if (e && e->type == PatternElement::SpreadElement)
+ break;
+ for (Elision *elision = it->elision; elision; elision = elision->next)
+ push(nullptr);
+
+ if (!e)
+ continue;
+
+ push(e->initializer);
if (hasError)
- return;
- (void) r.storeOnStack(temp);
+ return false;
}
- ++argc;
+
+ if (args == -1) {
+ Q_ASSERT(argc == 0);
+ args = 0;
+ }
+
+ Instruction::DefineArray call;
+ call.argc = argc;
+ call.args = Moth::StackSlot::createRegister(args);
+ bytecodeGenerator->addInstruction(call);
+ }
+
+ if (!it) {
+ _expr.setResult(Reference::fromAccumulator(this));
+ return false;
+ }
+ Q_ASSERT(it->element && it->element->type == PatternElement::SpreadElement);
+
+ RegisterScope scope(this);
+ Reference array = Reference::fromStackSlot(this);
+ array.storeConsumeAccumulator();
+ Reference index = Reference::storeConstOnStack(this, Encode(argc));
+
+ auto pushAccumulator = [&]() {
+ Reference slot = Reference::fromSubscript(array, index);
+ slot.storeConsumeAccumulator();
+
+ index.loadInAccumulator();
+ Instruction::Increment inc;
+ bytecodeGenerator->addInstruction(inc);
+ index.storeConsumeAccumulator();
};
- for (PatternElementList *it = ast->elements; it; it = it->next) {
- for (Elision *elision = it->elision; elision; elision = elision->next)
- push(nullptr);
+ while (it) {
+ for (Elision *elision = it->elision; elision; elision = elision->next) {
+ Reference::fromConst(this, Primitive::emptyValue().asReturnedValue()).loadInAccumulator();
+ pushAccumulator();
+ }
- PatternElement *e = it->element;
- if (!e)
+ if (!it->element) {
+ it = it->next;
continue;
- if (e->type == PatternElement::RestElement) {
- throwSyntaxError(it->firstSourceLocation(), QLatin1String("'...' in ArrayLiterals is unimplementd."));
- return false;
}
- push(e->initializer);
- if (hasError)
- return false;
- }
+ // handle spread element
+ if (it->element->type == PatternElement::SpreadElement) {
+ RegisterScope scope(this);
- if (args == -1) {
- Q_ASSERT(argc == 0);
- args = 0;
+ Reference iterator = Reference::fromStackSlot(this);
+ Reference lhsValue = Reference::fromStackSlot(this);
+
+ // There should be a temporal block, so that variables declared in lhs shadow outside vars.
+ // This block should define a temporal dead zone for those variables, which is not yet implemented.
+ {
+ RegisterScope innerScope(this);
+ Reference expr = expression(it->element->initializer);
+ if (hasError)
+ return false;
+
+ expr.loadInAccumulator();
+ Instruction::GetIterator iteratorObjInstr;
+ iteratorObjInstr.iterator = /*ForEachType::Of*/ 1;
+ bytecodeGenerator->addInstruction(iteratorObjInstr);
+ iterator.storeConsumeAccumulator();
+ }
+
+ BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
+ BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
+ BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
+
+ {
+ ControlFlowLoop flow(this, &end, &in, /*requiresUnwind*/ true);
+ bytecodeGenerator->jump().link(in);
+
+ BytecodeGenerator::Label body = bytecodeGenerator->label();
+
+ lhsValue.loadInAccumulator();
+ pushAccumulator();
+
+ in.link();
+ iterator.loadInAccumulator();
+ Instruction::IteratorNext next;
+ next.value = lhsValue.stackSlot();
+ bytecodeGenerator->addInstruction(next);
+ bytecodeGenerator->addJumpInstruction(Instruction::JumpFalse()).link(body);
+ bytecodeGenerator->jump().link(done);
+ }
+
+ end.link();
+
+ Reference iteratorDone = Reference::fromConst(this, Encode(false)).storeOnStack();
+ iterator.loadInAccumulator();
+ Instruction::IteratorClose close;
+ close.done = iteratorDone.stackSlot();
+ bytecodeGenerator->addInstruction(close);
+
+ done.link();
+ } else {
+ RegisterScope innerScope(this);
+ Reference expr = expression(it->element->initializer);
+ if (hasError)
+ return false;
+
+ expr.loadInAccumulator();
+ pushAccumulator();
+ }
+
+ it = it->next;
}
- Instruction::DefineArray call;
- call.argc = argc;
- call.args = Moth::StackSlot::createRegister(args);
- bytecodeGenerator->addInstruction(call);
+ array.loadInAccumulator();
_expr.setResult(Reference::fromAccumulator(this));
return false;
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 73c579f3eb..b879e3fc14 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -745,7 +745,10 @@ ReturnedValue Runtime::method_getIterator(ExecutionEngine *engine, const Value &
if (!f)
return engine->throwTypeError();
JSCallData cData(scope, 0, nullptr, o);
- return f->call(cData);
+ ScopedObject it(scope, f->call(cData));
+ if (!it)
+ return engine->throwTypeError();
+ return it->asReturnedValue();
}
return engine->newForInIteratorObject(o)->asReturnedValue();
}