summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/script/api/qscriptcontext.cpp29
-rw-r--r--src/script/bridge/qscriptactivationobject.cpp58
-rw-r--r--src/script/bridge/qscriptactivationobject_p.h22
-rw-r--r--tests/auto/qscriptcontext/tst_qscriptcontext.cpp39
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"