summaryrefslogtreecommitdiffstats
path: root/src/script/bridge
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2009-06-16 16:18:58 (GMT)
committerSimon Hausmann <simon.hausmann@nokia.com>2009-06-16 16:18:59 (GMT)
commitd612b4789f7ec891ada16afbbbf1c13ab0f0e575 (patch)
tree0e25f0dd66abbe087220c3de9c258bc6215db639 /src/script/bridge
parent94e39aff7dd02d4a631d5c40c6f5a5f6fa424035 (diff)
downloadQt-d612b4789f7ec891ada16afbbbf1c13ab0f0e575.zip
Qt-d612b4789f7ec891ada16afbbbf1c13ab0f0e575.tar.gz
Qt-d612b4789f7ec891ada16afbbbf1c13ab0f0e575.tar.bz2
Import JSC-based Qt Script from Kent's tree.
Diffstat (limited to 'src/script/bridge')
-rw-r--r--src/script/bridge/bridge.pri9
-rw-r--r--src/script/bridge/qscriptfunction.cpp137
-rw-r--r--src/script/bridge/qscriptfunction_p.h92
-rw-r--r--src/script/bridge/qscriptqobject.cpp1338
-rw-r--r--src/script/bridge/qscriptqobject_p.h134
-rw-r--r--src/script/bridge/qscriptvariant.cpp102
-rw-r--r--src/script/bridge/qscriptvariant_p.h72
7 files changed, 1884 insertions, 0 deletions
diff --git a/src/script/bridge/bridge.pri b/src/script/bridge/bridge.pri
new file mode 100644
index 0000000..585ccc0
--- /dev/null
+++ b/src/script/bridge/bridge.pri
@@ -0,0 +1,9 @@
+SOURCES += \
+ $$PWD/qscriptfunction.cpp \
+ $$PWD/qscriptvariant.cpp \
+ $$PWD/qscriptqobject.cpp
+
+HEADERS += \
+ $$PWD/qscriptfunction_p.h \
+ $$PWD/qscriptvariant_p.h \
+ $$PWD/qscriptqobject_p.h
diff --git a/src/script/bridge/qscriptfunction.cpp b/src/script/bridge/qscriptfunction.cpp
new file mode 100644
index 0000000..fd51df1
--- /dev/null
+++ b/src/script/bridge/qscriptfunction.cpp
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qscriptfunction_p.h"
+
+#ifndef QT_NO_SCRIPT
+
+#include "private/qscriptengine_p.h"
+#include "qscriptcontext.h"
+#include "private/qscriptcontext_p.h"
+
+#include "JSGlobalObject.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace JSC
+{
+ASSERT_CLASS_FITS_IN_CELL(QScript::FunctionWrapper);
+ASSERT_CLASS_FITS_IN_CELL(QScript::FunctionWithArgWrapper);
+}
+
+namespace QScript
+{
+
+FunctionWrapper::FunctionWrapper(QScriptEngine *engine, int length, const JSC::Identifier &name,
+ QScriptEngine::FunctionSignature function)
+ : JSC::PrototypeFunction(QScriptEnginePrivate::get(engine)->globalObject->globalExec(),
+ length, name, proxyCall), data(new Data())
+{
+ data->engine = engine;
+ data->function = function;
+}
+
+FunctionWrapper::~FunctionWrapper()
+{
+ delete data;
+}
+
+JSC::ConstructType FunctionWrapper::getConstructData(JSC::ConstructData& consData)
+{
+ consData.native.function = proxyConstruct;
+ return JSC::ConstructTypeHost;
+}
+
+JSC::JSValue FunctionWrapper::proxyCall(JSC::ExecState *, JSC::JSObject *callee,
+ JSC::JSValue thisObject, const JSC::ArgList &args)
+{
+ FunctionWrapper *self = static_cast<FunctionWrapper*>(callee);
+ QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(self->data->engine);
+ QScriptContextPrivate ctx_p(callee, thisObject, args,
+ /*calledAsConstructor=*/false, eng_p);
+ QScriptContext *ctx = QScriptContextPrivate::create(ctx_p);
+ QScriptValue result = self->data->function(ctx, self->data->engine);
+ delete ctx;
+ return eng_p->scriptValueToJSCValue(result);
+}
+
+JSC::JSObject* FunctionWrapper::proxyConstruct(JSC::ExecState *, JSC::JSObject *callee,
+ const JSC::ArgList &args)
+{
+ FunctionWrapper *self = static_cast<FunctionWrapper*>(callee);
+ QScriptValue object = self->data->engine->newObject();
+ QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(self->data->engine);
+ QScriptContextPrivate ctx_p(callee, eng_p->scriptValueToJSCValue(object),
+ args, /*calledAsConstructor=*/true, eng_p);
+ QScriptContext *ctx = QScriptContextPrivate::create(ctx_p);
+ QScriptValue result = self->data->function(ctx, self->data->engine);
+ delete ctx;
+ if (result.isObject())
+ return static_cast<JSC::JSObject*>(JSC::asObject(eng_p->scriptValueToJSCValue(result)));
+ return static_cast<JSC::JSObject*>(JSC::asObject(eng_p->scriptValueToJSCValue(object)));
+}
+
+FunctionWithArgWrapper::FunctionWithArgWrapper(QScriptEngine *engine, int length, const JSC::Identifier &name,
+ QScriptEngine::FunctionWithArgSignature function, void *arg)
+ : JSC::PrototypeFunction(QScriptEnginePrivate::get(engine)->globalObject->globalExec(),
+ length, name, /*proxyCall*/0), data(new Data())
+{
+ Q_ASSERT_X(false, Q_FUNC_INFO, "implement me");
+ data->engine = engine;
+ data->function = function;
+ data->arg = arg;
+}
+
+FunctionWithArgWrapper::~FunctionWithArgWrapper()
+{
+ delete data;
+}
+
+JSC::ConstructType FunctionWithArgWrapper::getConstructData(JSC::ConstructData& consData)
+{
+ consData.native.function = proxyConstruct;
+ return JSC::ConstructTypeHost;
+}
+
+JSC::JSValue FunctionWithArgWrapper::proxyCall(JSC::ExecState *, JSC::JSObject *callee,
+ JSC::JSValue thisObject, const JSC::ArgList &args)
+{
+ FunctionWithArgWrapper *self = static_cast<FunctionWithArgWrapper*>(callee);
+ QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(self->data->engine);
+ QScriptContextPrivate ctx_p(callee, thisObject, args,
+ /*calledAsConstructor=*/false, eng_p);
+ QScriptContext *ctx = QScriptContextPrivate::create(ctx_p);
+ QScriptValue result = self->data->function(ctx, self->data->engine, self->data->arg);
+ delete ctx;
+ return eng_p->scriptValueToJSCValue(result);
+}
+
+JSC::JSObject* FunctionWithArgWrapper::proxyConstruct(JSC::ExecState *, JSC::JSObject *callee,
+ const JSC::ArgList &args)
+{
+ FunctionWithArgWrapper *self = static_cast<FunctionWithArgWrapper*>(callee);
+ QScriptValue object = self->data->engine->newObject();
+ QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(self->data->engine);
+ QScriptContextPrivate ctx_p(callee, eng_p->scriptValueToJSCValue(object),
+ args, /*calledAsConstructor=*/true, eng_p);
+ QScriptContext *ctx = QScriptContextPrivate::create(ctx_p);
+ QScriptValue result = self->data->function(ctx, self->data->engine, self->data->arg);
+ delete ctx;
+ if (result.isObject())
+ return static_cast<JSC::JSObject*>(JSC::asObject(eng_p->scriptValueToJSCValue(result)));
+ return static_cast<JSC::JSObject*>(JSC::asObject(eng_p->scriptValueToJSCValue(object)));
+}
+
+} // namespace QScript
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SCRIPT
diff --git a/src/script/bridge/qscriptfunction_p.h b/src/script/bridge/qscriptfunction_p.h
new file mode 100644
index 0000000..87e3d59
--- /dev/null
+++ b/src/script/bridge/qscriptfunction_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCRIPTFUNCTION_P_H
+#define QSCRIPTFUNCTIOn_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#ifndef QT_NO_SCRIPT
+
+#include "qscriptengine.h"
+
+#include "PrototypeFunction.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QScript
+{
+
+class FunctionWrapper : public JSC::PrototypeFunction // ### subclass InternalFunction instead
+{
+public:
+ // work around CELL_SIZE limitation
+ struct Data
+ {
+ QScriptEngine *engine;
+ QScriptEngine::FunctionSignature function;
+ };
+
+ FunctionWrapper(QScriptEngine *, int length, const JSC::Identifier&, QScriptEngine::FunctionSignature);
+ ~FunctionWrapper();
+
+private:
+ virtual JSC::ConstructType getConstructData(JSC::ConstructData&);
+
+ static JSC::JSValue JSC_HOST_CALL proxyCall(JSC::ExecState *, JSC::JSObject *, JSC::JSValue, const JSC::ArgList &);
+ static JSC::JSObject* proxyConstruct(JSC::ExecState *, JSC::JSObject *, const JSC::ArgList &);
+
+private:
+ Data *data;
+};
+
+class FunctionWithArgWrapper : public JSC::PrototypeFunction
+{
+public:
+ // work around CELL_SIZE limitation
+ struct Data
+ {
+ QScriptEngine *engine;
+ QScriptEngine::FunctionWithArgSignature function;
+ void *arg;
+ };
+
+ FunctionWithArgWrapper(QScriptEngine *, int length, const JSC::Identifier&, QScriptEngine::FunctionWithArgSignature, void *);
+ ~FunctionWithArgWrapper();
+
+private:
+ virtual JSC::ConstructType getConstructData(JSC::ConstructData&);
+
+ static JSC::JSValue proxyCall(JSC::ExecState *, JSC::JSObject *, JSC::JSValue , const JSC::ArgList &);
+ static JSC::JSObject* proxyConstruct(JSC::ExecState *, JSC::JSObject *, const JSC::ArgList &);
+
+private:
+ Data *data;
+};
+
+} // namespace QScript
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SCRIPT
+
+#endif
diff --git a/src/script/bridge/qscriptqobject.cpp b/src/script/bridge/qscriptqobject.cpp
new file mode 100644
index 0000000..84f6108d
--- /dev/null
+++ b/src/script/bridge/qscriptqobject.cpp
@@ -0,0 +1,1338 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qscriptqobject_p.h"
+
+#ifndef QT_NO_SCRIPT
+
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qdebug.h>
+#include <QtScript/qscriptable.h>
+#include "../api/qscriptengine_p.h"
+#include "../api/qscriptable_p.h"
+
+#include "Error.h"
+#include "PrototypeFunction.h"
+#include "PropertyNameArray.h"
+#include "JSFunction.h"
+#include "JSString.h"
+#include "JSValue.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace JSC
+{
+ASSERT_CLASS_FITS_IN_CELL(QScript::QObjectWrapperObject);
+ASSERT_CLASS_FITS_IN_CELL(QScript::QObjectPrototype);
+}
+
+namespace QScript
+{
+
+struct QObjectConnection
+{
+ int slotIndex;
+ JSC::JSValue receiver;
+ JSC::JSValue slot;
+ JSC::JSValue senderWrapper;
+
+ QObjectConnection(int i, JSC::JSValue r, JSC::JSValue s,
+ JSC::JSValue sw)
+ : slotIndex(i), receiver(r), slot(s), senderWrapper(sw) {}
+ QObjectConnection() : slotIndex(-1) {}
+
+ bool hasTarget(JSC::JSValue r, JSC::JSValue s) const
+ {
+ if (r.isObject() != receiver.isObject())
+ return false;
+ if ((r.isObject() && receiver.isObject())
+ && (r != receiver)) {
+ return false;
+ }
+ return (s == slot);
+ }
+
+ void mark()
+ {
+ Q_ASSERT_X(false, Q_FUNC_INFO, "implement me");
+/* if (senderWrapper && !senderWrapper->isMarked()) {
+ // see if the sender should be marked or not
+ if ((inst->ownership == QScriptEngine::ScriptOwnership)
+ || ((inst->ownership == QScriptEngine::AutoOwnership)
+ && inst->value && !inst->value->parent())) {
+ senderWrapper.invalidate();
+ } else {
+ senderWrapper.mark(generation);
+ }
+ }*/
+ if (receiver)
+ receiver.mark();
+ if (slot)
+ slot.mark();
+ }
+};
+
+class QObjectConnectionManager: public QObject
+{
+public:
+ QObjectConnectionManager(QScriptEnginePrivate *engine);
+ ~QObjectConnectionManager();
+
+ bool addSignalHandler(QObject *sender, const char *signal,
+ JSC::JSValue receiver,
+ JSC::JSValue slot,
+ JSC::JSValue senderWrapper = 0);
+ bool removeSignalHandler(QObject *sender, const char *signal,
+ JSC::JSValue receiver,
+ JSC::JSValue slot);
+
+ static const QMetaObject staticMetaObject;
+ virtual const QMetaObject *metaObject() const;
+ virtual void *qt_metacast(const char *);
+ virtual int qt_metacall(QMetaObject::Call, int, void **argv);
+
+ void execute(int slotIndex, void **argv);
+
+ void mark();
+
+private:
+ QScriptEnginePrivate *engine;
+ int slotCounter;
+ QVector<QVector<QObjectConnection> > connections;
+};
+
+static bool hasMethodAccess(const QMetaMethod &method, int index, const QScriptEngine::QObjectWrapOptions &opt)
+{
+ return (method.access() != QMetaMethod::Private)
+ && ((index != 2) || !(opt & QScriptEngine::ExcludeDeleteLater));
+}
+
+static bool isEnumerableMetaProperty(const QMetaProperty &prop,
+ const QMetaObject *mo, int index)
+{
+ return prop.isScriptable() && prop.isValid()
+ // the following lookup is to ensure that we have the
+ // "most derived" occurrence of the property with this name
+ && (mo->indexOfProperty(prop.name()) == index);
+}
+
+static inline QByteArray methodName(const QMetaMethod &method)
+{
+ QByteArray signature = method.signature();
+ return signature.left(signature.indexOf('('));
+}
+
+static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
+{
+ QByteArray scope;
+ QByteArray name;
+ int scopeIdx = str.indexOf("::");
+ if (scopeIdx != -1) {
+ scope = str.left(scopeIdx);
+ name = str.mid(scopeIdx + 2);
+ } else {
+ name = str;
+ }
+ for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
+ QMetaEnum m = meta->enumerator(i);
+ if ((m.name() == name)/* && (scope.isEmpty() || (m.scope() == scope))*/)
+ return i;
+ }
+ return -1;
+}
+
+static inline QScriptable *scriptableFromQObject(QObject *qobj)
+{
+ void *ptr = qobj->qt_metacast("QScriptable");
+ return reinterpret_cast<QScriptable*>(ptr);
+}
+
+JSC::UString qtStringToJSCUString(const QString &str);
+QString qtStringFromJSCUString(const JSC::UString &str);
+
+static JSC::JSValue JSC_HOST_CALL QtFunction_call(JSC::ExecState *exec, JSC::JSObject*,
+ JSC::JSValue thisValue, const JSC::ArgList &args);
+
+class QtFunction: public JSC::InternalFunction
+{
+public:
+ // work around CELL_SIZE limitation
+ struct Data
+ {
+ JSC::JSValue object;
+ int initialIndex;
+ bool maybeOverloaded;
+
+ Data(JSC::JSValue o, int ii, bool mo)
+ : object(o), initialIndex(ii), maybeOverloaded(mo) {}
+ };
+
+ QtFunction(JSC::JSValue object, int initialIndex, bool maybeOverloaded,
+ JSC::JSGlobalData*, WTF::PassRefPtr<JSC::Structure>, const JSC::Identifier&);
+ virtual ~QtFunction();
+
+ virtual JSC::CallType getCallData(JSC::CallData&);
+ virtual void mark();
+
+ virtual const JSC::ClassInfo* classInfo() const { return &info; }
+ static const JSC::ClassInfo info;
+
+ JSC::JSValue call(JSC::ExecState *exec, JSC::JSValue thisValue,
+ const JSC::ArgList &args);
+
+private:
+ Data *data;
+};
+
+QtFunction::QtFunction(JSC::JSValue object, int initialIndex, bool maybeOverloaded,
+ JSC::JSGlobalData *data, WTF::PassRefPtr<JSC::Structure> sid,
+ const JSC::Identifier &ident)
+ : JSC::InternalFunction(data, sid, ident),
+ data(new Data(object, initialIndex, maybeOverloaded))
+{
+}
+
+QtFunction::~QtFunction()
+{
+ delete data;
+}
+
+JSC::CallType QtFunction::getCallData(JSC::CallData &callData)
+{
+ callData.native.function = QtFunction_call;
+ return JSC::CallTypeHost;
+}
+
+void QtFunction::mark()
+{
+ data->object.mark();
+}
+
+class QScriptMetaType
+{
+public:
+ enum Kind {
+ Invalid,
+ Variant,
+ MetaType,
+ Unresolved,
+ MetaEnum
+ };
+
+ inline QScriptMetaType()
+ : m_kind(Invalid) { }
+
+ inline Kind kind() const
+ { return m_kind; }
+
+ int typeId() const;
+
+ inline bool isValid() const
+ { return (m_kind != Invalid); }
+
+ inline bool isVariant() const
+ { return (m_kind == Variant); }
+
+ inline bool isMetaType() const
+ { return (m_kind == MetaType); }
+
+ inline bool isUnresolved() const
+ { return (m_kind == Unresolved); }
+
+ inline bool isMetaEnum() const
+ { return (m_kind == MetaEnum); }
+
+ QByteArray name() const;
+
+ inline int enumeratorIndex() const
+ { Q_ASSERT(isMetaEnum()); return m_typeId; }
+
+ static inline QScriptMetaType variant()
+ { return QScriptMetaType(Variant); }
+
+ static inline QScriptMetaType metaType(int typeId, const QByteArray &name)
+ { return QScriptMetaType(MetaType, typeId, name); }
+
+ static inline QScriptMetaType metaEnum(int enumIndex, const QByteArray &name)
+ { return QScriptMetaType(MetaEnum, enumIndex, name); }
+
+ static inline QScriptMetaType unresolved(const QByteArray &name)
+ { return QScriptMetaType(Unresolved, /*typeId=*/0, name); }
+
+private:
+ inline QScriptMetaType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
+ : m_kind(kind), m_typeId(typeId), m_name(name) { }
+
+ Kind m_kind;
+ int m_typeId;
+ QByteArray m_name;
+};
+
+int QScriptMetaType::typeId() const
+{
+ if (isVariant())
+ return QMetaType::type("QVariant");
+ return isMetaEnum() ? 2/*int*/ : m_typeId;
+}
+
+QByteArray QScriptMetaType::name() const
+{
+ if (!m_name.isEmpty())
+ return m_name;
+ else if (m_kind == Variant)
+ return "QVariant";
+ return QMetaType::typeName(typeId());
+}
+
+class QScriptMetaMethod
+{
+public:
+ inline QScriptMetaMethod()
+ { }
+ inline QScriptMetaMethod(const QByteArray &name, const QVector<QScriptMetaType> &types)
+ : m_name(name), m_types(types), m_firstUnresolvedIndex(-1)
+ {
+ QVector<QScriptMetaType>::const_iterator it;
+ for (it = m_types.constBegin(); it != m_types.constEnd(); ++it) {
+ if ((*it).kind() == QScriptMetaType::Unresolved) {
+ m_firstUnresolvedIndex = it - m_types.constBegin();
+ break;
+ }
+ }
+ }
+ inline bool isValid() const
+ { return !m_types.isEmpty(); }
+
+ QByteArray name() const
+ { return m_name; }
+
+ inline QScriptMetaType returnType() const
+ { return m_types.at(0); }
+
+ inline int argumentCount() const
+ { return m_types.count() - 1; }
+
+ inline QScriptMetaType argumentType(int arg) const
+ { return m_types.at(arg + 1); }
+
+ inline bool fullyResolved() const
+ { return m_firstUnresolvedIndex == -1; }
+
+ inline bool hasUnresolvedReturnType() const
+ { return (m_firstUnresolvedIndex == 0); }
+
+ inline int firstUnresolvedIndex() const
+ { return m_firstUnresolvedIndex; }
+
+ inline int count() const
+ { return m_types.count(); }
+
+ inline QScriptMetaType type(int index) const
+ { return m_types.at(index); }
+
+private:
+ QByteArray m_name;
+ QVector<QScriptMetaType> m_types;
+ int m_firstUnresolvedIndex;
+};
+
+struct QScriptMetaArguments
+{
+ int matchDistance;
+ int index;
+ QScriptMetaMethod method;
+ QVarLengthArray<QVariant, 9> args;
+
+ inline QScriptMetaArguments(int dist, int idx, const QScriptMetaMethod &mtd,
+ const QVarLengthArray<QVariant, 9> &as)
+ : matchDistance(dist), index(idx), method(mtd), args(as) { }
+ inline QScriptMetaArguments()
+ : index(-1) { }
+
+ inline bool isValid() const
+ { return (index != -1); }
+};
+
+JSC::JSValue QtFunction::call(JSC::ExecState *exec, JSC::JSValue thisValue,
+ const JSC::ArgList &scriptArgs)
+{
+ Q_ASSERT(data->object.isObject(&QObjectWrapperObject::info));
+ QObjectWrapperObject *wrapper = static_cast<QObjectWrapperObject*>(JSC::asObject(data->object));
+ QScriptEnginePrivate *engine = static_cast<QScript::GlobalObject*>(exec->dynamicGlobalObject())->engine;
+ QObject *qobj = wrapper->value();
+ Q_ASSERT_X(qobj != 0, "QtFunction::call", "handle the case when QObject has been deleted");
+
+ const QMetaObject *meta = qobj->metaObject();
+ QObject *thisQObject;
+ if (thisValue.isObject(&QObjectWrapperObject::info))
+ thisQObject = static_cast<QObjectWrapperObject*>(JSC::asObject(thisValue))->value();
+ else
+ thisQObject = qobj; // ### TypeError
+
+ if (!meta->cast(thisQObject)) {
+ // invoking a function in the prototype
+ thisQObject = qobj;
+ }
+
+ QByteArray funName;
+ QScriptMetaMethod chosenMethod;
+ int chosenIndex = -1;
+ QVarLengthArray<QVariant, 9> args;
+ QVector<QScriptMetaArguments> candidates;
+ QVector<QScriptMetaArguments> unresolved;
+ QVector<int> tooFewArgs;
+ QVector<int> conversionFailed;
+ int index;
+ for (index = data->initialIndex; index >= 0; --index) {
+ QMetaMethod method = meta->method(index);
+
+ if (index == data->initialIndex)
+ funName = methodName(method);
+ else {
+ if (methodName(method) != funName)
+ continue;
+ }
+
+ QVector<QScriptMetaType> types;
+ // resolve return type
+ QByteArray returnTypeName = method.typeName();
+ int rtype = QMetaType::type(returnTypeName);
+ if ((rtype == 0) && !returnTypeName.isEmpty()) {
+ if (returnTypeName == "QVariant") {
+ types.append(QScriptMetaType::variant());
+ } else {
+ int enumIndex = indexOfMetaEnum(meta, returnTypeName);
+ if (enumIndex != -1)
+ types.append(QScriptMetaType::metaEnum(enumIndex, returnTypeName));
+ else
+ types.append(QScriptMetaType::unresolved(returnTypeName));
+ }
+ } else {
+/* if (callType == QMetaMethod::Constructor)
+ types.append(QScriptMetaType::metaType(QMetaType::QObjectStar, "QObject*"));
+ else*/ if (returnTypeName == "QVariant")
+ types.append(QScriptMetaType::variant());
+ else
+ types.append(QScriptMetaType::metaType(rtype, returnTypeName));
+ }
+
+ // resolve argument types
+ QList<QByteArray> parameterTypeNames = method.parameterTypes();
+ for (int i = 0; i < parameterTypeNames.count(); ++i) {
+ QByteArray argTypeName = parameterTypeNames.at(i);
+ int atype = QMetaType::type(argTypeName);
+ if (atype == 0) {
+ if (argTypeName == "QVariant") {
+ types.append(QScriptMetaType::variant());
+ } else {
+ int enumIndex = indexOfMetaEnum(meta, argTypeName);
+ if (enumIndex != -1)
+ types.append(QScriptMetaType::metaEnum(enumIndex, argTypeName));
+ else
+ types.append(QScriptMetaType::unresolved(argTypeName));
+ }
+ } else {
+ if (argTypeName == "QVariant")
+ types.append(QScriptMetaType::variant());
+ else
+ types.append(QScriptMetaType::metaType(atype, argTypeName));
+ }
+ }
+
+ QScriptMetaMethod mtd = QScriptMetaMethod(methodName(method), types);
+
+ if (args.count() < mtd.argumentCount()) {
+ tooFewArgs.append(index);
+ continue;
+ }
+
+ if (!mtd.fullyResolved()) {
+ // remember it so we can give an error message later, if necessary
+ unresolved.append(QScriptMetaArguments(/*matchDistance=*/INT_MAX, index,
+ mtd, QVarLengthArray<QVariant, 9>()));
+ if (mtd.hasUnresolvedReturnType())
+ continue;
+ }
+
+ if (args.count() != mtd.count())
+ args.resize(mtd.count());
+
+ QScriptMetaType retType = mtd.returnType();
+ args[0] = QVariant(retType.typeId(), (void *)0); // the result
+
+ // try to convert arguments
+ bool converted = true;
+ int matchDistance = 0;
+ for (int i = 0; converted && i < mtd.argumentCount(); ++i) {
+ QScriptValue actual = engine->scriptValueFromJSCValue(scriptArgs.at(i));
+ QScriptMetaType argType = mtd.argumentType(i);
+ int tid = -1;
+ QVariant v;
+ if (argType.isUnresolved()) {
+ v = QVariant(QMetaType::QObjectStar, (void *)0);
+ converted = engine->convertToNativeQObject(
+ actual, argType.name(), reinterpret_cast<void* *>(v.data()));
+ } else if (argType.isVariant()) {
+ if (actual.isVariant()) {
+ v = actual.toVariant();
+ } else {
+ v = actual.toVariant();
+ converted = v.isValid() || actual.isUndefined() || actual.isNull();
+ }
+ } else {
+ tid = argType.typeId();
+ v = QVariant(tid, (void *)0);
+ converted = QScriptEnginePrivate::convert(actual, tid, v.data(), engine);
+ // ###
+// if (engine->hasUncaughtException())
+// return;
+ }
+
+ if (!converted) {
+ if (actual.isVariant()) {
+ if (tid == -1)
+ tid = argType.typeId();
+ QVariant vv = actual.toVariant();
+ if (vv.canConvert(QVariant::Type(tid))) {
+ v = vv;
+ converted = v.convert(QVariant::Type(tid));
+ if (converted && (vv.userType() != tid))
+ matchDistance += 10;
+ } else {
+ QByteArray vvTypeName = vv.typeName();
+ if (vvTypeName.endsWith('*')
+ && (vvTypeName.left(vvTypeName.size()-1) == argType.name())) {
+ v = QVariant(tid, *reinterpret_cast<void* *>(vv.data()));
+ converted = true;
+ matchDistance += 10;
+ }
+ }
+ } else if (actual.isNumber()) {
+ // see if it's an enum value
+ QMetaEnum m;
+ if (argType.isMetaEnum()) {
+ m = meta->enumerator(argType.enumeratorIndex());
+ } else {
+ int mi = indexOfMetaEnum(meta, argType.name());
+ if (mi != -1)
+ m = meta->enumerator(mi);
+ }
+ if (m.isValid()) {
+ int ival = actual.toInt32();
+ if (m.valueToKey(ival) != 0) {
+ qVariantSetValue(v, ival);
+ converted = true;
+ matchDistance += 10;
+ }
+ }
+ }
+ } else {
+ // determine how well the conversion matched
+ if (actual.isNumber()) {
+ switch (tid) {
+ case QMetaType::Double:
+ // perfect
+ break;
+ case QMetaType::Float:
+ matchDistance += 1;
+ break;
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ matchDistance += 2;
+ break;
+ case QMetaType::Long:
+ case QMetaType::ULong:
+ matchDistance += 3;
+ break;
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ matchDistance += 4;
+ break;
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ matchDistance += 5;
+ break;
+ case QMetaType::Char:
+ case QMetaType::UChar:
+ matchDistance += 6;
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isString()) {
+ switch (tid) {
+ case QMetaType::QString:
+ // perfect
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isBoolean()) {
+ switch (tid) {
+ case QMetaType::Bool:
+ // perfect
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isDate()) {
+ switch (tid) {
+ case QMetaType::QDateTime:
+ // perfect
+ break;
+ case QMetaType::QDate:
+ matchDistance += 1;
+ break;
+ case QMetaType::QTime:
+ matchDistance += 2;
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isRegExp()) {
+ switch (tid) {
+ case QMetaType::QRegExp:
+ // perfect
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isVariant()) {
+ if (argType.isVariant()
+ || (actual.toVariant().userType() == tid)) {
+ // perfect
+ } else {
+ matchDistance += 10;
+ }
+ } else if (actual.isArray()) {
+ switch (tid) {
+ case QMetaType::QStringList:
+ case QMetaType::QVariantList:
+ matchDistance += 5;
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isQObject()) {
+ switch (tid) {
+ case QMetaType::QObjectStar:
+ case QMetaType::QWidgetStar:
+ // perfect
+ break;
+ default:
+ matchDistance += 10;
+ break;
+ }
+ } else if (actual.isNull()) {
+ switch (tid) {
+ case QMetaType::VoidStar:
+ case QMetaType::QObjectStar:
+ case QMetaType::QWidgetStar:
+ // perfect
+ break;
+ default:
+ if (!argType.name().endsWith('*'))
+ matchDistance += 10;
+ break;
+ }
+ } else {
+ matchDistance += 10;
+ }
+ }
+
+ if (converted)
+ args[i+1] = v;
+ }
+
+ if (converted) {
+ if ((scriptArgs.size() == (size_t)mtd.argumentCount())
+ && (matchDistance == 0)) {
+ // perfect match, use this one
+ chosenMethod = mtd;
+ chosenIndex = index;
+ break;
+ } else {
+ QScriptMetaArguments metaArgs(matchDistance, index, mtd, args);
+ if (candidates.isEmpty()) {
+ candidates.append(metaArgs);
+ } else {
+ QScriptMetaArguments otherArgs = candidates.at(0);
+ if ((args.count() > otherArgs.args.count())
+ || ((args.count() == otherArgs.args.count())
+ && (matchDistance <= otherArgs.matchDistance))) {
+ candidates.prepend(metaArgs);
+ } else {
+ candidates.append(metaArgs);
+ }
+ }
+ }
+ } else if (mtd.fullyResolved()) {
+ conversionFailed.append(index);
+ }
+
+ if (!data->maybeOverloaded)
+ break;
+ }
+
+ JSC::JSValue result;
+ if ((chosenIndex == -1) && candidates.isEmpty()) {
+// context->calleeMetaIndex = initialIndex;
+//#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
+// engine->notifyFunctionEntry(context);
+//#endif
+ if (!conversionFailed.isEmpty()) {
+ QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
+ .arg(QLatin1String(funName));
+ for (int i = 0; i < conversionFailed.size(); ++i) {
+ if (i > 0)
+ message += QLatin1String("\n");
+ QMetaMethod mtd = meta->method(conversionFailed.at(i));
+ message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
+ }
+ result = JSC::throwError(exec, JSC::TypeError, qtStringToJSCUString(message));
+ } else if (!unresolved.isEmpty()) {
+ QScriptMetaArguments argsInstance = unresolved.first();
+ int unresolvedIndex = argsInstance.method.firstUnresolvedIndex();
+ Q_ASSERT(unresolvedIndex != -1);
+ QScriptMetaType unresolvedType = argsInstance.method.type(unresolvedIndex);
+ QString unresolvedTypeName = QString::fromLatin1(unresolvedType.name());
+ QString message = QString::fromLatin1("cannot call %0(): ")
+ .arg(QString::fromLatin1(funName));
+ if (unresolvedIndex > 0) {
+ message.append(QString::fromLatin1("argument %0 has unknown type `%1'").
+ arg(unresolvedIndex).arg(unresolvedTypeName));
+ } else {
+ message.append(QString::fromLatin1("unknown return type `%0'")
+ .arg(unresolvedTypeName));
+ }
+ message.append(QString::fromLatin1(" (register the type with qScriptRegisterMetaType())"));
+ result = JSC::throwError(exec, JSC::TypeError, qtStringToJSCUString(message));
+ } else {
+ QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
+ .arg(QLatin1String(funName));
+ for (int i = 0; i < tooFewArgs.size(); ++i) {
+ if (i > 0)
+ message += QLatin1String("\n");
+ QMetaMethod mtd = meta->method(tooFewArgs.at(i));
+ message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
+ }
+ result = JSC::throwError(exec, JSC::SyntaxError, qtStringToJSCUString(message));
+ }
+ } else {
+ if (chosenIndex == -1) {
+ QScriptMetaArguments metaArgs = candidates.at(0);
+ if ((candidates.size() > 1)
+ && (metaArgs.args.count() == candidates.at(1).args.count())
+ && (metaArgs.matchDistance == candidates.at(1).matchDistance)) {
+ // ambiguous call
+ QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
+ .arg(QLatin1String(funName));
+ for (int i = 0; i < candidates.size(); ++i) {
+ if (i > 0)
+ message += QLatin1String("\n");
+ QMetaMethod mtd = meta->method(candidates.at(i).index);
+ message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
+ }
+ result = JSC::throwError(exec, JSC::TypeError, qtStringToJSCUString(message));
+ } else {
+ chosenMethod = metaArgs.method;
+ chosenIndex = metaArgs.index;
+ args = metaArgs.args;
+ }
+ }
+
+ if (chosenIndex != -1) {
+ // call it
+// context->calleeMetaIndex = chosenIndex;
+
+ QVarLengthArray<void*, 9> array(args.count());
+ void **params = array.data();
+ for (int i = 0; i < args.count(); ++i) {
+ const QVariant &v = args[i];
+ switch (chosenMethod.type(i).kind()) {
+ case QScriptMetaType::Variant:
+ params[i] = const_cast<QVariant*>(&v);
+ break;
+ case QScriptMetaType::MetaType:
+ case QScriptMetaType::MetaEnum:
+ case QScriptMetaType::Unresolved:
+ params[i] = const_cast<void*>(v.constData());
+ break;
+ default:
+ Q_ASSERT(0);
+ }
+ }
+
+ QScriptable *scriptable = 0;
+ if (thisQObject)
+ scriptable = scriptableFromQObject(thisQObject);
+ QScriptEngine *oldEngine = 0;
+ if (scriptable) {
+ oldEngine = QScriptablePrivate::get(scriptable)->engine;
+ QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine);
+ }
+
+// ### fixme
+//#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
+// engine->notifyFunctionEntry(context);
+//#endif
+
+/* if (callType == QMetaMethod::Constructor) {
+ Q_ASSERT(meta != 0);
+ meta->static_metacall(QMetaObject::CreateInstance, chosenIndex, params);
+ } else*/ {
+ Q_ASSERT(thisQObject != 0);
+ thisQObject->qt_metacall(QMetaObject::InvokeMetaMethod, chosenIndex, params);
+ }
+
+ if (scriptable)
+ QScriptablePrivate::get(scriptable)->engine = oldEngine;
+
+ if (exec->hadException()) {
+ result = exec->exception() ; // propagate
+ } else {
+ QScriptMetaType retType = chosenMethod.returnType();
+ if (retType.isVariant()) {
+ result = engine->jscValueFromVariant(*(QVariant *)params[0]);
+ } else if (retType.typeId() != 0) {
+ result = engine->scriptValueToJSCValue(engine->create(retType.typeId(), params[0]));
+ if (!result) {
+ QScriptValue sv = QScriptEnginePrivate::get(engine)->newVariant(QVariant(retType.typeId(), params[0]));
+ result = engine->scriptValueToJSCValue(sv);
+ }
+ } else {
+ result = JSC::jsUndefined();
+ }
+ }
+ }
+ }
+
+ return JSC::JSValue();
+}
+
+const JSC::ClassInfo QtFunction::info = { "QtFunction", 0, 0, 0 };
+
+JSC::JSValue QtFunction_call(JSC::ExecState *exec, JSC::JSObject *callee,
+ JSC::JSValue thisValue, const JSC::ArgList &args)
+{
+ if (!callee->isObject(&QtFunction::info))
+ return throwError(exec, JSC::TypeError);
+ return static_cast<QtFunction*>(callee)->call(exec, thisValue, args);
+}
+
+const JSC::ClassInfo QObjectWrapperObject::info = { "QObject", 0, 0, 0 };
+
+QObjectWrapperObject::QObjectWrapperObject(
+ QObject *object, QScriptEngine::ValueOwnership ownership,
+ const QScriptEngine::QObjectWrapOptions &options,
+ WTF::PassRefPtr<JSC::Structure> sid)
+ : JSC::JSObject(sid), data(new Data(object, ownership, options))
+{
+}
+
+QObjectWrapperObject::~QObjectWrapperObject()
+{
+ switch (data->ownership) {
+ case QScriptEngine::QtOwnership:
+ break;
+ case QScriptEngine::ScriptOwnership:
+ if (data->value)
+ delete data->value; // ### fixme
+// eng->disposeQObject(value);
+ break;
+ case QScriptEngine::AutoOwnership:
+ if (data->value && !data->value->parent())
+ delete data->value; // ### fixme
+// eng->disposeQObject(value);
+ break;
+ }
+ delete data;
+}
+
+bool QObjectWrapperObject::getOwnPropertySlot(JSC::ExecState *exec,
+ const JSC::Identifier &propertyName,
+ JSC::PropertySlot &slot)
+{
+ QByteArray name = qtStringFromJSCUString(propertyName.ustring()).toLatin1();
+ QObject *qobject = data->value;
+ if (!qobject) {
+ QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
+ .arg(QString::fromLatin1(name));
+ JSC::throwError(exec, JSC::GeneralError, qtStringToJSCUString(message));
+ return false;
+ }
+
+ const QScriptEngine::QObjectWrapOptions &opt = data->options;
+ const QMetaObject *meta = qobject->metaObject();
+ QScriptEnginePrivate *eng = static_cast<QScript::GlobalObject*>(exec->dynamicGlobalObject())->engine;
+ int index = -1;
+ if (name.contains('(')) {
+ QByteArray normalized = QMetaObject::normalizedSignature(name);
+ if (-1 != (index = meta->indexOfMethod(normalized))) {
+ QMetaMethod method = meta->method(index);
+ if (hasMethodAccess(method, index, opt)) {
+ if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
+ || (index >= meta->methodOffset())) {
+ QtFunction *fun = new (exec)QtFunction(
+ this, index, /*maybeOverloaded=*/false,
+ &exec->globalData(), exec->dynamicGlobalObject()->functionStructure(),
+ propertyName);
+ slot.setValue(fun);
+ return true;
+ }
+ }
+ }
+ }
+
+ index = meta->indexOfProperty(name);
+ if (index != -1) {
+ QMetaProperty prop = meta->property(index);
+ if (prop.isScriptable()) {
+ if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
+ || (index >= meta->propertyOffset())) {
+ JSC::JSValue val = eng->jscValueFromVariant(prop.read(qobject));
+ slot.setValue(val);
+ return true;
+ }
+ }
+ }
+
+ index = qobject->dynamicPropertyNames().indexOf(name);
+ if (index != -1) {
+ JSC::JSValue val = eng->jscValueFromVariant(qobject->property(name));
+ slot.setValue(val);
+ return true;
+ }
+
+ const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
+ ? meta->methodOffset() : 0;
+ for (index = meta->methodCount() - 1; index >= offset; --index) {
+ QMetaMethod method = meta->method(index);
+ if (hasMethodAccess(method, index, opt)
+ && (methodName(method) == name)) {
+ QtFunction *fun = new (exec)QtFunction(
+ this, index, /*maybeOverloaded=*/true,
+ &exec->globalData(), exec->dynamicGlobalObject()->functionStructure(),
+ propertyName);
+ slot.setValue(fun);
+ return true;
+ }
+ }
+
+ if (!(opt & QScriptEngine::ExcludeChildObjects)) {
+ QList<QObject*> children = qobject->children();
+ for (index = 0; index < children.count(); ++index) {
+ QObject *child = children.at(index);
+ if (child->objectName() == qtStringFromJSCUString(propertyName.ustring())) {
+ QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
+ QScriptValue tmp = QScriptEnginePrivate::get(eng)->newQObject(child, QScriptEngine::QtOwnership, opt);
+ slot.setValue(eng->scriptValueToJSCValue(tmp));
+ return true;
+ }
+ }
+ }
+
+ return JSC::JSObject::getOwnPropertySlot(exec, propertyName, slot);
+}
+
+void QObjectWrapperObject::put(JSC::ExecState* exec, const JSC::Identifier& propertyName,
+ JSC::JSValue value, JSC::PutPropertySlot &slot)
+{
+ QByteArray name = qtStringFromJSCUString(propertyName.ustring()).toLatin1();
+ QObject *qobject = data->value;
+ if (!qobject) {
+ QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
+ .arg(QString::fromLatin1(name));
+ JSC::throwError(exec, JSC::GeneralError, qtStringToJSCUString(message));
+ return;
+ }
+
+ const QScriptEngine::QObjectWrapOptions &opt = data->options;
+ const QMetaObject *meta = qobject->metaObject();
+ QScriptEnginePrivate *eng = static_cast<QScript::GlobalObject*>(exec->dynamicGlobalObject())->engine;
+ int index = -1;
+ if (name.contains('(')) {
+ QByteArray normalized = QMetaObject::normalizedSignature(name);
+ if (-1 != (index = meta->indexOfMethod(normalized))) {
+ QMetaMethod method = meta->method(index);
+ if (hasMethodAccess(method, index, opt)) {
+ if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
+ || (index >= meta->methodOffset())) {
+ Q_ASSERT(0);
+ return;
+ }
+ }
+ }
+ }
+
+ index = meta->indexOfProperty(name);
+ if (index != -1) {
+ QMetaProperty prop = meta->property(index);
+ if (prop.isScriptable()) {
+ if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
+ || (index >= meta->propertyOffset())) {
+ QVariant v = eng->jscValueToVariant(value, prop.userType());
+ (void)prop.write(qobject, v);
+ return;
+ }
+ }
+ }
+
+ index = qobject->dynamicPropertyNames().indexOf(name);
+ if (index != -1) {
+ QVariant v = eng->scriptValueFromJSCValue(value).toVariant();
+ (void)qobject->setProperty(name, v);
+ return;
+ }
+
+ JSC::JSObject::put(exec, propertyName, value, slot);
+}
+
+bool QObjectWrapperObject::deleteProperty(JSC::ExecState *exec,
+ const JSC::Identifier& propertyName)
+{
+ QByteArray name = qtStringFromJSCUString(propertyName.ustring()).toLatin1();
+ QObject *qobject = data->value;
+ if (!qobject) {
+ QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
+ .arg(QString::fromLatin1(name));
+ JSC::throwError(exec, JSC::GeneralError, qtStringToJSCUString(message));
+ return false;
+ }
+
+ int index = qobject->dynamicPropertyNames().indexOf(name);
+ if (index != -1) {
+ (void)qobject->setProperty(name, QVariant());
+ return true;
+ }
+
+ return JSC::JSObject::deleteProperty(exec, propertyName);
+}
+
+void QObjectWrapperObject::getPropertyNames(JSC::ExecState *exec, JSC::PropertyNameArray &propertyNames)
+{
+ QObject *qobject = data->value;
+ if (!qobject) {
+ QString message = QString::fromLatin1("cannot get property names of deleted QObject");
+ JSC::throwError(exec, JSC::GeneralError, qtStringToJSCUString(message));
+ return;
+ }
+
+ const QScriptEngine::QObjectWrapOptions &opt = data->options;
+ const QMetaObject *meta = qobject->metaObject();
+ {
+ int i = (opt & QScriptEngine::ExcludeSuperClassProperties)
+ ? meta->propertyOffset() : 0;
+ for ( ; i < meta->propertyCount(); ++i) {
+ QMetaProperty prop = meta->property(i);
+ if (isEnumerableMetaProperty(prop, meta, i)) {
+ QString name = QString::fromLatin1(prop.name());
+ propertyNames.add(JSC::Identifier(exec, qtStringToJSCUString(name)));
+ }
+ }
+ }
+
+ {
+ QList<QByteArray> dpNames = qobject->dynamicPropertyNames();
+ for (int i = 0; i < dpNames.size(); ++i) {
+ QString name = QString::fromLatin1(dpNames.at(i));
+ propertyNames.add(JSC::Identifier(exec, qtStringToJSCUString(name)));
+ }
+ }
+
+ {
+ int i = (opt & QScriptEngine::ExcludeSuperClassMethods)
+ ? meta->methodOffset() : 0;
+ for ( ; i < meta->methodCount(); ++i) {
+ QMetaMethod method = meta->method(i);
+ if (hasMethodAccess(method, i, opt)) {
+ QMetaMethod method = meta->method(i);
+ QString name = QString::fromLatin1(methodName(method));
+ propertyNames.add(JSC::Identifier(exec, qtStringToJSCUString(name)));
+ QString sig = QString::fromLatin1(method.signature());
+ propertyNames.add(JSC::Identifier(exec, qtStringToJSCUString(sig)));
+ }
+ }
+ }
+
+ JSC::JSObject::getPropertyNames(exec, propertyNames);
+}
+
+static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncToString(JSC::ExecState *exec, JSC::JSObject*,
+ JSC::JSValue thisValue, const JSC::ArgList&)
+{
+ if (!thisValue.isObject(&QObjectWrapperObject::info))
+ return throwError(exec, JSC::TypeError);
+ QObject *obj = static_cast<QObjectWrapperObject*>(JSC::asObject(thisValue))->value();
+ const QMetaObject *meta = obj ? obj->metaObject() : &QObject::staticMetaObject;
+ QString name = obj ? obj->objectName() : QString::fromUtf8("unnamed");
+ QString str = QString::fromUtf8("%0(name = \"%1\")")
+ .arg(QLatin1String(meta->className())).arg(name);
+ return JSC::jsString(exec, qtStringToJSCUString(str));
+}
+
+QObjectPrototype::QObjectPrototype(JSC::ExecState* exec, WTF::PassRefPtr<JSC::Structure> structure,
+ JSC::Structure* prototypeFunctionStructure)
+ : QObjectWrapperObject(new QObject(), QScriptEngine::AutoOwnership, /*options=*/0, structure)
+{
+ putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/0, exec->propertyNames().toString, qobjectProtoFuncToString), JSC::DontEnum);
+ // ### findChild(), findChildren()
+}
+
+static const uint qt_meta_data_QObjectConnectionManager[] = {
+
+ // content:
+ 1, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 1, 10, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+
+ // slots: signature, parameters, type, tag, flags
+ 35, 34, 34, 34, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_QObjectConnectionManager[] = {
+ "QScript::QObjectConnectionManager\0\0execute()\0"
+};
+
+const QMetaObject QObjectConnectionManager::staticMetaObject = {
+ { &QObject::staticMetaObject, qt_meta_stringdata_QObjectConnectionManager,
+ qt_meta_data_QObjectConnectionManager, 0 }
+};
+
+const QMetaObject *QObjectConnectionManager::metaObject() const
+{
+ return &staticMetaObject;
+}
+
+void *QObjectConnectionManager::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_QObjectConnectionManager))
+ return static_cast<void*>(const_cast<QObjectConnectionManager*>(this));
+ return QObject::qt_metacast(_clname);
+}
+
+int QObjectConnectionManager::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ execute(_id, _a);
+ _id -= slotCounter;
+ }
+ return _id;
+}
+
+void QObjectConnectionManager::execute(int slotIndex, void **argv)
+{
+ JSC::JSValue receiver;
+ JSC::JSValue slot;
+ JSC::JSValue senderWrapper;
+ int signalIndex = -1;
+ for (int i = 0; i < connections.size(); ++i) {
+ const QVector<QObjectConnection> &cs = connections.at(i);
+ for (int j = 0; j < cs.size(); ++j) {
+ const QObjectConnection &c = cs.at(j);
+ if (c.slotIndex == slotIndex) {
+ receiver = c.receiver;
+ slot = c.slot;
+ senderWrapper = c.senderWrapper;
+ signalIndex = i;
+ break;
+ }
+ }
+ }
+// Q_ASSERT(slot != 0);
+
+#if 0
+ // ### fixme
+ if (engine->isCollecting()) {
+ // we can't do a script function call during GC,
+ // so we're forced to ignore this signal
+ return;
+ }
+
+ QScriptFunction *fun = engine->convertToNativeFunction(slot);
+ if (fun == 0) {
+ // the signal handler has been GC'ed. This can only happen when
+ // a QObject is owned by the engine, the engine is destroyed, and
+ // there is a script function connected to the destroyed() signal
+ Q_ASSERT(signalIndex <= 1); // destroyed(QObject*)
+ return;
+ }
+#endif
+
+ const QMetaObject *meta = sender()->metaObject();
+ const QMetaMethod method = meta->method(signalIndex);
+
+ QList<QByteArray> parameterTypes = method.parameterTypes();
+ int argc = parameterTypes.count();
+
+ JSC::ExecState *exec = engine->globalObject->globalExec();
+ JSC::ArgList jscArgs;
+ for (int i = 0; i < argc; ++i) {
+ int argType = QMetaType::type(parameterTypes.at(i));
+ QScriptValue arg = engine->create(argType, argv[i + 1]);
+ Q_ASSERT_X(false, Q_FUNC_INFO, "implement me");
+#if 0
+ jscArgs.append(engine->scriptValueToJSCValue(arg));
+#endif
+ }
+
+ JSC::JSValue senderObject;
+ if (senderWrapper && senderWrapper.isObject(&QObjectWrapperObject::info))
+ senderObject = senderWrapper;
+ else {
+ QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
+ senderObject = engine->newQObject(sender(), QScriptEngine::QtOwnership, opt);
+ }
+
+ JSC::JSValue thisObject;
+ if (receiver && receiver.isObject())
+ thisObject = receiver;
+ else
+ thisObject = exec->dynamicGlobalObject();
+
+ (void)static_cast<JSC::JSFunction*>(JSC::asFunction(slot))->call(exec, thisObject, jscArgs);
+ if (exec->hadException())
+ engine->emitSignalHandlerException();
+}
+
+QObjectConnectionManager::QObjectConnectionManager(QScriptEnginePrivate *eng)
+ : engine(eng), slotCounter(0)
+{
+}
+
+QObjectConnectionManager::~QObjectConnectionManager()
+{
+}
+
+void QObjectConnectionManager::mark()
+{
+ for (int i = 0; i < connections.size(); ++i) {
+ QVector<QObjectConnection> &cs = connections[i];
+ for (int j = 0; j < cs.size(); ++j)
+ cs[j].mark();
+ }
+}
+
+bool QObjectConnectionManager::addSignalHandler(
+ QObject *sender, const char *signal, JSC::JSValue receiver,
+ JSC::JSValue function, JSC::JSValue senderWrapper)
+{
+ Q_ASSERT(sender != 0);
+ Q_ASSERT(signal != 0);
+ Q_ASSERT(function.isObject(&JSC::JSFunction::info));
+ const QMetaObject *meta = sender->metaObject();
+ int signalIndex = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
+ if (signalIndex == -1)
+ return false;
+ if (connections.size() <= signalIndex)
+ connections.resize(signalIndex+1);
+ QVector<QObjectConnection> &cs = connections[signalIndex];
+ int absSlotIndex = slotCounter + metaObject()->methodOffset();
+ bool ok = QMetaObject::connect(sender, signalIndex, this, absSlotIndex);
+ if (ok)
+ cs.append(QObjectConnection(slotCounter++, receiver, function, senderWrapper));
+ return ok;
+}
+
+bool QObjectConnectionManager::removeSignalHandler(
+ QObject *sender, const char *signal,
+ JSC::JSValue receiver, JSC::JSValue slot)
+{
+ Q_ASSERT(sender != 0);
+ Q_ASSERT(signal != 0);
+ const QMetaObject *meta = sender->metaObject();
+ int signalIndex = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
+ if (signalIndex == -1)
+ return false;
+ if (connections.size() <= signalIndex)
+ return false;
+ QVector<QObjectConnection> &cs = connections[signalIndex];
+ for (int i = 0; i < cs.size(); ++i) {
+ const QObjectConnection &c = cs.at(i);
+ if (c.hasTarget(receiver, slot)) {
+ int absSlotIndex = c.slotIndex + metaObject()->methodOffset();
+ bool ok = QMetaObject::disconnect(sender, signalIndex, this, absSlotIndex);
+ if (ok)
+ cs.remove(i);
+ return ok;
+ }
+ }
+ return false;
+}
+
+QObjectData::QObjectData(QScriptEnginePrivate *eng)
+ : engine(eng), connectionManager(0)
+{
+}
+
+QObjectData::~QObjectData()
+{
+ if (connectionManager) {
+ delete connectionManager;
+ connectionManager = 0;
+ }
+}
+
+void QObjectData::mark()
+{
+ if (connectionManager)
+ connectionManager->mark();
+}
+
+bool QObjectData::addSignalHandler(QObject *sender,
+ const char *signal,
+ JSC::JSValue receiver,
+ JSC::JSValue slot,
+ JSC::JSValue senderWrapper)
+{
+ if (!connectionManager)
+ connectionManager = new QObjectConnectionManager(engine);
+ return connectionManager->addSignalHandler(
+ sender, signal, receiver, slot, senderWrapper);
+}
+
+bool QObjectData::removeSignalHandler(QObject *sender,
+ const char *signal,
+ JSC::JSValue receiver,
+ JSC::JSValue slot)
+{
+ if (!connectionManager)
+ return false;
+ return connectionManager->removeSignalHandler(
+ sender, signal, receiver, slot);
+}
+
+} // namespace QScript
+
+namespace JSC
+{
+ ASSERT_CLASS_FITS_IN_CELL(QScript::QtFunction);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SCRIPT
diff --git a/src/script/bridge/qscriptqobject_p.h b/src/script/bridge/qscriptqobject_p.h
new file mode 100644
index 0000000..3c2f2d2
--- /dev/null
+++ b/src/script/bridge/qscriptqobject_p.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCRIPTQOBJECT_P_H
+#define QSCRIPTQOBJECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qobject.h>
+
+#ifndef QT_NO_SCRIPT
+
+#include "qscriptengine.h"
+#include <QtCore/qpointer.h>
+
+#include "JSObject.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QScript
+{
+
+class QObjectWrapperObject : public JSC::JSObject
+{
+public:
+ // work around CELL_SIZE limitation
+ struct Data
+ {
+ QPointer<QObject> value;
+ QScriptEngine::ValueOwnership ownership;
+ QScriptEngine::QObjectWrapOptions options;
+
+ Data(QObject *o, QScriptEngine::ValueOwnership own,
+ QScriptEngine::QObjectWrapOptions opt)
+ : value(o), ownership(own), options(opt) {}
+ };
+
+ explicit QObjectWrapperObject(
+ QObject *object, QScriptEngine::ValueOwnership ownership,
+ const QScriptEngine::QObjectWrapOptions &options,
+ WTF::PassRefPtr<JSC::Structure> sid);
+ ~QObjectWrapperObject();
+
+ virtual bool getOwnPropertySlot(JSC::ExecState*,
+ const JSC::Identifier& propertyName,
+ JSC::PropertySlot&);
+ virtual void put(JSC::ExecState* exec, const JSC::Identifier& propertyName,
+ JSC::JSValue, JSC::PutPropertySlot&);
+ virtual bool deleteProperty(JSC::ExecState*,
+ const JSC::Identifier& propertyName);
+ virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&);
+
+ virtual const JSC::ClassInfo* classInfo() const { return &info; }
+ static const JSC::ClassInfo info;
+
+ inline QObject *value() const { return data->value; }
+ inline void setValue(QObject* value) { data->value = value; }
+
+ inline QScriptEngine::ValueOwnership ownership() const
+ { return data->ownership; }
+ inline void setOwnership(QScriptEngine::ValueOwnership ownership)
+ { data->ownership = ownership; }
+
+ inline QScriptEngine::QObjectWrapOptions options() const
+ { return data->options; }
+ inline void setOptions(QScriptEngine::QObjectWrapOptions options)
+ { data->options = options; }
+
+ static WTF::PassRefPtr<JSC::Structure> createStructureID(JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(prototype, JSC::TypeInfo(JSC::ObjectType));
+ }
+
+protected:
+ Data *data;
+};
+
+class QObjectPrototype : public QObjectWrapperObject
+{
+public:
+ QObjectPrototype(JSC::ExecState*, WTF::PassRefPtr<JSC::Structure>,
+ JSC::Structure* prototypeFunctionStructure);
+};
+
+class QObjectConnectionManager;
+
+class QObjectData // : public QObjectUserData
+{
+public:
+ QObjectData(QScriptEnginePrivate *engine);
+ ~QObjectData();
+
+ bool addSignalHandler(QObject *sender,
+ const char *signal,
+ JSC::JSValue receiver,
+ JSC::JSValue slot,
+ JSC::JSValue senderWrapper = 0);
+ bool removeSignalHandler(QObject *sender,
+ const char *signal,
+ JSC::JSValue receiver,
+ JSC::JSValue slot);
+
+ void mark();
+
+private:
+ QScriptEnginePrivate *engine;
+ QScript::QObjectConnectionManager *connectionManager;
+// QList<QScriptQObjectWrapperInfo> wrappers;
+};
+
+} // namespace QScript
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SCRIPT
+
+#endif
diff --git a/src/script/bridge/qscriptvariant.cpp b/src/script/bridge/qscriptvariant.cpp
new file mode 100644
index 0000000..0255961
--- /dev/null
+++ b/src/script/bridge/qscriptvariant.cpp
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qscriptvariant_p.h"
+
+#ifndef QT_NO_SCRIPT
+
+#include "Error.h"
+#include "PrototypeFunction.h"
+#include "JSString.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace JSC
+{
+ASSERT_CLASS_FITS_IN_CELL(QScript::QVariantWrapperObject);
+ASSERT_CLASS_FITS_IN_CELL(QScript::QVariantPrototype);
+}
+
+namespace QScript
+{
+
+JSC::UString qtStringToJSCUString(const QString &str);
+
+const JSC::ClassInfo QVariantWrapperObject::info = { "QVariant", 0, 0, 0 };
+
+QVariantWrapperObject::QVariantWrapperObject(WTF::PassRefPtr<JSC::Structure> sid)
+ : JSC::JSObject(sid), data(new Data())
+{
+}
+
+QVariantWrapperObject::~QVariantWrapperObject()
+{
+ delete data;
+}
+
+static JSC::JSValue JSC_HOST_CALL variantProtoFuncToString(JSC::ExecState *exec, JSC::JSObject*,
+ JSC::JSValue thisValue, const JSC::ArgList&)
+{
+ if (!thisValue.isObject(&QVariantWrapperObject::info))
+ return throwError(exec, JSC::TypeError);
+ const QVariant &v = static_cast<QVariantWrapperObject*>(JSC::asObject(thisValue))->value();
+ // ### check the type
+ return JSC::jsString(exec, QScript::qtStringToJSCUString(v.toString()));
+}
+
+static JSC::JSValue JSC_HOST_CALL variantProtoFuncValueOf(JSC::ExecState *exec, JSC::JSObject*,
+ JSC::JSValue thisValue, const JSC::ArgList&)
+{
+ if (!thisValue.isObject(&QVariantWrapperObject::info))
+ return throwError(exec, JSC::TypeError);
+ const QVariant &v = static_cast<QVariantWrapperObject*>(JSC::asObject(thisValue))->value();
+ switch (v.type()) {
+ case QVariant::Invalid:
+ return JSC::jsUndefined();
+
+ case QVariant::String:
+ return JSC::jsString(exec, QScript::qtStringToJSCUString(v.toString()));
+
+ case QVariant::Int:
+ return JSC::jsNumber(exec, v.toInt());
+
+ case QVariant::Bool:
+ return JSC::jsBoolean(v.toBool());
+
+ case QVariant::Double:
+ return JSC::jsNumber(exec, v.toDouble());
+
+// case QVariant::Char:
+// return JSC::jsNumber(exec, v.toChar().unicode());
+
+ case QVariant::UInt:
+ return JSC::jsNumber(exec, v.toUInt());
+ default:
+ ;
+ }
+ return thisValue;
+}
+
+QVariantPrototype::QVariantPrototype(JSC::ExecState* exec, WTF::PassRefPtr<JSC::Structure> structure,
+ JSC::Structure* prototypeFunctionStructure)
+ : QVariantWrapperObject(structure)
+{
+ setValue(QVariant());
+
+ putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, variantProtoFuncToString), JSC::DontEnum);
+ putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().valueOf, variantProtoFuncValueOf), JSC::DontEnum);
+}
+
+} // namespace QScript
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SCRIPT
diff --git a/src/script/bridge/qscriptvariant_p.h b/src/script/bridge/qscriptvariant_p.h
new file mode 100644
index 0000000..da0bb26
--- /dev/null
+++ b/src/script/bridge/qscriptvariant_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCRIPTVARIANT_P_H
+#define QSCRIPTVARIANT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qvariant.h>
+
+#ifndef QT_NO_SCRIPT
+
+#include "JSObject.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QScript
+{
+
+class QVariantWrapperObject : public JSC::JSObject
+{
+public:
+ // work around CELL_SIZE limitation
+ struct Data
+ {
+ QVariant value;
+ };
+
+ explicit QVariantWrapperObject(WTF::PassRefPtr<JSC::Structure> sid);
+ ~QVariantWrapperObject();
+
+ virtual const JSC::ClassInfo* classInfo() const { return &info; }
+ static const JSC::ClassInfo info;
+
+ inline const QVariant &value() const { return data->value; }
+ inline void setValue(const QVariant &value) { data->value = value; }
+
+private:
+ Data *data;
+};
+
+class QVariantPrototype : public QVariantWrapperObject
+{
+public:
+ QVariantPrototype(JSC::ExecState*, WTF::PassRefPtr<JSC::Structure>,
+ JSC::Structure* prototypeFunctionStructure);
+};
+
+} // namespace QScript
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SCRIPT
+
+#endif