diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-07-30 22:08:39 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-07-30 20:44:55 +0000 |
commit | 26f2eabe2847a3c98d7b84b09531ff82b13fcd67 (patch) | |
tree | 4369d83ae99ec2d986ada1effb38fda8a97cc49c | |
parent | 1cde99fbafe035cbd88237d8e0a3b52b780f68af (diff) |
Add support for @@unscopables
See ES7 spec, chapter 22.1.3.32
Change-Id: Ibe7df71cbc1bc848e205b9ca682f24841adfa2d9
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r-- | src/qml/jsruntime/qv4arrayobject.cpp | 35 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4context.cpp | 91 | ||||
-rw-r--r-- | tests/auto/qml/ecmascripttests/TestExpectations | 11 |
3 files changed, 106 insertions, 31 deletions
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 4dbb61298e..450916fbf7 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -100,15 +100,34 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) ctor->defineDefaultProperty(QStringLiteral("from"), method_from, 1); ctor->addSymbolSpecies(); + ScopedObject unscopables(scope, engine->newObject(engine->classes[EngineBase::Class_Empty]->changeVTable(QV4::Object::staticVTable()))); + ScopedString name(scope); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); defineDefaultProperty(QStringLiteral("concat"), method_concat, 1); - defineDefaultProperty(QStringLiteral("copyWithin"), method_copyWithin, 2); - defineDefaultProperty(QStringLiteral("entries"), method_entries, 0); - defineDefaultProperty(QStringLiteral("find"), method_find, 1); - defineDefaultProperty(QStringLiteral("findIndex"), method_findIndex, 1); + name = engine->newIdentifier(QStringLiteral("copyWithin")); + unscopables->put(name, Primitive::fromBoolean(true)); + defineDefaultProperty(name, method_copyWithin, 2); + name = engine->newIdentifier(QStringLiteral("entries")); + unscopables->put(name, Primitive::fromBoolean(true)); + defineDefaultProperty(name, method_entries, 0); + name = engine->newIdentifier(QStringLiteral("fill")); + unscopables->put(name, Primitive::fromBoolean(true)); + defineDefaultProperty(name, method_fill, 1); + name = engine->newIdentifier(QStringLiteral("find")); + unscopables->put(name, Primitive::fromBoolean(true)); + defineDefaultProperty(name, method_find, 1); + name = engine->newIdentifier(QStringLiteral("findIndex")); + unscopables->put(name, Primitive::fromBoolean(true)); + defineDefaultProperty(name, method_findIndex, 1); + name = engine->newIdentifier(QStringLiteral("includes")); + unscopables->put(name, Primitive::fromBoolean(true)); + defineDefaultProperty(name, method_includes, 1); defineDefaultProperty(QStringLiteral("join"), method_join, 1); + name = engine->newIdentifier(QStringLiteral("keys")); + unscopables->put(name, Primitive::fromBoolean(true)); + defineDefaultProperty(name, method_keys, 0); defineDefaultProperty(QStringLiteral("pop"), method_pop, 0); defineDefaultProperty(QStringLiteral("push"), method_push, 1); defineDefaultProperty(QStringLiteral("reverse"), method_reverse, 0); @@ -117,12 +136,9 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("sort"), method_sort, 1); defineDefaultProperty(QStringLiteral("splice"), method_splice, 2); defineDefaultProperty(QStringLiteral("unshift"), method_unshift, 1); - defineDefaultProperty(QStringLiteral("includes"), method_includes, 1); defineDefaultProperty(QStringLiteral("indexOf"), method_indexOf, 1); - defineDefaultProperty(QStringLiteral("keys"), method_keys, 0); defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1); defineDefaultProperty(QStringLiteral("every"), method_every, 1); - defineDefaultProperty(QStringLiteral("fill"), method_fill, 1); defineDefaultProperty(QStringLiteral("some"), method_some, 1); defineDefaultProperty(QStringLiteral("forEach"), method_forEach, 1); defineDefaultProperty(QStringLiteral("map"), method_map, 1); @@ -132,8 +148,11 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) ScopedString valuesString(scope, engine->newIdentifier(QStringLiteral("values"))); ScopedObject values(scope, FunctionObject::createBuiltinFunction(engine, valuesString, method_values, 0)); engine->jsObjects[ExecutionEngine::ArrayProtoValues] = values; - defineDefaultProperty(QStringLiteral("values"), values); + unscopables->put(valuesString, Primitive::fromBoolean(true)); + defineDefaultProperty(valuesString, values); defineDefaultProperty(engine->symbol_iterator(), values); + + defineReadonlyConfigurableProperty(engine->symbol_unscopables(), unscopables); } ReturnedValue ArrayPrototype::method_isArray(const FunctionObject *, const Value *, const Value *argv, int argc) diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index bb08d2786d..327e7b78c4 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -49,6 +49,7 @@ #include "qv4string_p.h" #include "qv4qmlcontext_p.h" #include "qv4stackframe_p.h" +#include "qv4symbol_p.h" using namespace QV4; @@ -189,11 +190,27 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) scope.engine->throwTypeError(); } +static bool unscopable(ExecutionEngine *engine, Heap::Object *withObject, PropertyKey id) +{ + if (!withObject) + return false; + Scope scope(engine); + ScopedObject w(scope, withObject); + ScopedObject o(scope, w->get(scope.engine->symbol_unscopables())); + if (o) { + ScopedValue blocked(scope, o->get(id)); + return blocked->toBoolean(); + } + return false; +} + bool ExecutionContext::deleteProperty(String *name) { PropertyKey id = name->toPropertyKey(); Heap::ExecutionContext *ctx = d(); + ExecutionEngine *engine = ctx->internalClass->engine; + for (; ctx; ctx = ctx->outer) { switch (ctx->type) { case Heap::ExecutionContext::Type_BlockContext: @@ -205,13 +222,27 @@ bool ExecutionContext::deleteProperty(String *name) return false; Q_FALLTHROUGH(); } - case Heap::ExecutionContext::Type_WithContext: + case Heap::ExecutionContext::Type_WithContext: { + if (ctx->activation) { + Scope scope(this); + ScopedObject object(scope, ctx->activation); + if (object && object->hasProperty(id)) { + bool u = ::unscopable(engine, ctx->activation, id); + if (engine->hasException) + return false; + if (u) + break; + return object->deleteProperty(id); + } + } + break; + } case Heap::ExecutionContext::Type_GlobalContext: { if (ctx->activation) { Scope scope(this); ScopedObject object(scope, ctx->activation); - if (object && object->hasProperty(name->toPropertyKey())) - return object->deleteProperty(name->toPropertyKey()); + if (object && object->hasProperty(id)) + return object->deleteProperty(id); } break; } @@ -221,22 +252,27 @@ bool ExecutionContext::deleteProperty(String *name) } } - return !engine()->currentStackFrame->v4Function->isStrict(); + return !engine->currentStackFrame->v4Function->isStrict(); } ExecutionContext::Error ExecutionContext::setProperty(String *name, const Value &value) { PropertyKey id = name->toPropertyKey(); - QV4::ExecutionEngine *v4 = engine(); Heap::ExecutionContext *ctx = d(); + QV4::ExecutionEngine *engine = ctx->internalClass->engine; for (; ctx; ctx = ctx->outer) { switch (ctx->type) { case Heap::ExecutionContext::Type_WithContext: { - Scope scope(v4); + Scope scope(engine); ScopedObject w(scope, ctx->activation); - if (w->hasProperty(name->toPropertyKey())) { + if (w->hasProperty(id)) { + bool u = ::unscopable(engine, ctx->activation, id); + if (engine->hasException) + return TypeError; + if (u) + break; if (!w->put(name, value)) return TypeError; return NoError; @@ -248,7 +284,7 @@ ExecutionContext::Error ExecutionContext::setProperty(String *name, const Value Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx); uint index = c->internalClass->find(id); if (index < UINT_MAX) { - static_cast<Heap::CallContext *>(c)->locals.set(v4, index, value); + static_cast<Heap::CallContext *>(c)->locals.set(engine, index, value); return NoError; } } @@ -257,7 +293,7 @@ ExecutionContext::Error ExecutionContext::setProperty(String *name, const Value if (ctx->activation) { uint member = ctx->activation->internalClass->find(id); if (member < UINT_MAX) { - Scope scope(v4); + Scope scope(engine); ScopedObject a(scope, ctx->activation); if (!a->putValue(member, value)) return TypeError; @@ -266,7 +302,7 @@ ExecutionContext::Error ExecutionContext::setProperty(String *name, const Value } break; case Heap::ExecutionContext::Type_QmlContext: { - Scope scope(v4); + Scope scope(engine); ScopedObject activation(scope, ctx->activation); if (!activation->put(name, value)) return TypeError; @@ -284,6 +320,8 @@ ReturnedValue ExecutionContext::getProperty(String *name) PropertyKey id = name->toPropertyKey(); Heap::ExecutionContext *ctx = d(); + QV4::ExecutionEngine *engine = ctx->internalClass->engine; + for (; ctx; ctx = ctx->outer) { switch (ctx->type) { case Heap::ExecutionContext::Type_BlockContext: @@ -296,6 +334,19 @@ ReturnedValue ExecutionContext::getProperty(String *name) Q_FALLTHROUGH(); } case Heap::ExecutionContext::Type_WithContext: + if (ctx->activation) { + Scope scope(this); + ScopedObject activation(scope, ctx->activation); + if (activation->hasProperty(id)) { + bool u = ::unscopable(engine, ctx->activation, id); + if (engine->hasException) + return false; + if (u) + break; + return activation->get(id); + } + } + break; case Heap::ExecutionContext::Type_GlobalContext: case Heap::ExecutionContext::Type_QmlContext: { if (ctx->activation) { @@ -310,7 +361,7 @@ ReturnedValue ExecutionContext::getProperty(String *name) } } } - return engine()->throwReferenceError(*name); + return engine->throwReferenceError(*name); } ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) @@ -319,6 +370,8 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) PropertyKey id = name->toPropertyKey(); Heap::ExecutionContext *ctx = d(); + QV4::ExecutionEngine *engine = ctx->internalClass->engine; + for (; ctx; ctx = ctx->outer) { switch (ctx->type) { case Heap::ExecutionContext::Type_BlockContext: @@ -342,6 +395,20 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) break; } case Heap::ExecutionContext::Type_WithContext: + if (ctx->activation) { + Scope scope(this); + ScopedObject activation(scope, ctx->activation); + if (activation->hasProperty(id)) { + bool u = ::unscopable(engine, ctx->activation, id); + if (engine->hasException) + return false; + if (u) + break; + base->setM(activation->d()); + return activation->get(id); + } + } + break; case Heap::ExecutionContext::Type_QmlContext: { Scope scope(this); ScopedObject o(scope, ctx->activation); @@ -355,7 +422,7 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) } } } - return engine()->throwReferenceError(*name); + return engine->throwReferenceError(*name); } void Heap::CallContext::setArg(uint index, Value v) diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations index d919269b3a..6b220b963f 100644 --- a/tests/auto/qml/ecmascripttests/TestExpectations +++ b/tests/auto/qml/ecmascripttests/TestExpectations @@ -27,8 +27,6 @@ built-ins/Array/isArray/proxy.js fails built-ins/Array/length/define-own-prop-length-overflow-realm.js fails built-ins/Array/of/proto-from-ctor-realm.js fails built-ins/Array/proto-from-ctor-realm.js fails -built-ins/Array/prototype/Symbol.unscopables/prop-desc.js fails -built-ins/Array/prototype/Symbol.unscopables/value.js fails built-ins/Array/prototype/concat/Array.prototype.concat_large-typed-array.js fails built-ins/Array/prototype/concat/Array.prototype.concat_sloppy-arguments-with-dupes.js sloppyFails built-ins/Array/prototype/concat/Array.prototype.concat_sloppy-arguments.js fails @@ -778,13 +776,7 @@ built-ins/Proxy/getOwnPropertyDescriptor/trap-is-not-callable-realm.js fails built-ins/Proxy/getOwnPropertyDescriptor/trap-is-undefined.js fails built-ins/Proxy/getPrototypeOf/trap-is-not-callable-realm.js fails built-ins/Proxy/has/call-object-create.js fails -built-ins/Proxy/has/call-with.js sloppyFails -built-ins/Proxy/has/return-false-target-not-extensible-using-with.js sloppyFails -built-ins/Proxy/has/return-false-target-prop-exists-using-with.js sloppyFails -built-ins/Proxy/has/return-false-targetdesc-not-configurable-using-with.js sloppyFails -built-ins/Proxy/has/return-is-abrupt-with.js sloppyFails built-ins/Proxy/has/trap-is-not-callable-realm.js fails -built-ins/Proxy/has/trap-is-not-callable-using-with.js sloppyFails built-ins/Proxy/isExtensible/trap-is-not-callable-realm.js fails built-ins/Proxy/ownKeys/call-parameters-object-getownpropertynames.js fails built-ins/Proxy/ownKeys/call-parameters-object-getownpropertysymbols.js fails @@ -2201,7 +2193,6 @@ language/expressions/object/method-definition/yield-as-identifier-in-nested-func language/expressions/object/method-definition/yield-as-literal-property-name.js fails language/expressions/object/method-definition/yield-as-property-name.js fails language/expressions/object/method-definition/yield-star-before-newline.js fails -language/expressions/object/prop-def-id-eval-error-2.js sloppyFails language/expressions/object/properties-names-eval-arguments.js strictFails language/expressions/object/scope-gen-meth-body-lex-distinct.js sloppyFails language/expressions/object/scope-gen-meth-param-elem-var-close.js sloppyFails @@ -2658,8 +2649,6 @@ language/statements/try/tco-catch.js strictFails language/statements/try/tco-finally.js strictFails language/statements/variable/binding-resolution.js sloppyFails language/statements/while/tco-body.js strictFails -language/statements/with/binding-blocked-by-unscopables.js sloppyFails -language/statements/with/has-property-err.js sloppyFails language/statements/with/unscopables-inc-dec.js sloppyFails language/types/reference/get-value-prop-base-primitive-realm.js fails language/types/reference/put-value-prop-base-primitive-realm.js fails |