summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKent Hansen <khansen@trolltech.com>2009-08-05 15:29:18 (GMT)
committerKent Hansen <khansen@trolltech.com>2009-08-05 15:29:18 (GMT)
commit43ab9a27363681c5db81004c95141b3d0695cabd (patch)
treede9997688b7c007e57001607d4623c328346e05f
parenta11921c7ae4428cfaa53356dbc0b3415a297e083 (diff)
downloadQt-43ab9a27363681c5db81004c95141b3d0695cabd.zip
Qt-43ab9a27363681c5db81004c95141b3d0695cabd.tar.gz
Qt-43ab9a27363681c5db81004c95141b3d0695cabd.tar.bz2
make QScriptEngine::newQMetaObject() work
-rw-r--r--src/script/api/qscriptengine.cpp2
-rw-r--r--src/script/bridge/qscriptqobject.cpp165
-rw-r--r--src/script/bridge/qscriptqobject_p.h5
-rw-r--r--tests/auto/qscriptengine/tst_qscriptengine.cpp3
-rw-r--r--tests/auto/qscriptqobject/tst_qscriptqobject.cpp1
5 files changed, 107 insertions, 69 deletions
diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp
index 02a5e2d..9abc5da 100644
--- a/src/script/api/qscriptengine.cpp
+++ b/src/script/api/qscriptengine.cpp
@@ -1208,7 +1208,7 @@ JSC::JSValue QScriptEnginePrivate::newQMetaObject(
if (!metaObject)
return JSC::jsNull();
JSC::ExecState* exec = currentFrame;
- QScript::QMetaObjectWrapperObject *result = new (exec) QScript::QMetaObjectWrapperObject(metaObject, ctor, qmetaobjectWrapperObjectStructure);
+ QScript::QMetaObjectWrapperObject *result = new (exec) QScript::QMetaObjectWrapperObject(exec, metaObject, ctor, qmetaobjectWrapperObjectStructure);
return result;
}
diff --git a/src/script/bridge/qscriptqobject.cpp b/src/script/bridge/qscriptqobject.cpp
index 324b149..3887fb7 100644
--- a/src/script/bridge/qscriptqobject.cpp
+++ b/src/script/bridge/qscriptqobject.cpp
@@ -50,6 +50,7 @@
#include "../api/qscriptengine_p.h"
#include "../api/qscriptable_p.h"
#include "../api/qscriptcontext_p.h"
+#include "qscriptfunction_p.h"
#include "Error.h"
#include "PrototypeFunction.h"
@@ -500,35 +501,21 @@ struct QScriptMetaArguments
{ return (index != -1); }
};
-JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
- const JSC::ArgList &scriptArgs)
+static QMetaMethod metaMethod(const QMetaObject *meta,
+ QMetaMethod::MethodType type,
+ int index)
+{
+ if (type != QMetaMethod::Constructor)
+ return meta->method(index);
+ else
+ return meta->constructor(index);
+}
+
+static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType callType,
+ QObject *thisQObject, const JSC::ArgList &scriptArgs,
+ const QMetaObject *meta, int initialIndex,
+ bool maybeOverloaded)
{
- Q_ASSERT(data->object.isObject(&QScriptObject::info));
- QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(data->object));
- QScriptObjectDelegate *delegate = scriptObject->delegate();
- Q_ASSERT(delegate && (delegate->type() == QScriptObjectDelegate::QtObject));
- QObject *qobj = static_cast<QScript::QObjectDelegate*>(delegate)->value();
- Q_ASSERT_X(qobj != 0, "QtFunction::call", "handle the case when QObject has been deleted");
- QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
-
- const QMetaObject *meta = qobj->metaObject();
- QObject *thisQObject = 0;
- thisValue = engine->toUsableValue(thisValue);
- if (thisValue.isObject(&QScriptObject::info)) {
- delegate = static_cast<QScriptObject*>(JSC::asObject(thisValue))->delegate();
- if (delegate && (delegate->type() == QScriptObjectDelegate::QtObject))
- thisQObject = static_cast<QScript::QObjectDelegate*>(delegate)->value();
- }
- if (!thisQObject)
- thisQObject = qobj; // ### TypeError
-
- if (!meta->cast(thisQObject)) {
- // invoking a function in the prototype
- thisQObject = qobj;
- }
-
- exec->clearException();
-
QByteArray funName;
QScriptMetaMethod chosenMethod;
int chosenIndex = -1;
@@ -538,10 +525,12 @@ JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
QVector<int> tooFewArgs;
QVector<int> conversionFailed;
int index;
- for (index = data->initialIndex; index >= 0; --index) {
- QMetaMethod method = meta->method(index);
+ exec->clearException();
+ QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(exec);
+ for (index = initialIndex; index >= 0; --index) {
+ QMetaMethod method = metaMethod(meta, callType, index);
- if (index == data->initialIndex)
+ if (index == initialIndex)
funName = methodName(method);
else {
if (methodName(method) != funName)
@@ -563,9 +552,9 @@ JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
types.append(QScriptMetaType::unresolved(returnTypeName));
}
} else {
-/* if (callType == QMetaMethod::Constructor)
+ if (callType == QMetaMethod::Constructor)
types.append(QScriptMetaType::metaType(QMetaType::QObjectStar, "QObject*"));
- else*/ if (returnTypeName == "QVariant")
+ else if (returnTypeName == "QVariant")
types.append(QScriptMetaType::variant());
else
types.append(QScriptMetaType::metaType(rtype, returnTypeName));
@@ -619,7 +608,11 @@ JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
bool converted = true;
int matchDistance = 0;
for (int i = 0; converted && i < mtd.argumentCount(); ++i) {
- QScriptValue actual = engine->scriptValueFromJSCValue(scriptArgs.at(i));
+ QScriptValue actual;
+ if (i < (int)scriptArgs.size())
+ actual = engine->scriptValueFromJSCValue(scriptArgs.at(i));
+ else
+ actual = QScriptValue::QScriptValue(QScriptValue::UndefinedValue);
QScriptMetaType argType = mtd.argumentType(i);
int tid = -1;
QVariant v;
@@ -823,8 +816,8 @@ JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
break;
} else {
bool redundant = false;
- if (/*(callType != QMetaMethod::Constructor)
- &&*/ (index < meta->methodOffset())) {
+ if ((callType != QMetaMethod::Constructor)
+ && (index < meta->methodOffset())) {
// it is possible that a virtual method is redeclared in a subclass,
// in which case we want to ignore the superclass declaration
for (int i = 0; i < candidates.size(); ++i) {
@@ -855,7 +848,7 @@ JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
conversionFailed.append(index);
}
- if (!data->maybeOverloaded)
+ if (!maybeOverloaded)
break;
}
@@ -871,7 +864,7 @@ JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
for (int i = 0; i < conversionFailed.size(); ++i) {
if (i > 0)
message += QLatin1String("\n");
- QMetaMethod mtd = meta->method(conversionFailed.at(i));
+ QMetaMethod mtd = metaMethod(meta, callType, conversionFailed.at(i));
message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
}
result = JSC::throwError(exec, JSC::TypeError, qtStringToJSCUString(message));
@@ -898,7 +891,7 @@ JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
for (int i = 0; i < tooFewArgs.size(); ++i) {
if (i > 0)
message += QLatin1String("\n");
- QMetaMethod mtd = meta->method(tooFewArgs.at(i));
+ QMetaMethod mtd = metaMethod(meta, callType, tooFewArgs.at(i));
message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
}
result = JSC::throwError(exec, JSC::SyntaxError, qtStringToJSCUString(message));
@@ -915,7 +908,7 @@ JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
for (int i = 0; i < candidates.size(); ++i) {
if (i > 0)
message += QLatin1String("\n");
- QMetaMethod mtd = meta->method(candidates.at(i).index);
+ QMetaMethod mtd = metaMethod(meta, callType, candidates.at(i).index);
message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
}
result = JSC::throwError(exec, JSC::TypeError, qtStringToJSCUString(message));
@@ -962,11 +955,10 @@ JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
// engine->notifyFunctionEntry(context);
//#endif
-/* if (callType == QMetaMethod::Constructor) {
+ if (callType == QMetaMethod::Constructor) {
Q_ASSERT(meta != 0);
meta->static_metacall(QMetaObject::CreateInstance, chosenIndex, params);
- } else*/ {
- Q_ASSERT(thisQObject != 0);
+ } else {
thisQObject->qt_metacall(QMetaObject::InvokeMetaMethod, chosenIndex, params);
}
@@ -995,6 +987,37 @@ JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
return result;
}
+JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
+ const JSC::ArgList &scriptArgs)
+{
+ Q_ASSERT(data->object.isObject(&QScriptObject::info));
+ QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(data->object));
+ QScriptObjectDelegate *delegate = scriptObject->delegate();
+ Q_ASSERT(delegate && (delegate->type() == QScriptObjectDelegate::QtObject));
+ QObject *qobj = static_cast<QScript::QObjectDelegate*>(delegate)->value();
+ Q_ASSERT_X(qobj != 0, "QtFunction::call", "handle the case when QObject has been deleted");
+ QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
+
+ const QMetaObject *meta = qobj->metaObject();
+ QObject *thisQObject = 0;
+ thisValue = engine->toUsableValue(thisValue);
+ if (thisValue.isObject(&QScriptObject::info)) {
+ delegate = static_cast<QScriptObject*>(JSC::asObject(thisValue))->delegate();
+ if (delegate && (delegate->type() == QScriptObjectDelegate::QtObject))
+ thisQObject = static_cast<QScript::QObjectDelegate*>(delegate)->value();
+ }
+ if (!thisQObject)
+ thisQObject = qobj; // ### TypeError
+
+ if (!meta->cast(thisQObject)) {
+ // invoking a function in the prototype
+ thisQObject = qobj;
+ }
+
+ return callQtMethod(exec, QMetaMethod::Method, thisQObject, scriptArgs,
+ meta, data->initialIndex, data->maybeOverloaded);
+}
+
const JSC::ClassInfo QtFunction::info = { "QtFunction", &InternalFunction::info, 0, 0 };
JSC::JSValue JSC_HOST_CALL QtFunction::call(JSC::ExecState *exec, JSC::JSObject *callee,
@@ -1656,10 +1679,13 @@ QObjectPrototype::QObjectPrototype(JSC::ExecState* exec, WTF::PassRefPtr<JSC::St
const JSC::ClassInfo QMetaObjectWrapperObject::info = { "QMetaObject", 0, 0, 0 };
QMetaObjectWrapperObject::QMetaObjectWrapperObject(
- const QMetaObject *metaObject, JSC::JSValue ctor,
+ JSC::ExecState *exec, const QMetaObject *metaObject, JSC::JSValue ctor,
WTF::PassRefPtr<JSC::Structure> sid)
- : JSC::JSObject(sid), data(new Data(metaObject, ctor))
+ : JSC::JSObject(sid),
+ data(new Data(metaObject, ctor))
{
+ if (!ctor)
+ data->prototype = new (exec)JSC::JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
}
QMetaObjectWrapperObject::~QMetaObjectWrapperObject()
@@ -1813,7 +1839,7 @@ JSC::JSValue JSC_HOST_CALL QMetaObjectWrapperObject::call(
QMetaObjectWrapperObject *self = static_cast<QMetaObjectWrapperObject*>(callee);
JSC::ExecState *previousFrame = eng_p->currentFrame;
eng_p->currentFrame = exec;
- JSC::JSValue result = self->execute(exec, args);
+ JSC::JSValue result = self->execute(exec, args, /*calledAsConstructor=*/false);
eng_p->currentFrame = previousFrame;
return result;
}
@@ -1824,7 +1850,7 @@ JSC::JSObject* QMetaObjectWrapperObject::construct(JSC::ExecState *exec, JSC::JS
QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
JSC::ExecState *previousFrame = eng_p->currentFrame;
eng_p->currentFrame = exec;
- JSC::JSValue result = self->execute(exec, args);
+ JSC::JSValue result = self->execute(exec, args, /*calledAsConstructor=*/true);
eng_p->currentFrame = previousFrame;
if (!result || !result.isObject())
return 0;
@@ -1832,28 +1858,43 @@ JSC::JSObject* QMetaObjectWrapperObject::construct(JSC::ExecState *exec, JSC::JS
}
JSC::JSValue QMetaObjectWrapperObject::execute(JSC::ExecState *exec,
- const JSC::ArgList &args)
+ const JSC::ArgList &args,
+ bool calledAsConstructor)
{
if (data->ctor) {
+ QScriptEnginePrivate *eng_p = QScript::scriptEngineFromExec(exec);
+ QScriptContext *ctx = eng_p->contextForFrame(exec);
+ QScriptPushScopeHelper scope(exec, calledAsConstructor);
JSC::CallData callData;
JSC::CallType callType = data->ctor.getCallData(callData);
- return JSC::call(exec, data->ctor, callType, callData, /*thisValue=*/JSC::JSValue(), args);
+ Q_ASSERT_X(callType == JSC::CallTypeHost, Q_FUNC_INFO, "script constructors not supported");
+ if (data->ctor.isObject(&FunctionWithArgWrapper::info)) {
+ FunctionWithArgWrapper *wrapper = static_cast<FunctionWithArgWrapper*>(JSC::asObject(data->ctor));
+ QScriptValue result = wrapper->function()(ctx, QScriptEnginePrivate::get(eng_p), wrapper->arg());
+ return eng_p->scriptValueToJSCValue(result);
+ } else {
+ Q_ASSERT(data->ctor.isObject(&FunctionWrapper::info));
+ FunctionWrapper *wrapper = static_cast<FunctionWrapper*>(JSC::asObject(data->ctor));
+ QScriptValue result = wrapper->function()(ctx, QScriptEnginePrivate::get(eng_p));
+ return eng_p->scriptValueToJSCValue(result);
+ }
} else {
- if (data->value->constructorCount() > 0) {
- Q_ASSERT_X(false, Q_FUNC_INFO, "implement me");
-#if 0
- callQtMethod(context, QMetaMethod::Constructor, /*thisQObject=*/0,
- value, value->constructorCount()-1, /*maybeOverloaded=*/true);
- if (context->state() == QScriptContext::NormalState) {
- ExtQObject::Instance *inst = ExtQObject::Instance::get(context->m_result);
- Q_ASSERT(inst != 0);
- inst->ownership = QScriptEngine::AutoOwnership;
- context->m_result.setPrototype(prototype);
+ const QMetaObject *meta = data->value;
+ if (meta->constructorCount() > 0) {
+ JSC::JSValue result = callQtMethod(exec, QMetaMethod::Constructor, /*thisQObject=*/0,
+ args, meta, meta->constructorCount()-1, /*maybeOverloaded=*/true);
+ if (!exec->hadException()) {
+ Q_ASSERT(result && result.isObject(&QScriptObject::info));
+ QScriptObject *object = static_cast<QScriptObject*>(JSC::asObject(result));
+ QScript::QObjectDelegate *delegate = static_cast<QScript::QObjectDelegate*>(object->delegate());
+ delegate->setOwnership(QScriptEngine::AutoOwnership);
+ if (data->prototype)
+ object->setPrototype(data->prototype);
}
-#endif
+ return result;
} else {
QString message = QString::fromLatin1("no constructor for %0")
- .arg(QLatin1String(data->value->className()));
+ .arg(QLatin1String(meta->className()));
return JSC::throwError(exec, JSC::TypeError, qtStringToJSCUString(message));
}
}
@@ -1879,7 +1920,7 @@ static JSC::JSValue JSC_HOST_CALL qmetaobjectProtoFuncClassName(
QMetaObjectPrototype::QMetaObjectPrototype(
JSC::ExecState *exec, WTF::PassRefPtr<JSC::Structure> structure,
JSC::Structure* prototypeFunctionStructure)
- : QMetaObjectWrapperObject(StaticQtMetaObject::get(), /*ctor=*/JSC::JSValue(), structure)
+ : QMetaObjectWrapperObject(exec, StaticQtMetaObject::get(), /*ctor=*/JSC::JSValue(), structure)
{
putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/0, JSC::Identifier(exec, "className"), qmetaobjectProtoFuncClassName), JSC::DontEnum);
}
diff --git a/src/script/bridge/qscriptqobject_p.h b/src/script/bridge/qscriptqobject_p.h
index 0af6632..15c6e22 100644
--- a/src/script/bridge/qscriptqobject_p.h
+++ b/src/script/bridge/qscriptqobject_p.h
@@ -282,7 +282,7 @@ public:
};
explicit QMetaObjectWrapperObject(
- const QMetaObject *metaobject, JSC::JSValue ctor,
+ JSC::ExecState *, const QMetaObject *metaobject, JSC::JSValue ctor,
WTF::PassRefPtr<JSC::Structure> sid);
~QMetaObjectWrapperObject();
@@ -310,7 +310,8 @@ public:
JSC::JSValue, const JSC::ArgList&);
static JSC::JSObject* construct(JSC::ExecState *, JSC::JSObject *, const JSC::ArgList &);
- JSC::JSValue execute(JSC::ExecState *exec, const JSC::ArgList &args);
+ JSC::JSValue execute(JSC::ExecState *exec, const JSC::ArgList &args,
+ bool calledAsConstructor);
inline const QMetaObject *value() const { return data->value; }
inline void setValue(const QMetaObject* value) { data->value = value; }
diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp
index 25e84dc..ec84406 100644
--- a/tests/auto/qscriptengine/tst_qscriptengine.cpp
+++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp
@@ -832,7 +832,6 @@ void tst_QScriptEngine::newQMetaObject()
QScriptValue ret = qclass3.construct();
QVERIFY(ret.isObject());
QVERIFY(ret.property("isCalledAsConstructor").isBoolean());
- QEXPECT_FAIL("", "isCalledAsConstructor not yet implemented for script function", Continue);
QVERIFY(ret.property("isCalledAsConstructor").toBoolean());
QVERIFY(ret.instanceOf(qclass3));
}
@@ -843,8 +842,6 @@ void tst_QScriptEngine::newQMetaObject()
// with meta-constructor
QScriptValue qclass4 = eng.newQMetaObject(&QObject::staticMetaObject);
- QEXPECT_FAIL("", "Crashes!!!", Abort);
- QVERIFY(false);
{
QScriptValue inst = qclass4.construct();
QVERIFY(inst.isQObject());
diff --git a/tests/auto/qscriptqobject/tst_qscriptqobject.cpp b/tests/auto/qscriptqobject/tst_qscriptqobject.cpp
index d7eb137..3959023 100644
--- a/tests/auto/qscriptqobject/tst_qscriptqobject.cpp
+++ b/tests/auto/qscriptqobject/tst_qscriptqobject.cpp
@@ -2098,7 +2098,6 @@ public:
void tst_QScriptExtQObject::classConstructor()
{
- QSKIP("Crashes", SkipAll);
QScriptValue myClass = qScriptValueFromQMetaObject<MyQObject>(m_engine);
m_engine->globalObject().setProperty("MyQObject", myClass);