diff options
-rw-r--r-- | src/script/api/qscriptcontext.cpp | 29 | ||||
-rw-r--r-- | src/script/bridge/qscriptactivationobject.cpp | 58 | ||||
-rw-r--r-- | src/script/bridge/qscriptactivationobject_p.h | 22 | ||||
-rw-r--r-- | tests/auto/qscriptcontext/tst_qscriptcontext.cpp | 39 |
4 files changed, 135 insertions, 13 deletions
diff --git a/src/script/api/qscriptcontext.cpp b/src/script/api/qscriptcontext.cpp index 1b69ac1..4a78f7c 100644 --- a/src/script/api/qscriptcontext.cpp +++ b/src/script/api/qscriptcontext.cpp @@ -461,6 +461,13 @@ QScriptValue QScriptContext::activationObject() const result = new (frame)JSC::JSActivation(frame, body); }*/ } + + if (result && result->isObject(&QScript::QScriptActivationObject::info) + && (static_cast<QScript::QScriptActivationObject*>(result)->delegate() != 0)) { + // Return the object that property access is being delegated to + result = static_cast<QScript::QScriptActivationObject*>(result)->delegate(); + } + return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result); } @@ -485,15 +492,16 @@ void QScriptContext::setActivationObject(const QScriptValue &activation) JSC::JSObject *object = JSC::asObject(engine->scriptValueToJSCValue(activation)); if (object == engine->originalGlobalObjectProxy) object = engine->originalGlobalObject(); - if (!object->isVariableObject()) { - qWarning("QScriptContext::setActivationObject() failed: not an activation object"); - return; - } uint flags = QScriptEnginePrivate::contextFlags(frame); if ((flags & QScriptEnginePrivate::NativeContext) && !(flags & QScriptEnginePrivate::HasScopeContext)) { //For native functions, we create a scope node - frame->setScopeChain(frame->scopeChain()->copy()->push(object)); + JSC::JSObject *scope = object; + if (!scope->isVariableObject()) { + // Create a QScriptActivationObject that acts as a proxy + scope = new (frame) QScript::QScriptActivationObject(frame, scope); + } + frame->setScopeChain(frame->scopeChain()->copy()->push(scope)); QScriptEnginePrivate::setContextFlags(frame, flags | QScriptEnginePrivate::HasScopeContext); return; } @@ -502,7 +510,16 @@ void QScriptContext::setActivationObject(const QScriptValue &activation) JSC::ScopeChainNode *node = frame->scopeChain(); while (node != 0) { if (node->object && node->object->isVariableObject()) { - node->object = object; + if (!object->isVariableObject()) { + if (node->object->isObject(&QScript::QScriptActivationObject::info)) { + static_cast<QScript::QScriptActivationObject*>(node->object)->setDelegate(object); + } else { + // Create a QScriptActivationObject that acts as a proxy + node->object = new (frame) QScript::QScriptActivationObject(frame, object); + } + } else { + node->object = object; + } break; } node = node->next; diff --git a/src/script/bridge/qscriptactivationobject.cpp b/src/script/bridge/qscriptactivationobject.cpp index ae466e8..5faf7fe 100644 --- a/src/script/bridge/qscriptactivationobject.cpp +++ b/src/script/bridge/qscriptactivationobject.cpp @@ -63,8 +63,9 @@ namespace QScript const JSC::ClassInfo QScriptActivationObject::info = { "QScriptActivationObject", 0, 0, 0 }; -QScriptActivationObject::QScriptActivationObject(JSC::ExecState *callFrame) - : JSC::JSVariableObject(callFrame->globalData().activationStructure, new QScriptActivationObjectData(callFrame->registers())) +QScriptActivationObject::QScriptActivationObject(JSC::ExecState *callFrame, JSC::JSObject *delegate) + : JSC::JSVariableObject(callFrame->globalData().activationStructure, + new QScriptActivationObjectData(callFrame->registers(), delegate)) { } @@ -73,8 +74,36 @@ QScriptActivationObject::~QScriptActivationObject() delete d; } +bool QScriptActivationObject::getOwnPropertySlot(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertySlot& slot) +{ + if (d_ptr()->delegate != 0) + return d_ptr()->delegate->getOwnPropertySlot(exec, propertyName, slot); + return JSC::JSVariableObject::getOwnPropertySlot(exec, propertyName, slot); +} + +bool QScriptActivationObject::getPropertyAttributes(JSC::ExecState* exec, const JSC::Identifier& propertyName, unsigned& attributes) const +{ + if (d_ptr()->delegate != 0) + return d_ptr()->delegate->getPropertyAttributes(exec, propertyName, attributes); + return JSC::JSVariableObject::getPropertyAttributes(exec, propertyName, attributes); +} + +void QScriptActivationObject::getPropertyNames(JSC::ExecState* exec, JSC::PropertyNameArray& propertyNames, unsigned listedAttributes) +{ + if (d_ptr()->delegate != 0) { + d_ptr()->delegate->getPropertyNames(exec, propertyNames, listedAttributes); + return; + } + return JSC::JSVariableObject::getPropertyNames(exec, propertyNames, listedAttributes); +} + void QScriptActivationObject::putWithAttributes(JSC::ExecState *exec, const JSC::Identifier &propertyName, JSC::JSValue value, unsigned attributes) { + if (d_ptr()->delegate != 0) { + d_ptr()->delegate->putWithAttributes(exec, propertyName, value, attributes); + return; + } + if (symbolTablePutWithAttributes(propertyName, value, attributes)) return; @@ -82,6 +111,31 @@ void QScriptActivationObject::putWithAttributes(JSC::ExecState *exec, const JSC: JSObject::putWithAttributes(exec, propertyName, value, attributes, true, slot); } +void QScriptActivationObject::put(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::JSValue value, JSC::PutPropertySlot& slot) +{ + if (d_ptr()->delegate != 0) { + d_ptr()->delegate->put(exec, propertyName, value, slot); + return; + } + JSC::JSVariableObject::put(exec, propertyName, value, slot); +} + +void QScriptActivationObject::put(JSC::ExecState* exec, unsigned propertyName, JSC::JSValue value) +{ + if (d_ptr()->delegate != 0) { + d_ptr()->delegate->put(exec, propertyName, value); + return; + } + JSC::JSVariableObject::put(exec, propertyName, value); +} + +bool QScriptActivationObject::deleteProperty(JSC::ExecState* exec, const JSC::Identifier& propertyName, bool checkDontDelete) +{ + if (d_ptr()->delegate != 0) + return d_ptr()->delegate->deleteProperty(exec, propertyName, checkDontDelete); + return JSC::JSVariableObject::deleteProperty(exec, propertyName, checkDontDelete); +} + } // namespace QScript QT_END_NAMESPACE diff --git a/src/script/bridge/qscriptactivationobject_p.h b/src/script/bridge/qscriptactivationobject_p.h index 8c62b23..fd7b0be 100644 --- a/src/script/bridge/qscriptactivationobject_p.h +++ b/src/script/bridge/qscriptactivationobject_p.h @@ -64,21 +64,37 @@ namespace QScript class QScriptActivationObject : public JSC::JSVariableObject { public: - QScriptActivationObject(JSC::ExecState *callFrame); + QScriptActivationObject(JSC::ExecState *callFrame, JSC::JSObject *delegate = 0); virtual ~QScriptActivationObject(); virtual bool isDynamicScope() const { return true; } + + virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&); + virtual bool getPropertyAttributes(JSC::ExecState*, const JSC::Identifier&, unsigned&) const; + virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&, unsigned listedAttributes = JSC::Structure::Prototype); + virtual void putWithAttributes(JSC::ExecState *exec, const JSC::Identifier &propertyName, JSC::JSValue value, unsigned attributes); + virtual void put(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue value, JSC::PutPropertySlot&); + virtual void put(JSC::ExecState*, unsigned propertyName, JSC::JSValue value); + + virtual bool deleteProperty(JSC::ExecState*, const JSC::Identifier& propertyName, bool checkDontDelete = true); virtual const JSC::ClassInfo* classInfo() const { return &info; } static const JSC::ClassInfo info; struct QScriptActivationObjectData : public JSVariableObjectData { - QScriptActivationObjectData(JSC::Register* registers) - : JSVariableObjectData(&symbolTable, registers) + QScriptActivationObjectData(JSC::Register* registers, JSC::JSObject *dlg) + : JSVariableObjectData(&symbolTable, registers), + delegate(dlg) { } JSC::SymbolTable symbolTable; + JSC::JSObject *delegate; }; + JSC::JSObject *delegate() const + { return d_ptr()->delegate; } + void setDelegate(JSC::JSObject *delegate) + { d_ptr()->delegate = delegate; } + QScriptActivationObjectData *d_ptr() const { return static_cast<QScriptActivationObjectData *>(d); } }; diff --git a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp index 761b233..6401f62 100644 --- a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp +++ b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp @@ -77,6 +77,7 @@ private slots: void calledAsConstructor(); void argumentsObjectInNative(); void jsActivationObject(); + void qobjectAsActivationObject(); }; tst_QScriptContext::tst_QScriptContext() @@ -716,9 +717,7 @@ void tst_QScriptContext::getSetActivationObject() QCOMPARE(ctx->engine(), &eng); QScriptValue obj = eng.newObject(); - QTest::ignoreMessage(QtWarningMsg, "QScriptContext::setActivationObject() failed: not an activation object"); ctx->setActivationObject(obj); - QEXPECT_FAIL("", "Normal object cannot be set as activation object", Continue); QVERIFY(ctx->activationObject().equals(obj)); { @@ -913,5 +912,41 @@ void tst_QScriptContext::jsActivationObject() QCOMPARE(result2.property("arguments").property(1).toString() , QString::fromLatin1("2")); } +void tst_QScriptContext::qobjectAsActivationObject() +{ + QScriptEngine eng; + QObject object; + QScriptValue scriptObject = eng.newQObject(&object); + QScriptContext *ctx = eng.pushContext(); + ctx->setActivationObject(scriptObject); + QVERIFY(ctx->activationObject().equals(scriptObject)); + + QVERIFY(!scriptObject.property("foo").isValid()); + eng.evaluate("function foo() { return 123; }"); + { + QScriptValue val = scriptObject.property("foo"); + QVERIFY(val.isValid()); + QVERIFY(val.isFunction()); + } + QVERIFY(!eng.globalObject().property("foo").isValid()); + + QVERIFY(!scriptObject.property("bar").isValid()); + eng.evaluate("var bar = 123"); + { + QScriptValue val = scriptObject.property("bar"); + QVERIFY(val.isValid()); + QVERIFY(val.isNumber()); + QCOMPARE(val.toInt32(), 123); + } + QVERIFY(!eng.globalObject().property("bar").isValid()); + + { + QScriptValue val = eng.evaluate("delete foo"); + QVERIFY(val.isBool()); + QVERIFY(val.toBool()); + QVERIFY(!scriptObject.property("foo").isValid()); + } +} + QTEST_MAIN(tst_QScriptContext) #include "tst_qscriptcontext.moc" |