From 1f85383957abbc6863a8c75e9be7acbf08c6c2ad Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Sat, 26 May 2018 19:19:57 +0200 Subject: qv4arrayobject: Implement Array.of from ES7 One small difficulty: We can't accurately tell whether a thisObject is a constructor or not, so right now we're just swallowing all exceptions and creating an array if they occur. This isn't correct, but it isn't trivial to fix, either: I think we would have to somehow mark our builtins that are constructors, and allow those, but use the array fallback for other builtins, calling user functions and bubbling up if they throw. This is probably good enough for the time being though, as writing something like: function Test() { throw "Foo"; } Array.of.call(Test) ... is probably not very likely, compared to more "usual" use. Change-Id: Ied341a7fa9c3a7fd907e2815c019bc431171ce62 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4arrayobject.cpp | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'src/qml/jsruntime/qv4arrayobject.cpp') diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 2c4be85014..ad1558785d 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -95,6 +95,7 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1)); ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); ctor->defineDefaultProperty(QStringLiteral("isArray"), method_isArray, 1); + ctor->defineDefaultProperty(QStringLiteral("of"), method_of, 0); ctor->addSymbolSpecies(); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); @@ -138,6 +139,50 @@ ReturnedValue ArrayPrototype::method_isArray(const FunctionObject *, const Value return Encode(isArray); } +ReturnedValue ArrayPrototype::method_of(const FunctionObject *builtin, const Value *thisObject, const Value *argv, int argc) +{ + Scope scope(builtin); + ScopedObject object(scope, Primitive::undefinedValue()); + ScopedFunctionObject that(scope, thisObject); + + if (that) { + // ### the spec says that we should only call constructors if + // IsConstructor(that), but we have no way of knowing if a builtin is a + // constructor. so for the time being, just try call it, and silence any + // exceptions-- this is not ideal, as the spec also says that we should + // return on exception. + ScopedValue argument(scope, QV4::Encode(argc)); + object = ScopedObject(scope, that->callAsConstructor(argument, 1)); + if (scope.engine->hasException) { + scope.engine->catchException(); // probably not a constructor, then. + } + } + + if (!object) { + object = ScopedObject(scope, scope.engine->newArrayObject()); + CHECK_EXCEPTION(); + } + + int k = 0; + while (k < argc) { + if (object->hasOwnProperty(k)) { + return scope.engine->throwTypeError(QString::fromLatin1("Cannot redefine property: %1").arg(k)); + } + object->arraySet(k, argv[k]); + CHECK_EXCEPTION(); + + k++; + } + + // ArrayObject updates its own length, and will throw if we try touch it. + if (!object->as()) { + object->set(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(argc)), QV4::Object::DoThrowOnRejection); + CHECK_EXCEPTION(); + } + + return object.asReturnedValue(); +} + ReturnedValue ArrayPrototype::method_toString(const FunctionObject *builtin, const Value *thisObject, const Value *argv, int argc) { Scope scope(builtin); -- cgit v1.2.3