aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4runtime.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-05-31 16:06:34 +0200
committerLars Knoll <lars.knoll@qt.io>2018-09-07 10:32:01 +0000
commitff5bc526b4868aef9fb3a551afc5636b308a3d83 (patch)
tree692e956d6fcfd5fc4f064dce7275abeb51429c3a /src/qml/jsruntime/qv4runtime.cpp
parentbd4064eabf79a6166805c877ee622931df6fb172 (diff)
Add support for yield*
Change-Id: I5b054b59519ed825459a5b0b0a7cd2c6fc8a3797 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4runtime.cpp')
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 59fff91e7b..b59b9c3f50 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -782,6 +782,78 @@ ReturnedValue Runtime::method_iteratorNext(ExecutionEngine *engine, const Value
return Encode(false);
}
+ReturnedValue Runtime::method_iteratorNextForYieldStar(ExecutionEngine *engine, const Value &received, const Value &iterator, Value *object)
+{
+ // the return value encodes how to continue the yield* iteration.
+ // true implies iteration is done, false for iteration to continue
+ // a return value of undefines is a special marker, that the iterator has been invoked with return()
+
+ Scope scope(engine);
+ Q_ASSERT(iterator.isObject());
+
+ const Value *arg = &received;
+ bool returnCalled = false;
+ FunctionObject *f = nullptr;
+ if (engine->hasException) {
+ if (engine->exceptionValue->isEmpty()) {
+ // generator called with return()
+ *engine->exceptionValue = Encode::undefined();
+ engine->hasException = false;
+
+ ScopedValue ret(scope, static_cast<const Object &>(iterator).get(engine->id_return()));
+ if (ret->isUndefined()) {
+ // propagate return()
+ return Encode::undefined();
+ }
+ returnCalled = true;
+ f = ret->as<FunctionObject>();
+ } else {
+ // generator called with throw
+ ScopedValue exceptionValue(scope, *engine->exceptionValue);
+ *engine->exceptionValue = Encode::undefined();
+ engine->hasException = false;
+
+ ScopedValue t(scope, static_cast<const Object &>(iterator).get(engine->id_throw()));
+ if (engine->hasException)
+ return Encode::undefined();
+ if (t->isUndefined()) {
+ // no throw method on the iterator
+ ScopedValue done(scope, Encode(false));
+ method_iteratorClose(engine, iterator, done);
+ if (engine->hasException)
+ return Encode::undefined();
+ return engine->throwTypeError();
+ }
+ f = t->as<FunctionObject>();
+ arg = exceptionValue;
+ }
+ } else {
+ // generator called with next()
+ ScopedFunctionObject next(scope, static_cast<const Object &>(iterator).get(engine->id_next()));
+ f = next->as<FunctionObject>();
+ }
+
+ if (!f)
+ return engine->throwTypeError();
+
+ ScopedObject o(scope, f->call(&iterator, arg, 1));
+ if (scope.hasException())
+ return Encode(true);
+ if (!o)
+ return engine->throwTypeError();
+
+ ScopedValue d(scope, o->get(engine->id_done()));
+ if (scope.hasException())
+ return Encode(true);
+ bool done = d->toBoolean();
+ if (done) {
+ *object = o->get(engine->id_value());
+ return returnCalled ? Encode::undefined() : Encode(true);
+ }
+ *object = o;
+ return Encode(false);
+}
+
ReturnedValue Runtime::method_iteratorClose(ExecutionEngine *engine, const Value &iterator, const Value &done)
{
Q_ASSERT(iterator.isObject());