diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-06-14 10:12:20 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-06-21 19:43:32 +0000 |
commit | 99d8808bc5b85d54e8e735953a27a0c0c788f10e (patch) | |
tree | 9d4ea0fb0bcaee583c7b8510ca92d4b6c744a70c /src/qml/jsruntime/qv4runtime.cpp | |
parent | 6969aa5932f0eb7171dea2b4da39c21d1c09cc60 (diff) |
Add support for function calls with spread
Function calls with thread are modelled by pushing
an empty value in front of every argument that
requires spreading. The runtime methods callWithSpread
and constructWithSpread then take care of spreading
out the arguments.
Change-Id: Ie877c59d3d9d08fc5f20d7befb7153c7b716bf30
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4runtime.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 4c2477ded2..4e782fea00 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1256,6 +1256,60 @@ ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engi return fo->call(qmlContextValue, argv, argc); } +struct CallArgs { + Value *argv; + int argc; +}; + +static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc) +{ + ScopedValue it(scope); + ScopedValue done(scope); + + int argCount = 0; + + Value *v = scope.alloc<Scope::Uninitialized>(); + Value *arguments = v; + for (int i = 0; i < argc; ++i) { + if (!argv[i].isEmpty()) { + *v = argv[i]; + ++argCount; + v = scope.alloc<Scope::Uninitialized>(); + continue; + } + // spread element + ++i; + it = Runtime::method_getIterator(scope.engine, argv[i], /* ForInIterator */ 1); + if (scope.engine->hasException) + return { nullptr, 0 }; + while (1) { + done = Runtime::method_iteratorNext(scope.engine, it, v); + if (scope.engine->hasException) + return { nullptr, 0 }; + Q_ASSERT(done->isBoolean()); + if (done->booleanValue()) + break; + ++argCount; + v = scope.alloc<Scope::Uninitialized>(); + } + } + return { arguments, argCount }; +} + +ReturnedValue Runtime::method_callWithSpread(ExecutionEngine *engine, const Value &function, const Value &thisObject, Value *argv, int argc) +{ + Q_ASSERT(argc >= 1); + if (!function.isFunctionObject()) + return engine->throwTypeError(); + + Scope scope(engine); + CallArgs arguments = createSpreadArguments(scope, argv, argc); + if (engine->hasException) + return Encode::undefined(); + + return static_cast<const FunctionObject &>(function).call(&thisObject, arguments.argv, arguments.argc); +} + ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &function, Value *argv, int argc) { if (!function.isFunctionObject()) @@ -1264,6 +1318,20 @@ ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &fu return static_cast<const FunctionObject &>(function).callAsConstructor(argv, argc); } +ReturnedValue Runtime::method_constructWithSpread(ExecutionEngine *engine, const Value &function, Value *argv, int argc) +{ + Q_UNIMPLEMENTED(); + if (!function.isFunctionObject()) + return engine->throwTypeError(); + + Scope scope(engine); + CallArgs arguments = createSpreadArguments(scope, argv, argc); + if (engine->hasException) + return Encode::undefined(); + + return static_cast<const FunctionObject &>(function).callAsConstructor(arguments.argv, arguments.argc); +} + void Runtime::method_throwException(ExecutionEngine *engine, const Value &value) { if (!value.isEmpty()) |