summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKent Hansen <khansen@trolltech.com>2009-07-02 14:38:52 (GMT)
committerKent Hansen <khansen@trolltech.com>2009-07-02 14:38:52 (GMT)
commit2b54a6831ebf8af0540c72519173a9c5e2d94aef (patch)
tree7b019f9d143e4c52f6df3fc220b06671b65ad2c1
parent0357533025a7e4066def7665f3c77337f1ab21db (diff)
downloadQt-2b54a6831ebf8af0540c72519173a9c5e2d94aef.zip
Qt-2b54a6831ebf8af0540c72519173a9c5e2d94aef.tar.gz
Qt-2b54a6831ebf8af0540c72519173a9c5e2d94aef.tar.bz2
implement a fair amount of the QScriptClass functionality
Enumeration is missing, as is the ability to change the class of an object after it has been created.
-rw-r--r--src/script/api/qscriptengine.cpp136
-rw-r--r--src/script/api/qscriptengine_p.h58
-rw-r--r--src/script/api/qscriptstring.cpp8
-rw-r--r--src/script/api/qscriptvalue.cpp22
-rw-r--r--tests/auto/qscriptclass/tst_qscriptclass.cpp3
5 files changed, 212 insertions, 15 deletions
diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp
index e8a2436..be6cdba 100644
--- a/src/script/api/qscriptengine.cpp
+++ b/src/script/api/qscriptengine.cpp
@@ -19,6 +19,7 @@
#include "qscriptstring_p.h"
#include "qscriptvalue_p.h"
#include "qscriptvalueiterator.h"
+#include "qscriptclass.h"
#include <QtCore/qstringlist.h>
#include <QtCore/qmetaobject.h>
@@ -292,6 +293,122 @@ QString qtStringFromJSCUString(const JSC::UString &str)
return QString(reinterpret_cast<const QChar*>(str.data()), str.size());
}
+// ### move
+const JSC::ClassInfo ClassObject::info = { "QScript::ClassObject", 0, 0, 0 };
+
+ClassObject::ClassObject(QScriptClass *scriptClass, WTF::PassRefPtr<JSC::Structure> sid)
+ : JSC::JSObject(sid), data(new Data(scriptClass))
+{
+}
+
+ClassObject::~ClassObject()
+{
+ delete data;
+}
+
+bool ClassObject::getOwnPropertySlot(JSC::ExecState *exec,
+ const JSC::Identifier &propertyName,
+ JSC::PropertySlot &slot)
+{
+ QScriptEnginePrivate *engine = static_cast<QScript::GlobalObject*>(exec->dynamicGlobalObject())->engine;
+ QScriptValue scriptObject = engine->scriptValueFromJSCValue(this);
+ QString name = qtStringFromJSCUString(propertyName.ustring());
+ QScriptString scriptName = QScriptEnginePrivate::get(engine)->toStringHandle(name);
+ uint id = 0;
+ QScriptClass::QueryFlags flags = data->scriptClass->queryProperty(
+ scriptObject, scriptName, QScriptClass::HandlesReadAccess, &id);
+ if (flags & QScriptClass::HandlesReadAccess) {
+ QScriptValue value = data->scriptClass->property(scriptObject, scriptName, id);
+ slot.setValue(engine->scriptValueToJSCValue(value));
+ return true;
+ }
+ return JSC::JSObject::getOwnPropertySlot(exec, propertyName, slot);
+}
+
+void ClassObject::put(JSC::ExecState *exec, const JSC::Identifier &propertyName,
+ JSC::JSValue value, JSC::PutPropertySlot &slot)
+{
+ QScriptEnginePrivate *engine = static_cast<QScript::GlobalObject*>(exec->dynamicGlobalObject())->engine;
+ QScriptValue scriptObject = engine->scriptValueFromJSCValue(this);
+ QString name = qtStringFromJSCUString(propertyName.ustring());
+ QScriptString scriptName = QScriptEnginePrivate::get(engine)->toStringHandle(name);
+ uint id = 0;
+ QScriptClass::QueryFlags flags = data->scriptClass->queryProperty(
+ scriptObject, scriptName, QScriptClass::HandlesWriteAccess, &id);
+ if (flags & QScriptClass::HandlesWriteAccess) {
+ data->scriptClass->setProperty(scriptObject, scriptName, id, engine->scriptValueFromJSCValue(value));
+ return;
+ }
+ JSC::JSObject::put(exec, propertyName, value, slot);
+}
+
+bool ClassObject::deleteProperty(JSC::ExecState *exec,
+ const JSC::Identifier &propertyName)
+{
+ Q_ASSERT_X(false, Q_FUNC_INFO, "implement me");
+ return JSC::JSObject::deleteProperty(exec, propertyName);
+}
+
+bool ClassObject::getPropertyAttributes(JSC::ExecState *exec,
+ const JSC::Identifier &propertyName,
+ unsigned &attribs) const
+{
+ QScriptEnginePrivate *engine = static_cast<QScript::GlobalObject*>(exec->dynamicGlobalObject())->engine;
+ QScriptValue scriptObject = engine->scriptValueFromJSCValue(this);
+ QString name = qtStringFromJSCUString(propertyName.ustring());
+ QScriptString scriptName = QScriptEnginePrivate::get(engine)->toStringHandle(name);
+ uint id = 0;
+ QScriptClass::QueryFlags flags = data->scriptClass->queryProperty(
+ scriptObject, scriptName, QScriptClass::HandlesReadAccess, &id);
+ if (flags & QScriptClass::HandlesReadAccess) {
+ QScriptValue::PropertyFlags flags = data->scriptClass->propertyFlags(scriptObject, scriptName, id);
+ attribs = 0;
+ if (flags & QScriptValue::ReadOnly)
+ attribs |= JSC::ReadOnly;
+ if (flags & QScriptValue::SkipInEnumeration)
+ attribs |= JSC::DontEnum;
+ if (flags & QScriptValue::Undeletable)
+ attribs |= JSC::DontDelete;
+ if (flags & QScriptValue::PropertyGetter)
+ attribs |= JSC::Getter;
+ if (flags & QScriptValue::PropertySetter)
+ attribs |= JSC::Setter;
+ attribs |= flags & QScriptValue::UserRange;
+ return true;
+ }
+ return JSC::JSObject::getPropertyAttributes(exec, propertyName, attribs);
+}
+
+void ClassObject::getPropertyNames(JSC::ExecState *exec,
+ JSC::PropertyNameArray &propertyNames)
+{
+ qWarning("Enumeration of custom script objects not implemented");
+ JSC::JSObject::getPropertyNames(exec, propertyNames);
+}
+
+const JSC::ClassInfo* ClassObject::classInfo() const
+{
+ // ### respect QScriptClass::name()
+ return &info;
+}
+
+QScriptClass *ClassObject::scriptClass() const
+{
+ return data->scriptClass;
+}
+
+void ClassObject::setScriptClass(QScriptClass *scriptClass)
+{
+ data->scriptClass = scriptClass;
+}
+
+ClassObjectPrototype::ClassObjectPrototype(JSC::ExecState* exec, WTF::PassRefPtr<JSC::Structure> structure,
+ JSC::Structure* prototypeFunctionStructure)
+ : ClassObject(/*scriptClass=*/0, structure)
+{
+}
+
+
bool isFunction(JSC::JSValue value)
{
if (!value || !value.isObject())
@@ -667,11 +784,16 @@ QScriptEnginePrivate::QScriptEnginePrivate()
qobjectPrototype = new (exec) QScript::QObjectPrototype(exec, QScript::QObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
qobjectWrapperObjectStructure = QScript::QObjectWrapperObject::createStructure(qobjectPrototype);
+
qmetaobjectPrototype = new (exec) QScript::QMetaObjectPrototype(exec, QScript::QMetaObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
qmetaobjectWrapperObjectStructure = QScript::QMetaObjectWrapperObject::createStructure(qmetaobjectPrototype);
+
variantPrototype = new (exec) QScript::QVariantPrototype(exec, QScript::QVariantPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
variantWrapperObjectStructure = QScript::QVariantWrapperObject::createStructure(variantPrototype);
+ classObjectPrototype = new (exec) QScript::ClassObjectPrototype(exec, QScript::ClassObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
+ classObjectStructure = QScript::ClassObject::createStructure(classObjectPrototype);
+
globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "print"), QScript::functionPrint));
globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 0, JSC::Identifier(exec, "gc"), QScript::functionGC));
globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 0, JSC::Identifier(exec, "version"), QScript::functionVersion));
@@ -1386,11 +1508,15 @@ QScriptValue QScriptEngine::newObject()
QScriptValue QScriptEngine::newObject(QScriptClass *scriptClass,
const QScriptValue &data)
{
- Q_ASSERT_X(false, Q_FUNC_INFO, "not implemented");
- // use an internal map from JSObject -> data
- Q_UNUSED(scriptClass);
- Q_UNUSED(data);
- return QScriptValue();
+ Q_D(QScriptEngine);
+ JSC::ExecState* exec = d->globalObject->globalExec();
+ QScript::ClassObject *result = new (exec) QScript::ClassObject(scriptClass, d->classObjectStructure);
+ QScriptValue scriptObject = d->scriptValueFromJSCValue(result);
+ scriptObject.setData(data);
+ QScriptValue proto = scriptClass->prototype();
+ if (proto.isValid())
+ scriptObject.setPrototype(proto);
+ return scriptObject;
}
/*!
diff --git a/src/script/api/qscriptengine_p.h b/src/script/api/qscriptengine_p.h
index 8a81fd3..b1b0d2d 100644
--- a/src/script/api/qscriptengine_p.h
+++ b/src/script/api/qscriptengine_p.h
@@ -48,6 +48,7 @@ namespace QScript
class QObjectPrototype;
class QMetaObjectPrototype;
class QVariantPrototype;
+ class ClassObjectPrototype;
#ifndef QT_NO_QOBJECT
class QObjectData;
#endif
@@ -142,11 +143,16 @@ public:
QScript::QObjectPrototype *qobjectPrototype;
WTF::RefPtr<JSC::Structure> qobjectWrapperObjectStructure;
+
QScript::QMetaObjectPrototype *qmetaobjectPrototype;
WTF::RefPtr<JSC::Structure> qmetaobjectWrapperObjectStructure;
+
QScript::QVariantPrototype *variantPrototype;
WTF::RefPtr<JSC::Structure> variantWrapperObjectStructure;
+ QScript::ClassObjectPrototype *classObjectPrototype;
+ WTF::RefPtr<JSC::Structure> classObjectStructure;
+
QScriptEngineAgent *agent;
QHash<JSC::JSCell*, QBasicAtomicInt> keepAliveValues;
QHash<int, QScriptTypeInfo*> m_typeInfos;
@@ -176,7 +182,57 @@ public:
QScriptEnginePrivate *engine;
};
-}
+// ### move
+class ClassObject : public JSC::JSObject
+{
+public:
+ // work around CELL_SIZE limitation
+ struct Data
+ {
+ QScriptClass *scriptClass;
+
+ Data(QScriptClass *sc)
+ : scriptClass(sc) {}
+ };
+
+ explicit ClassObject(QScriptClass *scriptClass,
+ WTF::PassRefPtr<JSC::Structure> sid);
+ ~ClassObject();
+
+ 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 bool getPropertyAttributes(JSC::ExecState*, const JSC::Identifier&,
+ unsigned&) const;
+ virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&);
+
+ virtual const JSC::ClassInfo* classInfo() const;
+ static const JSC::ClassInfo info;
+
+ static WTF::PassRefPtr<JSC::Structure> createStructure(JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(prototype, JSC::TypeInfo(JSC::ObjectType));
+ }
+
+ QScriptClass *scriptClass() const;
+ void setScriptClass(QScriptClass *scriptClass);
+
+private:
+ Data *data;
+};
+
+class ClassObjectPrototype : public ClassObject
+{
+public:
+ ClassObjectPrototype(JSC::ExecState*, WTF::PassRefPtr<JSC::Structure>,
+ JSC::Structure* prototypeFunctionStructure);
+};
+
+} // namespace QScript
QT_END_NAMESPACE
diff --git a/src/script/api/qscriptstring.cpp b/src/script/api/qscriptstring.cpp
index 89ac4ac..ce38d81 100644
--- a/src/script/api/qscriptstring.cpp
+++ b/src/script/api/qscriptstring.cpp
@@ -138,7 +138,9 @@ bool QScriptString::isValid() const
bool QScriptString::operator==(const QScriptString &other) const
{
Q_D(const QScriptString);
- return (d == other.d_func());
+ // ### change back once proper string handles are implemented
+ return toString() == other.toString();
+// return (d == other.d_func());
}
/*!
@@ -148,7 +150,9 @@ bool QScriptString::operator==(const QScriptString &other) const
bool QScriptString::operator!=(const QScriptString &other) const
{
Q_D(const QScriptString);
- return (d != other.d_func());
+ // ### change back once proper string handles are implemented
+ return toString() != other.toString();
+// return (d != other.d_func());
}
/*!
diff --git a/src/script/api/qscriptvalue.cpp b/src/script/api/qscriptvalue.cpp
index 4d8f18a..09f0d0c 100644
--- a/src/script/api/qscriptvalue.cpp
+++ b/src/script/api/qscriptvalue.cpp
@@ -2323,11 +2323,13 @@ void QScriptValue::setData(const QScriptValue &data)
*/
QScriptClass *QScriptValue::scriptClass() const
{
- if (isObject())
+ Q_D(const QScriptValue);
+ if (!d || !d->isJSC() || !d->jscValue.isObject())
return 0;
- // ### implement me
- Q_ASSERT_X(false, Q_FUNC_INFO, "not implemented");
- return 0;
+ if (!d->jscValue.isObject(&QScript::ClassObject::info))
+ return 0;
+ QScript::ClassObject *instance = static_cast<QScript::ClassObject*>(JSC::asObject(d->jscValue));
+ return instance->scriptClass();
}
/*!
@@ -2345,9 +2347,15 @@ QScriptClass *QScriptValue::scriptClass() const
*/
void QScriptValue::setScriptClass(QScriptClass *scriptClass)
{
- Q_ASSERT_X(false, Q_FUNC_INFO, "not implemented");
- // no idea... use a "hidden" property?
- Q_UNUSED(scriptClass);
+ Q_D(QScriptValue);
+ if (!d || !d->isJSC() || !d->jscValue.isObject())
+ return;
+ if (!d->jscValue.isObject(&QScript::ClassObject::info)) {
+ qWarning("QScriptValue::setScriptClass() not implemented");
+ return;
+ }
+ QScript::ClassObject *instance = static_cast<QScript::ClassObject*>(JSC::asObject(d->jscValue));
+ instance->setScriptClass(scriptClass);
}
/*!
diff --git a/tests/auto/qscriptclass/tst_qscriptclass.cpp b/tests/auto/qscriptclass/tst_qscriptclass.cpp
index 48ea51d..10d2183 100644
--- a/tests/auto/qscriptclass/tst_qscriptclass.cpp
+++ b/tests/auto/qscriptclass/tst_qscriptclass.cpp
@@ -558,6 +558,7 @@ void tst_QScriptClass::newInstance()
QScriptValue obj1 = eng.newObject(&cls);
QVERIFY(!obj1.data().isValid());
QVERIFY(obj1.prototype().strictlyEquals(cls.prototype()));
+ QEXPECT_FAIL("", "classname is not implemented", Continue);
QCOMPARE(obj1.toString(), QString::fromLatin1("[object TestClass]"));
QCOMPARE(obj1.scriptClass(), (QScriptClass*)&cls);
@@ -627,11 +628,13 @@ void tst_QScriptClass::getAndSetProperty()
QVERIFY(!cls.lastPropertyObject().isValid());
QVERIFY(!cls.lastSetPropertyObject().isValid());
// ### ideally, we should only test for HandlesWriteAccess in this case
+ QEXPECT_FAIL("", "Doesn't work yet", Continue);
QVERIFY(cls.lastQueryPropertyFlags() == (QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess));
// re-read property
cls.clearReceivedArgs();
QVERIFY(o.property(s).strictlyEquals(num));
+ QEXPECT_FAIL("", "Doesn't work yet", Continue);
QVERIFY(!cls.lastQueryPropertyObject().isValid());
}
}