aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2011-07-29 10:25:44 +0200
committerQt by Nokia <qt-info@nokia.com>2011-07-29 13:00:52 +0200
commitd410ad364ec0b8877797145c68a4d7c3c98ce1c0 (patch)
tree11862c21e5e465abe3275768918f82cbec2bc6e7
parent43b783d09e0899165bbe964a175785ccdfedf6e5 (diff)
Merge the QJSEngine and QJSValue development branch into master.
This replaces the dependency to QtScript with two new builtin classes QJSValue and QJSEngine. This is still work in progress, development continues now in the master branch. Change-Id: I7f5487feb45c972f25a22b10cc81b9218b9805de Reviewed-on: http://codereview.qt.nokia.com/2299 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Simon Hausmann <simon.hausmann@nokia.com>
-rw-r--r--modules/qt_declarative.pri2
m---------src/3rdparty/v80
-rw-r--r--src/declarative/debugger/qdeclarativedebughelper.cpp4
-rw-r--r--src/declarative/debugger/qjsdebuggeragent.cpp296
-rw-r--r--src/declarative/debugger/qjsdebuggeragent_p.h19
-rw-r--r--src/declarative/declarative.pro2
-rw-r--r--src/declarative/items/context2d/qsgcontext2d.cpp6
-rw-r--r--src/declarative/items/context2d/qsgcontext2d_p.h6
-rw-r--r--src/declarative/items/qsgitem.cpp2
-rw-r--r--src/declarative/qml/qdeclarative.h8
-rw-r--r--src/declarative/qml/qdeclarativebinding.cpp2
-rw-r--r--src/declarative/qml/qdeclarativecompileddata.cpp4
-rw-r--r--src/declarative/qml/qdeclarativecompiler.cpp8
-rw-r--r--src/declarative/qml/qdeclarativecompiler_p.h4
-rw-r--r--src/declarative/qml/qdeclarativecomponent.cpp3
-rw-r--r--src/declarative/qml/qdeclarativecomponent.h2
-rw-r--r--src/declarative/qml/qdeclarativecontext.cpp4
-rw-r--r--src/declarative/qml/qdeclarativecontext.h2
-rw-r--r--src/declarative/qml/qdeclarativecontext_p.h2
-rw-r--r--src/declarative/qml/qdeclarativedata_p.h2
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp11
-rw-r--r--src/declarative/qml/qdeclarativeengine.h7
-rw-r--r--src/declarative/qml/qdeclarativeengine_p.h5
-rw-r--r--src/declarative/qml/qdeclarativeexpression.cpp20
-rw-r--r--src/declarative/qml/qdeclarativemetatype.cpp14
-rw-r--r--src/declarative/qml/qdeclarativemetatype_p.h12
-rw-r--r--src/declarative/qml/qdeclarativeprivate.h8
-rw-r--r--src/declarative/qml/qdeclarativepropertycache.cpp8
-rw-r--r--src/declarative/qml/qdeclarativepropertycache_p.h5
-rw-r--r--src/declarative/qml/qdeclarativesqldatabase_p.h2
-rw-r--r--src/declarative/qml/qdeclarativetypeloader.cpp2
-rw-r--r--src/declarative/qml/qdeclarativetypeloader_p.h3
-rw-r--r--src/declarative/qml/qdeclarativetypenamecache_p.h2
-rw-r--r--src/declarative/qml/qdeclarativevme.cpp4
-rw-r--r--src/declarative/qml/qdeclarativevme_p.h2
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject.cpp40
-rw-r--r--src/declarative/qml/qdeclarativeworkerscript.cpp10
-rw-r--r--src/declarative/qml/qdeclarativeworkerscript_p.h2
-rw-r--r--src/declarative/qml/qdeclarativexmlhttprequest.cpp5
-rw-r--r--src/declarative/qml/qdeclarativexmlhttprequest_p.h2
-rw-r--r--src/declarative/qml/v4/qdeclarativev4bindings.cpp44
-rw-r--r--src/declarative/qml/v4/qdeclarativev4irbuilder.cpp2
-rw-r--r--src/declarative/qml/v8/qjsconverter_p.h272
-rw-r--r--src/declarative/qml/v8/qjsengine.cpp431
-rw-r--r--src/declarative/qml/v8/qjsengine.h151
-rw-r--r--src/declarative/qml/v8/qjsvalue.cpp1024
-rw-r--r--src/declarative/qml/v8/qjsvalue.h165
-rw-r--r--src/declarative/qml/v8/qjsvalue_impl_p.h1133
-rw-r--r--src/declarative/qml/v8/qjsvalue_p.h213
-rw-r--r--src/declarative/qml/v8/qjsvalueiterator.cpp294
-rw-r--r--src/declarative/qml/v8/qjsvalueiterator.h64
-rw-r--r--src/declarative/qml/v8/qscript_impl_p.h41
-rw-r--r--src/declarative/qml/v8/qscriptisolate_p.h71
-rw-r--r--src/declarative/qml/v8/qscriptoriginalglobalobject_p.h158
-rw-r--r--src/declarative/qml/v8/qscriptshareddata_p.h151
-rw-r--r--src/declarative/qml/v8/qscripttools_p.h216
-rw-r--r--src/declarative/qml/v8/qv8bindings.cpp2
-rw-r--r--src/declarative/qml/v8/qv8engine.cpp751
-rw-r--r--src/declarative/qml/v8/qv8engine_impl_p.h131
-rw-r--r--src/declarative/qml/v8/qv8engine_p.h108
-rw-r--r--src/declarative/qml/v8/qv8include.cpp2
-rw-r--r--src/declarative/qml/v8/qv8qobjectwrapper.cpp36
-rw-r--r--src/declarative/qml/v8/qv8typewrapper.cpp20
-rw-r--r--src/declarative/qml/v8/qv8variantwrapper.cpp38
-rw-r--r--src/declarative/qml/v8/qv8variantwrapper_p.h4
-rw-r--r--src/declarative/qml/v8/script.pri20
-rw-r--r--src/declarative/qml/v8/v8.pri4
-rw-r--r--src/declarative/util/qdeclarativebind.cpp5
-rw-r--r--src/declarative/util/qdeclarativelistmodel.cpp4
-rw-r--r--src/imports/folderlistmodel/folderlistmodel.pro2
-rw-r--r--src/imports/gestures/gestures.pro2
-rwxr-xr-xsrc/imports/inputcontext/inputcontext.pro2
-rw-r--r--src/imports/inputcontext/plugin.cpp2
-rw-r--r--src/imports/testlib/main.cpp6
-rw-r--r--src/imports/testlib/testlib.pro2
-rw-r--r--src/qmltest/qmltest.pro2
-rw-r--r--src/qmltest/quicktest.cpp7
-rw-r--r--src/qtquick1/graphicsitems/qdeclarativeitem.cpp2
-rw-r--r--src/qtquick1/qtquick1.pro2
-rw-r--r--src/qtquick1/util/qdeclarativebind.cpp5
-rw-r--r--src/qtquick1/util/qdeclarativelistmodel.cpp2
-rw-r--r--src/qtquick1/util/qdeclarativelistmodel_p.h2
-rw-r--r--src/qtquick1/util/qdeclarativelistmodel_p_p.h2
-rw-r--r--src/qtquick1/util/qdeclarativelistmodelworkeragent_p.h2
-rw-r--r--src/qtquick1/util/qdeclarativeview.cpp1
-rw-r--r--src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch286
-rw-r--r--src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch397
-rw-r--r--src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch63
-rw-r--r--tests/auto/declarative/declarative.pro5
-rw-r--r--tests/auto/declarative/qdeclarativecomponent/qdeclarativecomponent.pro2
-rw-r--r--tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro2
-rw-r--r--tests/auto/declarative/qdeclarativedebug/qdeclarativedebug.pro2
-rw-r--r--tests/auto/declarative/qdeclarativedebugclient/qdeclarativedebugclient.pro2
-rw-r--r--tests/auto/declarative/qdeclarativedebughelper/private_headers/qdeclarativedebughelper_p.h4
-rw-r--r--tests/auto/declarative/qdeclarativedebughelper/qdeclarativedebughelper.pro4
-rw-r--r--tests/auto/declarative/qdeclarativedebugservice/qdeclarativedebugservice.pro2
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro4
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp10
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/testtypes.h10
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp25
-rw-r--r--tests/auto/declarative/qdeclarativeinstruction/qdeclarativeinstruction.pro4
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro4
-rw-r--r--tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro3
-rw-r--r--tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro2
-rw-r--r--tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro4
-rw-r--r--tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro4
-rw-r--r--tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro2
-rw-r--r--tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro2
-rw-r--r--tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro4
-rw-r--r--tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro2
-rw-r--r--tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro4
-rw-r--r--tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro2
-rw-r--r--tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro4
-rw-r--r--tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp2
-rw-r--r--tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro4
-rw-r--r--tests/auto/declarative/qjsengine/qjsengine.pro21
-rw-r--r--tests/auto/declarative/qjsengine/script/com/__init__.js9
-rw-r--r--tests/auto/declarative/qjsengine/script/com/trolltech/__init__.js9
-rw-r--r--tests/auto/declarative/qjsengine/script/com/trolltech/recursive/__init__.js1
-rw-r--r--tests/auto/declarative/qjsengine/script/com/trolltech/syntaxerror/__init__.js5
-rw-r--r--tests/auto/declarative/qjsengine/tst_qjsengine.cpp6491
-rw-r--r--tests/auto/declarative/qjsvalue/qjsvalue.pro10
-rw-r--r--tests/auto/declarative/qjsvalue/tst_qjsvalue.cpp4109
-rw-r--r--tests/auto/declarative/qjsvalue/tst_qjsvalue.h205
-rw-r--r--tests/auto/declarative/qjsvalueiterator/qjsvalueiterator.pro5
-rw-r--r--tests/auto/declarative/qjsvalueiterator/tst_qjsvalueiterator.cpp527
-rw-r--r--tests/auto/declarative/qsganimatedimage/qsganimatedimage.pro1
-rw-r--r--tests/auto/declarative/qsgborderimage/qsgborderimage.pro1
-rw-r--r--tests/auto/declarative/qsgflickable/qsgflickable.pro1
-rw-r--r--tests/auto/declarative/qsgflipable/qsgflipable.pro1
-rw-r--r--tests/auto/declarative/qsggridview/qsggridview.pro1
-rw-r--r--tests/auto/declarative/qsgitem2/qsgitem.pro1
-rw-r--r--tests/auto/declarative/qsglistview/qsglistview.pro1
-rw-r--r--tests/auto/declarative/qsgpathview/qsgpathview.pro1
-rw-r--r--tests/auto/declarative/qsgpositioners/qsgpositioners.pro1
-rw-r--r--tests/auto/declarative/qsgtext/qsgtext.pro1
-rw-r--r--tests/auto/declarative/qsgtextedit/qsgtextedit.pro1
-rw-r--r--tests/auto/declarative/qsgtextinput/qsgtextinput.pro1
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/qsgvisualdatamodel.pro1
-rw-r--r--tests/auto/qtquick1/qdeclarativeconnection/qdeclarativeconnection.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativeflickable/qdeclarativeflickable.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativegridview/qdeclarativegridview.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativelistmodel/qdeclarativelistmodel.pro3
-rw-r--r--tests/auto/qtquick1/qdeclarativelistview/qdeclarativelistview.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativepathview/qdeclarativepathview.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativespringanimation/qdeclarativespringanimation.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativestates/qdeclarativestates.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativetext/qdeclarativetext.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativevisualdatamodel/qdeclarativevisualdatamodel.pro2
-rw-r--r--tests/auto/qtquick1/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro4
-rw-r--r--tests/benchmarks/declarative/holistic/holistic.pro2
-rw-r--r--tests/benchmarks/declarative/holistic/testtypes.h2
-rw-r--r--tests/benchmarks/declarative/script/script.pro2
-rw-r--r--tools/qmlviewer/qml.pri2
156 files changed, 17932 insertions, 515 deletions
diff --git a/modules/qt_declarative.pri b/modules/qt_declarative.pri
index ed1750e55c..ef7db54a2b 100644
--- a/modules/qt_declarative.pri
+++ b/modules/qt_declarative.pri
@@ -11,7 +11,7 @@ QT.declarative.sources = $$QT_MODULE_BASE/src/declarative
QT.declarative.libs = $$QT_MODULE_LIB_BASE
QT.declarative.plugins = $$QT_MODULE_PLUGIN_BASE
QT.declarative.imports = $$QT_MODULE_IMPORT_BASE
-QT.declarative.depends = gui script network opengl xmlpatterns
+QT.declarative.depends = gui network opengl xmlpatterns
QT.declarative.DEFINES = QT_DECLARATIVE_LIB
QT_CONFIG += declarative
diff --git a/src/3rdparty/v8 b/src/3rdparty/v8
-Subproject bec11b8b7f89d135e7d9a823ac4fe98c70d017c
+Subproject 472c04c9e7a64e8734c76d2cf97a7cc5b773b78
diff --git a/src/declarative/debugger/qdeclarativedebughelper.cpp b/src/declarative/debugger/qdeclarativedebughelper.cpp
index 6eea82c948..5f5d8754bb 100644
--- a/src/declarative/debugger/qdeclarativedebughelper.cpp
+++ b/src/declarative/debugger/qdeclarativedebughelper.cpp
@@ -39,12 +39,10 @@
**
****************************************************************************/
-#include <QtScript/QScriptEngine>
-
#include "private/qdeclarativedebughelper_p.h"
#include <QtCore/QAbstractAnimation>
-#include <QtScript/QScriptEngine>
+#include <QtDeclarative/QJSEngine>
#include <private/qdeclarativeengine_p.h>
#include <private/qabstractanimation_p.h>
diff --git a/src/declarative/debugger/qjsdebuggeragent.cpp b/src/declarative/debugger/qjsdebuggeragent.cpp
index 3169f91b59..f47def802a 100644
--- a/src/declarative/debugger/qjsdebuggeragent.cpp
+++ b/src/declarative/debugger/qjsdebuggeragent.cpp
@@ -46,9 +46,9 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qset.h>
#include <QtCore/qurl.h>
-#include <QtScript/qscriptcontextinfo.h>
-#include <QtScript/qscriptengine.h>
-#include <QtScript/qscriptvalueiterator.h>
+#include <QtDeclarative/qjsengine.h>
+
+#include <QtCore/qstringlist.h>
QT_BEGIN_NAMESPACE
@@ -61,9 +61,9 @@ public:
void continueExec();
void recordKnownObjects(const QList<JSAgentWatchData> &);
- QList<JSAgentWatchData> getLocals(QScriptContext *);
+ QList<JSAgentWatchData> getLocals(void *);
void positionChange(qint64 scriptId, int lineNumber, int columnNumber);
- QScriptEngine *engine() { return q->engine(); }
+ QJSEngine *engine() { return q->engine(); }
void stopped();
public:
@@ -111,7 +111,7 @@ private:
} // anonymous namespace
static JSAgentWatchData fromScriptValue(const QString &expression,
- const QScriptValue &value)
+ const QJSValue &value)
{
static const QString arrayStr = QCoreApplication::translate
("Debugger::JSAgentWatchData", "[Array of length %1]");
@@ -123,7 +123,7 @@ static JSAgentWatchData fromScriptValue(const QString &expression,
data.name = data.exp;
data.hasChildren = false;
data.value = value.toString().toUtf8();
- data.objectId = value.objectId();
+ // data.objectId = value.objectId();
if (value.isArray()) {
data.type = "Array";
data.value = arrayStr.arg(value.property(QLatin1String("length")).toString()).toUtf8();
@@ -167,30 +167,30 @@ static JSAgentWatchData fromScriptValue(const QString &expression,
return data;
}
-static QList<JSAgentWatchData> expandObject(const QScriptValue &object)
+static QList<JSAgentWatchData> expandObject(const QJSValue &object)
{
QList<JSAgentWatchData> result;
- QScriptValueIterator it(object);
- while (it.hasNext()) {
- it.next();
- if (it.flags() & QScriptValue::SkipInEnumeration)
- continue;
- if (/*object.isQObject() &&*/ it.value().isFunction()) {
- // Cosmetics: skip all functions and slot, there are too many of them,
- // and it is not useful information in the debugger.
- continue;
- }
- JSAgentWatchData data = fromScriptValue(it.name(), it.value());
- result.append(data);
- }
- if (result.isEmpty()) {
- JSAgentWatchData data;
- data.name = "<no initialized data>";
- data.hasChildren = false;
- data.value = " ";
- data.objectId = 0;
- result.append(data);
- }
+// QScriptValueIterator it(object);
+// while (it.hasNext()) {
+// it.next();
+// if (it.flags() & QScriptValue::SkipInEnumeration)
+// continue;
+// if (/*object.isQObject() &&*/ it.value().isFunction()) {
+// // Cosmetics: skip all functions and slot, there are too many of them,
+// // and it is not useful information in the debugger.
+// continue;
+// }
+// JSAgentWatchData data = fromScriptValue(it.name(), it.value());
+// result.append(data);
+// }
+// if (result.isEmpty()) {
+// JSAgentWatchData data;
+// data.name = "<no initialized data>";
+// data.hasChildren = false;
+// data.value = " ";
+// data.objectId = 0;
+// result.append(data);
+// }
return result;
}
@@ -206,20 +206,20 @@ void QJSDebuggerAgentPrivate::recordKnownObjects(const QList<JSAgentWatchData>&
knownObjectIds << data.objectId;
}
-QList<JSAgentWatchData> QJSDebuggerAgentPrivate::getLocals(QScriptContext *ctx)
+QList<JSAgentWatchData> QJSDebuggerAgentPrivate::getLocals(void *ctx)
{
QList<JSAgentWatchData> locals;
- if (ctx) {
- QScriptValue activationObject = ctx->activationObject();
- QScriptValue thisObject = ctx->thisObject();
- locals = expandObject(activationObject);
- if (thisObject.isObject()
- && thisObject.objectId() != engine()->globalObject().objectId()
- && QScriptValueIterator(thisObject).hasNext())
- locals.prepend(fromScriptValue(QLatin1String("this"), thisObject));
- recordKnownObjects(locals);
- knownObjectIds << activationObject.objectId();
- }
+// if (ctx) {
+// QScriptValue activationObject = ctx->activationObject();
+// QScriptValue thisObject = ctx->thisObject();
+// locals = expandObject(activationObject);
+// if (thisObject.isObject()
+// && thisObject.objectId() != engine()->globalObject().objectId()
+// && QScriptValueIterator(thisObject).hasNext())
+// locals.prepend(fromScriptValue(QLatin1String("this"), thisObject));
+// recordKnownObjects(locals);
+// knownObjectIds << activationObject.objectId();
+// }
return locals;
}
@@ -228,20 +228,18 @@ QList<JSAgentWatchData> QJSDebuggerAgentPrivate::getLocals(QScriptContext *ctx)
report debugging-related events (e.g. step completion) to the given
\a backend.
*/
-QJSDebuggerAgent::QJSDebuggerAgent(QScriptEngine *engine, QObject *parent)
+QJSDebuggerAgent::QJSDebuggerAgent(QJSEngine *engine, QObject *parent)
: QObject(parent)
- , QScriptEngineAgent(engine)
, d(new QJSDebuggerAgentPrivate(this))
{
- QJSDebuggerAgent::engine()->setAgent(this);
+ //QJSDebuggerAgent::engine()->setAgent(this);
}
QJSDebuggerAgent::QJSDebuggerAgent(QDeclarativeEngine *engine, QObject *parent)
: QObject(parent)
- , QScriptEngineAgent(0)
, d(new QJSDebuggerAgentPrivate(this))
{
- QJSDebuggerAgent::engine()->setAgent(this);
+ //QJSDebuggerAgent::engine()->setAgent(this);
}
/*!
@@ -249,7 +247,7 @@ QJSDebuggerAgent::QJSDebuggerAgent(QDeclarativeEngine *engine, QObject *parent)
*/
QJSDebuggerAgent::~QJSDebuggerAgent()
{
- engine()->setAgent(0);
+ //engine()->setAgent(0);
delete d;
}
@@ -317,9 +315,9 @@ QList<JSAgentWatchData> QJSDebuggerAgent::expandObjectById(quint64 objectId)
{
SetupExecEnv execEnv(d);
- QScriptValue v;
- if (d->knownObjectIds.contains(objectId))
- v = engine()->objectById(objectId);
+ QJSValue v;
+// if (d->knownObjectIds.contains(objectId))
+// v = engine()->objectById(objectId);
QList<JSAgentWatchData> result = expandObject(v);
d->recordKnownObjects(result);
@@ -329,21 +327,21 @@ QList<JSAgentWatchData> QJSDebuggerAgent::expandObjectById(quint64 objectId)
QList<JSAgentWatchData> QJSDebuggerAgent::locals()
{
SetupExecEnv execEnv(d);
- return d->getLocals(engine()->currentContext());
+ return d->getLocals(0/*engine()->currentContext()*/);
}
QList<JSAgentWatchData> QJSDebuggerAgent::localsAtFrame(int frameId)
{
SetupExecEnv execEnv(d);
- int deep = 0;
- QScriptContext *ctx = engine()->currentContext();
- while (ctx && deep < frameId) {
- ctx = ctx->parentContext();
- deep++;
- }
+// int deep = 0;
+// QScriptContext *ctx = engine()->currentContext();
+// while (ctx && deep < frameId) {
+// ctx = ctx->parentContext();
+// deep++;
+// }
- return d->getLocals(ctx);
+ return d->getLocals(0/*ctx*/);
}
QList<JSAgentStackData> QJSDebuggerAgent::backtrace()
@@ -352,37 +350,37 @@ QList<JSAgentStackData> QJSDebuggerAgent::backtrace()
QList<JSAgentStackData> backtrace;
- for (QScriptContext *ctx = engine()->currentContext(); ctx; ctx = ctx->parentContext()) {
- QScriptContextInfo info(ctx);
-
- JSAgentStackData frame;
- frame.functionName = info.functionName().toUtf8();
- if (frame.functionName.isEmpty()) {
- if (ctx->parentContext()) {
- switch (info.functionType()) {
- case QScriptContextInfo::ScriptFunction:
- frame.functionName = "<anonymous>";
- break;
- case QScriptContextInfo::NativeFunction:
- frame.functionName = "<native>";
- break;
- case QScriptContextInfo::QtFunction:
- case QScriptContextInfo::QtPropertyFunction:
- frame.functionName = "<native slot>";
- break;
- }
- } else {
- frame.functionName = "<global>";
- }
- }
- frame.lineNumber = info.lineNumber();
- // if the line number is unknown, fallback to the function line number
- if (frame.lineNumber == -1)
- frame.lineNumber = info.functionStartLineNumber();
-
- frame.fileUrl = info.fileName().toUtf8();
- backtrace.append(frame);
- }
+// for (QScriptContext *ctx = engine()->currentContext(); ctx; ctx = ctx->parentContext()) {
+// QScriptContextInfo info(ctx);
+
+// JSAgentStackData frame;
+// frame.functionName = info.functionName().toUtf8();
+// if (frame.functionName.isEmpty()) {
+// if (ctx->parentContext()) {
+// switch (info.functionType()) {
+// case QScriptContextInfo::ScriptFunction:
+// frame.functionName = "<anonymous>";
+// break;
+// case QScriptContextInfo::NativeFunction:
+// frame.functionName = "<native>";
+// break;
+// case QScriptContextInfo::QtFunction:
+// case QScriptContextInfo::QtPropertyFunction:
+// frame.functionName = "<native slot>";
+// break;
+// }
+// } else {
+// frame.functionName = "<global>";
+// }
+// }
+// frame.lineNumber = info.lineNumber();
+// // if the line number is unknown, fallback to the function line number
+// if (frame.lineNumber == -1)
+// frame.lineNumber = info.functionStartLineNumber();
+
+// frame.fileUrl = info.fileName().toUtf8();
+// backtrace.append(frame);
+// }
return backtrace;
}
@@ -405,9 +403,9 @@ void QJSDebuggerAgent::setProperty(qint64 objectId,
SetupExecEnv execEnv(d);
if (d->knownObjectIds.contains(objectId)) {
- QScriptValue object = engine()->objectById(objectId);
+ QJSValue object;// = engine()->objectById(objectId);
if (object.isObject()) {
- QScriptValue result = engine()->evaluate(value);
+ QJSValue result = engine()->evaluate(value);
object.setProperty(property, result);
}
}
@@ -457,7 +455,7 @@ void QJSDebuggerAgent::functionEntry(qint64 scriptId)
/*!
\reimp
*/
-void QJSDebuggerAgent::functionExit(qint64 scriptId, const QScriptValue &returnValue)
+void QJSDebuggerAgent::functionExit(qint64 scriptId, const QJSValue &returnValue)
{
Q_UNUSED(scriptId);
Q_UNUSED(returnValue);
@@ -476,53 +474,53 @@ void QJSDebuggerAgentPrivate::positionChange(qint64 scriptId, int lineNumber, in
{
Q_UNUSED(columnNumber);
- if (state == StoppedState)
- return; //no re-entrency
-
- // check breakpoints
- if (!breakpoints.isEmpty()) {
- QHash<qint64, QString>::const_iterator it = filenames.constFind(scriptId);
- QScriptContext *ctx = engine()->currentContext();
- QScriptContextInfo info(ctx);
- if (it == filenames.constEnd()) {
- // It is possible that the scripts are loaded before the agent is attached
- QString filename = info.fileName();
-
- JSAgentStackData frame;
- frame.functionName = info.functionName().toUtf8();
-
- QPair<QString, qint32> key = qMakePair(filename, lineNumber);
- it = filenames.insert(scriptId, filename);
- }
-
- const QString filePath = it.value();
- JSAgentBreakpoints bps = fileNameToBreakpoints.values(fileName(filePath)).toSet();
-
- foreach (const JSAgentBreakpointData &bp, bps) {
- if (bp.lineNumber == lineNumber) {
- stopped();
- return;
- }
- }
- }
-
- switch (state) {
- case NoState:
- case StoppedState:
- // Do nothing
- break;
- case SteppingOutState:
- if (stepDepth >= 0)
- break;
- //fallthough
- case SteppingOverState:
- if (stepDepth > 0)
- break;
- //fallthough
- case SteppingIntoState:
- stopped();
- break;
- }
+// if (state == StoppedState)
+// return; //no re-entrency
+
+// // check breakpoints
+// if (!breakpoints.isEmpty()) {
+// QHash<qint64, QString>::const_iterator it = filenames.constFind(scriptId);
+// QScriptContext *ctx = engine()->currentContext();
+// QScriptContextInfo info(ctx);
+// if (it == filenames.constEnd()) {
+// // It is possible that the scripts are loaded before the agent is attached
+// QString filename = info.fileName();
+
+// JSAgentStackData frame;
+// frame.functionName = info.functionName().toUtf8();
+
+// QPair<QString, qint32> key = qMakePair(filename, lineNumber);
+// it = filenames.insert(scriptId, filename);
+// }
+
+// const QString filePath = it.value();
+// JSAgentBreakpoints bps = fileNameToBreakpoints.values(fileName(filePath)).toSet();
+
+// foreach (const JSAgentBreakpointData &bp, bps) {
+// if (bp.lineNumber == lineNumber) {
+// stopped();
+// return;
+// }
+// }
+// }
+
+// switch (state) {
+// case NoState:
+// case StoppedState:
+// // Do nothing
+// break;
+// case SteppingOutState:
+// if (stepDepth >= 0)
+// break;
+// //fallthough
+// case SteppingOverState:
+// if (stepDepth > 0)
+// break;
+// //fallthough
+// case SteppingIntoState:
+// stopped();
+// break;
+// }
}
@@ -530,7 +528,7 @@ void QJSDebuggerAgentPrivate::positionChange(qint64 scriptId, int lineNumber, in
\reimp
*/
void QJSDebuggerAgent::exceptionThrow(qint64 scriptId,
- const QScriptValue &exception,
+ const QJSValue &exception,
bool hasHandler)
{
Q_UNUSED(scriptId);
@@ -546,30 +544,16 @@ void QJSDebuggerAgent::exceptionThrow(qint64 scriptId,
/*!
\reimp
*/
-void QJSDebuggerAgent::exceptionCatch(qint64 scriptId, const QScriptValue &exception)
+void QJSDebuggerAgent::exceptionCatch(qint64 scriptId, const QJSValue &exception)
{
Q_UNUSED(scriptId);
Q_UNUSED(exception);
}
-bool QJSDebuggerAgent::supportsExtension(Extension extension) const
-{
- return extension == QScriptEngineAgent::DebuggerInvocationRequest;
-}
-
-QVariant QJSDebuggerAgent::extension(Extension extension, const QVariant &argument)
-{
- if (extension == QScriptEngineAgent::DebuggerInvocationRequest) {
- d->stopped();
- return QVariant();
- }
- return QScriptEngineAgent::extension(extension, argument);
-}
-
void QJSDebuggerAgentPrivate::stopped()
{
bool becauseOfException = false;
- const QScriptValue &exception = QScriptValue();
+ const QJSValue &exception = QJSValue();
knownObjectIds.clear();
state = StoppedState;
diff --git a/src/declarative/debugger/qjsdebuggeragent_p.h b/src/declarative/debugger/qjsdebuggeragent_p.h
index 309588eb2f..30cbfe67b4 100644
--- a/src/declarative/debugger/qjsdebuggeragent_p.h
+++ b/src/declarative/debugger/qjsdebuggeragent_p.h
@@ -53,11 +53,11 @@
// We mean it.
//
-#include <QtScript/qscriptengineagent.h>
#include <QtCore/qset.h>
+#include <QtDeclarative/qjsengine.h>
QT_BEGIN_NAMESPACE
-class QScriptValue;
+class QJSValue;
class QDeclarativeEngine;
QT_END_NAMESPACE
@@ -136,16 +136,17 @@ inline uint qHash(const JSAgentBreakpointData &b)
}
-class QJSDebuggerAgent : public QObject, public QScriptEngineAgent
+class QJSDebuggerAgent : public QObject
{
Q_OBJECT
public:
- QJSDebuggerAgent(QScriptEngine *engine, QObject *parent = 0);
+ QJSDebuggerAgent(QJSEngine *engine, QObject *parent = 0);
QJSDebuggerAgent(QDeclarativeEngine *engine, QObject *parent = 0);
~QJSDebuggerAgent();
bool isInitialized() const;
+ QJSEngine * engine() {return 0; }
void setBreakpoints(const JSAgentBreakpoints &);
void setWatchExpressions(const QStringList &);
@@ -175,20 +176,16 @@ public:
void functionEntry(qint64 scriptId);
void functionExit(qint64 scriptId,
- const QScriptValue &returnValue);
+ const QJSValue &returnValue);
void positionChange(qint64 scriptId,
int lineNumber, int columnNumber);
void exceptionThrow(qint64 scriptId,
- const QScriptValue &exception,
+ const QJSValue &exception,
bool hasHandler);
void exceptionCatch(qint64 scriptId,
- const QScriptValue &exception);
-
- bool supportsExtension(Extension extension) const;
- QVariant extension(Extension extension,
- const QVariant &argument = QVariant());
+ const QJSValue &exception);
Q_SIGNALS:
void stopped(bool becauseOfException,
diff --git a/src/declarative/declarative.pro b/src/declarative/declarative.pro
index aa638e468e..2d9248ef66 100644
--- a/src/declarative/declarative.pro
+++ b/src/declarative/declarative.pro
@@ -6,7 +6,7 @@ QPRO_PWD = $$PWD
CONFIG += module
MODULE_PRI += ../../modules/qt_declarative.pri
-QT = core-private gui-private script-private network script opengl-private
+QT = core-private gui-private network opengl-private
contains(QT_CONFIG, svg): QT += svg
DEFINES += QT_BUILD_DECLARATIVE_LIB QT_NO_URL_CAST_FROM_STRING
win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000
diff --git a/src/declarative/items/context2d/qsgcontext2d.cpp b/src/declarative/items/context2d/qsgcontext2d.cpp
index 97234a6315..4cfe1ba012 100644
--- a/src/declarative/items/context2d/qsgcontext2d.cpp
+++ b/src/declarative/items/context2d/qsgcontext2d.cpp
@@ -3361,7 +3361,7 @@ void QSGContext2D::release()
}
}
-void QSGContext2D::processCommands(const QScriptValue& commands)
+void QSGContext2D::processCommands(const QJSValue& commands)
{
#ifdef QSGCANVASITEM_DEBUG
QElapsedTimer t;
@@ -3369,7 +3369,7 @@ void QSGContext2D::processCommands(const QScriptValue& commands)
#endif
int ii = 0;
if (commands.isArray()) {
- QScriptValue cmd = commands.property(ii);
+ QJSValue cmd = commands.property(ii);
while(cmd.isValid()) {
processCommand(cmd);
ii++;
@@ -3460,7 +3460,7 @@ bool QSGContext2D::event(QEvent *e)
return QObject::event(e);
}
-void QSGContext2D::processCommand(const QScriptValue& cmd)
+void QSGContext2D::processCommand(const QJSValue& cmd)
{
int action = cmd.property(0).toInt32();
switch (action) {
diff --git a/src/declarative/items/context2d/qsgcontext2d_p.h b/src/declarative/items/context2d/qsgcontext2d_p.h
index 335d954fc1..f8fc9b75a2 100644
--- a/src/declarative/items/context2d/qsgcontext2d_p.h
+++ b/src/declarative/items/context2d/qsgcontext2d_p.h
@@ -55,7 +55,7 @@
#include <QtCore/qmetatype.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qvariant.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
#include <private/qv8engine_p.h>
#include <QMutex>
#include <QWaitCondition>
@@ -323,7 +323,7 @@ public slots:
void paint(QPainter* painter);
void sync();
- void processCommands(const QScriptValue& commands);
+ void processCommands(const QJSValue& commands);
signals:
void changed();
void painted();
@@ -385,7 +385,7 @@ protected:
virtual bool event(QEvent *);
private:
- void processCommand(const QScriptValue& command);
+ void processCommand(const QJSValue& command);
Q_DECLARE_PRIVATE(QSGContext2D)
};
diff --git a/src/declarative/items/qsgitem.cpp b/src/declarative/items/qsgitem.cpp
index 55d84a7fa5..043c568a82 100644
--- a/src/declarative/items/qsgitem.cpp
+++ b/src/declarative/items/qsgitem.cpp
@@ -42,7 +42,7 @@
#include "qsgitem.h"
#include "qsgcanvas.h"
-#include <QtScript/qscriptengine.h>
+#include <QtDeclarative/qjsengine.h>
#include "qsgcanvas_p.h"
#include "qsgevent.h"
diff --git a/src/declarative/qml/qdeclarative.h b/src/declarative/qml/qdeclarative.h
index 38b2a841ba..4c962f890e 100644
--- a/src/declarative/qml/qdeclarative.h
+++ b/src/declarative/qml/qdeclarative.h
@@ -395,8 +395,8 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
class QDeclarativeContext;
class QDeclarativeEngine;
-class QScriptValue;
-class QScriptEngine;
+class QJSValue;
+class QJSEngine;
Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *);
Q_DECLARATIVE_EXPORT QDeclarativeContext *qmlContext(const QObject *);
Q_DECLARATIVE_EXPORT QDeclarativeEngine *qmlEngine(const QObject *);
@@ -454,7 +454,7 @@ Q_DECLARATIVE_EXPORT void qmlRegisterBaseTypes(const char *uri, int versionMajor
\endqml
*/
inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor,
- QScriptValue (*callback)(QDeclarativeEngine *, QScriptEngine *))
+ QJSValue (*callback)(QDeclarativeEngine *, QJSEngine *))
{
QDeclarativePrivate::RegisterModuleApi api = {
0,
@@ -537,7 +537,7 @@ inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMi
\endqml
*/
inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor,
- QObject *(*callback)(QDeclarativeEngine *, QScriptEngine *))
+ QObject *(*callback)(QDeclarativeEngine *, QJSEngine *))
{
QDeclarativePrivate::RegisterModuleApi api = {
0,
diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp
index 684726d346..069744153a 100644
--- a/src/declarative/qml/qdeclarativebinding.cpp
+++ b/src/declarative/qml/qdeclarativebinding.cpp
@@ -367,7 +367,7 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
bool isUndefined = false;
v8::HandleScope handle_scope;
- v8::Context::Scope scope(ep->v8engine.context());
+ v8::Context::Scope scope(ep->v8engine()->context());
v8::Local<v8::Value> result = d->v8value(0, &isUndefined);
bool needsErrorData = false;
diff --git a/src/declarative/qml/qdeclarativecompileddata.cpp b/src/declarative/qml/qdeclarativecompileddata.cpp
index d08a808d77..da7c3fea7b 100644
--- a/src/declarative/qml/qdeclarativecompileddata.cpp
+++ b/src/declarative/qml/qdeclarativecompileddata.cpp
@@ -126,7 +126,6 @@ QDeclarativeCompiledData::~QDeclarativeCompiledData()
if (rootPropertyCache)
rootPropertyCache->release();
- qDeleteAll(cachedPrograms);
qDeleteAll(cachedClosures);
for (int ii = 0; ii < v8bindings.count(); ++ii)
@@ -135,12 +134,9 @@ QDeclarativeCompiledData::~QDeclarativeCompiledData()
void QDeclarativeCompiledData::clear()
{
- qDeleteAll(cachedPrograms);
qDeleteAll(cachedClosures);
for (int ii = 0; ii < cachedClosures.count(); ++ii)
cachedClosures[ii] = 0;
- for (int ii = 0; ii < cachedPrograms.count(); ++ii)
- cachedPrograms[ii] = 0;
}
const QMetaObject *QDeclarativeCompiledData::TypeReference::metaObject() const
diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp
index 7a15aed460..5e1d3f60a9 100644
--- a/src/declarative/qml/qdeclarativecompiler.cpp
+++ b/src/declarative/qml/qdeclarativecompiler.cpp
@@ -2371,7 +2371,7 @@ bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
if (propName.at(0).isUpper())
COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
- if (enginePrivate->v8engine.illegalNames().contains(propName))
+ if (enginePrivate->v8engine()->illegalNames().contains(propName))
COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
propNames.insert(prop.name);
@@ -2384,7 +2384,7 @@ bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
QString nameStr = QString::fromUtf8(name);
if (nameStr.at(0).isUpper())
COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
- if (enginePrivate->v8engine.illegalNames().contains(nameStr))
+ if (enginePrivate->v8engine()->illegalNames().contains(nameStr))
COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
methodNames.insert(name);
}
@@ -2395,7 +2395,7 @@ bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
QString nameStr = QString::fromUtf8(name);
if (nameStr.at(0).isUpper())
COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
- if (enginePrivate->v8engine.illegalNames().contains(nameStr))
+ if (enginePrivate->v8engine()->illegalNames().contains(nameStr))
COMPILE_EXCEPTION(obj, tr("Illegal method name"));
methodNames.insert(name);
}
@@ -2689,7 +2689,7 @@ bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QStr
}
- if (enginePrivate->v8engine.illegalNames().contains(val))
+ if (enginePrivate->v8engine()->illegalNames().contains(val))
COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
return true;
diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h
index a1dfabbd46..a2b959a568 100644
--- a/src/declarative/qml/qdeclarativecompiler_p.h
+++ b/src/declarative/qml/qdeclarativecompiler_p.h
@@ -76,7 +76,6 @@ class QDeclarativeComponent;
class QDeclarativeContext;
class QDeclarativeContextData;
-class QScriptProgram;
class Q_AUTOTEST_EXPORT QDeclarativeCompiledData : public QDeclarativeRefCount, public QDeclarativeCleanup
{
public:
@@ -112,8 +111,7 @@ public:
QList<QString> primitives;
QList<QByteArray> datas;
QByteArray bytecode;
- QList<QScriptProgram *> cachedPrograms;
- QList<QScriptValue *> cachedClosures;
+ QList<QJSValue *> cachedClosures;
QList<QDeclarativePropertyCache *> propertyCaches;
QList<QDeclarativeIntegerCache *> contextCaches;
QList<QDeclarativeScriptData *> scripts;
diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp
index b6bcc64afa..ca7f3e0f74 100644
--- a/src/declarative/qml/qdeclarativecomponent.cpp
+++ b/src/declarative/qml/qdeclarativecomponent.cpp
@@ -54,7 +54,6 @@
#include "private/qdeclarativescriptparser_p.h"
#include "private/qdeclarativedebugtrace_p.h"
#include "private/qdeclarativeenginedebug_p.h"
-#include <QtScript/qscriptvalueiterator.h>
#include <QStack>
#include <QStringList>
@@ -672,7 +671,7 @@ void QDeclarativeComponent::createObject(QDeclarativeV8Function *args)
QDeclarativeEngine *engine = d->engine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QV8Engine *v8engine = &ep->v8engine;
+ QV8Engine *v8engine = ep->v8engine();
QDeclarativeContext *ctxt = creationContext();
if (!ctxt) ctxt = engine->rootContext();
diff --git a/src/declarative/qml/qdeclarativecomponent.h b/src/declarative/qml/qdeclarativecomponent.h
index bb4d886914..a3457d1446 100644
--- a/src/declarative/qml/qdeclarativecomponent.h
+++ b/src/declarative/qml/qdeclarativecomponent.h
@@ -47,7 +47,7 @@
#include <QtCore/qobject.h>
#include <QtCore/qstring.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
QT_BEGIN_HEADER
diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp
index d625a1fd98..ff6e628c66 100644
--- a/src/declarative/qml/qdeclarativecontext.cpp
+++ b/src/declarative/qml/qdeclarativecontext.cpp
@@ -50,12 +50,10 @@
#include "private/qdeclarativev4bindings_p.h"
#include "private/qv8bindings_p.h"
-#include <qscriptengine.h>
+#include <qjsengine.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qdebug.h>
-#include <private/qscriptdeclarativeclass_p.h>
-
QT_BEGIN_NAMESPACE
QDeclarativeContextPrivate::QDeclarativeContextPrivate()
diff --git a/src/declarative/qml/qdeclarativecontext.h b/src/declarative/qml/qdeclarativecontext.h
index d8e8506dad..9c2fd01645 100644
--- a/src/declarative/qml/qdeclarativecontext.h
+++ b/src/declarative/qml/qdeclarativecontext.h
@@ -44,7 +44,7 @@
#include <QtCore/qurl.h>
#include <QtCore/qobject.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qvariant.h>
diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h
index bb9c2ada02..5f4072130a 100644
--- a/src/declarative/qml/qdeclarativecontext_p.h
+++ b/src/declarative/qml/qdeclarativecontext_p.h
@@ -63,7 +63,7 @@
#include "private/qdeclarativeparser_p.h"
#include <QtCore/qhash.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
#include <QtCore/qset.h>
#include <private/qobject_p.h>
diff --git a/src/declarative/qml/qdeclarativedata_p.h b/src/declarative/qml/qdeclarativedata_p.h
index 9fe5e732b7..aebea738bd 100644
--- a/src/declarative/qml/qdeclarativedata_p.h
+++ b/src/declarative/qml/qdeclarativedata_p.h
@@ -53,7 +53,7 @@
// We mean it.
//
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
#include <private/qobject_p.h>
#include <private/qv8_p.h>
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index cf672ef337..a2f724e3f8 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -441,7 +441,7 @@ void QDeclarativeEnginePrivate::init()
Q_Q(QDeclarativeEngine);
qRegisterMetaType<QVariant>("QVariant");
qRegisterMetaType<QDeclarativeScriptString>("QDeclarativeScriptString");
- qRegisterMetaType<QScriptValue>("QScriptValue");
+ qRegisterMetaType<QJSValue>("QJSValue");
qRegisterMetaType<QDeclarativeComponent::Status>("QDeclarativeComponent::Status");
qRegisterMetaType<QList<QObject*> >("QList<QObject*>");
qRegisterMetaType<QList<int> >("QList<int>");
@@ -449,8 +449,7 @@ void QDeclarativeEnginePrivate::init()
QDeclarativeData::init();
- // Init V8 data
- v8engine.init(q);
+ v8engine()->setEngine(q);
rootContext = new QDeclarativeContext(q,true);
@@ -505,7 +504,7 @@ QDeclarativeWorkerScriptEngine *QDeclarativeEnginePrivate::getWorkerScriptEngine
Create a new QDeclarativeEngine with the given \a parent.
*/
QDeclarativeEngine::QDeclarativeEngine(QObject *parent)
-: QObject(*new QDeclarativeEnginePrivate(this), parent)
+: QJSEngine(*new QDeclarativeEnginePrivate(this), parent)
{
Q_D(QDeclarativeEngine);
d->init();
@@ -1386,13 +1385,13 @@ bool QDeclarativeEngine::importPlugin(const QString &filePath, const QString &ur
void QDeclarativeEngine::setOfflineStoragePath(const QString& dir)
{
Q_D(QDeclarativeEngine);
- qt_qmlsqldatabase_setOfflineStoragePath(&d->v8engine, dir);
+ qt_qmlsqldatabase_setOfflineStoragePath(d->v8engine(), dir);
}
QString QDeclarativeEngine::offlineStoragePath() const
{
Q_D(const QDeclarativeEngine);
- return qt_qmlsqldatabase_getOfflineStoragePath(&d->v8engine);
+ return qt_qmlsqldatabase_getOfflineStoragePath(d->v8engine());
}
static void voidptr_destructor(void *v)
diff --git a/src/declarative/qml/qdeclarativeengine.h b/src/declarative/qml/qdeclarativeengine.h
index e97c2d96b0..3f90296681 100644
--- a/src/declarative/qml/qdeclarativeengine.h
+++ b/src/declarative/qml/qdeclarativeengine.h
@@ -45,7 +45,8 @@
#include <QtCore/qurl.h>
#include <QtCore/qobject.h>
#include <QtCore/qmap.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsengine.h>
+#include <QtDeclarative/qjsvalue.h>
#include <QtDeclarative/qdeclarativeerror.h>
QT_BEGIN_HEADER
@@ -61,12 +62,12 @@ class QDeclarativeExpression;
class QDeclarativeContext;
class QDeclarativeType;
class QUrl;
-class QScriptEngine;
+class QJSEngine;
class QScriptContext;
class QDeclarativeImageProvider;
class QNetworkAccessManager;
class QDeclarativeNetworkAccessManagerFactory;
-class Q_DECLARATIVE_EXPORT QDeclarativeEngine : public QObject
+class Q_DECLARATIVE_EXPORT QDeclarativeEngine : public QJSEngine
{
Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath)
Q_OBJECT
diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h
index 538e8a05a0..6ff12189da 100644
--- a/src/declarative/qml/qdeclarativeengine_p.h
+++ b/src/declarative/qml/qdeclarativeengine_p.h
@@ -139,8 +139,7 @@ public:
QDeclarativeDelayedError *erroredBindings;
int inProgressCreations;
- // V8 Engine
- QV8Engine v8engine;
+ QV8Engine *v8engine() const { return q_func()->handle(); }
QDeclarativeWorkerScriptEngine *getWorkerScriptEngine();
QDeclarativeWorkerScriptEngine *workerScriptEngine;
@@ -256,7 +255,7 @@ public:
static void warning(QDeclarativeEnginePrivate *, const QDeclarativeError &);
static void warning(QDeclarativeEnginePrivate *, const QList<QDeclarativeError> &);
- static QV8Engine *getV8Engine(QDeclarativeEngine *e) { return &e->d_func()->v8engine; }
+ static QV8Engine *getV8Engine(QDeclarativeEngine *e) { return e->d_func()->v8engine(); }
static QDeclarativeEnginePrivate *get(QDeclarativeEngine *e) { return e->d_func(); }
static QDeclarativeEnginePrivate *get(QDeclarativeContext *c) { return (c && c->engine()) ? QDeclarativeEnginePrivate::get(c->engine()) : 0; }
static QDeclarativeEnginePrivate *get(QDeclarativeContextData *c) { return (c && c->engine) ? QDeclarativeEnginePrivate::get(c->engine) : 0; }
diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp
index ff19a07313..8806996bd4 100644
--- a/src/declarative/qml/qdeclarativeexpression.cpp
+++ b/src/declarative/qml/qdeclarativeexpression.cpp
@@ -144,11 +144,11 @@ QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObje
// XXX TODO: Implement script caching, like we used to do with QScriptProgram in the
// QtScript days
v8::HandleScope handle_scope;
- v8::Context::Scope ctxtscope(ep->v8engine.context());
+ v8::Context::Scope ctxtscope(ep->v8engine()->context());
v8::TryCatch tc;
- v8::Local<v8::Object> scopeobject = ep->v8engine.qmlScope(ctxt, scope);
- v8::Local<v8::Script> script = ep->v8engine.qmlModeCompile(code, filename, line);
+ v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
+ v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, filename, line);
v8::Local<v8::Value> result = script->Run(scopeobject);
if (tc.HasCaught()) return v8::Persistent<v8::Function>();
if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
@@ -485,9 +485,9 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F
v8::Local<v8::Value> result;
{
v8::TryCatch try_catch;
- v8::Handle<v8::Object> This = ep->v8engine.global();
+ v8::Handle<v8::Object> This = ep->v8engine()->global();
if (scopeObject() && requiresThisObject()) {
- v8::Handle<v8::Value> value = ep->v8engine.newQObject(scopeObject());
+ v8::Handle<v8::Value> value = ep->v8engine()->newQObject(scopeObject());
if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
}
@@ -498,7 +498,7 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F
if (watcher.wasDeleted()) {
} else if (try_catch.HasCaught()) {
- v8::Context::Scope scope(ep->v8engine.context());
+ v8::Context::Scope scope(ep->v8engine()->context());
v8::Local<v8::Message> message = try_catch.Message();
if (!message.IsEmpty()) {
QDeclarativeExpressionPrivate::exceptionToError(message, error);
@@ -638,9 +638,9 @@ v8::Local<v8::Value> QDeclarativeExpressionPrivate::v8value(QObject *secondarySc
v8::Local<v8::Value> result;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
QObject *restoreSecondaryScope = 0;
- restoreSecondaryScope = ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
+ restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
result = evaluate(v8function, isUndefined);
- ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
+ ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
return result;
} else {
return evaluate(v8function, isUndefined);
@@ -663,9 +663,9 @@ QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isU
{
v8::HandleScope handle_scope;
- v8::Context::Scope context_scope(ep->v8engine.context());
+ v8::Context::Scope context_scope(ep->v8engine()->context());
v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined);
- rv = ep->v8engine.toVariant(result, qMetaTypeId<QList<QObject*> >());
+ rv = ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >());
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp
index 18eea0b614..41705bce72 100644
--- a/src/declarative/qml/qdeclarativemetatype.cpp
+++ b/src/declarative/qml/qdeclarativemetatype.cpp
@@ -61,7 +61,7 @@
#include <qvector.h>
#include <qlocale.h>
#include <QtCore/qcryptographichash.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
#include <ctype.h>
@@ -1114,7 +1114,7 @@ QT_END_NAMESPACE
#include <QtGui/qquaternion.h>
#include <private/qv8engine_p.h>
-Q_DECLARE_METATYPE(QScriptValue);
+Q_DECLARE_METATYPE(QJSValue);
Q_DECLARE_METATYPE(QDeclarativeV8Handle);
QT_BEGIN_NAMESPACE
@@ -1195,7 +1195,7 @@ bool QDeclarativeMetaType::canCopy(int type)
default:
if (type == qMetaTypeId<QVariant>() ||
- type == qMetaTypeId<QScriptValue>() ||
+ type == qMetaTypeId<QJSValue>() ||
type == qMetaTypeId<QDeclarativeV8Handle>() ||
typeCategory(type) != Unknown) {
return true;
@@ -1416,8 +1416,8 @@ bool QDeclarativeMetaType::copy(int type, void *data, const void *copy)
if (type == qMetaTypeId<QVariant>()) {
*static_cast<NS(QVariant) *>(data) = *static_cast<const NS(QVariant)*>(copy);
return true;
- } else if (type == qMetaTypeId<QScriptValue>()) {
- *static_cast<NS(QScriptValue) *>(data) = *static_cast<const NS(QScriptValue)*>(copy);
+ } else if (type == qMetaTypeId<QJSValue>()) {
+ *static_cast<NS(QJSValue) *>(data) = *static_cast<const NS(QJSValue)*>(copy);
return true;
} else if (type == qMetaTypeId<QDeclarativeV8Handle>()) {
*static_cast<NS(QDeclarativeV8Handle) *>(data) = *static_cast<const NS(QDeclarativeV8Handle)*>(copy);
@@ -1626,8 +1626,8 @@ bool QDeclarativeMetaType::copy(int type, void *data, const void *copy)
if (type == qMetaTypeId<QVariant>()) {
*static_cast<NS(QVariant) *>(data) = NS(QVariant)();
return true;
- } else if (type == qMetaTypeId<QScriptValue>()) {
- *static_cast<NS(QScriptValue) *>(data) = NS(QScriptValue)();
+ } else if (type == qMetaTypeId<QJSValue>()) {
+ *static_cast<NS(QJSValue) *>(data) = NS(QJSValue)();
return true;
} else if (type == qMetaTypeId<QDeclarativeV8Handle>()) {
*static_cast<NS(QDeclarativeV8Handle) *>(data) = NS(QDeclarativeV8Handle)();
diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h
index cfc4f077f8..429aa7a98f 100644
--- a/src/declarative/qml/qdeclarativemetatype_p.h
+++ b/src/declarative/qml/qdeclarativemetatype_p.h
@@ -59,7 +59,7 @@
#include <QtCore/qvariant.h>
#include <QtCore/qbitarray.h>
#include <private/qdeclarativeglobal_p.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
QT_BEGIN_NAMESPACE
@@ -113,9 +113,9 @@ public:
ModuleApiInstance()
: scriptCallback(0), qobjectCallback(0), qobjectApi(0) {}
- QScriptValue (*scriptCallback)(QDeclarativeEngine *, QScriptEngine *);
- QObject *(*qobjectCallback)(QDeclarativeEngine *, QScriptEngine *);
- QScriptValue scriptApi;
+ QJSValue (*scriptCallback)(QDeclarativeEngine *, QJSEngine *);
+ QObject *(*qobjectCallback)(QDeclarativeEngine *, QJSEngine *);
+ QJSValue scriptApi;
QObject *qobjectApi;
};
struct ModuleApi {
@@ -123,8 +123,8 @@ public:
inline bool operator==(const ModuleApi &) const;
int major;
int minor;
- QScriptValue (*script)(QDeclarativeEngine *, QScriptEngine *);
- QObject *(*qobject)(QDeclarativeEngine *, QScriptEngine *);
+ QJSValue (*script)(QDeclarativeEngine *, QJSEngine *);
+ QObject *(*qobject)(QDeclarativeEngine *, QJSEngine *);
};
static ModuleApi moduleApi(const QByteArray &, int, int);
};
diff --git a/src/declarative/qml/qdeclarativeprivate.h b/src/declarative/qml/qdeclarativeprivate.h
index 9eacc1d1cb..e8e8f229cf 100644
--- a/src/declarative/qml/qdeclarativeprivate.h
+++ b/src/declarative/qml/qdeclarativeprivate.h
@@ -74,8 +74,8 @@ public:
};
-class QScriptValue;
-class QScriptEngine;
+class QJSValue;
+class QJSEngine;
class QDeclarativeEngine;
class QDeclarativeCustomParser;
namespace QDeclarativePrivate
@@ -243,8 +243,8 @@ namespace QDeclarativePrivate
int versionMajor;
int versionMinor;
- QScriptValue (*scriptApi)(QDeclarativeEngine *, QScriptEngine *);
- QObject *(*qobjectApi)(QDeclarativeEngine *, QScriptEngine *);
+ QJSValue (*scriptApi)(QDeclarativeEngine *, QJSEngine *);
+ QObject *(*qobjectApi)(QDeclarativeEngine *, QJSEngine *);
};
enum RegistrationType {
diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp
index 6ff47d7b57..d2148ad874 100644
--- a/src/declarative/qml/qdeclarativepropertycache.cpp
+++ b/src/declarative/qml/qdeclarativepropertycache.cpp
@@ -49,7 +49,7 @@
#include <QtCore/qdebug.h>
-Q_DECLARE_METATYPE(QScriptValue)
+Q_DECLARE_METATYPE(QJSValue)
Q_DECLARE_METATYPE(QDeclarativeV8Handle);
QT_BEGIN_NAMESPACE
@@ -83,8 +83,8 @@ static QDeclarativePropertyCache::Data::Flags flagsForPropertyType(int propType,
if (propType < QMetaType::User && propType != QMetaType::QObjectStar && propType != QMetaType::QWidgetStar) {
} else if (propType == qMetaTypeId<QDeclarativeBinding *>()) {
flags |= QDeclarativePropertyCache::Data::IsQmlBinding;
- } else if (propType == qMetaTypeId<QScriptValue>()) {
- flags |= QDeclarativePropertyCache::Data::IsQScriptValue;
+ } else if (propType == qMetaTypeId<QJSValue>()) {
+ flags |= QDeclarativePropertyCache::Data::IsQJSValue;
} else if (propType == qMetaTypeId<QDeclarativeV8Handle>()) {
flags |= QDeclarativePropertyCache::Data::IsV8Handle;
} else {
@@ -518,7 +518,7 @@ QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
rv = cache->property(name);
} else {
QString strname = QV8Engine::toStringStatic(name.string());
- // QString strname = ep->v8engine.toString(name);
+ // QString strname = ep->v8engine()->toString(name);
local = QDeclarativePropertyCache::create(obj->metaObject(), strname);
if (local.isValid())
rv = &local;
diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h
index 621463dad9..cdbd49388f 100644
--- a/src/declarative/qml/qdeclarativepropertycache_p.h
+++ b/src/declarative/qml/qdeclarativepropertycache_p.h
@@ -60,7 +60,6 @@
#include "private/qhashedstring_p.h"
#include <QtCore/qvector.h>
-#include <QtScript/private/qscriptdeclarativeclass_p.h>
QT_BEGIN_NAMESPACE
class QDeclarativeEngine;
@@ -96,7 +95,7 @@ public:
IsEnumType = 0x00000100, // Property type is an enum
IsQList = 0x00000200, // Property type is a QML list
IsQmlBinding = 0x00000400, // Property type is a QDeclarativeBinding*
- IsQScriptValue = 0x00000800, // Property type is a QScriptValue
+ IsQJSValue = 0x00000800, // Property type is a QScriptValue
IsV8Handle = 0x00001000, // Property type is a QDeclarativeV8Handle
// Apply only to IsFunctions
@@ -127,7 +126,7 @@ public:
bool isEnum() const { return flags & IsEnumType; }
bool isQList() const { return flags & IsQList; }
bool isQmlBinding() const { return flags & IsQmlBinding; }
- bool isQScriptValue() const { return flags & IsQScriptValue; }
+ bool isQJSValue() const { return flags & IsQJSValue; }
bool isV8Handle() const { return flags & IsV8Handle; }
bool isVMEFunction() const { return flags & IsVMEFunction; }
bool hasArguments() const { return flags & HasArguments; }
diff --git a/src/declarative/qml/qdeclarativesqldatabase_p.h b/src/declarative/qml/qdeclarativesqldatabase_p.h
index 337f717b1e..ef88b2e4f5 100644
--- a/src/declarative/qml/qdeclarativesqldatabase_p.h
+++ b/src/declarative/qml/qdeclarativesqldatabase_p.h
@@ -42,7 +42,7 @@
#ifndef QDECLARATIVESQLDATABASE_P_H
#define QDECLARATIVESQLDATABASE_P_H
-#include <QtScript/qscriptengine.h>
+#include <QtDeclarative/qjsengine.h>
//
// W A R N I N G
// -------------
diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp
index cb3e8aef3e..97c5b38c20 100644
--- a/src/declarative/qml/qdeclarativetypeloader.cpp
+++ b/src/declarative/qml/qdeclarativetypeloader.cpp
@@ -1230,7 +1230,7 @@ void QDeclarativeScriptBlob::done()
m_scriptData->pragmas = m_pragmas;
// XXX TODO: Handle errors that occur duing the script compile
- QV8Engine *v8engine = &QDeclarativeEnginePrivate::get(engine)->v8engine;
+ QV8Engine *v8engine = QDeclarativeEnginePrivate::get(engine)->v8engine();
v8::HandleScope handle_scope;
v8::Context::Scope scope(v8engine->context());
v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_source, finalUrl().toString(), 1);
diff --git a/src/declarative/qml/qdeclarativetypeloader_p.h b/src/declarative/qml/qdeclarativetypeloader_p.h
index 20e16750cf..1ca6f8c9c2 100644
--- a/src/declarative/qml/qdeclarativetypeloader_p.h
+++ b/src/declarative/qml/qdeclarativetypeloader_p.h
@@ -55,8 +55,7 @@
#include <QtCore/qobject.h>
#include <QtNetwork/qnetworkreply.h>
-#include <QtScript/qscriptvalue.h>
-#include <QtScript/qscriptprogram.h>
+#include <QtDeclarative/qjsvalue.h>
#include <QtDeclarative/qdeclarativeerror.h>
#include <QtDeclarative/qdeclarativeengine.h>
#include <private/qdeclarativecleanup_p.h>
diff --git a/src/declarative/qml/qdeclarativetypenamecache_p.h b/src/declarative/qml/qdeclarativetypenamecache_p.h
index abf18ce384..e89747b15a 100644
--- a/src/declarative/qml/qdeclarativetypenamecache_p.h
+++ b/src/declarative/qml/qdeclarativetypenamecache_p.h
@@ -57,8 +57,6 @@
#include "private/qdeclarativecleanup_p.h"
#include "private/qdeclarativemetatype_p.h"
-#include <private/qscriptdeclarativeclass_p.h>
-
#include <private/qhashedstring_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp
index 3b7abe6028..45e4745c1a 100644
--- a/src/declarative/qml/qdeclarativevme.cpp
+++ b/src/declarative/qml/qdeclarativevme.cpp
@@ -74,7 +74,7 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qvarlengtharray.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
QT_BEGIN_NAMESPACE
@@ -1025,7 +1025,7 @@ v8::Persistent<v8::Object> QDeclarativeVME::run(QDeclarativeContextData *parentC
return qPersistentNew<v8::Object>(script->m_value);
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(parentCtxt->engine);
- QV8Engine *v8engine = &ep->v8engine;
+ QV8Engine *v8engine = ep->v8engine();
bool shared = script->pragmas & QDeclarativeParser::Object::ScriptBlock::Shared;
diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h
index 5312e7e128..d0c98d448e 100644
--- a/src/declarative/qml/qdeclarativevme_p.h
+++ b/src/declarative/qml/qdeclarativevme_p.h
@@ -64,7 +64,7 @@
QT_BEGIN_NAMESPACE
class QObject;
-class QScriptValue;
+class QJSValue;
class QDeclarativeScriptData;
class QDeclarativeCompiledData;
class QDeclarativeCompiledData;
diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp
index 247c1aa533..746c9f650b 100644
--- a/src/declarative/qml/qdeclarativevmemetaobject.cpp
+++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp
@@ -48,7 +48,7 @@
#include "private/qdeclarativecontext_p.h"
#include "private/qdeclarativebinding_p.h"
-Q_DECLARE_METATYPE(QScriptValue);
+Q_DECLARE_METATYPE(QJSValue);
QT_BEGIN_NAMESPACE
@@ -73,7 +73,7 @@ public:
inline const QTime &asQTime();
inline const QDate &asQDate();
inline const QDateTime &asQDateTime();
- inline const QScriptValue &asQScriptValue();
+ inline const QJSValue &asQJSValue();
inline void setValue(QObject *);
inline void setValue(const QVariant &);
@@ -86,7 +86,7 @@ public:
inline void setValue(const QTime &);
inline void setValue(const QDate &);
inline void setValue(const QDateTime &);
- inline void setValue(const QScriptValue &);
+ inline void setValue(const QJSValue &);
private:
int type;
void *data[4]; // Large enough to hold all types
@@ -135,8 +135,8 @@ void QDeclarativeVMEVariant::cleanup()
} else if (type == qMetaTypeId<QVariant>()) {
((QVariant *)dataPtr())->~QVariant();
type = QVariant::Invalid;
- } else if (type == qMetaTypeId<QScriptValue>()) {
- ((QScriptValue *)dataPtr())->~QScriptValue();
+ } else if (type == qMetaTypeId<QJSValue>()) {
+ ((QJSValue *)dataPtr())->~QJSValue();
type = QVariant::Invalid;
}
@@ -245,12 +245,12 @@ const QDateTime &QDeclarativeVMEVariant::asQDateTime()
return *(QDateTime *)(dataPtr());
}
-const QScriptValue &QDeclarativeVMEVariant::asQScriptValue()
+const QJSValue &QDeclarativeVMEVariant::asQJSValue()
{
- if (type != qMetaTypeId<QScriptValue>())
- setValue(QScriptValue());
+ if (type != qMetaTypeId<QJSValue>())
+ setValue(QJSValue());
- return *(QScriptValue *)(dataPtr());
+ return *(QJSValue *)(dataPtr());
}
void QDeclarativeVMEVariant::setValue(QObject *v)
@@ -367,14 +367,14 @@ void QDeclarativeVMEVariant::setValue(const QDateTime &v)
}
}
-void QDeclarativeVMEVariant::setValue(const QScriptValue &v)
+void QDeclarativeVMEVariant::setValue(const QJSValue &v)
{
- if (type != qMetaTypeId<QScriptValue>()) {
+ if (type != qMetaTypeId<QJSValue>()) {
cleanup();
- type = qMetaTypeId<QScriptValue>();
- new (dataPtr()) QScriptValue(v);
+ type = qMetaTypeId<QJSValue>();
+ new (dataPtr()) QJSValue(v);
} else {
- *(QScriptValue *)(dataPtr()) = v;
+ *(QJSValue *)(dataPtr()) = v;
}
}
@@ -656,18 +656,18 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + id;
v8::HandleScope handle_scope;
- v8::Context::Scope scope(ep->v8engine.context());
+ v8::Context::Scope scope(ep->v8engine()->context());
v8::Handle<v8::Value> *args = 0;
if (data->parameterCount) {
args = new v8::Handle<v8::Value>[data->parameterCount];
for (int ii = 0; ii < data->parameterCount; ++ii)
- args[ii] = ep->v8engine.fromVariant(*(QVariant *)a[ii + 1]);
+ args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]);
}
v8::TryCatch try_catch;
- v8::Local<v8::Value> result = function->Call(ep->v8engine.global(), data->parameterCount, args);
+ v8::Local<v8::Value> result = function->Call(ep->v8engine()->global(), data->parameterCount, args);
QVariant rv;
if (try_catch.HasCaught()) {
@@ -677,7 +677,7 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
ep->warning(error);
if (a[0]) *(QVariant *)a[0] = QVariant();
} else {
- if (a[0]) *(QVariant *)a[0] = ep->v8engine.toVariant(result, 0);
+ if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0);
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
@@ -720,7 +720,7 @@ v8::Handle<v8::Function> QDeclarativeVMEMetaObject::method(int index)
QScriptValue QDeclarativeVMEMetaObject::readVarProperty(int id)
{
if (data[id].dataType() == qMetaTypeId<QScriptValue>())
- return data[id].asQScriptValue();
+ return data[id].asQJSValue();
else if (data[id].dataType() == QMetaType::QObjectStar)
return QDeclarativeEnginePrivate::get(ctxt->engine)->objectClass->newQObject(data[id].asQObject());
else
@@ -732,7 +732,7 @@ QVariant QDeclarativeVMEMetaObject::readVarPropertyAsVariant(int id)
{
#if 0
if (data[id].dataType() == qMetaTypeId<QScriptValue>())
- return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueToVariant(data[id].asQScriptValue());
+ return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueToVariant(data[id].asQJSValue());
else
#endif
if (data[id].dataType() == QMetaType::QObjectStar)
diff --git a/src/declarative/qml/qdeclarativeworkerscript.cpp b/src/declarative/qml/qdeclarativeworkerscript.cpp
index b519573ccf..fc9bb887e8 100644
--- a/src/declarative/qml/qdeclarativeworkerscript.cpp
+++ b/src/declarative/qml/qdeclarativeworkerscript.cpp
@@ -48,10 +48,9 @@
#include <QtCore/qcoreevent.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdebug.h>
-#include <QtScript/qscriptengine.h>
+#include <QtDeclarative/qjsengine.h>
#include <QtCore/qmutex.h>
#include <QtCore/qwaitcondition.h>
-#include <QtScript/qscriptvalueiterator.h>
#include <QtCore/qfile.h>
#include <QtCore/qdatetime.h>
#include <QtNetwork/qnetworkaccessmanager.h>
@@ -190,7 +189,7 @@ private:
};
QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QDeclarativeWorkerScriptEnginePrivate *parent)
-: p(parent), accessManager(0)
+: QV8Engine(0), p(parent), accessManager(0)
{
}
@@ -203,8 +202,7 @@ QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine()
void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::init()
{
- QV8Engine::init(0);
-
+ initDeclarativeGlobalObject();
#define CALL_ONMESSAGE_SCRIPT \
"(function(object, message) { "\
"var isfunction = false; "\
@@ -705,7 +703,7 @@ bool QDeclarativeWorkerScript::event(QEvent *event)
QDeclarativeEngine *engine = qmlEngine(this);
if (engine) {
WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
- QV8Engine *v8engine = &QDeclarativeEnginePrivate::get(engine)->v8engine;
+ QV8Engine *v8engine = QDeclarativeEnginePrivate::get(engine)->v8engine();
v8::HandleScope handle_scope;
v8::Context::Scope scope(v8engine->context());
v8::Handle<v8::Value> value = QV8Worker::deserialize(workerEvent->data(), v8engine);
diff --git a/src/declarative/qml/qdeclarativeworkerscript_p.h b/src/declarative/qml/qdeclarativeworkerscript_p.h
index 85910b16e9..d953b0ff18 100644
--- a/src/declarative/qml/qdeclarativeworkerscript_p.h
+++ b/src/declarative/qml/qdeclarativeworkerscript_p.h
@@ -57,7 +57,7 @@
#include "qdeclarativeparserstatus.h"
#include <QtCore/qthread.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
#include <QtCore/qurl.h>
QT_BEGIN_HEADER
diff --git a/src/declarative/qml/qdeclarativexmlhttprequest.cpp b/src/declarative/qml/qdeclarativexmlhttprequest.cpp
index 194a60f2d3..abcc283610 100644
--- a/src/declarative/qml/qdeclarativexmlhttprequest.cpp
+++ b/src/declarative/qml/qdeclarativexmlhttprequest.cpp
@@ -51,9 +51,8 @@
#include "qdeclarativeglobal_p.h"
#include <QtCore/qobject.h>
-#include <QtScript/qscriptvalue.h>
-#include <QtScript/qscriptcontext.h>
-#include <QtScript/qscriptengine.h>
+#include <QtDeclarative/qjsvalue.h>
+#include <QtDeclarative/qjsengine.h>
#include <QtNetwork/qnetworkreply.h>
#include <QtCore/qtextcodec.h>
#include <QtCore/qxmlstream.h>
diff --git a/src/declarative/qml/qdeclarativexmlhttprequest_p.h b/src/declarative/qml/qdeclarativexmlhttprequest_p.h
index a2082db59f..c5c53a6ce1 100644
--- a/src/declarative/qml/qdeclarativexmlhttprequest_p.h
+++ b/src/declarative/qml/qdeclarativexmlhttprequest_p.h
@@ -42,7 +42,7 @@
#ifndef QDECLARATIVEXMLHTTPREQUEST_P_H
#define QDECLARATIVEXMLHTTPREQUEST_P_H
-#include <QtScript/qscriptengine.h>
+#include <QtDeclarative/qjsengine.h>
//
// W A R N I N G
// -------------
diff --git a/src/declarative/qml/v4/qdeclarativev4bindings.cpp b/src/declarative/qml/v4/qdeclarativev4bindings.cpp
index 29c9ce05c5..d93d930034 100644
--- a/src/declarative/qml/v4/qdeclarativev4bindings.cpp
+++ b/src/declarative/qml/v4/qdeclarativev4bindings.cpp
@@ -217,7 +217,6 @@ public:
typedef QDeclarativeNotifierEndpoint Subscription;
Subscription *subscriptions;
- QScriptDeclarativeClass::PersistentIdentifier *identifiers;
void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags);
@@ -240,20 +239,19 @@ public:
inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex);
inline void subscribe(QObject *o, int notifyIndex, int subIndex);
- inline static qint32 toInt32(qsreal n);
- static const qsreal D32;
- static quint32 toUint32(qsreal n);
+ inline static qint32 toInt32(qreal n);
+ static const qreal D32;
+ static quint32 toUint32(qreal n);
};
QDeclarativeV4BindingsPrivate::QDeclarativeV4BindingsPrivate()
-: subscriptions(0), identifiers(0), program(0), bindings(0)
+: subscriptions(0), program(0), bindings(0)
{
}
QDeclarativeV4BindingsPrivate::~QDeclarativeV4BindingsPrivate()
{
delete [] subscriptions; subscriptions = 0;
- delete [] identifiers; identifiers = 0;
}
int QDeclarativeV4BindingsPrivate::methodCount = -1;
@@ -508,8 +506,6 @@ void QDeclarativeV4BindingsPrivate::init()
{
if (program->subscriptions)
subscriptions = new QDeclarativeV4BindingsPrivate::Subscription[program->subscriptions];
- if (program->identifiers)
- identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers];
bindings = new QDeclarativeV4BindingsPrivate::Binding[program->bindings];
}
@@ -679,15 +675,15 @@ static void throwException(int id, QDeclarativeDelayedError *error,
QDeclarativeEnginePrivate::warning(context->engine, error->error);
}
-const qsreal QDeclarativeV4BindingsPrivate::D32 = 4294967296.0;
+const qreal QDeclarativeV4BindingsPrivate::D32 = 4294967296.0;
-qint32 QDeclarativeV4BindingsPrivate::toInt32(qsreal n)
+qint32 QDeclarativeV4BindingsPrivate::toInt32(qreal n)
{
if (qIsNaN(n) || qIsInf(n) || (n == 0))
return 0;
double sign = (n < 0) ? -1.0 : 1.0;
- qsreal abs_n = fabs(n);
+ qreal abs_n = fabs(n);
n = ::fmod(sign * ::floor(abs_n), D32);
const double D31 = D32 / 2.0;
@@ -701,13 +697,13 @@ qint32 QDeclarativeV4BindingsPrivate::toInt32(qsreal n)
return qint32 (n);
}
-inline quint32 QDeclarativeV4BindingsPrivate::toUint32(qsreal n)
+inline quint32 QDeclarativeV4BindingsPrivate::toUint32(qreal n)
{
if (qIsNaN(n) || qIsInf(n) || (n == 0))
return 0;
double sign = (n < 0) ? -1.0 : 1.0;
- qsreal abs_n = fabs(n);
+ qreal abs_n = fabs(n);
n = ::fmod(sign * ::floor(abs_n), D32);
@@ -1015,7 +1011,7 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks,
} else {
// Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
// Ideally we should just call the methods in the QScript namespace directly.
- QScriptValue tmp(*src.getstringptr());
+ QJSValue tmp(*src.getstringptr());
if (instr->unaryop.src == instr->unaryop.output) {
output.cleanupString();
MARK_CLEAN_REGISTER(instr->unaryop.output);
@@ -1035,7 +1031,7 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks,
} else {
// Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
// Ideally we should just call the methods in the QScript namespace directly.
- QScriptValue tmp(*src.getstringptr());
+ QJSValue tmp(*src.getstringptr());
if (instr->unaryop.src == instr->unaryop.output) {
output.cleanupString();
MARK_CLEAN_REGISTER(instr->unaryop.output);
@@ -1055,7 +1051,7 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks,
} else {
// Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
// Ideally we should just call the methods in the QScript namespace directly.
- QScriptValue tmp(*src.getstringptr());
+ QJSValue tmp(*src.getstringptr());
if (instr->unaryop.src == instr->unaryop.output) {
output.cleanupString();
MARK_CLEAN_REGISTER(instr->unaryop.output);
@@ -1103,7 +1099,7 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks,
QML_V4_BEGIN_INSTR(MathPIReal, unaryop)
{
- static const qsreal qmlPI = 2.0 * qAsin(1.0);
+ static const qreal qmlPI = 2.0 * qAsin(1.0);
Register &output = registers[instr->unaryop.output];
output.setqreal(qmlPI);
}
@@ -1480,16 +1476,16 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks,
executedBlocks |= instr->blockop.block;
QML_V4_END_INSTR(Block, blockop)
+ // XXX not applicable in v8
QML_V4_BEGIN_INSTR(InitString, initstring)
- if (!identifiers[instr->initstring.offset].identifier) {
- quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
- QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32));
+// if (!identifiers[instr->initstring.offset].identifier) {
+// quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
+// QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32));
- QString str = QString::fromRawData(strdata, len);
+// QString str = QString::fromRawData(strdata, len);
- // XXX not applicable in v8
- // identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
- }
+// // identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
+// }
QML_V4_END_INSTR(InitString, initstring)
QML_V4_BEGIN_INSTR(CleanupRegister, cleanup)
diff --git a/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp
index 34a59caf1a..bddfca18b4 100644
--- a/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp
+++ b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp
@@ -436,7 +436,7 @@ bool QDeclarativeV4IRBuilder::visit(AST::IdentifierExpression *ast)
if (name.at(0) == QLatin1Char('u') && name.length() == 9 && name == QLatin1String("undefined")) {
_expr.code = _block->CONST(IR::UndefinedType, 0); // ### undefined value
- } else if(m_engine->v8engine.illegalNames().contains(name) ) {
+ } else if (m_engine->v8engine()->illegalNames().contains(name) ) {
if (qmlVerboseCompiler()) qWarning() << "*** illegal symbol:" << name;
return false;
} else if (const QDeclarativeParser::Object *obj = m_expression->ids.value(name)) {
diff --git a/src/declarative/qml/v8/qjsconverter_p.h b/src/declarative/qml/v8/qjsconverter_p.h
new file mode 100644
index 0000000000..4aec472c7a
--- /dev/null
+++ b/src/declarative/qml/v8/qjsconverter_p.h
@@ -0,0 +1,272 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJSCONVERTER_P_H
+#define QJSCONVERTER_P_H
+
+#include "qjsvalue.h"
+#include <QtCore/qglobal.h>
+#include <QtCore/qnumeric.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qregexp.h>
+#include <QtCore/qdatetime.h>
+
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+extern char *qdtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **digits_str);
+Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
+
+/*
+ \internal
+ \class QJSConverter
+ QJSValue and QJSEngine helper class. This class's responsibility is to convert values
+ between JS values and Qt/C++ values.
+
+ This is a nice way to inline these functions in both QJSValue and QJSEngine.
+*/
+class QJSConverter {
+public:
+ static quint32 toArrayIndex(const QString& string)
+ {
+ // FIXME this function should be exported by JSC C API.
+ bool ok;
+ quint32 idx = string.toUInt(&ok);
+ if (!ok || toString(idx) != string)
+ idx = 0xffffffff;
+
+ return idx;
+ }
+
+ static QString toString(v8::Handle<v8::String> jsString)
+ {
+ if (jsString.IsEmpty())
+ return QString();
+ QString qstr;
+ qstr.resize(jsString->Length());
+ jsString->Write(reinterpret_cast<uint16_t*>(qstr.data()));
+ return qstr;
+ }
+
+ static v8::Handle<v8::String> toString(const QString& string)
+ {
+ return v8::String::New(reinterpret_cast<const uint16_t*>(string.data()), string.size());
+ }
+
+ static QString toString(double value)
+ {
+ // FIXME this should be easier. The ideal fix is to create
+ // a new function in V8 API which could cover the functionality.
+
+ if (qIsNaN(value))
+ return QString::fromLatin1("NaN");
+ if (qIsInf(value))
+ return QString::fromLatin1(value < 0 ? "-Infinity" : "Infinity");
+ if (!value)
+ return QString::fromLatin1("0");
+
+ QVarLengthArray<char, 25> buf;
+ int decpt;
+ int sign;
+ char* result = 0;
+ char* endresult;
+ (void)qdtoa(value, 0, 0, &decpt, &sign, &endresult, &result);
+
+ if (!result)
+ return QString();
+
+ int resultLen = endresult - result;
+ if (decpt <= 0 && decpt > -6) {
+ buf.resize(-decpt + 2 + sign);
+ qMemSet(buf.data(), '0', -decpt + 2 + sign);
+ if (sign) // fix the sign.
+ buf[0] = '-';
+ buf[sign + 1] = '.';
+ buf.append(result, resultLen);
+ } else {
+ if (sign)
+ buf.append('-');
+ int length = buf.size() - sign + resultLen;
+ if (decpt <= 21 && decpt > 0) {
+ if (length <= decpt) {
+ const char* zeros = "0000000000000000000000000";
+ buf.append(result, resultLen);
+ buf.append(zeros, decpt - length);
+ } else {
+ buf.append(result, decpt);
+ buf.append('.');
+ buf.append(result + decpt, resultLen - decpt);
+ }
+ } else if (result[0] >= '0' && result[0] <= '9') {
+ if (length > 1) {
+ buf.append(result, 1);
+ buf.append('.');
+ buf.append(result + 1, resultLen - 1);
+ } else
+ buf.append(result, resultLen);
+ buf.append('e');
+ buf.append(decpt >= 0 ? '+' : '-');
+ int e = qAbs(decpt - 1);
+ if (e >= 100)
+ buf.append('0' + e / 100);
+ if (e >= 10)
+ buf.append('0' + (e % 100) / 10);
+ buf.append('0' + e % 10);
+ }
+ }
+ free(result);
+ buf.append(0);
+ return QString::fromLatin1(buf.constData());
+ }
+
+ enum {
+ PropertyAttributeMask = v8::ReadOnly | v8::DontDelete | v8::DontEnum,
+ };
+
+ // return a mask of v8::PropertyAttribute that may also contains QScriptValue::PropertyGetter or QScriptValue::PropertySetter
+ static uint toPropertyAttributes(const QFlags<QJSValue::PropertyFlag>& flags)
+ {
+ uint attr = 0;
+ if (flags.testFlag(QJSValue::ReadOnly))
+ attr |= v8::ReadOnly;
+ if (flags.testFlag(QJSValue::Undeletable))
+ attr |= v8::DontDelete;
+ if (flags.testFlag(QJSValue::SkipInEnumeration))
+ attr |= v8::DontEnum;
+// if (flags.testFlag(QScriptValue::PropertyGetter))
+// attr |= QScriptValue::PropertyGetter;
+// if (flags.testFlag(QScriptValue::PropertySetter))
+// attr |= QScriptValue::PropertySetter;
+ return attr;
+ }
+
+ // Converts a JS RegExp to a QRegExp.
+ // The conversion is not 100% exact since ECMA regexp and QRegExp
+ // have different semantics/flags, but we try to do our best.
+ static QRegExp toRegExp(v8::Handle<v8::RegExp> jsRegExp)
+ {
+ QString pattern = QJSConverter::toString(jsRegExp->GetSource());
+ Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive;
+ if (jsRegExp->GetFlags() & v8::RegExp::kIgnoreCase)
+ caseSensitivity = Qt::CaseInsensitive;
+ return QRegExp(pattern, caseSensitivity, QRegExp::RegExp2);
+ }
+
+ // Converts a QRegExp to a JS RegExp.
+ // The conversion is not 100% exact since ECMA regexp and QRegExp
+ // have different semantics/flags, but we try to do our best.
+ static v8::Handle<v8::RegExp> toRegExp(const QRegExp &re)
+ {
+ // Convert the pattern to a ECMAScript pattern.
+ QString pattern = qt_regexp_toCanonical(re.pattern(), re.patternSyntax());
+ if (re.isMinimal()) {
+ QString ecmaPattern;
+ int len = pattern.length();
+ ecmaPattern.reserve(len);
+ int i = 0;
+ const QChar *wc = pattern.unicode();
+ bool inBracket = false;
+ while (i < len) {
+ QChar c = wc[i++];
+ ecmaPattern += c;
+ switch (c.unicode()) {
+ case '?':
+ case '+':
+ case '*':
+ case '}':
+ if (!inBracket)
+ ecmaPattern += QLatin1Char('?');
+ break;
+ case '\\':
+ if (i < len)
+ ecmaPattern += wc[i++];
+ break;
+ case '[':
+ inBracket = true;
+ break;
+ case ']':
+ inBracket = false;
+ break;
+ default:
+ break;
+ }
+ }
+ pattern = ecmaPattern;
+ }
+
+ int flags = v8::RegExp::kNone;
+ if (re.caseSensitivity() == Qt::CaseInsensitive)
+ flags |= v8::RegExp::kIgnoreCase;
+
+ return v8::RegExp::New(QJSConverter::toString(pattern), static_cast<v8::RegExp::Flags>(flags));
+ }
+
+ // Converts a QStringList to JS.
+ // The result is a new Array object with length equal to the length
+ // of the QStringList, and the elements being the QStringList's
+ // elements converted to JS Strings.
+ static v8::Handle<v8::Array> toStringList(const QStringList &lst)
+ {
+ v8::Handle<v8::Array> result = v8::Array::New(lst.size());
+ for (int i = 0; i < lst.size(); ++i)
+ result->Set(i, toString(lst.at(i)));
+ return result;
+ }
+
+ // Converts a JS Array object to a QStringList.
+ // The result is a QStringList with length equal to the length
+ // of the JS Array, and elements being the JS Array's elements
+ // converted to QStrings.
+ static QStringList toStringList(v8::Handle<v8::Array> jsArray)
+ {
+ QStringList result;
+ uint32_t length = jsArray->Length();
+ for (uint32_t i = 0; i < length; ++i)
+ result.append(toString(jsArray->Get(i)->ToString()));
+ return result;
+ }
+
+
+ // Converts a JS Date to a QDateTime.
+ static QDateTime toDateTime(v8::Handle<v8::Date> jsDate)
+ {
+ return QDateTime::fromMSecsSinceEpoch(jsDate->NumberValue());
+ }
+
+ // Converts a QDateTime to a JS Date.
+ static v8::Handle<v8::Value> toDateTime(const QDateTime &dt)
+ {
+ double date;
+ if (!dt.isValid())
+ date = qSNaN();
+ else
+ date = dt.toMSecsSinceEpoch();
+ return v8::Date::New(date);
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/qml/v8/qjsengine.cpp b/src/declarative/qml/v8/qjsengine.cpp
new file mode 100644
index 0000000000..e80fcb4e7e
--- /dev/null
+++ b/src/declarative/qml/v8/qjsengine.cpp
@@ -0,0 +1,431 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qjsengine.h"
+#include "qjsvalue.h"
+#include "qjsvalue_p.h"
+#include "qscriptisolate_p.h"
+#include "qscript_impl_p.h"
+#include "qv8engine_p.h"
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qdatetime.h>
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qpluginloader.h>
+#include <qthread.h>
+#include <qmutex.h>
+#include <qwaitcondition.h>
+
+#undef Q_D
+#undef Q_Q
+#define Q_D(blah)
+#define Q_Q(blah)
+
+Q_DECLARE_METATYPE(QJSValue)
+Q_DECLARE_METATYPE(QObjectList)
+Q_DECLARE_METATYPE(QList<int>)
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ Constructs a QJSEngine object.
+
+ The globalObject() is initialized to have properties as described in
+ \l{ECMA-262}, Section 15.1.
+*/
+QJSEngine::QJSEngine()
+ : d(new QV8Engine(this))
+{
+}
+
+/*!
+ \internal
+*/
+QJSEngine::QJSEngine(QJSEngine::ContextOwnership ownership)
+ : d(new QV8Engine(this, ownership))
+{
+}
+
+/*!
+ Constructs a QJSEngine object with the given \a parent.
+
+ The globalObject() is initialized to have properties as described in
+ \l{ECMA-262}, Section 15.1.
+*/
+
+QJSEngine::QJSEngine(QObject *parent)
+ : QObject(parent)
+ , d(new QV8Engine(this))
+{
+}
+
+QJSEngine::QJSEngine(QObjectPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+ , d(new QV8Engine(this))
+{
+}
+
+/*!
+ Destroys this QJSEngine.
+*/
+QJSEngine::~QJSEngine()
+{
+ delete d;
+}
+
+/*!
+ Returns true if the last script evaluation resulted in an uncaught
+ exception; otherwise returns false.
+
+ The exception state is cleared when evaluate() is called.
+
+ \sa uncaughtException(), uncaughtExceptionLineNumber(),
+ uncaughtExceptionBacktrace()
+*/
+bool QJSEngine::hasUncaughtException() const
+{
+ Q_D(const QJSEngine);
+ QScriptIsolate api(d);
+ return d->hasUncaughtException();
+}
+
+/*!
+ Returns the current uncaught exception, or an invalid QJSValue
+ if there is no uncaught exception.
+
+ The exception value is typically an \c{Error} object; in that case,
+ you can call toString() on the return value to obtain an error
+ message.
+
+ \sa hasUncaughtException(), uncaughtExceptionLineNumber(),
+ uncaughtExceptionBacktrace()
+*/
+QJSValue QJSEngine::uncaughtException() const
+{
+ Q_D(const QJSEngine);
+ QScriptIsolate api(d);
+ return d->scriptValueFromInternal(d->uncaughtException());
+}
+
+/*!
+ Clears any uncaught exceptions in this engine.
+
+ \sa hasUncaughtException()
+*/
+void QJSEngine::clearExceptions()
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d);
+ d->clearExceptions();
+}
+
+
+/*!
+ Runs the garbage collector.
+
+ The garbage collector will attempt to reclaim memory by locating and disposing of objects that are
+ no longer reachable in the script environment.
+
+ Normally you don't need to call this function; the garbage collector will automatically be invoked
+ when the QJSEngine decides that it's wise to do so (i.e. when a certain number of new objects
+ have been created). However, you can call this function to explicitly request that garbage
+ collection should be performed as soon as possible.
+
+ \sa reportAdditionalMemoryCost()
+*/
+void QJSEngine::collectGarbage()
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d);
+ d->collectGarbage();
+}
+
+/*!
+ Evaluates \a program, using \a lineNumber as the base line number,
+ and returns the result of the evaluation.
+
+ The script code will be evaluated in the current context.
+
+ The evaluation of \a program can cause an exception in the
+ engine; in this case the return value will be the exception
+ that was thrown (typically an \c{Error} object). You can call
+ hasUncaughtException() to determine if an exception occurred in
+ the last call to evaluate().
+
+ \a lineNumber is used to specify a starting line number for \a
+ program; line number information reported by the engine that pertain
+ to this evaluation (e.g. uncaughtExceptionLineNumber()) will be
+ based on this argument. For example, if \a program consists of two
+ lines of code, and the statement on the second line causes a script
+ exception, uncaughtExceptionLineNumber() would return the given \a
+ lineNumber plus one. When no starting line number is specified, line
+ numbers will be 1-based.
+
+ \a fileName is used for error reporting. For example in error objects
+ the file name is accessible through the "fileName" property if it's
+ provided with this function.
+*/
+QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, int lineNumber)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return QJSValuePrivate::get(d->evaluate(program, fileName, lineNumber));
+}
+
+QJSValue QJSEngine::nullValue()
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return QJSValuePrivate::get(new QJSValuePrivate(d, v8::Null()));
+}
+
+QJSValue QJSEngine::undefinedValue()
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return QJSValuePrivate::get(new QJSValuePrivate(d, v8::Undefined()));
+}
+
+QJSValue QJSEngine::newObject()
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return QJSValuePrivate::get(new QJSValuePrivate(d, v8::Object::New()));
+}
+
+QJSValue QJSEngine::newArray(uint length)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return QJSValuePrivate::get(d->newArray(length));
+}
+
+/*!
+ Creates a QtScript object that wraps the given QObject \a
+ object, using the given \a ownership. The given \a options control
+ various aspects of the interaction with the resulting script object.
+
+ Signals and slots, properties and children of \a object are
+ available as properties of the created QJSValue. For more
+ information, see the \l{QtScript} documentation.
+
+ If \a object is a null pointer, this function returns nullValue().
+
+ If a default prototype has been registered for the \a object's class
+ (or its superclass, recursively), the prototype of the new script
+ object will be set to be that default prototype.
+
+ If the given \a object is deleted outside of QtScript's control, any
+ attempt to access the deleted QObject's members through the QtScript
+ wrapper object (either by script code or C++) will result in a
+ script exception.
+
+ \sa QJSValue::toQObject(), reportAdditionalMemoryCost()
+*/
+QJSValue QJSEngine::newQObject(QObject *object)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return d->scriptValueFromInternal(d->newQObject(object));
+}
+
+/*!
+ Creates a QtScript object holding the given variant \a value.
+
+ If a default prototype has been registered with the meta type id of
+ \a value, then the prototype of the created object will be that
+ prototype; otherwise, the prototype will be the Object prototype
+ object.
+
+ \sa setDefaultPrototype(), QJSValue::toVariant(), reportAdditionalMemoryCost()
+*/
+QJSValue QJSEngine::newVariant(const QVariant &value)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return d->scriptValueFromInternal(d->newVariant(value));
+}
+
+
+QJSValue QJSEngine::globalObject() const
+{
+ Q_D(const QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return d->scriptValueFromInternal(d->global());
+}
+
+QJSValue QJSEngine::toObject(const QJSValue& value)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return QJSValuePrivate::get(QJSValuePrivate::get(value)->toObject(d));
+}
+
+/*!
+ Creates a QtScript object of class Date from the given \a value.
+
+ \sa QJSValue::toDateTime()
+*/
+QJSValue QJSEngine::newDate(const QDateTime &dt)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return d->scriptValueFromInternal(v8::Handle<v8::Value>(QJSConverter::toDateTime(dt)));
+}
+
+/*!
+ Creates a QtScript object of class Date with the given
+ \a value (the number of milliseconds since 01 January 1970,
+ UTC).
+*/
+QJSValue QJSEngine::newDate(double date)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return d->scriptValueFromInternal(v8::Handle<v8::Value>(v8::Date::New(date)));
+}
+
+/*!
+ Creates a QtScript object of class RegExp with the given
+ \a regexp.
+
+ \sa QJSValue::toRegExp()
+*/
+QJSValue QJSEngine::newRegExp(const QRegExp &regexp)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return QJSValuePrivate::get(d->newRegExp(regexp));
+}
+
+/*!
+ Creates a QtScript object of class RegExp with the given
+ \a pattern and \a flags.
+
+ The legal flags are 'g' (global), 'i' (ignore case), and 'm'
+ (multiline).
+*/
+QJSValue QJSEngine::newRegExp(const QString &pattern, const QString &flags)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return QJSValuePrivate::get(d->newRegExp(pattern, flags));
+}
+
+/*!
+ * \internal
+ * used by QJSEngine::toScriptValue
+ */
+QJSValue QJSEngine::create(int type, const void *ptr)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return d->scriptValueFromInternal(d->metaTypeToJS(type, ptr));
+}
+
+/*!
+ \internal
+ \since 4.5
+ convert \a value to \a type, store the result in \a ptr
+*/
+bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
+{
+ QJSValuePrivate *vp = QJSValuePrivate::get(value);
+ QV8Engine *engine = vp->engine();
+ if (engine) {
+ QScriptIsolate api(engine, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return engine->metaTypeFromJS(*vp, type, ptr);
+ } else {
+ switch (type) {
+ case QMetaType::Bool:
+ *reinterpret_cast<bool*>(ptr) = vp->toBool();
+ return true;
+ case QMetaType::Int:
+ *reinterpret_cast<int*>(ptr) = vp->toInt32();
+ return true;
+ case QMetaType::UInt:
+ *reinterpret_cast<uint*>(ptr) = vp->toUInt32();
+ return true;
+ case QMetaType::LongLong:
+ *reinterpret_cast<qlonglong*>(ptr) = vp->toInteger();
+ return true;
+ case QMetaType::ULongLong:
+ *reinterpret_cast<qulonglong*>(ptr) = vp->toInteger();
+ return true;
+ case QMetaType::Double:
+ *reinterpret_cast<double*>(ptr) = vp->toNumber();
+ return true;
+ case QMetaType::QString:
+ *reinterpret_cast<QString*>(ptr) = vp->toString();
+ return true;
+ case QMetaType::Float:
+ *reinterpret_cast<float*>(ptr) = vp->toNumber();
+ return true;
+ case QMetaType::Short:
+ *reinterpret_cast<short*>(ptr) = vp->toInt32();
+ return true;
+ case QMetaType::UShort:
+ *reinterpret_cast<unsigned short*>(ptr) = vp->toUInt16();
+ return true;
+ case QMetaType::Char:
+ *reinterpret_cast<char*>(ptr) = vp->toInt32();
+ return true;
+ case QMetaType::UChar:
+ *reinterpret_cast<unsigned char*>(ptr) = vp->toUInt16();
+ return true;
+ case QMetaType::QChar:
+ *reinterpret_cast<QChar*>(ptr) = vp->toUInt16();
+ return true;
+ default:
+ return false;
+ }
+ }
+}
+
+
+QT_END_NAMESPACE
+
+#include "moc_qjsengine.cpp"
diff --git a/src/declarative/qml/v8/qjsengine.h b/src/declarative/qml/v8/qjsengine.h
new file mode 100644
index 0000000000..5109cefcf4
--- /dev/null
+++ b/src/declarative/qml/v8/qjsengine.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJSENGINE_H
+#define QJSENGINE_H
+
+#include <QtCore/qmetatype.h>
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qobject.h>
+#include <QtDeclarative/qjsvalue.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Script)
+
+class QDateTime;
+class QV8Engine;
+
+class QRegExp;
+
+template <typename T>
+inline T qjsvalue_cast(const QJSValue &);
+
+class Q_SCRIPT_EXPORT QJSEngine
+ : public QObject
+{
+ Q_OBJECT
+public:
+ enum ContextOwnership {
+ AdoptCurrentContext,
+ CreateNewContext
+ };
+
+ QJSEngine();
+ explicit QJSEngine(ContextOwnership ownership);
+ explicit QJSEngine(QObject *parent);
+ virtual ~QJSEngine();
+
+ QJSValue globalObject() const;
+
+ QJSValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1);
+
+ bool hasUncaughtException() const;
+ QJSValue uncaughtException() const;
+ void clearExceptions();
+
+ QJSValue nullValue();
+ QJSValue undefinedValue();
+
+ QJSValue newVariant(const QVariant &value);
+
+ QJSValue newRegExp(const QRegExp &regexp);
+
+ QJSValue newObject();
+ QJSValue newArray(uint length = 0);
+ QJSValue newRegExp(const QString &pattern, const QString &flags);
+ QJSValue newDate(double value);
+ QJSValue newDate(const QDateTime &value);
+
+ QJSValue newQObject(QObject *object);
+
+ template <typename T>
+ inline QJSValue toScriptValue(const T &value)
+ {
+ return create(qMetaTypeId<T>(), &value);
+ }
+ template <typename T>
+ inline T fromScriptValue(const QJSValue &value)
+ {
+ return qjsvalue_cast<T>(value);
+ }
+
+ void collectGarbage();
+
+ QJSValue toObject(const QJSValue &value);
+
+ QV8Engine *handle() const { return d; }
+
+Q_SIGNALS:
+ void signalHandlerException(const QJSValue &exception);
+
+private:
+ QJSValue create(int type, const void *ptr);
+
+ static bool convertV2(const QJSValue &value, int type, void *ptr);
+
+ friend inline bool qjsvalue_cast_helper(const QJSValue &, int, void *);
+
+protected:
+ QJSEngine(QObjectPrivate &dd, QObject *parent = 0);
+
+private:
+ QV8Engine *d;
+ Q_DISABLE_COPY(QJSEngine)
+ friend class QV8Engine;
+};
+
+inline bool qjsvalue_cast_helper(const QJSValue &value, int type, void *ptr)
+{
+ return QJSEngine::convertV2(value, type, ptr);
+}
+
+template<typename T>
+T qjsvalue_cast(const QJSValue &value)
+{
+ T t;
+ const int id = qMetaTypeId<T>();
+
+ if (qjsvalue_cast_helper(value, id, &t))
+ return t;
+ else if (value.isVariant())
+ return qvariant_cast<T>(value.toVariant());
+
+ return T();
+}
+
+template <>
+inline QVariant qjsvalue_cast<QVariant>(const QJSValue &value)
+{
+ return value.toVariant();
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QJSENGINE_H
diff --git a/src/declarative/qml/v8/qjsvalue.cpp b/src/declarative/qml/v8/qjsvalue.cpp
new file mode 100644
index 0000000000..eff7b4321a
--- /dev/null
+++ b/src/declarative/qml/v8/qjsvalue.cpp
@@ -0,0 +1,1024 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qscriptisolate_p.h"
+#include "qjsengine.h"
+#include "qv8engine_p.h"
+#include "qjsvalue.h"
+#include "qjsvalue_p.h"
+#include "qscript_impl_p.h"
+#include "qscriptshareddata_p.h"
+#include <QtCore/qregexp.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ Constructs an invalid value.
+*/
+QJSValue::QJSValue()
+ : d_ptr(InvalidValue())
+{
+}
+
+/*!
+ Constructs a new QJSValue with a boolean \a value.
+*/
+QJSValue::QJSValue(bool value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ \enum QJSValue::PropertyFlag
+
+ This enum describes the attributes of a property.
+
+ \value ReadOnly The property is read-only. Attempts by Qt Script code to write to the property will be ignored.
+
+ \value Undeletable Attempts by Qt Script code to \c{delete} the property will be ignored.
+
+ \value SkipInEnumeration The property is not to be enumerated by a \c{for-in} enumeration.
+
+ \value PropertyGetter The property is defined by a function which will be called to get the property value.
+
+ \value PropertySetter The property is defined by a function which will be called to set the property value.
+
+ \omitvalue QObjectMember This flag is used to indicate that an existing property is a QObject member (a property or method).
+
+ \value KeepExistingFlags This value is used to indicate to setProperty() that the property's flags should be left unchanged. If the property doesn't exist, the default flags (0) will be used.
+
+ \omitvalue UserRange Flags in this range are not used by Qt Script, and can be used for custom purposes.
+*/
+
+/*!
+ Constructs a new QJSValue with a number \a value.
+*/
+QJSValue::QJSValue(int value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ Constructs a new QJSValue with a number \a value.
+*/
+QJSValue::QJSValue(uint value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ Constructs a new QJSValue with a number \a value.
+*/
+QJSValue::QJSValue(double value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ Constructs a new QJSValue with a string \a value.
+*/
+QJSValue::QJSValue(const QString& value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ Constructs a new QJSValue with a special \a value.
+*/
+QJSValue::QJSValue(SpecialValue value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ Constructs a new QJSValue with a string \a value.
+*/
+QJSValue::QJSValue(const QLatin1String &value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ \fn QJSValue::QJSValue(const QLatin1String &value)
+
+ Constructs a new QJSValue with a string \a value.
+*/
+#ifndef QT_NO_CAST_FROM_ASCII
+QJSValue::QJSValue(const char *value)
+ : d_ptr(new QJSValuePrivate(QString::fromAscii(value)))
+{
+}
+#endif
+
+/*!
+ Block automatic convertion to bool
+ \internal
+*/
+QJSValue::QJSValue(void* d)
+{
+ Q_UNUSED(d);
+ Q_ASSERT(false);
+}
+
+/*!
+ Constructs a new QJSValue from private
+ \internal
+*/
+QJSValue::QJSValue(QJSValuePrivate* d)
+ : d_ptr(d)
+{
+}
+
+/*!
+ Constructs a new QJSValue from private
+ \internal
+*/
+QJSValue::QJSValue(QScriptPassPointer<QJSValuePrivate> d)
+ : d_ptr(d.give())
+{
+}
+
+/*!
+ \obsolete
+
+ Constructs a new QJSValue with the boolean \a value and
+ registers it with the script \a engine.
+*/
+QJSValue::QJSValue(QJSEngine* engine, bool value)
+{
+ if (engine) {
+ QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine);
+ d_ptr = new QJSValuePrivate(QV8Engine::get(engine), value);
+ } else {
+ d_ptr = new QJSValuePrivate(value);
+ }
+}
+
+/*!
+ \obsolete
+
+ Constructs a new QJSValue with the integer \a value and
+ registers it with the script \a engine.
+*/
+QJSValue::QJSValue(QJSEngine* engine, int value)
+{
+ if (engine) {
+ QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine);
+ d_ptr = new QJSValuePrivate(QV8Engine::get(engine), value);
+ } else {
+ d_ptr = new QJSValuePrivate(value);
+ }
+}
+
+/*!
+ \obsolete
+
+ Constructs a new QJSValue with the unsigned integer \a value and
+ registers it with the script \a engine.
+ */
+QJSValue::QJSValue(QJSEngine* engine, uint value)
+{
+ if (engine) {
+ QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine);
+ d_ptr = new QJSValuePrivate(QV8Engine::get(engine), value);
+ } else {
+ d_ptr = new QJSValuePrivate(value);
+ }
+}
+
+/*!
+ \obsolete
+
+ Constructs a new QJSValue with the double \a value and
+ registers it with the script \a engine.
+*/
+QJSValue::QJSValue(QJSEngine* engine, double value)
+{
+ if (engine) {
+ QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine);
+ d_ptr = new QJSValuePrivate(QV8Engine::get(engine), value);
+ } else {
+ d_ptr = new QJSValuePrivate(value);
+ }
+}
+
+/*!
+ \obsolete
+
+ Constructs a new QJSValue with the string \a value and
+ registers it with the script \a engine.
+*/
+QJSValue::QJSValue(QJSEngine* engine, const QString& value)
+{
+ if (engine) {
+ QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine);
+ d_ptr = new QJSValuePrivate(QV8Engine::get(engine), value);
+ } else {
+ d_ptr = new QJSValuePrivate(value);
+ }
+}
+
+/*!
+ \obsolete
+
+ Constructs a new QJSValue with the string \a value and
+ registers it with the script \a engine.
+*/
+QJSValue::QJSValue(QJSEngine* engine, const char* value)
+{
+ if (engine) {
+ QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine);
+ d_ptr = new QJSValuePrivate(QV8Engine::get(engine), QString::fromUtf8(value));
+ } else {
+ d_ptr = new QJSValuePrivate(QString::fromUtf8(value));
+ }
+}
+
+/*!
+ \obsolete
+
+ Constructs a new QJSValue with the special \a value and
+ registers it with the script \a engine.
+*/
+QJSValue::QJSValue(QJSEngine* engine, SpecialValue value)
+{
+ if (engine) {
+ QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine);
+ d_ptr = new QJSValuePrivate(QV8Engine::get(engine), value);
+ } else {
+ d_ptr = new QJSValuePrivate(value);
+ }
+}
+
+/*!
+ Constructs a new QJSValue that is a copy of \a other.
+
+ Note that if \a other is an object (i.e., isObject() would return
+ true), then only a reference to the underlying object is copied into
+ the new script value (i.e., the object itself is not copied).
+*/
+QJSValue::QJSValue(const QJSValue& other)
+ : d_ptr(other.d_ptr)
+{
+}
+
+/*!
+ Destroys this QJSValue.
+*/
+QJSValue::~QJSValue()
+{
+}
+
+/*!
+ Returns true if this QJSValue is valid; otherwise returns
+ false.
+*/
+bool QJSValue::isValid() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isValid();
+}
+
+/*!
+ Returns true if this QJSValue is of the primitive type Boolean;
+ otherwise returns false.
+
+ \sa toBool()
+*/
+bool QJSValue::isBool() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isBool();
+}
+
+/*!
+ \obsolete
+
+ Use isBool() instead.
+ Returns true if this QJSValue is of the primitive type Boolean;
+ otherwise returns false.
+*/
+bool QJSValue::isBoolean() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isBool();
+}
+
+/*!
+ Returns true if this QJSValue is of the primitive type Number;
+ otherwise returns false.
+
+ \sa toNumber()
+*/
+bool QJSValue::isNumber() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isNumber();
+}
+
+/*!
+ Returns true if this QJSValue is of the primitive type Null;
+ otherwise returns false.
+
+ \sa QJSEngine::nullValue()
+*/
+bool QJSValue::isNull() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isNull();
+}
+
+/*!
+ Returns true if this QJSValue is of the primitive type String;
+ otherwise returns false.
+
+ \sa toString()
+*/
+bool QJSValue::isString() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isString();
+}
+
+/*!
+ Returns true if this QJSValue is of the primitive type Undefined;
+ otherwise returns false.
+
+ \sa QJSEngine::undefinedValue()
+*/
+bool QJSValue::isUndefined() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isUndefined();
+}
+
+/*!
+ Returns true if this QJSValue is an object of the Error class;
+ otherwise returns false.
+
+ \sa QScriptContext::throwError()
+*/
+bool QJSValue::isError() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isError();
+}
+
+/*!
+ Returns true if this QJSValue is an object of the Array class;
+ otherwise returns false.
+
+ \sa QJSEngine::newArray()
+*/
+bool QJSValue::isArray() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isArray();
+ }
+
+/*!
+ Returns true if this QJSValue is of the Object type; otherwise
+ returns false.
+
+ Note that function values, variant values, and QObject values are
+ objects, so this function returns true for such values.
+
+ \sa toObject(), QJSEngine::newObject()
+*/
+bool QJSValue::isObject() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isObject();
+}
+
+/*!
+ Returns true if this QJSValue is a function; otherwise returns
+ false.
+
+ \sa call()
+*/
+bool QJSValue::isFunction() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isCallable();
+}
+
+/*!
+ Returns true if this QJSValue is a variant value;
+ otherwise returns false.
+
+ \sa toVariant(), QJSEngine::newVariant()
+*/
+bool QJSValue::isVariant() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isVariant();
+}
+
+/*!
+ Returns the string value of this QJSValue, as defined in
+ \l{ECMA-262} section 9.8, "ToString".
+
+ Note that if this QJSValue is an object, calling this function
+ has side effects on the script engine, since the engine will call
+ the object's toString() function (and possibly valueOf()) in an
+ attempt to convert the object to a primitive value (possibly
+ resulting in an uncaught script exception).
+
+ \sa isString()
+*/
+QString QJSValue::toString() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toString();
+}
+
+/*!
+ Returns the number value of this QJSValue, as defined in
+ \l{ECMA-262} section 9.3, "ToNumber".
+
+ Note that if this QJSValue is an object, calling this function
+ has side effects on the script engine, since the engine will call
+ the object's valueOf() function (and possibly toString()) in an
+ attempt to convert the object to a primitive value (possibly
+ resulting in an uncaught script exception).
+
+ \sa isNumber(), toInteger(), toInt32(), toUInt32(), toUInt16()
+*/
+double QJSValue::toNumber() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toNumber();
+}
+
+/*!
+ Returns the boolean value of this QJSValue, using the conversion
+ rules described in \l{ECMA-262} section 9.2, "ToBoolean".
+
+ Note that if this QJSValue is an object, calling this function
+ has side effects on the script engine, since the engine will call
+ the object's valueOf() function (and possibly toString()) in an
+ attempt to convert the object to a primitive value (possibly
+ resulting in an uncaught script exception).
+
+ \sa isBool()
+*/
+bool QJSValue::toBool() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toBool();
+}
+
+/*!
+ \obsolete
+
+ Use toBool() instead.
+*/
+bool QJSValue::toBoolean() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toBool();
+}
+
+/*!
+ Returns the integer value of this QJSValue, using the conversion
+ rules described in \l{ECMA-262} section 9.4, "ToInteger".
+
+ Note that if this QJSValue is an object, calling this function
+ has side effects on the script engine, since the engine will call
+ the object's valueOf() function (and possibly toString()) in an
+ attempt to convert the object to a primitive value (possibly
+ resulting in an uncaught script exception).
+
+ \sa toNumber()
+*/
+double QJSValue::toInteger() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toInteger();
+}
+
+/*!
+ Returns the signed 32-bit integer value of this QJSValue, using
+ the conversion rules described in \l{ECMA-262} section 9.5, "ToInt32".
+
+ Note that if this QJSValue is an object, calling this function
+ has side effects on the script engine, since the engine will call
+ the object's valueOf() function (and possibly toString()) in an
+ attempt to convert the object to a primitive value (possibly
+ resulting in an uncaught script exception).
+
+ \sa toNumber(), toUInt32()
+*/
+qint32 QJSValue::toInt32() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toInt32();
+}
+
+/*!
+ Returns the unsigned 32-bit integer value of this QJSValue, using
+ the conversion rules described in \l{ECMA-262} section 9.6, "ToUint32".
+
+ Note that if this QJSValue is an object, calling this function
+ has side effects on the script engine, since the engine will call
+ the object's valueOf() function (and possibly toString()) in an
+ attempt to convert the object to a primitive value (possibly
+ resulting in an uncaught script exception).
+
+ \sa toNumber(), toInt32()
+*/
+quint32 QJSValue::toUInt32() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toUInt32();
+}
+
+/*!
+ Returns the unsigned 16-bit integer value of this QJSValue, using
+ the conversion rules described in \l{ECMA-262} section 9.7, "ToUint16".
+
+ Note that if this QJSValue is an object, calling this function
+ has side effects on the script engine, since the engine will call
+ the object's valueOf() function (and possibly toString()) in an
+ attempt to convert the object to a primitive value (possibly
+ resulting in an uncaught script exception).
+
+ \sa toNumber()
+*/
+quint16 QJSValue::toUInt16() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toUInt16();
+}
+
+/*!
+ \obsolete
+
+ This function is obsolete; use QJSEngine::toObject() instead.
+*/
+QJSValue QJSValue::toObject() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return QJSValuePrivate::get(d->toObject());
+}
+
+/*!
+ Returns the QVariant value of this QJSValue, if it can be
+ converted to a QVariant; otherwise returns an invalid QVariant.
+ The conversion is performed according to the following table:
+
+ \table
+ \header \o Input Type \o Result
+ \row \o Undefined \o An invalid QVariant.
+ \row \o Null \o An invalid QVariant.
+ \row \o Boolean \o A QVariant containing the value of the boolean.
+ \row \o Number \o A QVariant containing the value of the number.
+ \row \o String \o A QVariant containing the value of the string.
+ \row \o QVariant Object \o The result is the QVariant value of the object (no conversion).
+ \row \o QObject Object \o A QVariant containing a pointer to the QObject.
+ \row \o Date Object \o A QVariant containing the date value (toDateTime()).
+ \row \o RegExp Object \o A QVariant containing the regular expression value (toRegExp()).
+ \row \o Array Object \o The array is converted to a QVariantList. Each element is converted to a QVariant, recursively; cyclic references are not followed.
+ \row \o Object \o The object is converted to a QVariantMap. Each property is converted to a QVariant, recursively; cyclic references are not followed.
+ \endtable
+
+ \sa isVariant()
+*/
+QVariant QJSValue::toVariant() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toVariant();
+}
+
+
+/*!
+ Calls this QJSValue as a function, using \a thisObject as
+ the `this' object in the function call, and passing \a args
+ as arguments to the function. Returns the value returned from
+ the function.
+
+ If this QJSValue is not a function, call() does nothing
+ and returns an invalid QJSValue.
+
+ Note that if \a thisObject is not an object, the global object
+ (see \l{QJSEngine::globalObject()}) will be used as the
+ `this' object.
+
+ Calling call() can cause an exception to occur in the script engine;
+ in that case, call() returns the value that was thrown (typically an
+ \c{Error} object). You can call
+ QJSEngine::hasUncaughtException() to determine if an exception
+ occurred.
+
+ \snippet doc/src/snippets/code/src_script_qscriptvalue.cpp 2
+
+ \sa construct()
+*/
+QJSValue QJSValue::call(const QJSValue& thisObject, const QJSValueList& args)
+{
+ Q_D(QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->call(QJSValuePrivate::get(thisObject), args);
+}
+
+/*!
+ Creates a new \c{Object} and calls this QJSValue as a
+ constructor, using the created object as the `this' object and
+ passing \a args as arguments. If the return value from the
+ constructor call is an object, then that object is returned;
+ otherwise the default constructed object is returned.
+
+ If this QJSValue is not a function, construct() does nothing
+ and returns an invalid QJSValue.
+
+ Calling construct() can cause an exception to occur in the script
+ engine; in that case, construct() returns the value that was thrown
+ (typically an \c{Error} object). You can call
+ QJSEngine::hasUncaughtException() to determine if an exception
+ occurred.
+
+ \sa call(), QJSEngine::newObject()
+*/
+QJSValue QJSValue::construct(const QJSValueList &args)
+{
+ Q_D(QJSValue);
+ QScriptIsolate api(d->engine());
+ return QJSValuePrivate::get(d->construct(args));
+}
+
+/*!
+ Returns the QJSEngine that created this QJSValue,
+ or 0 if this QJSValue is invalid or the value is not
+ associated with a particular engine.
+*/
+QJSEngine* QJSValue::engine() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ QV8Engine* engine = d->engine();
+ if (engine)
+ return QV8Engine::get(engine);
+ return 0;
+}
+
+
+/*!
+ If this QJSValue is an object, returns the internal prototype
+ (\c{__proto__} property) of this object; otherwise returns an
+ invalid QJSValue.
+
+ \sa setPrototype(), isObject()
+*/
+QJSValue QJSValue::prototype() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return QJSValuePrivate::get(d->prototype());
+}
+
+/*!
+ If this QJSValue is an object, sets the internal prototype
+ (\c{__proto__} property) of this object to be \a prototype;
+ otherwise does nothing.
+
+ The internal prototype should not be confused with the public
+ property with name "prototype"; the public prototype is usually
+ only set on functions that act as constructors.
+
+ \sa prototype(), isObject()
+*/
+void QJSValue::setPrototype(const QJSValue& prototype)
+{
+ Q_D(QJSValue);
+ QScriptIsolate api(d->engine());
+ d->setPrototype(QJSValuePrivate::get(prototype));
+}
+
+/*!
+ Assigns the \a other value to this QJSValue.
+
+ Note that if \a other is an object (isObject() returns true),
+ only a reference to the underlying object will be assigned;
+ the object itself will not be copied.
+*/
+QJSValue& QJSValue::operator=(const QJSValue& other)
+{
+ d_ptr = other.d_ptr;
+ return *this;
+}
+
+/*!
+ Returns true if this QJSValue is equal to \a other, otherwise
+ returns false. The comparison follows the behavior described in
+ \l{ECMA-262} section 11.9.3, "The Abstract Equality Comparison
+ Algorithm".
+
+ This function can return true even if the type of this QJSValue
+ is different from the type of the \a other value; i.e. the
+ comparison is not strict. For example, comparing the number 9 to
+ the string "9" returns true; comparing an undefined value to a null
+ value returns true; comparing a \c{Number} object whose primitive
+ value is 6 to a \c{String} object whose primitive value is "6"
+ returns true; and comparing the number 1 to the boolean value
+ \c{true} returns true. If you want to perform a comparison
+ without such implicit value conversion, use strictlyEquals().
+
+ Note that if this QJSValue or the \a other value are objects,
+ calling this function has side effects on the script engine, since
+ the engine will call the object's valueOf() function (and possibly
+ toString()) in an attempt to convert the object to a primitive value
+ (possibly resulting in an uncaught script exception).
+
+ \sa strictlyEquals(), lessThan()
+*/
+bool QJSValue::equals(const QJSValue& other) const
+{
+ Q_D(const QJSValue);
+ QJSValuePrivate* otherValue = QJSValuePrivate::get(other);
+ QScriptIsolate api(d->engine() ? d->engine() : otherValue->engine());
+ return d_ptr->equals(otherValue);
+}
+
+/*!
+ Returns true if this QJSValue is equal to \a other using strict
+ comparison (no conversion), otherwise returns false. The comparison
+ follows the behavior described in \l{ECMA-262} section 11.9.6, "The
+ Strict Equality Comparison Algorithm".
+
+ If the type of this QJSValue is different from the type of the
+ \a other value, this function returns false. If the types are equal,
+ the result depends on the type, as shown in the following table:
+
+ \table
+ \header \o Type \o Result
+ \row \o Undefined \o true
+ \row \o Null \o true
+ \row \o Boolean \o true if both values are true, false otherwise
+ \row \o Number \o false if either value is NaN (Not-a-Number); true if values are equal, false otherwise
+ \row \o String \o true if both values are exactly the same sequence of characters, false otherwise
+ \row \o Object \o true if both values refer to the same object, false otherwise
+ \endtable
+
+ \sa equals()
+*/
+bool QJSValue::strictlyEquals(const QJSValue& other) const
+{
+ Q_D(const QJSValue);
+ QJSValuePrivate* o = QJSValuePrivate::get(other);
+ QScriptIsolate api(d->engine() ? d->engine() : o->engine());
+ return d_ptr->strictlyEquals(o);
+}
+
+/*!
+ Returns true if this QJSValue is an instance of
+ \a other; otherwise returns false.
+
+ This QJSValue is considered to be an instance of \a other if
+ \a other is a function and the value of the \c{prototype}
+ property of \a other is in the prototype chain of this
+ QJSValue.
+*/
+bool QJSValue::instanceOf(const QJSValue &other) const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->instanceOf(QJSValuePrivate::get(other));
+}
+
+/*!
+ Returns the value of this QJSValue's property with the given \a name,
+ using the given \a mode to resolve the property.
+
+ If no such property exists, an invalid QJSValue is returned.
+
+ If the property is implemented using a getter function (i.e. has the
+ PropertyGetter flag set), calling property() has side-effects on the
+ script engine, since the getter function will be called (possibly
+ resulting in an uncaught script exception). If an exception
+ occurred, property() returns the value that was thrown (typically
+ an \c{Error} object).
+
+ \sa setProperty(), propertyFlags(), QJSValueIterator
+*/
+QJSValue QJSValue::property(const QString& name) const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return QJSValuePrivate::get(d->property(name));
+}
+
+/*!
+ \overload
+
+ Returns the property at the given \a arrayIndex, using the given \a
+ mode to resolve the property.
+
+ This function is provided for convenience and performance when
+ working with array objects.
+
+ If this QJSValue is not an Array object, this function behaves
+ as if property() was called with the string representation of \a
+ arrayIndex.
+*/
+QJSValue QJSValue::property(quint32 arrayIndex) const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return QJSValuePrivate::get(d->property(arrayIndex));
+}
+
+/*!
+ Sets the value of this QJSValue's property with the given \a name to
+ the given \a value.
+
+ If this QJSValue is not an object, this function does nothing.
+
+ If this QJSValue does not already have a property with name \a name,
+ a new property is created; the given \a flags then specify how this
+ property may be accessed by script code.
+
+ If \a value is invalid, the property is removed.
+
+ If the property is implemented using a setter function (i.e. has the
+ PropertySetter flag set), calling setProperty() has side-effects on
+ the script engine, since the setter function will be called with the
+ given \a value as argument (possibly resulting in an uncaught script
+ exception).
+
+ Note that you cannot specify custom getter or setter functions for
+ built-in properties, such as the \c{length} property of Array objects
+ or meta properties of QObject objects.
+
+ \sa property()
+*/
+void QJSValue::setProperty(const QString& name, const QJSValue& value)
+{
+ Q_D(QJSValue);
+ QScriptIsolate api(d->engine());
+ d->setProperty(name, QJSValuePrivate::get(value));
+}
+
+/*!
+ \overload
+
+ Sets the property at the given \a arrayIndex to the given \a value.
+
+ This function is provided for convenience and performance when
+ working with array objects.
+
+ If this QJSValue is not an Array object, this function behaves
+ as if setProperty() was called with the string representation of \a
+ arrayIndex.
+*/
+void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
+{
+ Q_D(QJSValue);
+ QScriptIsolate api(d->engine());
+ d->setProperty(arrayIndex, QJSValuePrivate::get(value));
+}
+
+/*!
+ Returns the flags of the property with the given \a name, using the
+ given \a mode to resolve the property.
+
+ \sa property()
+*/
+QJSValue::PropertyFlags QJSValue::propertyFlags(const QString& name) const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->propertyFlags(name);
+}
+
+/*!
+ * If this QJSValue is a QObject, returns the QObject pointer
+ * that the QJSValue represents; otherwise, returns 0.
+ *
+ * If the QObject that this QJSValue wraps has been deleted,
+ * this function returns 0 (i.e. it is possible for toQObject()
+ * to return 0 even when isQObject() returns true).
+ *
+ * \sa isQObject()
+ */
+QObject *QJSValue::toQObject() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toQObject();
+}
+
+/*!
+ Returns a QDateTime representation of this value, in local time.
+ If this QJSValue is not a date, or the value of the date is NaN
+ (Not-a-Number), an invalid QDateTime is returned.
+
+ \sa isDate()
+*/
+QDateTime QJSValue::toDateTime() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toDataTime();
+}
+
+/*!
+ Returns the QRegExp representation of this value.
+ If this QJSValue is not a regular expression, an empty
+ QRegExp is returned.
+
+ \sa isRegExp()
+*/
+QRegExp QJSValue::toRegExp() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toRegExp();
+}
+
+/*!
+ Returns true if this QJSValue is an object of the Date class;
+ otherwise returns false.
+
+ \sa QJSEngine::newDate()
+*/
+bool QJSValue::isDate() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isDate();
+}
+
+/*!
+ Returns true if this QJSValue is an object of the RegExp class;
+ otherwise returns false.
+
+ \sa QJSEngine::newRegExp()
+*/
+bool QJSValue::isRegExp() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isRegExp();
+}
+
+/*!
+ Returns true if this QJSValue is a QObject; otherwise returns
+ false.
+
+ Note: This function returns true even if the QObject that this
+ QJSValue wraps has been deleted.
+
+ \sa toQObject(), QJSEngine::newQObject()
+*/
+bool QJSValue::isQObject() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isQObject();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v8/qjsvalue.h b/src/declarative/qml/v8/qjsvalue.h
new file mode 100644
index 0000000000..07276bc694
--- /dev/null
+++ b/src/declarative/qml/v8/qjsvalue.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJSVALUE_H
+#define QJSVALUE_H
+
+#include <QtCore/qstring.h>
+
+#include <QtCore/qlist.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Script)
+
+class QJSValue;
+class QJSEngine;
+class QVariant;
+class QObject;
+struct QMetaObject;
+class QDateTime;
+class QRegExp;
+
+typedef QList<QJSValue> QJSValueList;
+
+class QJSValuePrivate;
+struct QScriptValuePrivatePointerDeleter;
+template <class T> class QScriptPassPointer;
+
+class Q_SCRIPT_EXPORT QJSValue
+{
+public:
+ enum PropertyFlag {
+ ReadOnly = 0x00000001,
+ Undeletable = 0x00000002,
+ SkipInEnumeration = 0x00000004
+ };
+ Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag)
+
+ enum SpecialValue {
+ NullValue,
+ UndefinedValue
+ };
+
+public:
+ QJSValue();
+ ~QJSValue();
+ QJSValue(const QJSValue &other);
+ QJSValue(QJSEngine *engine, SpecialValue val);
+ QJSValue(QJSEngine *engine, bool val);
+ QJSValue(QJSEngine *engine, int val);
+ QJSValue(QJSEngine *engine, uint val);
+ QJSValue(QJSEngine *engine, double val);
+ QJSValue(QJSEngine *engine, const QString &val);
+
+ QJSValue(SpecialValue value);
+ QJSValue(bool value);
+ QJSValue(int value);
+ QJSValue(uint value);
+ QJSValue(double value);
+ QJSValue(const QString &value);
+ QJSValue(const QLatin1String &value);
+#ifndef QT_NO_CAST_FROM_ASCII
+ QT_ASCII_CAST_WARN_CONSTRUCTOR QJSValue(const char *str);
+#endif
+
+ QJSValue &operator=(const QJSValue &other);
+
+ QJSEngine *engine() const;
+ bool isValid() const;
+ bool isBool() const;
+ bool isBoolean() const;
+ bool isNumber() const;
+ bool isFunction() const;
+ bool isNull() const;
+ bool isString() const;
+ bool isUndefined() const;
+ bool isVariant() const;
+ bool isQObject() const;
+ bool isObject() const;
+ bool isDate() const;
+ bool isRegExp() const;
+ bool isArray() const;
+ bool isError() const;
+
+ QString toString() const;
+ double toNumber() const;
+ bool toBool() const;
+ bool toBoolean() const;
+ double toInteger() const;
+ qint32 toInt32() const;
+ quint32 toUInt32() const;
+ quint16 toUInt16() const;
+ QVariant toVariant() const;
+ QObject *toQObject() const;
+ QJSValue toObject() const;
+ QDateTime toDateTime() const;
+ QRegExp toRegExp() const;
+
+ bool instanceOf(const QJSValue &other) const;
+
+ bool equals(const QJSValue &other) const;
+ bool strictlyEquals(const QJSValue &other) const;
+
+ QJSValue prototype() const;
+ void setPrototype(const QJSValue &prototype);
+
+ QJSValue property(const QString &name) const;
+ void setProperty(const QString &name, const QJSValue &value);
+
+ QJSValue property(quint32 arrayIndex) const;
+ void setProperty(quint32 arrayIndex, const QJSValue &value);
+
+ QJSValue::PropertyFlags propertyFlags(const QString &name) const;
+
+ QJSValue call(const QJSValue &thisObject = QJSValue(),
+ const QJSValueList &args = QJSValueList());
+ QJSValue construct(const QJSValueList &args = QJSValueList());
+
+private:
+ // force compile error, prevent QJSValue(bool) to be called
+ QJSValue(void *);
+ // force compile error, prevent QJSValue(QScriptEngine*, bool) to be called
+ QJSValue(QJSEngine *, void *);
+ QJSValue(QJSEngine *, const char *);
+
+ QJSValue(QJSValuePrivate*);
+ QJSValue(QScriptPassPointer<QJSValuePrivate>);
+
+private:
+ QExplicitlySharedDataPointer<QJSValuePrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QJSValue)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QJSValue::PropertyFlags)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/qml/v8/qjsvalue_impl_p.h b/src/declarative/qml/v8/qjsvalue_impl_p.h
new file mode 100644
index 0000000000..adff6ce945
--- /dev/null
+++ b/src/declarative/qml/v8/qjsvalue_impl_p.h
@@ -0,0 +1,1133 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+
+#ifndef QJSVALUE_IMPL_P_H
+#define QJSVALUE_IMPL_P_H
+
+#include "qjsconverter_p.h"
+#include "qjsvalue_p.h"
+#include "qv8engine_p.h"
+#include "qscriptisolate_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+QJSValuePrivate* QJSValuePrivate::get(const QJSValue& q) { Q_ASSERT(q.d_ptr.data()); return q.d_ptr.data(); }
+
+QJSValue QJSValuePrivate::get(const QJSValuePrivate* d)
+{
+ Q_ASSERT(d);
+ return QJSValue(const_cast<QJSValuePrivate*>(d));
+}
+
+QJSValue QJSValuePrivate::get(QScriptPassPointer<QJSValuePrivate> d)
+{
+ Q_ASSERT(d);
+ return QJSValue(d);
+}
+
+QJSValue QJSValuePrivate::get(QJSValuePrivate* d)
+{
+ Q_ASSERT(d);
+ return QJSValue(d);
+}
+
+QJSValuePrivate::QJSValuePrivate()
+ : m_engine(0), m_state(Invalid)
+{
+}
+
+QJSValuePrivate::QJSValuePrivate(bool value)
+ : m_engine(0), m_state(CBool), u(value)
+{
+}
+
+QJSValuePrivate::QJSValuePrivate(int value)
+ : m_engine(0), m_state(CNumber), u(value)
+{
+}
+
+QJSValuePrivate::QJSValuePrivate(uint value)
+ : m_engine(0), m_state(CNumber), u(value)
+{
+}
+
+QJSValuePrivate::QJSValuePrivate(double value)
+ : m_engine(0), m_state(CNumber), u(value)
+{
+}
+
+QJSValuePrivate::QJSValuePrivate(const QString& value)
+ : m_engine(0), m_state(CString), u(new QString(value))
+{
+}
+
+QJSValuePrivate::QJSValuePrivate(QJSValue::SpecialValue value)
+ : m_engine(0), m_state(value == QJSValue::NullValue ? CNull : CUndefined)
+{
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, bool value)
+ : m_engine(engine), m_state(JSValue)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, int value)
+ : m_engine(engine), m_state(JSValue)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, uint value)
+ : m_engine(engine), m_state(JSValue)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, double value)
+ : m_engine(engine), m_state(JSValue)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, const QString& value)
+ : m_engine(engine), m_state(JSValue)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, QJSValue::SpecialValue value)
+ : m_engine(engine), m_state(JSValue)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine *engine, v8::Handle<v8::Value> value)
+ : m_engine(engine), m_state(JSValue), m_value(v8::Persistent<v8::Value>::New(value))
+{
+ Q_ASSERT(engine);
+ // It shouldn't happen, v8 shows errors by returning an empty handler. This is important debug
+ // information and it can't be simply ignored.
+ Q_ASSERT(!value.IsEmpty());
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::~QJSValuePrivate()
+{
+ if (isJSBased()) {
+ m_engine->unregisterValue(this);
+ QScriptIsolate api(m_engine);
+ m_value.Dispose();
+ } else if (isStringBased()) {
+ delete u.m_string;
+ }
+}
+
+bool QJSValuePrivate::toBool() const
+{
+ switch (m_state) {
+ case JSValue:
+ {
+ v8::HandleScope scope;
+ return m_value->ToBoolean()->Value();
+ }
+ case CNumber:
+ return !(qIsNaN(u.m_number) || !u.m_number);
+ case CBool:
+ return u.m_bool;
+ case Invalid:
+ case CNull:
+ case CUndefined:
+ return false;
+ case CString:
+ return u.m_string->length();
+ }
+
+ Q_ASSERT_X(false, "toBool()", "Not all states are included in the previous switch statement.");
+ return false; // Avoid compiler warning.
+}
+
+double QJSValuePrivate::toNumber() const
+{
+ switch (m_state) {
+ case JSValue:
+ {
+ v8::HandleScope scope;
+ return m_value->ToNumber()->Value();
+ }
+ case CNumber:
+ return u.m_number;
+ case CBool:
+ return u.m_bool ? 1 : 0;
+ case CNull:
+ case Invalid:
+ return 0;
+ case CUndefined:
+ return qQNaN();
+ case CString:
+ bool ok;
+ double result = u.m_string->toDouble(&ok);
+ if (ok)
+ return result;
+ result = u.m_string->toInt(&ok, 0); // Try other bases.
+ if (ok)
+ return result;
+ if (*u.m_string == QLatin1String("Infinity"))
+ return qInf();
+ if (*u.m_string == QLatin1String("-Infinity"))
+ return -qInf();
+ return u.m_string->length() ? qQNaN() : 0;
+ }
+
+ Q_ASSERT_X(false, "toNumber()", "Not all states are included in the previous switch statement.");
+ return 0; // Avoid compiler warning.
+}
+
+QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::toObject(QV8Engine* engine) const
+{
+ Q_ASSERT(engine);
+ if (this->engine() && engine != this->engine()) {
+ qWarning("QJSEngine::toObject: cannot convert value created in a different engine");
+ return InvalidValue();
+ }
+
+ v8::HandleScope scope;
+ switch (m_state) {
+ case Invalid:
+ case CNull:
+ case CUndefined:
+ return new QJSValuePrivate;
+ case CString:
+ return new QJSValuePrivate(engine, engine->makeJSValue(*u.m_string)->ToObject());
+ case CNumber:
+ return new QJSValuePrivate(engine, engine->makeJSValue(u.m_number)->ToObject());
+ case CBool:
+ return new QJSValuePrivate(engine, engine->makeJSValue(u.m_bool)->ToObject());
+ case JSValue:
+ if (m_value->IsObject())
+ return const_cast<QJSValuePrivate*>(this);
+ if (m_value->IsNull() || m_value->IsUndefined()) // avoid "Uncaught TypeError: Cannot convert null to object"
+ return InvalidValue();
+ return new QJSValuePrivate(engine, m_value->ToObject());
+ default:
+ Q_ASSERT_X(false, Q_FUNC_INFO, "Not all states are included in this switch");
+ return InvalidValue();
+ }
+}
+
+/*!
+ This method is created only for QJSValue::toObject() purpose which is obsolete.
+ \internal
+ */
+QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::toObject() const
+{
+ if (isJSBased())
+ return toObject(engine());
+
+ // Without an engine there is not much we can do.
+ return new QJSValuePrivate;
+}
+
+QString QJSValuePrivate::toString() const
+{
+ switch (m_state) {
+ case Invalid:
+ return QString();
+ case CBool:
+ return u.m_bool ? QString::fromLatin1("true") : QString::fromLatin1("false");
+ case CString:
+ return *u.m_string;
+ case CNumber:
+ return QJSConverter::toString(u.m_number);
+ case CNull:
+ return QString::fromLatin1("null");
+ case CUndefined:
+ return QString::fromLatin1("undefined");
+ case JSValue:
+ Q_ASSERT(!m_value.IsEmpty());
+ v8::HandleScope handleScope;
+ v8::TryCatch tryCatch;
+ v8::Local<v8::String> result = m_value->ToString();
+ if (result.IsEmpty()) {
+ result = tryCatch.Exception()->ToString();
+ m_engine->setException(tryCatch.Exception(), tryCatch.Message());
+ }
+ return QJSConverter::toString(result);
+ }
+
+ Q_ASSERT_X(false, "toString()", "Not all states are included in the previous switch statement.");
+ return QString(); // Avoid compiler warning.
+}
+
+QVariant QJSValuePrivate::toVariant() const
+{
+ switch (m_state) {
+ case Invalid:
+ return QVariant();
+ case CBool:
+ return QVariant(u.m_bool);
+ case CString:
+ return QVariant(*u.m_string);
+ case CNumber:
+ return QVariant(u.m_number);
+ case CNull:
+ return QVariant();
+ case CUndefined:
+ return QVariant();
+ case JSValue:
+ break;
+ }
+
+ Q_ASSERT(m_state == JSValue);
+ Q_ASSERT(!m_value.IsEmpty());
+ Q_ASSERT(m_engine);
+
+ v8::HandleScope handleScope;
+ return m_engine->variantFromJS(m_value);
+}
+
+inline QDateTime QJSValuePrivate::toDataTime() const
+{
+ if (!isDate())
+ return QDateTime();
+
+ v8::HandleScope handleScope;
+ return QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(m_value));
+
+}
+
+inline QRegExp QJSValuePrivate::toRegExp() const
+{
+ if (!isRegExp())
+ return QRegExp();
+
+ v8::HandleScope handleScope;
+ return QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(m_value));
+}
+
+QObject* QJSValuePrivate::toQObject() const
+{
+ if (!isJSBased())
+ return 0;
+
+ v8::HandleScope handleScope;
+ return engine()->qtObjectFromJS(m_value);
+}
+
+double QJSValuePrivate::toInteger() const
+{
+ double result = toNumber();
+ if (qIsNaN(result))
+ return 0;
+ if (qIsInf(result))
+ return result;
+ return (result > 0) ? qFloor(result) : -1 * qFloor(-result);
+}
+
+qint32 QJSValuePrivate::toInt32() const
+{
+ double result = toInteger();
+ // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but
+ // some of these operation are invoked in toInteger subcall.
+ if (qIsInf(result))
+ return 0;
+ return result;
+}
+
+quint32 QJSValuePrivate::toUInt32() const
+{
+ double result = toInteger();
+ // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but
+ // some of these operation are invoked in toInteger subcall.
+ if (qIsInf(result))
+ return 0;
+ return result;
+}
+
+quint16 QJSValuePrivate::toUInt16() const
+{
+ return toInt32();
+}
+
+inline bool QJSValuePrivate::isArray() const
+{
+ return isJSBased() && m_value->IsArray();
+}
+
+inline bool QJSValuePrivate::isBool() const
+{
+ return m_state == CBool || (isJSBased() && m_value->IsBoolean());
+}
+
+inline bool QJSValuePrivate::isCallable() const
+{
+ if (isFunction())
+ return true;
+ if (isObject()) {
+ // Our C++ wrappers register function handlers but not always act as callables.
+ return v8::Object::Cast(*m_value)->IsCallable();
+ }
+ return false;
+}
+
+inline bool QJSValuePrivate::isError() const
+{
+ if (!isJSBased())
+ return false;
+ v8::HandleScope handleScope;
+ return m_value->IsError();
+}
+
+inline bool QJSValuePrivate::isFunction() const
+{
+ return isJSBased() && m_value->IsFunction();
+}
+
+inline bool QJSValuePrivate::isNull() const
+{
+ return m_state == CNull || (isJSBased() && m_value->IsNull());
+}
+
+inline bool QJSValuePrivate::isNumber() const
+{
+ return m_state == CNumber || (isJSBased() && m_value->IsNumber());
+}
+
+inline bool QJSValuePrivate::isObject() const
+{
+ return isJSBased() && m_value->IsObject();
+}
+
+inline bool QJSValuePrivate::isString() const
+{
+ return m_state == CString || (isJSBased() && m_value->IsString());
+}
+
+inline bool QJSValuePrivate::isUndefined() const
+{
+ return m_state == CUndefined || (isJSBased() && m_value->IsUndefined());
+}
+
+inline bool QJSValuePrivate::isValid() const
+{
+ return m_state != Invalid;
+}
+
+inline bool QJSValuePrivate::isVariant() const
+{
+ return isJSBased() && m_engine->isVariant(m_value);
+}
+
+bool QJSValuePrivate::isDate() const
+{
+ return (isJSBased() && m_value->IsDate());
+}
+
+bool QJSValuePrivate::isRegExp() const
+{
+ return (isJSBased() && m_value->IsRegExp());
+}
+
+bool QJSValuePrivate::isQObject() const
+{
+ return isJSBased() && engine()->isQObject(m_value);
+}
+
+inline bool QJSValuePrivate::equals(QJSValuePrivate* other)
+{
+ if (!isValid())
+ return !other->isValid();
+
+ if (!other->isValid())
+ return false;
+
+ if (!isJSBased() && !other->isJSBased()) {
+ switch (m_state) {
+ case CNull:
+ case CUndefined:
+ return other->isUndefined() || other->isNull();
+ case CNumber:
+ switch (other->m_state) {
+ case CBool:
+ case CString:
+ return u.m_number == other->toNumber();
+ case CNumber:
+ return u.m_number == other->u.m_number;
+ default:
+ return false;
+ }
+ case CBool:
+ switch (other->m_state) {
+ case CBool:
+ return u.m_bool == other->u.m_bool;
+ case CNumber:
+ return toNumber() == other->u.m_number;
+ case CString:
+ return toNumber() == other->toNumber();
+ default:
+ return false;
+ }
+ case CString:
+ switch (other->m_state) {
+ case CBool:
+ return toNumber() == other->toNumber();
+ case CNumber:
+ return toNumber() == other->u.m_number;
+ case CString:
+ return *u.m_string == *other->u.m_string;
+ default:
+ return false;
+ }
+ default:
+ Q_ASSERT_X(false, "QJSValue::equals", "Not all states are included in the previous switch statement.");
+ }
+ }
+
+ v8::HandleScope handleScope;
+ if (isJSBased() && !other->isJSBased()) {
+ if (!other->assignEngine(engine())) {
+ qWarning("QJSValue::equals: cannot compare to a value created in a different engine");
+ return false;
+ }
+ } else if (!isJSBased() && other->isJSBased()) {
+ if (!assignEngine(other->engine())) {
+ qWarning("QJSValue::equals: cannot compare to a value created in a different engine");
+ return false;
+ }
+ }
+
+ Q_ASSERT(this->engine() && other->engine());
+ if (this->engine() != other->engine()) {
+ qWarning("QJSValue::equals: cannot compare to a value created in a different engine");
+ return false;
+ }
+ return m_value->Equals(other->m_value);
+}
+
+inline bool QJSValuePrivate::strictlyEquals(QJSValuePrivate* other)
+{
+ if (isJSBased()) {
+ // We can't compare these two values without binding to the same engine.
+ if (!other->isJSBased()) {
+ if (other->assignEngine(engine()))
+ return m_value->StrictEquals(other->m_value);
+ return false;
+ }
+ if (other->engine() != engine()) {
+ qWarning("QJSValue::strictlyEquals: cannot compare to a value created in a different engine");
+ return false;
+ }
+ return m_value->StrictEquals(other->m_value);
+ }
+ if (isStringBased()) {
+ if (other->isStringBased())
+ return *u.m_string == *(other->u.m_string);
+ if (other->isJSBased()) {
+ assignEngine(other->engine());
+ return m_value->StrictEquals(other->m_value);
+ }
+ }
+ if (isNumberBased()) {
+ if (other->isJSBased()) {
+ assignEngine(other->engine());
+ return m_value->StrictEquals(other->m_value);
+ }
+ if (m_state != other->m_state)
+ return false;
+ if (m_state == CNumber)
+ return u.m_number == other->u.m_number;
+ Q_ASSERT(m_state == CBool);
+ return u.m_bool == other->u.m_bool;
+ }
+
+ if (!isValid() && !other->isValid())
+ return true;
+
+ return false;
+}
+
+inline bool QJSValuePrivate::lessThan(QJSValuePrivate *other) const
+{
+ if (engine() != other->engine() && engine() && other->engine()) {
+ qWarning("QJSValue::lessThan: cannot compare to a value created in a different engine");
+ return false;
+ }
+
+ if (!isValid() || !other->isValid())
+ return false;
+
+ if (isString() && other->isString())
+ return toString() < other->toString();
+
+ if (isObject() || other->isObject()) {
+ v8::HandleScope handleScope;
+ QV8Engine *eng = m_engine ? engine() : other->engine();
+ // FIXME: lessThan can throw an exception which will be dropped by this code:
+ Q_ASSERT(eng);
+ eng->saveException();
+ QScriptSharedDataPointer<QJSValuePrivate> cmp(eng->evaluate(QString::fromLatin1("(function(a,b){return a<b})")));
+ Q_ASSERT(cmp->isFunction());
+ v8::Handle<v8::Value> args[2];
+ cmp->prepareArgumentsForCall(args, QJSValueList() << QJSValuePrivate::get(this) << QJSValuePrivate::get(other));
+ QScriptSharedDataPointer<QJSValuePrivate> resultValue(cmp->call(0, 2, args));
+ bool result = resultValue->toBool();
+ eng->restoreException();
+ return result;
+ }
+
+ double nthis = toNumber();
+ double nother = other->toNumber();
+ if (qIsNaN(nthis) || qIsNaN(nother)) {
+ // Should return undefined in ECMA standard.
+ return false;
+ }
+ return nthis < nother;
+}
+
+inline bool QJSValuePrivate::instanceOf(QJSValuePrivate* other) const
+{
+ if (!isObject() || !other->isFunction())
+ return false;
+ if (engine() != other->engine()) {
+ qWarning("QJSValue::instanceof: cannot perform operation on a value created in a different engine");
+ return false;
+ }
+ v8::HandleScope handleScope;
+ return instanceOf(v8::Handle<v8::Object>::Cast(other->m_value));
+}
+
+inline bool QJSValuePrivate::instanceOf(v8::Handle<v8::Object> other) const
+{
+ Q_ASSERT(isObject());
+ Q_ASSERT(other->IsFunction());
+
+ v8::Handle<v8::Object> self = v8::Handle<v8::Object>::Cast(m_value);
+ v8::Handle<v8::Value> selfPrototype = self->GetPrototype();
+ v8::Handle<v8::Value> otherPrototype = other->Get(v8::String::New("prototype"));
+
+ while (!selfPrototype->IsNull()) {
+ if (selfPrototype->StrictEquals(otherPrototype))
+ return true;
+ // In general a prototype can be an object or null, but in the loop it can't be null, so
+ // we can cast it safely.
+ selfPrototype = v8::Handle<v8::Object>::Cast(selfPrototype)->GetPrototype();
+ }
+ return false;
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::prototype() const
+{
+ if (isObject()) {
+ v8::HandleScope handleScope;
+ return new QJSValuePrivate(engine(), v8::Handle<v8::Object>::Cast(m_value)->GetPrototype());
+ }
+ return InvalidValue();
+}
+
+inline void QJSValuePrivate::setPrototype(QJSValuePrivate* prototype)
+{
+ if (isObject() && (prototype->isObject() || prototype->isNull())) {
+ if (engine() != prototype->engine()) {
+ if (prototype->engine()) {
+ qWarning("QJSValue::setPrototype() failed: cannot set a prototype created in a different engine");
+ return;
+ }
+ prototype->assignEngine(engine());
+ }
+ v8::HandleScope handleScope;
+ if (!v8::Handle<v8::Object>::Cast(m_value)->SetPrototype(*prototype))
+ qWarning("QJSValue::setPrototype() failed: cyclic prototype value");
+ }
+}
+
+inline void QJSValuePrivate::setProperty(const QString& name, QJSValuePrivate* value, uint attribs)
+{
+ if (!isObject())
+ return;
+ v8::HandleScope handleScope;
+ setProperty(QJSConverter::toString(name), value, attribs);
+}
+
+inline void QJSValuePrivate::setProperty(v8::Handle<v8::String> name, QJSValuePrivate* value, uint attribs)
+{
+ if (!isObject())
+ return;
+
+ if (!value->isJSBased())
+ value->assignEngine(engine());
+
+ if (!value->isValid()) {
+ // Remove the property.
+ v8::HandleScope handleScope;
+ v8::TryCatch tryCatch;
+ v8::Handle<v8::Object> recv(v8::Object::Cast(*m_value));
+// if (attribs & QJSValue::PropertyGetter && !(attribs & QJSValue::PropertySetter)) {
+// v8::Local<v8::Object> descriptor = engine()->originalGlobalObject()->getOwnPropertyDescriptor(recv, name);
+// if (!descriptor.IsEmpty()) {
+// v8::Local<v8::Value> setter = descriptor->Get(v8::String::New("set"));
+// if (!setter.IsEmpty() && !setter->IsUndefined()) {
+// recv->Delete(name);
+// engine()->originalGlobalObject()->defineGetterOrSetter(recv, name, setter, QJSValue::PropertySetter);
+// if (tryCatch.HasCaught())
+// engine()->setException(tryCatch.Exception(), tryCatch.Message());
+// return;
+// }
+// }
+// } else if (attribs & QJSValue::PropertySetter && !(attribs & QJSValue::PropertyGetter)) {
+// v8::Local<v8::Object> descriptor = engine()->originalGlobalObject()->getOwnPropertyDescriptor(recv, name);
+// if (!descriptor.IsEmpty()) {
+// v8::Local<v8::Value> getter = descriptor->Get(v8::String::New("get"));
+// if (!getter.IsEmpty() && !getter->IsUndefined()) {
+// recv->Delete(name);
+// engine()->originalGlobalObject()->defineGetterOrSetter(recv, name, getter, QJSValue::PropertyGetter);
+// if (tryCatch.HasCaught())
+// engine()->setException(tryCatch.Exception(), tryCatch.Message());
+// return;
+// }
+// }
+// }
+ recv->Delete(name);
+ if (tryCatch.HasCaught())
+ engine()->setException(tryCatch.Exception(), tryCatch.Message());
+ return;
+ }
+
+ if (engine() != value->engine()) {
+ qWarning("QJSValue::setProperty(%s) failed: "
+ "cannot set value created in a different engine",
+ qPrintable(QJSConverter::toString(name)));
+ return;
+ }
+
+ v8::TryCatch tryCatch;
+// if (attribs & (QJSValue::PropertyGetter | QJSValue::PropertySetter)) {
+// engine()->originalGlobalObject()->defineGetterOrSetter(*this, name, value->m_value, attribs);
+// } else {
+ v8::Object::Cast(*m_value)->Set(name, value->m_value, v8::PropertyAttribute(attribs & QJSConverter::PropertyAttributeMask));
+// }
+ if (tryCatch.HasCaught())
+ engine()->setException(tryCatch.Exception(), tryCatch.Message());
+}
+
+inline void QJSValuePrivate::setProperty(quint32 index, QJSValuePrivate* value, uint attribs)
+{
+ // FIXME this method should by integrated with other overloads to use the same code patch.
+ // for now it is not possible as v8 doesn't allow to set property attributes using index based api.
+
+ if (!isObject())
+ return;
+
+ if (attribs) {
+ // FIXME we dont need to convert index to a string.
+ //Object::Set(int,value) do not take attributes.
+ setProperty(QString::number(index), value, attribs);
+ return;
+ }
+
+ if (!value->isJSBased())
+ value->assignEngine(engine());
+
+ if (!value->isValid()) {
+ // Remove the property.
+ v8::HandleScope handleScope;
+ v8::TryCatch tryCatch;
+ v8::Object::Cast(*m_value)->Delete(index);
+ if (tryCatch.HasCaught())
+ engine()->setException(tryCatch.Exception(), tryCatch.Message());
+ return;
+ }
+
+ if (engine() != value->engine()) {
+ qWarning("QJSValue::setProperty() failed: cannot set value created in a different engine");
+ return;
+ }
+
+ v8::HandleScope handleScope;
+ v8::TryCatch tryCatch;
+ v8::Object::Cast(*m_value)->Set(index, value->m_value);
+ if (tryCatch.HasCaught())
+ engine()->setException(tryCatch.Exception(), tryCatch.Message());
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(const QString& name) const
+{
+ if (!name.length())
+ return InvalidValue();
+
+ v8::HandleScope handleScope;
+ return property(QJSConverter::toString(name));
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(v8::Handle<v8::String> name) const
+{
+ Q_ASSERT(!name.IsEmpty());
+ if (!isObject())
+ return InvalidValue();
+ return property<>(name);
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(quint32 index) const
+{
+ if (!isObject())
+ return InvalidValue();
+ return property<>(index);
+}
+
+template<typename T>
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(T name) const
+{
+ Q_ASSERT(isObject());
+ v8::HandleScope handleScope;
+ v8::Handle<v8::Object> self(v8::Object::Cast(*m_value));
+
+ v8::TryCatch tryCatch;
+ v8::Handle<v8::Value> result = self->Get(name);
+ if (tryCatch.HasCaught()) {
+ result = tryCatch.Exception();
+ engine()->setException(result, tryCatch.Message());
+ return new QJSValuePrivate(engine(), result);
+ }
+ if (result.IsEmpty() || (result->IsUndefined() && !self->Has(name))) {
+ // In QtScript we make a distinction between a property that exists and has value undefined,
+ // and a property that doesn't exist; in the latter case, we should return an invalid value.
+ return InvalidValue();
+ }
+ return new QJSValuePrivate(engine(), result);
+}
+
+inline bool QJSValuePrivate::deleteProperty(const QString& name)
+{
+ if (!isObject())
+ return false;
+
+ v8::HandleScope handleScope;
+ v8::Handle<v8::Object> self(v8::Handle<v8::Object>::Cast(m_value));
+ return self->Delete(QJSConverter::toString(name));
+}
+
+inline QJSValue::PropertyFlags QJSValuePrivate::propertyFlags(const QString& name) const
+{
+ if (!isObject())
+ return QJSValue::PropertyFlags(0);
+
+ v8::HandleScope handleScope;
+ return engine()->getPropertyFlags(v8::Handle<v8::Object>::Cast(m_value), QJSConverter::toString(name));
+}
+
+inline QJSValue::PropertyFlags QJSValuePrivate::propertyFlags(v8::Handle<v8::String> name) const
+{
+ if (!isObject())
+ return QJSValue::PropertyFlags(0);
+
+ v8::HandleScope handleScope;
+ return engine()->getPropertyFlags(v8::Handle<v8::Object>::Cast(m_value), name);
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::call(QJSValuePrivate* thisObject, const QJSValueList& args)
+{
+ if (!isCallable())
+ return InvalidValue();
+
+ v8::HandleScope handleScope;
+
+ // Convert all arguments and bind to the engine.
+ int argc = args.size();
+ QVarLengthArray<v8::Handle<v8::Value>, 8> argv(argc);
+ if (!prepareArgumentsForCall(argv.data(), args)) {
+ qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine");
+ return InvalidValue();
+ }
+
+ return call(thisObject, argc, argv.data());
+}
+
+QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::call(QJSValuePrivate* thisObject, int argc, v8::Handle<v8::Value> *argv)
+{
+ QV8Engine *e = engine();
+
+ v8::Handle<v8::Object> recv;
+
+ if (!thisObject || !thisObject->isObject()) {
+ recv = v8::Handle<v8::Object>(v8::Object::Cast(*e->global()));
+ } else {
+ if (!thisObject->assignEngine(e)) {
+ qWarning("QJSValue::call() failed: cannot call function with thisObject created in a different engine");
+ return InvalidValue();
+ }
+
+ recv = v8::Handle<v8::Object>(v8::Object::Cast(*thisObject->m_value));
+ }
+
+ if (argc < 0) {
+ v8::Local<v8::Value> exeption = v8::Exception::TypeError(v8::String::New("Arguments must be an array"));
+ e->setException(exeption);
+ return new QJSValuePrivate(e, exeption);
+ }
+
+ v8::TryCatch tryCatch;
+ v8::Handle<v8::Value> result = v8::Object::Cast(*m_value)->CallAsFunction(recv, argc, argv);
+
+ if (result.IsEmpty()) {
+ result = tryCatch.Exception();
+ // TODO: figure out why v8 doesn't always produce an exception value.
+ //Q_ASSERT(!result.IsEmpty());
+ if (result.IsEmpty())
+ result = v8::Exception::Error(v8::String::New("missing exception value"));
+ e->setException(result, tryCatch.Message());
+ }
+
+ return new QJSValuePrivate(e, result);
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::construct(int argc, v8::Handle<v8::Value> *argv)
+{
+ QV8Engine *e = engine();
+
+ if (argc < 0) {
+ v8::Local<v8::Value> exeption = v8::Exception::TypeError(v8::String::New("Arguments must be an array"));
+ e->setException(exeption);
+ return new QJSValuePrivate(e, exeption);
+ }
+
+ v8::TryCatch tryCatch;
+ v8::Handle<v8::Value> result = v8::Object::Cast(*m_value)->CallAsConstructor(argc, argv);
+
+ if (result.IsEmpty()) {
+ result = tryCatch.Exception();
+ e->setException(result, tryCatch.Message());
+ }
+
+ return new QJSValuePrivate(e, result);
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::construct(const QJSValueList& args)
+{
+ if (!isCallable())
+ return InvalidValue();
+
+ v8::HandleScope handleScope;
+
+ // Convert all arguments and bind to the engine.
+ int argc = args.size();
+ QVarLengthArray<v8::Handle<v8::Value>, 8> argv(argc);
+ if (!prepareArgumentsForCall(argv.data(), args)) {
+ qWarning("QJSValue::construct() failed: cannot construct function with argument created in a different engine");
+ return InvalidValue();
+ }
+
+ return construct(argc, argv.data());
+}
+
+/*! \internal
+ * Make sure this value is associated with a v8 value belogning to this engine.
+ * If the value was invalid, or belogning to another engine, return false.
+ */
+bool QJSValuePrivate::assignEngine(QV8Engine* engine)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ switch (m_state) {
+ case Invalid:
+ return false;
+ case CBool:
+ m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(u.m_bool));
+ break;
+ case CString:
+ m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(*u.m_string));
+ delete u.m_string;
+ break;
+ case CNumber:
+ m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(u.m_number));
+ break;
+ case CNull:
+ m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(QJSValue::NullValue));
+ break;
+ case CUndefined:
+ m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(QJSValue::UndefinedValue));
+ break;
+ default:
+ if (this->engine() == engine)
+ return true;
+ else if (!isJSBased())
+ Q_ASSERT_X(!isJSBased(), "assignEngine()", "Not all states are included in the previous switch statement.");
+ else
+ qWarning("JSValue can't be rassigned to an another engine.");
+ return false;
+ }
+ m_engine = engine;
+ m_state = JSValue;
+
+ m_engine->registerValue(this);
+ return true;
+}
+
+/*!
+ \internal
+ reinitialize this value to an invalid value.
+*/
+void QJSValuePrivate::reinitialize()
+{
+ if (isJSBased()) {
+ m_engine->unregisterValue(this);
+ m_value.Dispose();
+ m_value.Clear();
+ } else if (isStringBased()) {
+ delete u.m_string;
+ }
+ m_engine = 0;
+ m_state = Invalid;
+}
+
+/*!
+ \internal
+ reinitialize this value to an JSValue.
+*/
+void QJSValuePrivate::reinitialize(QV8Engine* engine, v8::Handle<v8::Value> value)
+{
+ Q_ASSERT_X(this != InvalidValue(), Q_FUNC_INFO, "static invalid can't be reinitialized to a different value");
+ if (isJSBased()) {
+ m_value.Dispose();
+ // avoid double registration
+ m_engine->unregisterValue(this);
+ } else if (isStringBased()) {
+ delete u.m_string;
+ }
+ m_engine = engine;
+ m_state = JSValue;
+ m_value = v8::Persistent<v8::Value>::New(value);
+ m_engine->registerValue(this);
+}
+
+QV8Engine* QJSValuePrivate::engine() const
+{
+ return m_engine;
+}
+
+inline QJSValuePrivate::operator v8::Handle<v8::Value>() const
+{
+ Q_ASSERT(isJSBased());
+ return m_value;
+}
+
+inline QJSValuePrivate::operator v8::Handle<v8::Object>() const
+{
+ Q_ASSERT(isObject());
+ return v8::Handle<v8::Object>::Cast(m_value);
+}
+
+/*!
+ * Return a v8::Handle, assign to the engine if needed.
+ */
+v8::Handle<v8::Value> QJSValuePrivate::asV8Value(QV8Engine* engine)
+{
+ if (!m_engine) {
+ if (!assignEngine(engine))
+ return v8::Handle<v8::Value>();
+ }
+ Q_ASSERT(isJSBased());
+ return m_value;
+}
+
+/*!
+ \internal
+ Returns true if QSV have an engine associated.
+*/
+bool QJSValuePrivate::isJSBased() const
+{
+#ifndef QT_NO_DEBUG
+ // internals check.
+ if (m_state >= JSValue)
+ Q_ASSERT(!m_value.IsEmpty());
+ else
+ Q_ASSERT(m_value.IsEmpty());
+#endif
+ return m_state >= JSValue;
+}
+
+/*!
+ \internal
+ Returns true if current value of QSV is placed in m_number.
+*/
+bool QJSValuePrivate::isNumberBased() const { return m_state == CNumber || m_state == CBool; }
+
+/*!
+ \internal
+ Returns true if current value of QSV is placed in m_string.
+*/
+bool QJSValuePrivate::isStringBased() const { return m_state == CString; }
+
+/*!
+ \internal
+ Converts arguments and bind them to the engine.
+ \attention argv should be big enough
+*/
+inline bool QJSValuePrivate::prepareArgumentsForCall(v8::Handle<v8::Value> argv[], const QJSValueList& args) const
+{
+ QJSValueList::const_iterator i = args.constBegin();
+ for (int j = 0; i != args.constEnd(); j++, i++) {
+ QJSValuePrivate* value = QJSValuePrivate::get(*i);
+ if ((value->isJSBased() && engine() != value->engine())
+ || (!value->isJSBased() && value->isValid() && !value->assignEngine(engine())))
+ // Different engines are not allowed!
+ return false;
+ if (value->isValid())
+ argv[j] = *value;
+ else
+ argv[j] = engine()->makeJSValue(QJSValue::UndefinedValue);
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/qml/v8/qjsvalue_p.h b/src/declarative/qml/v8/qjsvalue_p.h
new file mode 100644
index 0000000000..7b2a001f97
--- /dev/null
+++ b/src/declarative/qml/v8/qjsvalue_p.h
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+
+#ifndef QJSVALUE_P_H
+#define QJSVALUE_P_H
+
+#include <private/qv8_p.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qvarlengtharray.h>
+#include <qdebug.h>
+
+#include "qscripttools_p.h"
+#include "qscriptshareddata_p.h"
+#include "qjsvalue.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QJSValuePrivate
+*/
+class QJSValuePrivate
+ : public QSharedData
+ , public QScriptLinkedNode
+{
+public:
+ inline QJSValuePrivate();
+ inline static QJSValuePrivate* get(const QJSValue& q);
+ inline static QJSValue get(const QJSValuePrivate* d);
+ inline static QJSValue get(QJSValuePrivate* d);
+ inline static QJSValue get(QScriptPassPointer<QJSValuePrivate> d);
+ inline ~QJSValuePrivate();
+
+ inline QJSValuePrivate(bool value);
+ inline QJSValuePrivate(int value);
+ inline QJSValuePrivate(uint value);
+ inline QJSValuePrivate(double value);
+ inline QJSValuePrivate(const QString& value);
+ inline QJSValuePrivate(QJSValue::SpecialValue value);
+
+ inline QJSValuePrivate(QV8Engine *engine, bool value);
+ inline QJSValuePrivate(QV8Engine *engine, int value);
+ inline QJSValuePrivate(QV8Engine *engine, uint value);
+ inline QJSValuePrivate(QV8Engine *engine, double value);
+ inline QJSValuePrivate(QV8Engine *engine, const QString& value);
+ inline QJSValuePrivate(QV8Engine *engine, QJSValue::SpecialValue value);
+ inline QJSValuePrivate(QV8Engine *engine, v8::Handle<v8::Value>);
+ inline void reinitialize();
+ inline void reinitialize(QV8Engine *engine, v8::Handle<v8::Value> value);
+
+ inline bool toBool() const;
+ inline double toNumber() const;
+ inline QScriptPassPointer<QJSValuePrivate> toObject() const;
+ inline QScriptPassPointer<QJSValuePrivate> toObject(QV8Engine *engine) const;
+ inline QString toString() const;
+ inline double toInteger() const;
+ inline qint32 toInt32() const;
+ inline quint32 toUInt32() const;
+ inline quint16 toUInt16() const;
+ inline QDateTime toDataTime() const;
+ inline QRegExp toRegExp() const;
+ inline QObject *toQObject() const;
+ inline QVariant toVariant() const;
+
+ inline bool isArray() const;
+ inline bool isBool() const;
+ inline bool isCallable() const;
+ inline bool isError() const;
+ inline bool isFunction() const;
+ inline bool isNull() const;
+ inline bool isNumber() const;
+ inline bool isObject() const;
+ inline bool isString() const;
+ inline bool isUndefined() const;
+ inline bool isValid() const;
+ inline bool isVariant() const;
+ inline bool isDate() const;
+ inline bool isRegExp() const;
+ inline bool isQObject() const;
+
+ inline bool equals(QJSValuePrivate* other);
+ inline bool strictlyEquals(QJSValuePrivate* other);
+ inline bool lessThan(QJSValuePrivate *other) const;
+ inline bool instanceOf(QJSValuePrivate*) const;
+ inline bool instanceOf(v8::Handle<v8::Object> other) const;
+
+ inline QScriptPassPointer<QJSValuePrivate> prototype() const;
+ inline void setPrototype(QJSValuePrivate* prototype);
+
+ inline void setProperty(const QString &name, QJSValuePrivate *value, uint attribs = 0);
+ inline void setProperty(v8::Handle<v8::String> name, QJSValuePrivate *value, uint attribs = 0);
+ inline void setProperty(quint32 index, QJSValuePrivate* value, uint attribs = 0);
+ inline QScriptPassPointer<QJSValuePrivate> property(const QString& name) const;
+ inline QScriptPassPointer<QJSValuePrivate> property(v8::Handle<v8::String> name) const;
+ inline QScriptPassPointer<QJSValuePrivate> property(quint32 index) const;
+ template<typename T>
+ inline QScriptPassPointer<QJSValuePrivate> property(T name) const;
+ inline bool deleteProperty(const QString& name);
+ inline QJSValue::PropertyFlags propertyFlags(const QString& name) const;
+ inline QJSValue::PropertyFlags propertyFlags(v8::Handle<v8::String> name) const;
+
+ inline QScriptPassPointer<QJSValuePrivate> call(QJSValuePrivate* thisObject, const QJSValueList& args);
+ inline QScriptPassPointer<QJSValuePrivate> call(QJSValuePrivate* thisObject, const QJSValue& arguments);
+ inline QScriptPassPointer<QJSValuePrivate> call(QJSValuePrivate* thisObject, int argc, v8::Handle< v8::Value >* argv);
+ inline QScriptPassPointer<QJSValuePrivate> construct(int argc, v8::Handle<v8::Value> *argv);
+ inline QScriptPassPointer<QJSValuePrivate> construct(const QJSValueList& args);
+ inline QScriptPassPointer<QJSValuePrivate> construct(const QJSValue& arguments);
+
+ inline bool assignEngine(QV8Engine *engine);
+ inline QV8Engine *engine() const;
+
+ inline operator v8::Handle<v8::Value>() const;
+ inline operator v8::Handle<v8::Object>() const;
+ inline v8::Handle<v8::Value> asV8Value(QV8Engine *engine);
+private:
+ QV8Engine *m_engine;
+
+ // Please, update class documentation when you change the enum.
+ enum State {
+ Invalid = 0,
+ CString = 0x1000,
+ CNumber,
+ CBool,
+ CNull,
+ CUndefined,
+ JSValue = 0x2000, // V8 values are equal or higher then this value.
+ // JSPrimitive,
+ // JSObject
+ } m_state;
+
+ union CValue {
+ bool m_bool;
+ double m_number;
+ QString* m_string;
+
+ CValue() : m_number(0) {}
+ CValue(bool value) : m_bool(value) {}
+ CValue(int number) : m_number(number) {}
+ CValue(uint number) : m_number(number) {}
+ CValue(double number) : m_number(number) {}
+ CValue(QString* string) : m_string(string) {}
+ } u;
+ // v8::Persistent is not a POD, so can't be part of the union.
+ v8::Persistent<v8::Value> m_value;
+
+ Q_DISABLE_COPY(QJSValuePrivate)
+ inline bool isJSBased() const;
+ inline bool isNumberBased() const;
+ inline bool isStringBased() const;
+ inline bool prepareArgumentsForCall(v8::Handle<v8::Value> argv[], const QJSValueList& arguments) const;
+};
+
+// This template is used indirectly by the Q_GLOBAL_STATIC macro below
+template<>
+class QGlobalStaticDeleter<QJSValuePrivate>
+{
+public:
+ QGlobalStatic<QJSValuePrivate> &globalStatic;
+ QGlobalStaticDeleter(QGlobalStatic<QJSValuePrivate> &_globalStatic)
+ : globalStatic(_globalStatic)
+ {
+ globalStatic.pointer->ref.ref();
+ }
+
+ inline ~QGlobalStaticDeleter()
+ {
+ if (!globalStatic.pointer->ref.deref()) { // Logic copy & paste from SharedDataPointer
+ delete globalStatic.pointer;
+ }
+ globalStatic.pointer = 0;
+ globalStatic.destroyed = true;
+ }
+};
+
+Q_GLOBAL_STATIC(QJSValuePrivate, InvalidValue)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/qml/v8/qjsvalueiterator.cpp b/src/declarative/qml/v8/qjsvalueiterator.cpp
new file mode 100644
index 0000000000..ca9123f0c0
--- /dev/null
+++ b/src/declarative/qml/v8/qjsvalueiterator.cpp
@@ -0,0 +1,294 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qjsvalueiterator.h"
+
+#include "qscriptisolate_p.h"
+#include "qjsvalue_p.h"
+#include "qv8engine_p.h"
+#include "qscript_impl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QJSValueIterator
+
+ \brief The QJSValueIterator class provides a Java-style iterator for QJSValue.
+
+ \ingroup script
+
+
+ The QJSValueIterator constructor takes a QJSValue as
+ argument. After construction, the iterator is located at the very
+ beginning of the sequence of properties. Here's how to iterate over
+ all the properties of a QJSValue:
+
+ \snippet doc/src/snippets/code/src_script_QJSValueIterator.cpp 0
+
+ The next() advances the iterator. The name(), value() and flags()
+ functions return the name, value and flags of the last item that was
+ jumped over.
+
+ If you want to remove properties as you iterate over the
+ QJSValue, use remove(). If you want to modify the value of a
+ property, use setValue().
+
+ Note that QJSValueIterator only iterates over the QJSValue's
+ own properties; i.e. it does not follow the prototype chain. You can
+ use a loop like this to follow the prototype chain:
+
+ \snippet doc/src/snippets/code/src_script_QJSValueIterator.cpp 1
+
+ Note that QJSValueIterator will not automatically skip over
+ properties that have the QJSValue::SkipInEnumeration flag set;
+ that flag only affects iteration in script code. If you want, you
+ can skip over such properties with code like the following:
+
+ \snippet doc/src/snippets/code/src_script_QJSValueIterator.cpp 2
+
+ \sa QJSValue::property()
+*/
+
+using v8::Persistent;
+using v8::Local;
+using v8::Array;
+using v8::String;
+using v8::Handle;
+using v8::Object;
+using v8::Value;
+
+// FIXME (Qt5) This class should be refactored. It should use the common Iterator interface.
+// FIXME it could be faster!
+class QJSValueIteratorPrivate {
+public:
+ inline QJSValueIteratorPrivate(const QJSValuePrivate* value);
+ inline ~QJSValueIteratorPrivate();
+
+ inline bool hasNext() const;
+ inline bool next();
+
+ inline QString name() const;
+
+ inline QScriptPassPointer<QJSValuePrivate> value() const;
+
+ inline bool isValid() const;
+ inline QV8Engine* engine() const;
+private:
+ Q_DISABLE_COPY(QJSValueIteratorPrivate)
+ //void dump(QString) const;
+
+ QScriptSharedDataPointer<QJSValuePrivate> m_object;
+ QList<v8::Persistent<v8::String> > m_names;
+ QMutableListIterator<v8::Persistent<v8::String> > m_iterator;
+};
+
+inline QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValuePrivate* value)
+ : m_object(const_cast<QJSValuePrivate*>(value))
+ , m_iterator(m_names)
+{
+ Q_ASSERT(value);
+ QV8Engine *engine = m_object->engine();
+ QScriptIsolate api(engine);
+ if (!m_object->isObject())
+ m_object = 0;
+ else {
+ v8::HandleScope scope;
+ Handle<Value> tmp = *value;
+ Handle<Object> obj = Handle<Object>::Cast(tmp);
+ Local<Array> names;
+
+ // FIXME we need newer V8!
+ //names = obj->GetOwnPropertyNames();
+ names = engine->getOwnPropertyNames(obj);
+
+ // it is suboptimal, it would be better to write iterator instead
+ uint32_t count = names->Length();
+ Local<String> name;
+ m_names.reserve(count); // The count is the maximal count of values.
+ for (uint32_t i = count - 1; i < count; --i) {
+ name = names->Get(i)->ToString();
+ m_names.append(v8::Persistent<v8::String>::New(name));
+ }
+
+ // Reinitialize the iterator.
+ m_iterator = m_names;
+ }
+}
+
+inline QJSValueIteratorPrivate::~QJSValueIteratorPrivate()
+{
+ QMutableListIterator<v8::Persistent<v8::String> > it = m_names;
+ //FIXME: we need register this QJSVAlueIterator
+ if (engine()) {
+ while (it.hasNext()) {
+ it.next().Dispose();
+ }
+ } else {
+ // FIXME leak ?
+ }
+}
+
+inline bool QJSValueIteratorPrivate::hasNext() const
+{
+ //dump("hasNext()");
+ return isValid()
+ ? m_iterator.hasNext() : false;
+}
+
+inline bool QJSValueIteratorPrivate::next()
+{
+ //dump("next();");
+ if (m_iterator.hasNext()) {
+ m_iterator.next();
+ return true;
+ }
+ return false;
+}
+
+inline QString QJSValueIteratorPrivate::name() const
+{
+ //dump("name");
+ if (!isValid())
+ return QString();
+
+ return QJSConverter::toString(m_iterator.value());
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValueIteratorPrivate::value() const
+{
+ //dump("value()");
+ if (!isValid())
+ return InvalidValue();
+
+ return m_object->property(m_iterator.value());
+}
+
+inline bool QJSValueIteratorPrivate::isValid() const
+{
+ bool result = m_object ? m_object->isValid() : false;
+ // We know that if this object is still valid then it is an object
+ // if this assumption is not correct then some other logic in this class
+ // have to be changed too.
+ Q_ASSERT(!result || m_object->isObject());
+ return result;
+}
+
+inline QV8Engine* QJSValueIteratorPrivate::engine() const
+{
+ return m_object ? m_object->engine() : 0;
+}
+
+//void QJSValueIteratorPrivate::dump(QString fname) const
+//{
+// qDebug() << " *** " << fname << " ***";
+// foreach (Persistent<String> name, m_names) {
+// qDebug() << " - " << QJSConverter::toString(name);
+// }
+//}
+
+/*!
+ Constructs an iterator for traversing \a object. The iterator is
+ set to be at the front of the sequence of properties (before the
+ first property).
+*/
+QJSValueIterator::QJSValueIterator(const QJSValue& object)
+ : d_ptr(new QJSValueIteratorPrivate(QJSValuePrivate::get(object)))
+{}
+
+/*!
+ Destroys the iterator.
+*/
+QJSValueIterator::~QJSValueIterator()
+{}
+
+/*!
+ Returns true if there is at least one item ahead of the iterator
+ (i.e. the iterator is \e not at the back of the property sequence);
+ otherwise returns false.
+
+ \sa next(), hasPrevious()
+*/
+bool QJSValueIterator::hasNext() const
+{
+ Q_D(const QJSValueIterator);
+ QScriptIsolate api(d->engine());
+ return d->hasNext();
+}
+
+/*!
+ Advances the iterator by one position.
+
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+
+ \sa hasNext(), previous(), name()
+*/
+bool QJSValueIterator::next()
+{
+ Q_D(QJSValueIterator);
+ QScriptIsolate api(d->engine());
+ return d->next();
+}
+
+/*!
+ Returns the name of the last property that was jumped over using
+ next() or previous().
+
+ \sa value(), flags()
+*/
+QString QJSValueIterator::name() const
+{
+ Q_D(const QJSValueIterator);
+ QScriptIsolate api(d->engine());
+ return d_ptr->name();
+}
+
+
+/*!
+ Returns the value of the last property that was jumped over using
+ next() or previous().
+
+ \sa setValue(), name()
+*/
+QJSValue QJSValueIterator::value() const
+{
+ Q_D(const QJSValueIterator);
+ QScriptIsolate api(d->engine());
+ return QJSValuePrivate::get(d->value());
+}
+
+
+/*!
+ Makes the iterator operate on \a object. The iterator is set to be
+ at the front of the sequence of properties (before the first
+ property).
+*/
+QJSValueIterator& QJSValueIterator::operator=(QJSValue& object)
+{
+ Q_D(QJSValueIterator);
+ QScriptIsolate api(d->engine());
+ d_ptr.reset(new QJSValueIteratorPrivate(QJSValuePrivate::get(object)));
+ return *this;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v8/qjsvalueiterator.h b/src/declarative/qml/v8/qjsvalueiterator.h
new file mode 100644
index 0000000000..1ec4d4b63b
--- /dev/null
+++ b/src/declarative/qml/v8/qjsvalueiterator.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCRIPTVALUEITERATOR_H
+#define QSCRIPTVALUEITERATOR_H
+
+#include <QtDeclarative/qjsvalue.h>
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Script)
+
+class QString;
+
+class QJSValueIteratorPrivate;
+class Q_SCRIPT_EXPORT QJSValueIterator
+{
+public:
+ QJSValueIterator(const QJSValue &value);
+ ~QJSValueIterator();
+
+ bool hasNext() const;
+ bool next();
+
+ QString name() const;
+
+ QJSValue value() const;
+ QJSValueIterator& operator=(QJSValue &value);
+
+private:
+ QScopedPointer<QJSValueIteratorPrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QJSValueIterator)
+ Q_DISABLE_COPY(QJSValueIterator)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSCRIPTVALUEITERATOR_H
diff --git a/src/declarative/qml/v8/qscript_impl_p.h b/src/declarative/qml/v8/qscript_impl_p.h
new file mode 100644
index 0000000000..e66b561efe
--- /dev/null
+++ b/src/declarative/qml/v8/qscript_impl_p.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+
+#ifndef QSCRIPT_IMPL_P_H
+#define QSCRIPT_IMPL_P_H
+
+#include "qv8engine_impl_p.h"
+#include "qjsvalue_impl_p.h"
+
+#endif //QSCRIPT_IMPL_P_H
diff --git a/src/declarative/qml/v8/qscriptisolate_p.h b/src/declarative/qml/v8/qscriptisolate_p.h
new file mode 100644
index 0000000000..fa200c00b6
--- /dev/null
+++ b/src/declarative/qml/v8/qscriptisolate_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef APIPREAMBLE_P_H
+#define APIPREAMBLE_P_H
+
+#include <private/qv8_p.h>
+#include "qv8engine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/**
+ \internal
+ Class used to switch to the right isolate. It does the same thing as v8::Isolate::Scope but
+ it checks for a null engine.
+ \attention We decided to put context switching "up" which means that it should be as high
+ as possible on call stack. And it should be switched at most once per public API function call.
+*/
+class QScriptIsolate {
+public:
+ // OperationMode was introduced to reduce number of checking for a null engine pointer. If we
+ // know that given pointer is not null than we should pass NotNullEngine as constructor argument
+ // that would nicely remove checking on compilation time.
+ enum OperationMode {Default, NotNullEngine};
+ inline QScriptIsolate(const QV8Engine *engine, const OperationMode mode = Default)
+ : m_engine(engine)
+ , m_mode(mode)
+ {
+ if (m_mode == NotNullEngine || m_engine) {
+ Q_ASSERT(m_engine);
+ m_engine->context()->Enter();
+ }
+ }
+
+ inline ~QScriptIsolate()
+ {
+ if (m_mode == NotNullEngine || m_engine) {
+ m_engine->context()->Exit();
+ }
+ }
+
+private:
+ Q_DISABLE_COPY(QScriptIsolate);
+ const QV8Engine *m_engine;
+ const OperationMode m_mode;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // APIPREAMBLE_P_H
diff --git a/src/declarative/qml/v8/qscriptoriginalglobalobject_p.h b/src/declarative/qml/v8/qscriptoriginalglobalobject_p.h
new file mode 100644
index 0000000000..c46d0e37a0
--- /dev/null
+++ b/src/declarative/qml/v8/qscriptoriginalglobalobject_p.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCRIPTORIGINALGLOBALOBJECT_P_H
+#define QSCRIPTORIGINALGLOBALOBJECT_P_H
+
+#include "QtCore/qglobal.h"
+#include "qjsvalue.h"
+
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+
+/*!
+ \internal
+ This class is a workaround for missing V8 API functionality. This class keeps all important
+ properties of an original (default) global object, so we can use it even if the global object was
+ changed.
+
+ FIXME this class is a container for workarounds :-) it should be replaced by proper API calls.
+
+ The class have to be created on the QV8Engine creation time (before any change got applied to
+ global object).
+
+ \attention All methods (apart from constructor) assumes that a context and a scope are prepared correctly.
+*/
+class QScriptOriginalGlobalObject
+{
+public:
+ inline QScriptOriginalGlobalObject(const QV8Engine *engine, v8::Handle<v8::Context> context);
+ inline void destroy();
+
+ inline QJSValue::PropertyFlags getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property);
+ inline v8::Local<v8::Object> getOwnPropertyDescriptor(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property) const;
+ inline bool strictlyEquals(v8::Handle<v8::Object> object);
+private:
+ Q_DISABLE_COPY(QScriptOriginalGlobalObject)
+
+ // Copy of constructors and prototypes used in isType functions.
+ v8::Persistent<v8::Function> m_ownPropertyDescriptor;
+ v8::Persistent<v8::Object> m_globalObject;
+};
+
+QScriptOriginalGlobalObject::QScriptOriginalGlobalObject(const QV8Engine *engine, v8::Handle<v8::Context> context)
+{
+ // Please notice that engine is not fully initialized at this point.
+
+ v8::Context::Scope contextScope(context);
+
+ v8::HandleScope scope;
+
+ m_globalObject = v8::Persistent<v8::Object>::New(context->Global());
+
+ v8::Local<v8::Object> objectConstructor = m_globalObject->Get(v8::String::New("Object"))->ToObject();
+ Q_ASSERT(objectConstructor->IsObject());
+ { // Initialize m_ownPropertyDescriptor.
+ v8::Local<v8::Value> ownPropertyDescriptor = objectConstructor->Get(v8::String::New("getOwnPropertyDescriptor"));
+ Q_ASSERT(!ownPropertyDescriptor.IsEmpty());
+ m_ownPropertyDescriptor = v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(ownPropertyDescriptor));
+ }
+}
+
+/*!
+ \internal
+ QScriptOriginalGlobalObject lives as long as QV8Engine that keeps it. In ~QSEP
+ the v8 context is removed, so we need to remove our handlers before. to break this dependency
+ destroy method should be called before or insight QSEP destructor.
+*/
+inline void QScriptOriginalGlobalObject::destroy()
+{
+ m_ownPropertyDescriptor.Dispose();
+ m_globalObject.Dispose();
+ // After this line this instance is unusable.
+}
+
+inline QJSValue::PropertyFlags QScriptOriginalGlobalObject::getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property)
+{
+ Q_ASSERT(object->IsObject());
+ Q_ASSERT(!property.IsEmpty());
+ v8::Local<v8::Object> descriptor = getOwnPropertyDescriptor(object, property);
+ if (descriptor.IsEmpty()) {
+// // Property isn't owned by this object.
+// if (!(mode & QScriptValue::ResolvePrototype))
+// return 0;
+ v8::Local<v8::Value> prototype = object->GetPrototype();
+ if (prototype->IsNull())
+ return 0;
+ return getPropertyFlags(v8::Local<v8::Object>::Cast(prototype), property);
+ }
+ v8::Local<v8::String> writableName = v8::String::New("writable");
+ v8::Local<v8::String> configurableName = v8::String::New("configurable");
+ v8::Local<v8::String> enumerableName = v8::String::New("enumerable");
+// v8::Local<v8::String> getName = v8::String::New("get");
+// v8::Local<v8::String> setName = v8::String::New("set");
+
+ unsigned flags = 0;
+
+ if (!descriptor->Get(configurableName)->BooleanValue())
+ flags |= QJSValue::Undeletable;
+ if (!descriptor->Get(enumerableName)->BooleanValue())
+ flags |= QJSValue::SkipInEnumeration;
+
+ //"writable" is only a property of the descriptor if it is not an accessor
+ if (descriptor->Has(writableName)) {
+ if (!descriptor->Get(writableName)->BooleanValue())
+ flags |= QJSValue::ReadOnly;
+ } else {
+// if (descriptor->Get(getName)->IsObject())
+// flags |= QScriptValue::PropertyGetter;
+// if (descriptor->Get(setName)->IsObject())
+// flags |= QScriptValue::PropertySetter;
+ }
+
+ return QJSValue::PropertyFlag(flags);
+}
+
+inline v8::Local<v8::Object> QScriptOriginalGlobalObject::getOwnPropertyDescriptor(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property) const
+{
+ Q_ASSERT(object->IsObject());
+ Q_ASSERT(!property.IsEmpty());
+ // FIXME do we need try catch here?
+ v8::Handle<v8::Value> argv[] = {object, property};
+ v8::Local<v8::Value> descriptor = m_ownPropertyDescriptor->Call(m_globalObject, /* argc */ 2, argv);
+ if (descriptor.IsEmpty() || !descriptor->IsObject())
+ return v8::Local<v8::Object>();
+ return v8::Local<v8::Object>::Cast(descriptor);
+}
+
+inline bool QScriptOriginalGlobalObject::strictlyEquals(v8::Handle<v8::Object> object)
+{
+ return m_globalObject->GetPrototype()->StrictEquals(object);
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/qml/v8/qscriptshareddata_p.h b/src/declarative/qml/v8/qscriptshareddata_p.h
new file mode 100644
index 0000000000..6604b10e32
--- /dev/null
+++ b/src/declarative/qml/v8/qscriptshareddata_p.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+
+#ifndef QSCRIPTSHAREDDATA_P_H
+#define QSCRIPTSHAREDDATA_P_H
+
+#include "qglobal.h"
+#include "qshareddata.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ This class should have the same interface as the QSharedData, but implementation doesn't
+ need to be thread safe, so atomic ref count was replaced by normal integer value.
+*/
+class QScriptSharedData
+{
+public:
+ class ReferenceCounter {
+ // FIXME shouldn't it be uint or something longer?
+ mutable int m_ref;
+ ReferenceCounter(int ref) : m_ref(ref) {}
+ ~ReferenceCounter() { Q_ASSERT_X(!m_ref, Q_FUNC_INFO, "Memory problem found"); }
+ public:
+ bool ref() { return ++m_ref; }
+ bool deref() { return --m_ref; }
+ friend class QScriptSharedData;
+ };
+
+ ReferenceCounter ref;
+ inline QScriptSharedData() : ref(0) { }
+
+private:
+ Q_DISABLE_COPY(QScriptSharedData)
+};
+
+
+template <class T> class QScriptPassPointer;
+
+// FIXME: that could be reimplemented to not check for a null value.
+template<class T>
+class QScriptSharedDataPointer : public QExplicitlySharedDataPointer<T>
+{
+public:
+ inline QScriptSharedDataPointer() {}
+ explicit QScriptSharedDataPointer(QScriptPassPointer<T> data) : QExplicitlySharedDataPointer<T>(data.give()) {}
+ explicit QScriptSharedDataPointer(T *data) : QExplicitlySharedDataPointer<T>(data) {}
+
+ inline QScriptSharedDataPointer<T> &operator=(const QScriptPassPointer<T> &other)
+ {
+ this->QExplicitlySharedDataPointer<T>::operator =(other.give());
+ return *this;
+ }
+ inline QScriptSharedDataPointer<T> &operator=(T *other)
+ {
+ this->QExplicitlySharedDataPointer<T>::operator =(other);
+ return *this;
+ }
+};
+
+// FIXME: that could be reimplemented to not check for a null value.
+template <class T>
+class QScriptPassPointer {
+public:
+ QScriptPassPointer(T *data) : m_ptr(data) {}
+ inline QScriptPassPointer() { m_ptr = 0; }
+ inline QScriptPassPointer(const QScriptPassPointer<T> &other) : m_ptr(other.give()) {}
+ inline ~QScriptPassPointer() { Q_ASSERT_X(!m_ptr, Q_FUNC_INFO, "Ownership of the QScriptPassPointer hasn't been taken"); }
+
+ inline T &operator*() const { return *m_ptr; }
+ inline T *operator->() { return m_ptr; }
+ inline T *operator->() const { return m_ptr; }
+ inline T *data() const { return m_ptr; }
+ inline const T *constData() const { return m_ptr; }
+
+ inline bool operator==(const QScriptPassPointer<T> &other) const { return m_ptr == other.m_ptr; }
+ inline bool operator!=(const QScriptPassPointer<T> &other) const { return m_ptr != other.m_ptr; }
+ inline bool operator==(const QScriptSharedDataPointer<T> &other) const { return m_ptr == other.m_ptr; }
+ inline bool operator!=(const QScriptSharedDataPointer<T> &other) const { return m_ptr != other.m_ptr; }
+ inline bool operator==(const T *ptr) const { return m_ptr == ptr; }
+ inline bool operator!=(const T *ptr) const { return m_ptr != ptr; }
+
+ inline operator bool () const { return m_ptr != 0; }
+ inline bool operator!() const { return !m_ptr; }
+
+ inline QScriptPassPointer<T> & operator=(const QScriptPassPointer<T> &other)
+ {
+ if (other.m_ptr != m_ptr) {
+ if (m_ptr)
+ delete m_ptr;
+ m_ptr = other.give();
+ }
+ return *this;
+ }
+
+ inline QScriptPassPointer &operator=(T *other)
+ {
+ if (other != m_ptr) {
+ if (m_ptr)
+ delete m_ptr;
+ m_ptr = other;
+ }
+ return *this;
+ }
+
+ inline T* give() const
+ {
+ T* result = m_ptr;
+ m_ptr = 0;
+ return result;
+ }
+
+private:
+ mutable T* m_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSCRIPTSHAREDDATA_P_H
diff --git a/src/declarative/qml/v8/qscripttools_p.h b/src/declarative/qml/v8/qscripttools_p.h
new file mode 100644
index 0000000000..f74fbab83f
--- /dev/null
+++ b/src/declarative/qml/v8/qscripttools_p.h
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+
+
+#ifndef QSCRIPTTOOLS_P_H
+#define QSCRIPTTOOLS_P_H
+
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+template<class T>
+class QScriptBagContainer;
+
+/*!
+ \internal
+ \interface
+ Helper class for a container. The purpuse of it is to add two pointer properties to a class
+ inheriting this class without bloating an interface.
+
+ This class exist only as a memory storage implementation. The only way to use it is to inherit it.
+*/
+class QScriptLinkedNode
+{
+protected:
+ QScriptLinkedNode()
+ : m_next(0)
+ , m_prev(0)
+ {}
+
+ ~QScriptLinkedNode()
+ {
+ Q_ASSERT_X(!isUsed(), Q_FUNC_INFO, "Destorying QScriptLinkedNode instance that still is in a container");
+ }
+
+private:
+ bool isUsed() const
+ {
+ return m_next || m_prev;
+ }
+
+#if defined(Q_NO_TEMPLATE_FRIENDS)
+public:
+#else
+ template<class T>
+ friend class QScriptBagContainer;
+#endif
+ QScriptLinkedNode *m_next;
+ QScriptLinkedNode *m_prev;
+};
+
+/*!
+ \internal
+ The QScriptBagContainer is a simple, low level, set like container for a pointer type castable to
+ QScriptLinkedNode*.
+ Algorithms complexity:
+ put: O(1)
+ get: O(1)
+ forEach: O(n)
+ \note This container doesn't take ownership of pointed values.
+ \attention All values have to be unique.
+*/
+template<class T>
+class QScriptBagContainer
+{
+public:
+ QScriptBagContainer()
+ : m_first(0)
+ {}
+
+ /*!
+ \internal
+ Add a this \a value to this container
+ */
+ void insert(T* value)
+ {
+ //dump(Q_FUNC_INFO, value);
+ Q_ASSERT_X(!contains(value), Q_FUNC_INFO, "Can't insert a value which is in the bag already");
+ QScriptLinkedNode* v = static_cast<QScriptLinkedNode*>(value);
+ Q_ASSERT(v);
+ Q_ASSERT_X(!v->m_next && !v->m_prev, Q_FUNC_INFO, "Can't insert a value which is in an another bag");
+
+ if (m_first)
+ m_first->m_prev = v;
+
+ v->m_next = m_first;
+ v->m_prev = 0;
+ m_first = v;
+ }
+
+ /*!
+ \internal
+ Remove this \a value from this container
+ */
+ void remove(T* value)
+ {
+ //dump(Q_FUNC_INFO, value);
+ QScriptLinkedNode* v = static_cast<QScriptLinkedNode*>(value);
+ Q_ASSERT(v);
+
+ if (!v->m_next && !v->m_prev && m_first != v) {
+ // ignore that value as it is not registered at all
+ // FIXME: That may be optimized out if unregister call is removed from ~QtDataBase
+ return;
+ }
+
+ Q_ASSERT_X(contains(value), Q_FUNC_INFO, "Can't remove a value which is not in the bag");
+ Q_ASSERT(v->m_prev || (m_first == v && !v->m_prev));
+
+ if (v->m_next)
+ v->m_next->m_prev= v->m_prev;
+
+ if (v->m_prev)
+ v->m_prev->m_next = v->m_next;
+ else
+ m_first = v->m_next;
+ // reset removed value
+ v->m_next = v->m_prev = 0;
+ }
+
+ /*!
+ \internal
+ Call \a fun for each element in this container. Fun should accept T* as a parameter.
+ \note In general it is not allowed to change this container by calling put() or get() unless
+ given value is the same as currently procceded by forEach.
+ */
+ template<class Functor>
+ void forEach(Functor fun)
+ {
+ //dump(Q_FUNC_INFO);
+ QScriptLinkedNode *i = m_first;
+ QScriptLinkedNode *tmp;
+ while (i) {
+ tmp = i;
+ i = i->m_next;
+ fun(static_cast<T*>(tmp));
+ }
+ }
+
+ /*!
+ \internal
+ Clear this container.
+ */
+ void clear()
+ {
+ m_first = 0;
+ }
+
+ /*!
+ \internal
+ Returns true if this container is empty; false otherwise.
+ */
+ bool isEmpty() const
+ {
+ return !m_first;
+ }
+
+// void dump(const char* msg, T* obj = 0) const
+// {
+// qDebug() << msg << obj;
+// qDebug() << m_first;
+// QScriptLinkedNode *i = m_first;
+// while (i) {
+// qDebug() <<" - " << i << "(" << i->m_prev << ", " << i->m_next <<")";
+// i = i->m_next;
+// }
+// }
+
+private:
+ bool contains(T *value) const
+ {
+ QScriptLinkedNode *i = m_first;
+ while (i) {
+ if (static_cast<T*>(i) == value)
+ return true;
+ i = i->m_next;
+ }
+ return false;
+ }
+ QScriptLinkedNode *m_first;
+};
+
+QT_END_NAMESPACE
+
+#endif //QSCRIPTTOOLS_P_H
diff --git a/src/declarative/qml/v8/qv8bindings.cpp b/src/declarative/qml/v8/qv8bindings.cpp
index 4f5543e690..c45274a97f 100644
--- a/src/declarative/qml/v8/qv8bindings.cpp
+++ b/src/declarative/qml/v8/qv8bindings.cpp
@@ -129,7 +129,7 @@ void QV8BindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags
ep->referenceScarceResources();
v8::HandleScope handle_scope;
- v8::Context::Scope scope(ep->v8engine.context());
+ v8::Context::Scope scope(ep->v8engine()->context());
v8::Local<v8::Value> result = evaluate(v8::Handle<v8::Function>::Cast(parent->functions->Get(index)),
&isUndefined);
diff --git a/src/declarative/qml/v8/qv8engine.cpp b/src/declarative/qml/v8/qv8engine.cpp
index 0294a60871..acbfb92b15 100644
--- a/src/declarative/qml/v8/qv8engine.cpp
+++ b/src/declarative/qml/v8/qv8engine.cpp
@@ -49,6 +49,7 @@
#include <private/qdeclarativeengine_p.h>
#include <private/qdeclarativecomponent_p.h>
#include <private/qdeclarativestringconverters_p.h>
+#include <private/qdeclarativeapplication_p.h>
#include <QtDeclarative/qdeclarativecomponent.h>
@@ -58,10 +59,15 @@
#include <QtCore/qnumeric.h>
#include <QtGui/qdesktopservices.h>
#include <QtGui/qfontdatabase.h>
-#include <private/qdeclarativeapplication_p.h>
#include <private/qdeclarativexmlhttprequest_p.h>
#include <private/qdeclarativesqldatabase_p.h>
+#include "qscript_impl_p.h"
+
+Q_DECLARE_METATYPE(QJSValue)
+Q_DECLARE_METATYPE(QList<int>)
+
+
// XXX TODO: Need to check all the global functions will also work in a worker script where the
// QDeclarativeEngine is not available
QT_BEGIN_NAMESPACE
@@ -94,9 +100,41 @@ static bool ObjectComparisonCallback(v8::Local<v8::Object> lhs, v8::Local<v8::Ob
return false;
}
-QV8Engine::QV8Engine()
-: m_xmlHttpRequestData(0), m_sqlDatabaseData(0), m_listModelData(0)
+QV8Engine::QV8Engine(QJSEngine* qq, QJSEngine::ContextOwnership ownership)
+ : q(qq)
+ , m_engine(0)
+ , m_ownsV8Context(ownership == QJSEngine::CreateNewContext)
+ , m_context((ownership == QJSEngine::CreateNewContext) ? v8::Context::New() : v8::Persistent<v8::Context>::New(v8::Context::GetCurrent()))
+ , m_originalGlobalObject(this, m_context)
+ , m_xmlHttpRequestData(0)
+ , m_sqlDatabaseData(0)
+ , m_listModelData(0)
{
+ qMetaTypeId<QJSValue>();
+ qMetaTypeId<QList<int> >();
+
+ QByteArray v8args = qgetenv("V8ARGS");
+ if (!v8args.isEmpty())
+ v8::V8::SetFlagsFromString(v8args.constData(), v8args.length());
+
+ v8::HandleScope handle_scope;
+ qPersistentRegister(m_context);
+ v8::Context::Scope context_scope(m_context);
+
+ v8::V8::SetUserObjectComparisonCallbackFunction(ObjectComparisonCallback);
+
+ m_stringWrapper.init();
+ m_contextWrapper.init(this);
+ m_qobjectWrapper.init(this);
+ m_typeWrapper.init(this);
+ m_listWrapper.init(this);
+ m_variantWrapper.init(this);
+ m_valueTypeWrapper.init(this);
+
+ {
+ v8::Handle<v8::Value> v = global()->Get(v8::String::New("Object"))->ToObject()->Get(v8::String::New("getOwnPropertyNames"));
+ m_getOwnPropertyNames = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(v));
+ }
}
QV8Engine::~QV8Engine()
@@ -114,6 +152,10 @@ QV8Engine::~QV8Engine()
qPersistentDispose(m_freezeObject);
qPersistentDispose(m_getOwnPropertyNames);
+
+ invalidateAllValues();
+ clearExceptions();
+
m_valueTypeWrapper.destroy();
m_variantWrapper.destroy();
m_listWrapper.destroy();
@@ -121,39 +163,11 @@ QV8Engine::~QV8Engine()
m_qobjectWrapper.destroy();
m_contextWrapper.destroy();
m_stringWrapper.destroy();
- qPersistentDispose(m_context);
-}
-
-void QV8Engine::init(QDeclarativeEngine *engine)
-{
- m_engine = engine;
-
- QByteArray v8args = qgetenv("V8ARGS");
- if (!v8args.isEmpty())
- v8::V8::SetFlagsFromString(v8args.constData(), v8args.length());
-
- v8::HandleScope handle_scope;
- m_context = v8::Context::New();
- qPersistentRegister(m_context);
- v8::Context::Scope context_scope(m_context);
-
- v8::V8::SetUserObjectComparisonCallbackFunction(ObjectComparisonCallback);
- m_stringWrapper.init();
- m_contextWrapper.init(this);
- m_qobjectWrapper.init(this);
- m_typeWrapper.init(this);
- m_listWrapper.init(this);
- m_variantWrapper.init(this);
- m_valueTypeWrapper.init(this);
+ m_originalGlobalObject.destroy();
- {
- v8::Handle<v8::Value> v = global()->Get(v8::String::New("Object"))->ToObject()->Get(v8::String::New("getOwnPropertyNames"));
- m_getOwnPropertyNames = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(v));
- }
-
- initializeGlobal(m_context->Global());
- freezeObject(m_context->Global());
+ if (m_ownsV8Context)
+ qPersistentDispose(m_context);
}
QString QV8Engine::toStringStatic(v8::Handle<v8::Value> jsstr)
@@ -357,8 +371,10 @@ v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant)
break;
}
- if (QDeclarativeValueType *vt = QDeclarativeEnginePrivate::get(m_engine)->valueTypes[type])
- return m_valueTypeWrapper.newValueType(variant, vt);
+ if (m_engine) {
+ if (QDeclarativeValueType *vt = QDeclarativeEnginePrivate::get(m_engine)->valueTypes[type])
+ return m_valueTypeWrapper.newValueType(variant, vt);
+ }
} else {
if (type == qMetaTypeId<QDeclarativeListReference>()) {
@@ -386,7 +402,7 @@ v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant)
}
// XXX TODO: To be compatible, we still need to handle:
- // + QScriptValue
+ // + QJSValue
// + QObjectList
// + QList<int>
@@ -420,6 +436,7 @@ const QSet<QString> &QV8Engine::illegalNames() const
// Requires a handle scope
v8::Local<v8::Array> QV8Engine::getOwnPropertyNames(v8::Handle<v8::Object> o)
{
+ // FIXME Newer v8 have API for this function
v8::TryCatch tc;
v8::Handle<v8::Value> args[] = { o };
v8::Local<v8::Value> r = m_getOwnPropertyNames->Call(global(), 1, args);
@@ -531,9 +548,6 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
}
}
- if (m_engine)
- qt->Set(v8::String::New("application"), newQObject(new QDeclarativeApplication(m_engine)));
-
qt->Set(v8::String::New("include"), V8FUNCTION(QV8Include::include, this));
qt->Set(v8::String::New("isQtObject"), V8FUNCTION(isQtObject, this));
qt->Set(v8::String::New("rgba"), V8FUNCTION(rgba, this));
@@ -543,12 +557,6 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
qt->Set(v8::String::New("size"), V8FUNCTION(size, this));
qt->Set(v8::String::New("vector3d"), V8FUNCTION(vector3d, this));
- if (m_engine) {
- qt->Set(v8::String::New("lighter"), V8FUNCTION(lighter, this));
- qt->Set(v8::String::New("darker"), V8FUNCTION(darker, this));
- qt->Set(v8::String::New("tint"), V8FUNCTION(tint, this));
- }
-
qt->Set(v8::String::New("formatDate"), V8FUNCTION(formatDate, this));
qt->Set(v8::String::New("formatTime"), V8FUNCTION(formatTime, this));
qt->Set(v8::String::New("formatDateTime"), V8FUNCTION(formatDateTime, this));
@@ -561,6 +569,10 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
qt->Set(v8::String::New("resolvedUrl"), V8FUNCTION(resolvedUrl, this));
if (m_engine) {
+ qt->Set(v8::String::New("application"), newQObject(new QDeclarativeApplication(m_engine)));
+ qt->Set(v8::String::New("lighter"), V8FUNCTION(lighter, this));
+ qt->Set(v8::String::New("darker"), V8FUNCTION(darker, this));
+ qt->Set(v8::String::New("tint"), V8FUNCTION(tint, this));
qt->Set(v8::String::New("quit"), V8FUNCTION(quit, this));
qt->Set(v8::String::New("createQmlObject"), V8FUNCTION(createQmlObject, this));
qt->Set(v8::String::New("createComponent"), V8FUNCTION(createComponent, this));
@@ -1658,5 +1670,652 @@ v8::Handle<v8::Value> QV8Engine::qsTrIdNoOp(const v8::Arguments &args)
return args[0];
}
+void QV8Engine::initDeclarativeGlobalObject()
+{
+ v8::HandleScope handels;
+ v8::Context::Scope contextScope(m_context);
+ initializeGlobal(m_context->Global());
+ freezeObject(m_context->Global());
+}
+
+void QV8Engine::setEngine(QDeclarativeEngine *engine)
+{
+ m_engine = engine;
+ initDeclarativeGlobalObject();
+}
+
+void QV8Engine::setException(v8::Handle<v8::Value> value, v8::Handle<v8::Message> msg)
+{
+ m_exception.set(value, msg);
+}
+
+v8::Handle<v8::Value> QV8Engine::throwException(v8::Handle<v8::Value> value)
+{
+ setException(value);
+ v8::ThrowException(value);
+ return value;
+}
+
+void QV8Engine::clearExceptions()
+{
+ m_exception.clear();
+}
+
+v8::Handle<v8::Value> QV8Engine::uncaughtException() const
+{
+ if (!hasUncaughtException())
+ return v8::Handle<v8::Value>();
+ return m_exception;
+}
+
+bool QV8Engine::hasUncaughtException() const
+{
+ return m_exception;
+}
+
+int QV8Engine::uncaughtExceptionLineNumber() const
+{
+ return m_exception.lineNumber();
+}
+
+QStringList QV8Engine::uncaughtExceptionBacktrace() const
+{
+ return m_exception.backtrace();
+}
+
+/*!
+ \internal
+ Save the current exception on stack so it can be set again later.
+ \sa QV8Engine::restoreException
+*/
+void QV8Engine::saveException()
+{
+ m_exception.push();
+}
+
+/*!
+ \internal
+ Load a saved exception from stack. Current exception, if exists will be dropped
+ \sa QV8Engine::saveException
+*/
+void QV8Engine::restoreException()
+{
+ m_exception.pop();
+}
+
+QV8Engine::Exception::Exception() {}
+
+QV8Engine::Exception::~Exception()
+{
+ Q_ASSERT_X(m_stack.isEmpty(), Q_FUNC_INFO, "Some saved exceptions left. Asymetric pop/push found.");
+ clear();
+}
+
+void QV8Engine::Exception::set(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message)
+{
+ Q_ASSERT_X(!value.IsEmpty(), Q_FUNC_INFO, "Throwing an empty value handle is highly suspected");
+ clear();
+ m_value = v8::Persistent<v8::Value>::New(value);
+ m_message = v8::Persistent<v8::Message>::New(message);
+}
+
+void QV8Engine::Exception::clear()
+{
+ m_value.Dispose();
+ m_value.Clear();
+ m_message.Dispose();
+ m_message.Clear();
+}
+
+QV8Engine::Exception::operator bool() const
+{
+ return !m_value.IsEmpty();
+}
+
+QV8Engine::Exception::operator v8::Handle<v8::Value>() const
+{
+ Q_ASSERT(*this);
+ return m_value;
+}
+
+int QV8Engine::Exception::lineNumber() const
+{
+ if (m_message.IsEmpty())
+ return -1;
+ return m_message->GetLineNumber();
+}
+
+QStringList QV8Engine::Exception::backtrace() const
+{
+ if (m_message.IsEmpty())
+ return QStringList();
+
+ QStringList backtrace;
+ v8::Handle<v8::StackTrace> trace = m_message->GetStackTrace();
+ if (trace.IsEmpty())
+ // FIXME it should not happen (SetCaptureStackTraceForUncaughtExceptions is called).
+ return QStringList();
+
+ for (int i = 0; i < trace->GetFrameCount(); ++i) {
+ v8::Local<v8::StackFrame> frame = trace->GetFrame(i);
+ backtrace.append(QJSConverter::toString(frame->GetFunctionName()));
+ backtrace.append(QJSConverter::toString(frame->GetFunctionName()));
+ backtrace.append(QString::fromAscii("()@"));
+ backtrace.append(QJSConverter::toString(frame->GetScriptName()));
+ backtrace.append(QString::fromAscii(":"));
+ backtrace.append(QString::number(frame->GetLineNumber()));
+ }
+ return backtrace;
+}
+
+void QV8Engine::Exception::push()
+{
+ m_stack.push(qMakePair(m_value, m_message));
+ m_value.Clear();
+ m_message.Clear();
+}
+
+void QV8Engine::Exception::pop()
+{
+ Q_ASSERT_X(!m_stack.empty(), Q_FUNC_INFO, "Attempt to load unsaved exception found");
+ ValueMessagePair pair = m_stack.pop();
+ clear();
+ m_value = pair.first;
+ m_message = pair.second;
+}
+
+QScriptPassPointer<QJSValuePrivate> QV8Engine::newRegExp(const QString &pattern, const QString &flags)
+{
+ int f = v8::RegExp::kNone;
+
+ QString::const_iterator i = flags.constBegin();
+ for (; i != flags.constEnd(); ++i) {
+ switch (i->unicode()) {
+ case 'i':
+ f |= v8::RegExp::kIgnoreCase;
+ break;
+ case 'm':
+ f |= v8::RegExp::kMultiline;
+ break;
+ case 'g':
+ f |= v8::RegExp::kGlobal;
+ break;
+ default:
+ {
+ // ignore a Syntax Error.
+ }
+ }
+ }
+
+ v8::Handle<v8::RegExp> regexp = v8::RegExp::New(QJSConverter::toString(pattern), static_cast<v8::RegExp::Flags>(f));
+ return new QJSValuePrivate(this, regexp);
+}
+
+QScriptPassPointer<QJSValuePrivate> QV8Engine::newRegExp(const QRegExp &regexp)
+{
+ return new QJSValuePrivate(this, QJSConverter::toRegExp(regexp));
+}
+
+
+// Converts a QVariantList to JS.
+// The result is a new Array object with length equal to the length
+// of the QVariantList, and the elements being the QVariantList's
+// elements converted to JS, recursively.
+v8::Handle<v8::Array> QV8Engine::variantListToJS(const QVariantList &lst)
+{
+ v8::Handle<v8::Array> result = v8::Array::New(lst.size());
+ for (int i = 0; i < lst.size(); ++i)
+ result->Set(i, variantToJS(lst.at(i)));
+ return result;
+}
+
+// Converts a JS Array object to a QVariantList.
+// The result is a QVariantList with length equal to the length
+// of the JS Array, and elements being the JS Array's elements
+// converted to QVariants, recursively.
+QVariantList QV8Engine::variantListFromJS(v8::Handle<v8::Array> jsArray)
+{
+ QVariantList result;
+ int hash = jsArray->GetIdentityHash();
+ if (visitedConversionObjects.contains(hash))
+ return result; // Avoid recursion.
+ v8::HandleScope handleScope;
+ visitedConversionObjects.insert(hash);
+ uint32_t length = jsArray->Length();
+ for (uint32_t i = 0; i < length; ++i)
+ result.append(variantFromJS(jsArray->Get(i)));
+ visitedConversionObjects.remove(hash);
+ return result;
+}
+
+// Converts a QVariantMap to JS.
+// The result is a new Object object with property names being
+// the keys of the QVariantMap, and values being the values of
+// the QVariantMap converted to JS, recursively.
+v8::Handle<v8::Object> QV8Engine::variantMapToJS(const QVariantMap &vmap)
+{
+ v8::Handle<v8::Object> result = v8::Object::New();
+ QVariantMap::const_iterator it;
+ for (it = vmap.constBegin(); it != vmap.constEnd(); ++it)
+ result->Set(QJSConverter::toString(it.key()), variantToJS(it.value()));
+ return result;
+}
+
+// Converts a JS Object to a QVariantMap.
+// The result is a QVariantMap with keys being the property names
+// of the object, and values being the values of the JS object's
+// properties converted to QVariants, recursively.
+QVariantMap QV8Engine::variantMapFromJS(v8::Handle<v8::Object> jsObject)
+{
+ QVariantMap result;
+ int hash = jsObject->GetIdentityHash();
+ if (visitedConversionObjects.contains(hash))
+ return result; // Avoid recursion.
+ visitedConversionObjects.insert(hash);
+ v8::HandleScope handleScope;
+ // TODO: Only object's own property names. Include non-enumerable properties.
+ v8::Handle<v8::Array> propertyNames = jsObject->GetPropertyNames();
+ uint32_t length = propertyNames->Length();
+ for (uint32_t i = 0; i < length; ++i) {
+ v8::Handle<v8::Value> name = propertyNames->Get(i);
+ result.insert(QJSConverter::toString(name->ToString()), variantFromJS(jsObject->Get(name)));
+ }
+ visitedConversionObjects.remove(hash);
+ return result;
+}
+
+// Converts the meta-type defined by the given type and data to JS.
+// Returns the value if conversion succeeded, an empty handle otherwise.
+v8::Handle<v8::Value> QV8Engine::metaTypeToJS(int type, const void *data)
+{
+ Q_ASSERT(data != 0);
+ v8::Handle<v8::Value> result;
+
+ // check if it's one of the types we know
+ switch (QMetaType::Type(type)) {
+ case QMetaType::Void:
+ return v8::Undefined();
+ case QMetaType::Bool:
+ return v8::Boolean::New(*reinterpret_cast<const bool*>(data));
+ case QMetaType::Int:
+ return v8::Int32::New(*reinterpret_cast<const int*>(data));
+ case QMetaType::UInt:
+ return v8::Uint32::New(*reinterpret_cast<const uint*>(data));
+ case QMetaType::LongLong:
+ return v8::Number::New(double(*reinterpret_cast<const qlonglong*>(data)));
+ case QMetaType::ULongLong:
+#if defined(Q_OS_WIN) && defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 12008804
+#pragma message("** NOTE: You need the Visual Studio Processor Pack to compile support for 64bit unsigned integers.")
+ return v8::Number::New(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
+#elif defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET)
+ return v8::Number::New(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
+#else
+ return v8::Number::New(double(*reinterpret_cast<const qulonglong*>(data)));
+#endif
+ case QMetaType::Double:
+ return v8::Number::New(double(*reinterpret_cast<const double*>(data)));
+ case QMetaType::QString:
+ return QJSConverter::toString(*reinterpret_cast<const QString*>(data));
+ case QMetaType::Float:
+ return v8::Number::New(*reinterpret_cast<const float*>(data));
+ case QMetaType::Short:
+ return v8::Int32::New(*reinterpret_cast<const short*>(data));
+ case QMetaType::UShort:
+ return v8::Uint32::New(*reinterpret_cast<const unsigned short*>(data));
+ case QMetaType::Char:
+ return v8::Int32::New(*reinterpret_cast<const char*>(data));
+ case QMetaType::UChar:
+ return v8::Uint32::New(*reinterpret_cast<const unsigned char*>(data));
+ case QMetaType::QChar:
+ return v8::Uint32::New((*reinterpret_cast<const QChar*>(data)).unicode());
+ case QMetaType::QStringList:
+ result = QJSConverter::toStringList(*reinterpret_cast<const QStringList *>(data));
+ break;
+ case QMetaType::QVariantList:
+ result = variantListToJS(*reinterpret_cast<const QVariantList *>(data));
+ break;
+ case QMetaType::QVariantMap:
+ result = variantMapToJS(*reinterpret_cast<const QVariantMap *>(data));
+ break;
+ case QMetaType::QDateTime:
+ result = QJSConverter::toDateTime(*reinterpret_cast<const QDateTime *>(data));
+ break;
+ case QMetaType::QDate:
+ result = QJSConverter::toDateTime(QDateTime(*reinterpret_cast<const QDate *>(data)));
+ break;
+ case QMetaType::QRegExp:
+ result = QJSConverter::toRegExp(*reinterpret_cast<const QRegExp *>(data));
+ break;
+ case QMetaType::QObjectStar:
+ case QMetaType::QWidgetStar:
+ result = newQObject(*reinterpret_cast<QObject* const *>(data));
+ break;
+ case QMetaType::QVariant:
+ result = variantToJS(*reinterpret_cast<const QVariant*>(data));
+ break;
+ default:
+ if (type == qMetaTypeId<QJSValue>()) {
+ return QJSValuePrivate::get(*reinterpret_cast<const QJSValue*>(data))->asV8Value(this);
+ } else {
+ QByteArray typeName = QMetaType::typeName(type);
+ if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(data)) {
+ return v8::Null();
+ } else {
+ // Fall back to wrapping in a QVariant.
+ result = newVariant(QVariant(type, data));
+ }
+ }
+ }
+ return result;
+}
+
+// Converts a JS value to a meta-type.
+// data must point to a place that can store a value of the given type.
+// Returns true if conversion succeeded, false otherwise.
+bool QV8Engine::metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data) {
+ // check if it's one of the types we know
+ switch (QMetaType::Type(type)) {
+ case QMetaType::Bool:
+ *reinterpret_cast<bool*>(data) = value->ToBoolean()->Value();
+ return true;
+ case QMetaType::Int:
+ *reinterpret_cast<int*>(data) = value->ToInt32()->Value();
+ return true;
+ case QMetaType::UInt:
+ *reinterpret_cast<uint*>(data) = value->ToUint32()->Value();
+ return true;
+ case QMetaType::LongLong:
+ *reinterpret_cast<qlonglong*>(data) = qlonglong(value->ToInteger()->Value());
+ return true;
+ case QMetaType::ULongLong:
+ *reinterpret_cast<qulonglong*>(data) = qulonglong(value->ToInteger()->Value());
+ return true;
+ case QMetaType::Double:
+ *reinterpret_cast<double*>(data) = value->ToNumber()->Value();
+ return true;
+ case QMetaType::QString:
+ if (value->IsUndefined() || value->IsNull())
+ *reinterpret_cast<QString*>(data) = QString();
+ else
+ *reinterpret_cast<QString*>(data) = QJSConverter::toString(value->ToString());
+ return true;
+ case QMetaType::Float:
+ *reinterpret_cast<float*>(data) = value->ToNumber()->Value();
+ return true;
+ case QMetaType::Short:
+ *reinterpret_cast<short*>(data) = short(value->ToInt32()->Value());
+ return true;
+ case QMetaType::UShort:
+ *reinterpret_cast<unsigned short*>(data) = ushort(value->ToInt32()->Value()); // ### QScript::ToUInt16()
+ return true;
+ case QMetaType::Char:
+ *reinterpret_cast<char*>(data) = char(value->ToInt32()->Value());
+ return true;
+ case QMetaType::UChar:
+ *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->ToInt32()->Value());
+ return true;
+ case QMetaType::QChar:
+ if (value->IsString()) {
+ QString str = QJSConverter::toString(v8::Handle<v8::String>::Cast(value));
+ *reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0);
+ } else {
+ *reinterpret_cast<QChar*>(data) = QChar(ushort(value->ToInt32()->Value())); // ### QScript::ToUInt16()
+ }
+ return true;
+ case QMetaType::QDateTime:
+ if (value->IsDate()) {
+ *reinterpret_cast<QDateTime *>(data) = QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value));
+ return true;
+ } break;
+ case QMetaType::QDate:
+ if (value->IsDate()) {
+ *reinterpret_cast<QDate *>(data) = QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value)).date();
+ return true;
+ } break;
+ case QMetaType::QRegExp:
+ if (value->IsRegExp()) {
+ *reinterpret_cast<QRegExp *>(data) = QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(value));
+ return true;
+ } break;
+ case QMetaType::QObjectStar:
+ if (isQObject(value) || value->IsNull()) {
+ *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(value);
+ return true;
+ } break;
+ case QMetaType::QWidgetStar:
+ if (isQObject(value) || value->IsNull()) {
+ QObject *qo = qtObjectFromJS(value);
+ if (!qo || qo->isWidgetType()) {
+ *reinterpret_cast<QWidget* *>(data) = reinterpret_cast<QWidget*>(qo);
+ return true;
+ }
+ } break;
+ case QMetaType::QStringList:
+ if (value->IsArray()) {
+ *reinterpret_cast<QStringList *>(data) = QJSConverter::toStringList(v8::Handle<v8::Array>::Cast(value));
+ return true;
+ } break;
+ case QMetaType::QVariantList:
+ if (value->IsArray()) {
+ *reinterpret_cast<QVariantList *>(data) = variantListFromJS(v8::Handle<v8::Array>::Cast(value));
+ return true;
+ } break;
+ case QMetaType::QVariantMap:
+ if (value->IsObject()) {
+ *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(v8::Handle<v8::Object>::Cast(value));
+ return true;
+ } break;
+ case QMetaType::QVariant:
+ *reinterpret_cast<QVariant*>(data) = variantFromJS(value);
+ return true;
+ default:
+ ;
+ }
+
+#if 0
+ if (isQtVariant(value)) {
+ const QVariant &var = variantValue(value);
+ // ### Enable once constructInPlace() is in qt master.
+ if (var.userType() == type) {
+ QMetaType::constructInPlace(type, data, var.constData());
+ return true;
+ }
+ if (var.canConvert(QVariant::Type(type))) {
+ QVariant vv = var;
+ vv.convert(QVariant::Type(type));
+ Q_ASSERT(vv.userType() == type);
+ QMetaType::constructInPlace(type, data, vv.constData());
+ return true;
+ }
+
+ }
+#endif
+
+ // Try to use magic.
+
+ QByteArray name = QMetaType::typeName(type);
+ if (convertToNativeQObject(value, name, reinterpret_cast<void* *>(data)))
+ return true;
+ if (isVariant(value) && name.endsWith('*')) {
+ int valueType = QMetaType::type(name.left(name.size()-1));
+ QVariant var = variantValue(value);
+ if (valueType == var.userType()) {
+ // We have T t, T* is requested, so return &t.
+ *reinterpret_cast<void* *>(data) = var.data();
+ return true;
+ } else {
+ // Look in the prototype chain.
+ v8::Handle<v8::Value> proto = value->ToObject()->GetPrototype();
+ while (proto->IsObject()) {
+ bool canCast = false;
+ if (isVariant(proto)) {
+ canCast = (type == variantValue(proto).userType())
+ || (valueType && (valueType == variantValue(proto).userType()));
+ }
+ else if (isQObject(proto)) {
+ QByteArray className = name.left(name.size()-1);
+ if (QObject *qobject = qtObjectFromJS(proto))
+ canCast = qobject->qt_metacast(className) != 0;
+ }
+ if (canCast) {
+ QByteArray varTypeName = QMetaType::typeName(var.userType());
+ if (varTypeName.endsWith('*'))
+ *reinterpret_cast<void* *>(data) = *reinterpret_cast<void* *>(var.data());
+ else
+ *reinterpret_cast<void* *>(data) = var.data();
+ return true;
+ }
+ proto = proto->ToObject()->GetPrototype();
+ }
+ }
+ } else if (value->IsNull() && name.endsWith('*')) {
+ *reinterpret_cast<void* *>(data) = 0;
+ return true;
+ } else if (type == qMetaTypeId<QJSValue>()) {
+ *reinterpret_cast<QJSValue*>(data) = QJSValuePrivate::get(new QJSValuePrivate(this, value));
+ return true;
+ }
+
+ return false;
+}
+
+// Converts a QVariant to JS.
+v8::Handle<v8::Value> QV8Engine::variantToJS(const QVariant &value)
+{
+ return metaTypeToJS(value.userType(), value.constData());
+}
+
+// Converts a JS value to a QVariant.
+// Null, Undefined -> QVariant() (invalid)
+// Boolean -> QVariant(bool)
+// Number -> QVariant(double)
+// String -> QVariant(QString)
+// Array -> QVariantList(...)
+// Date -> QVariant(QDateTime)
+// RegExp -> QVariant(QRegExp)
+// [Any other object] -> QVariantMap(...)
+QVariant QV8Engine::variantFromJS(v8::Handle<v8::Value> value)
+{
+ Q_ASSERT(!value.IsEmpty());
+ if (value->IsNull() || value->IsUndefined())
+ return QVariant();
+ if (value->IsBoolean())
+ return value->ToBoolean()->Value();
+ else if (value->IsInt32())
+ return value->ToInt32()->Value();
+ else if (value->IsNumber())
+ return value->ToNumber()->Value();
+ if (value->IsString())
+ return QJSConverter::toString(value->ToString());
+ Q_ASSERT(value->IsObject());
+ if (value->IsArray())
+ return variantListFromJS(v8::Handle<v8::Array>::Cast(value));
+ if (value->IsDate())
+ return QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value));
+ if (value->IsRegExp())
+ return QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(value));
+ if (isVariant(value))
+ return variantValue(value);
+ if (isQObject(value))
+ return qVariantFromValue(qtObjectFromJS(value));
+ return variantMapFromJS(value->ToObject());
+}
+
+bool QV8Engine::convertToNativeQObject(v8::Handle<v8::Value> value,
+ const QByteArray &targetType,
+ void **result)
+{
+ if (!targetType.endsWith('*'))
+ return false;
+ if (QObject *qobject = qtObjectFromJS(value)) {
+ int start = targetType.startsWith("const ") ? 6 : 0;
+ QByteArray className = targetType.mid(start, targetType.size()-start-1);
+ if (void *instance = qobject->qt_metacast(className)) {
+ *result = instance;
+ return true;
+ }
+ }
+ return false;
+}
+
+QObject *QV8Engine::qtObjectFromJS(v8::Handle<v8::Value> value)
+{
+ if (!value->IsObject())
+ return 0;
+
+ QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource();
+ if (!r)
+ return 0;
+ QV8ObjectResource::ResourceType type = r->resourceType();
+ if (type == QV8ObjectResource::QObjectType)
+ return qobjectWrapper()->toQObject(r);
+ else if (type == QV8ObjectResource::VariantType) {
+ QVariant variant = variantWrapper()->toVariant(r);
+ int type = variant.userType();
+ if ((type == QMetaType::QObjectStar) || (type == QMetaType::QWidgetStar))
+ return *reinterpret_cast<QObject* const *>(variant.constData());
+ }
+ return 0;
+}
+
+
+QVariant QV8Engine::variantValue(v8::Handle<v8::Value> value)
+{
+ Q_ASSERT(isVariant(value));
+ return QV8Engine::toVariant(value, -1 /*whateever magic hint is*/);
+}
+
+// Creates a QVariant wrapper object.
+v8::Handle<v8::Object> QV8Engine::newVariant(const QVariant &value)
+{
+ v8::Handle<v8::Object> instance = variantWrapper()->newVariant(value);
+ return instance;
+}
+
+QScriptPassPointer<QJSValuePrivate> QV8Engine::evaluate(v8::Handle<v8::Script> script, v8::TryCatch& tryCatch)
+{
+ v8::HandleScope handleScope;
+
+ clearExceptions();
+ if (script.IsEmpty()) {
+ v8::Handle<v8::Value> exception = tryCatch.Exception();
+ if (exception.IsEmpty()) {
+ // This is possible on syntax errors like { a:12, b:21 } <- missing "(", ")" around expression.
+ return InvalidValue();
+ }
+ setException(exception, tryCatch.Message());
+ return new QJSValuePrivate(this, exception);
+ }
+ v8::Handle<v8::Value> result;
+ result = script->Run();
+ if (result.IsEmpty()) {
+ v8::Handle<v8::Value> exception = tryCatch.Exception();
+ // TODO: figure out why v8 doesn't always produce an exception value
+ //Q_ASSERT(!exception.IsEmpty());
+ if (exception.IsEmpty())
+ exception = v8::Exception::Error(v8::String::New("missing exception value"));
+ setException(exception, tryCatch.Message());
+ return new QJSValuePrivate(this, exception);
+ }
+ return new QJSValuePrivate(this, result);
+}
+
+QJSValue QV8Engine::scriptValueFromInternal(v8::Handle<v8::Value> value) const
+{
+ if (value.IsEmpty())
+ return QJSValuePrivate::get(InvalidValue());
+ return QJSValuePrivate::get(new QJSValuePrivate(const_cast<QV8Engine*>(this), value));
+}
+
+QScriptPassPointer<QJSValuePrivate> QV8Engine::newArray(uint length)
+{
+ return new QJSValuePrivate(this, v8::Array::New(length));
+}
+
+void QV8Engine::emitSignalHandlerException()
+{
+ emit q->signalHandlerException(scriptValueFromInternal(uncaughtException()));
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/v8/qv8engine_impl_p.h b/src/declarative/qml/v8/qv8engine_impl_p.h
new file mode 100644
index 0000000000..5c56efdf39
--- /dev/null
+++ b/src/declarative/qml/v8/qv8engine_impl_p.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8ENGINE_IMPL_P_H
+#define QV8ENGINE_IMPL_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 "qv8engine_p.h"
+#include "qjsvalue_p.h"
+#include "qjsconverter_p.h"
+
+QT_BEGIN_NAMESPACE
+
+inline v8::Handle<v8::Value> QV8Engine::makeJSValue(bool value)
+{
+ return value ? v8::True() : v8::False();
+}
+
+inline v8::Handle<v8::Value> QV8Engine::makeJSValue(int value)
+{
+ return v8::Integer::New(value);
+}
+
+inline v8::Handle<v8::Value> QV8Engine::makeJSValue(uint value)
+{
+ return v8::Integer::NewFromUnsigned(value);
+}
+
+inline v8::Handle<v8::Value> QV8Engine::makeJSValue(double value)
+{
+ return v8::Number::New(value);
+}
+
+inline v8::Handle<v8::Value> QV8Engine::makeJSValue(QJSValue::SpecialValue value) {
+ if (value == QJSValue::NullValue)
+ return v8::Null();
+ return v8::Undefined();
+}
+
+inline v8::Handle<v8::Value> QV8Engine::makeJSValue(const QString& value)
+{
+ return QJSConverter::toString(value);
+}
+
+class QtScriptBagCleaner
+{
+public:
+ template<class T>
+ void operator () (T* value) const
+ {
+ value->reinitialize();
+ }
+};
+
+inline void QV8Engine::registerValue(QJSValuePrivate *data)
+{
+ m_values.insert(data);
+}
+
+inline void QV8Engine::unregisterValue(QJSValuePrivate *data)
+{
+ m_values.remove(data);
+}
+
+inline void QV8Engine::invalidateAllValues()
+{
+ QtScriptBagCleaner invalidator;
+ m_values.forEach(invalidator);
+ m_values.clear();
+}
+
+/*!
+ \internal
+ \note property can be index (v8::Integer) or a property (v8::String) name, according to ECMA script
+ property would be converted to a string.
+*/
+inline QJSValue::PropertyFlags QV8Engine::getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property)
+{
+ QJSValue::PropertyFlags flags = m_originalGlobalObject.getPropertyFlags(object, property);
+ return flags;
+}
+
+QScriptPassPointer<QJSValuePrivate> QV8Engine::evaluate(const QString& program, const QString& fileName, int lineNumber)
+{
+ v8::TryCatch tryCatch;
+ v8::ScriptOrigin scriptOrigin(QJSConverter::toString(fileName), v8::Integer::New(lineNumber - 1));
+ v8::Handle<v8::Script> script;
+ script = v8::Script::Compile(QJSConverter::toString(program), &scriptOrigin);
+ if (script.IsEmpty()) {
+ // TODO: Why don't we get the exception, as with Script::Compile()?
+ // Q_ASSERT(tryCatch.HasCaught());
+ v8::Handle<v8::Value> error = v8::Exception::SyntaxError(v8::String::New(""));
+ setException(error);
+ return new QJSValuePrivate(this, error);
+ }
+ return evaluate(script, tryCatch);
+}
+
+QT_END_NAMESPACE
+
+#endif // QV8ENGINE_IMPL_P_H
diff --git a/src/declarative/qml/v8/qv8engine_p.h b/src/declarative/qml/v8/qv8engine_p.h
index 340945c6ee..b95e55002b 100644
--- a/src/declarative/qml/v8/qv8engine_p.h
+++ b/src/declarative/qml/v8/qv8engine_p.h
@@ -57,7 +57,14 @@
#include <QtCore/qvariant.h>
#include <QtCore/qset.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qstringlist.h>
+
#include <private/qv8_p.h>
+#include <qjsengine.h>
+#include <qjsvalue.h>
+#include "qscriptoriginalglobalobject_p.h"
+#include "qscripttools_p.h"
#include <private/qdeclarativepropertycache_p.h>
@@ -210,18 +217,49 @@ class QDeclarativeContextData;
class Q_DECLARATIVE_EXPORT QV8Engine
{
public:
- QV8Engine();
+ static QV8Engine* get(QJSEngine* q) { Q_ASSERT(q); return q->handle(); }
+ static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; }
+
+ QV8Engine(QJSEngine* qq,QJSEngine::ContextOwnership ownership = QJSEngine::CreateNewContext);
~QV8Engine();
struct Deletable {
virtual ~Deletable() {}
};
- void init(QDeclarativeEngine *);
+ class Exception
+ {
+ typedef QPair<v8::Persistent<v8::Value>, v8::Persistent<v8::Message> > ValueMessagePair;
+
+ v8::Persistent<v8::Value> m_value;
+ v8::Persistent<v8::Message> m_message;
+ QStack<ValueMessagePair> m_stack;
+
+ Q_DISABLE_COPY(Exception)
+ public:
+ inline Exception();
+ inline ~Exception();
+ inline void set(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message);
+ inline void clear();
+ inline operator bool() const;
+ inline operator v8::Handle<v8::Value>() const;
+ inline int lineNumber() const;
+ inline QStringList backtrace() const;
+
+ inline void push();
+ inline void pop();
+ };
+ void initDeclarativeGlobalObject();
+ void setEngine(QDeclarativeEngine *engine);
QDeclarativeEngine *engine() { return m_engine; }
v8::Local<v8::Object> global() { return m_context->Global(); }
- v8::Handle<v8::Context> context() { return m_context; }
+ v8::Handle<v8::Context> context() const { return m_context; }
+
+ inline void registerValue(QJSValuePrivate *data);
+ inline void unregisterValue(QJSValuePrivate *data);
+ inline void invalidateAllValues();
+
QV8ContextWrapper *contextWrapper() { return &m_contextWrapper; }
QV8QObjectWrapper *qobjectWrapper() { return &m_qobjectWrapper; }
QV8TypeWrapper *typeWrapper() { return &m_typeWrapper; }
@@ -237,6 +275,7 @@ public:
QDeclarativeContextData *callingContext();
v8::Local<v8::Array> getOwnPropertyNames(v8::Handle<v8::Object>);
+ inline QJSValue::PropertyFlags getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property);
void freezeObject(v8::Handle<v8::Value>);
inline QString toString(v8::Handle<v8::Value> string);
@@ -257,6 +296,9 @@ public:
// Return the QML global "scope" object for the \a ctxt context and \a scope object.
inline v8::Local<v8::Object> qmlScope(QDeclarativeContextData *ctxt, QObject *scope);
+ QScriptPassPointer<QJSValuePrivate> newRegExp(const QRegExp &regexp);
+ QScriptPassPointer<QJSValuePrivate> newRegExp(const QString &pattern, const QString &flags);
+
// Return a JS wrapper for the given QObject \a object
inline v8::Handle<v8::Value> newQObject(QObject *object);
inline bool isQObject(v8::Handle<v8::Value>);
@@ -281,8 +323,19 @@ public:
// Return the list of illegal id names (the names of the properties on the global object)
const QSet<QString> &illegalNames() const;
+ inline void collectGarbage() { gc(); }
static void gc();
+ void clearExceptions();
+ void setException(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message = v8::Handle<v8::Message>());
+ v8::Handle<v8::Value> throwException(v8::Handle<v8::Value> value);
+ bool hasUncaughtException() const;
+ int uncaughtExceptionLineNumber() const;
+ QStringList uncaughtExceptionBacktrace() const;
+ v8::Handle<v8::Value> uncaughtException() const;
+ void saveException();
+ void restoreException();
+
#ifdef QML_GLOBAL_HANDLE_DEBUGGING
// Used for handle debugging
static void registerHandle(void *);
@@ -295,9 +348,50 @@ public:
inline Deletable *extensionData(int) const;
void setExtensionData(int, Deletable *);
-private:
+ inline v8::Handle<v8::Value> makeJSValue(bool value);
+ inline v8::Handle<v8::Value> makeJSValue(int value);
+ inline v8::Handle<v8::Value> makeJSValue(uint value);
+ inline v8::Handle<v8::Value> makeJSValue(double value);
+ inline v8::Handle<v8::Value> makeJSValue(QJSValue::SpecialValue value);
+ inline v8::Handle<v8::Value> makeJSValue(const QString& value);
+
+ inline QScriptPassPointer<QJSValuePrivate> evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1);
+ QScriptPassPointer<QJSValuePrivate> evaluate(v8::Handle<v8::Script> script, v8::TryCatch& tryCatch);
+
+ QScriptPassPointer<QJSValuePrivate> newArray(uint length);
+ v8::Handle<v8::Object> newVariant(const QVariant &variant);
+ QScriptPassPointer<QJSValuePrivate> newVariant(QJSValuePrivate* value, const QVariant &variant);
+
+ v8::Handle<v8::Array> variantListToJS(const QVariantList &lst);
+ QVariantList variantListFromJS(v8::Handle<v8::Array> jsArray);
+
+ v8::Handle<v8::Object> variantMapToJS(const QVariantMap &vmap);
+ QVariantMap variantMapFromJS(v8::Handle<v8::Object> jsObject);
+
+ v8::Handle<v8::Value> variantToJS(const QVariant &value);
+ QVariant variantFromJS(v8::Handle<v8::Value> value);
+
+ v8::Handle<v8::Value> metaTypeToJS(int type, const void *data);
+ bool metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data);
+
+ bool convertToNativeQObject(v8::Handle<v8::Value> value,
+ const QByteArray &targetType,
+ void **result);
+
+ QVariant variantValue(v8::Handle<v8::Value> value);
+
+ QJSValue scriptValueFromInternal(v8::Handle<v8::Value>) const;
+
+ void emitSignalHandlerException();
+
+ QObject *qtObjectFromJS(v8::Handle<v8::Value> value);
+ QSet<int> visitedConversionObjects;
+protected:
+ QJSEngine* q;
QDeclarativeEngine *m_engine;
+ bool m_ownsV8Context;
v8::Persistent<v8::Context> m_context;
+ QScriptOriginalGlobalObject m_originalGlobalObject;
QV8StringWrapper m_stringWrapper;
QV8ContextWrapper m_contextWrapper;
@@ -318,6 +412,8 @@ private:
QSet<QString> m_illegalNames;
+ Exception m_exception;
+
QVariant toBasicVariant(v8::Handle<v8::Value>);
void initializeGlobal(v8::Handle<v8::Object>);
@@ -356,6 +452,10 @@ private:
double qtDateTimeToJsDate(const QDateTime &dt);
QDateTime qtDateTimeFromJsDate(double jsDate);
+private:
+ QScriptBagContainer<QJSValuePrivate> m_values;
+
+ Q_DISABLE_COPY(QV8Engine)
};
// Allocate a new Persistent handle. *ALL* persistent handles in QML must be allocated
diff --git a/src/declarative/qml/v8/qv8include.cpp b/src/declarative/qml/v8/qv8include.cpp
index e2161a9001..71937d0aad 100644
--- a/src/declarative/qml/v8/qv8include.cpp
+++ b/src/declarative/qml/v8/qv8include.cpp
@@ -41,7 +41,7 @@
#include "qv8include_p.h"
-#include <QtScript/qscriptengine.h>
+#include <QtDeclarative/qjsengine.h>
#include <QtNetwork/qnetworkrequest.h>
#include <QtNetwork/qnetworkreply.h>
#include <QtCore/qfile.h>
diff --git a/src/declarative/qml/v8/qv8qobjectwrapper.cpp b/src/declarative/qml/v8/qv8qobjectwrapper.cpp
index cc0380e684..f97f427ede 100644
--- a/src/declarative/qml/v8/qv8qobjectwrapper.cpp
+++ b/src/declarative/qml/v8/qv8qobjectwrapper.cpp
@@ -48,15 +48,17 @@
#include <private/qdeclarativeengine_p.h>
#include <private/qdeclarativevmemetaobject_p.h>
#include <private/qdeclarativebinding_p.h>
+#include <private/qjsvalue_p.h>
+#include <private/qscript_impl_p.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qtimer.h>
#include <QtCore/qatomic.h>
QT_BEGIN_NAMESPACE
-Q_DECLARE_METATYPE(QScriptValue);
+Q_DECLARE_METATYPE(QJSValue);
Q_DECLARE_METATYPE(QDeclarativeV8Handle);
#if defined(__GNUC__)
@@ -137,7 +139,7 @@ private:
QString *qstringPtr;
QVariant *qvariantPtr;
QList<QObject *> *qlistPtr;
- QScriptValue *qscriptValuePtr;
+ QJSValue *qjsValuePtr;
QDeclarativeV8Handle *handlePtr;
};
@@ -691,7 +693,9 @@ v8::Handle<v8::Array> QV8QObjectWrapper::Enumerator(const v8::AccessorInfo &info
QStringList result;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(resource->engine->engine());
+ QDeclarativeEnginePrivate *ep = resource->engine->engine()
+ ? QDeclarativeEnginePrivate::get(resource->engine->engine())
+ : 0;
QDeclarativePropertyCache *cache = 0;
QDeclarativeData *ddata = QDeclarativeData::get(object);
@@ -699,7 +703,7 @@ v8::Handle<v8::Array> QV8QObjectWrapper::Enumerator(const v8::AccessorInfo &info
cache = ddata->propertyCache;
if (!cache) {
- cache = ep->cache(object);
+ cache = ep ? ep->cache(object) : 0;
if (cache) {
if (ddata) { cache->addref(); ddata->propertyCache = cache; }
} else {
@@ -1837,8 +1841,8 @@ void MetaCallArgument::cleanup()
qstringPtr->~QString();
} else if (type == -1 || type == QMetaType::QVariant) {
qvariantPtr->~QVariant();
- } else if (type == qMetaTypeId<QScriptValue>()) {
- qscriptValuePtr->~QScriptValue();
+ } else if (type == qMetaTypeId<QJSValue>()) {
+ qjsValuePtr->~QJSValue();
} else if (type == qMetaTypeId<QList<QObject *> >()) {
qlistPtr->~QList<QObject *>();
}
@@ -1857,8 +1861,8 @@ void MetaCallArgument::initAsType(int callType)
if (type != 0) { cleanup(); type = 0; }
if (callType == 0) return;
- if (callType == qMetaTypeId<QScriptValue>()) {
- qscriptValuePtr = new (&allocData) QScriptValue();
+ if (callType == qMetaTypeId<QJSValue>()) {
+ qjsValuePtr = new (&allocData) QJSValue();
type = callType;
} else if (callType == QMetaType::Int ||
callType == QMetaType::UInt ||
@@ -1891,9 +1895,9 @@ void MetaCallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8:
{
if (type != 0) { cleanup(); type = 0; }
- if (callType == qMetaTypeId<QScriptValue>()) {
- qscriptValuePtr = new (&allocData) QScriptValue();
- type = qMetaTypeId<QScriptValue>();
+ if (callType == qMetaTypeId<QJSValue>()) {
+ qjsValuePtr = new (&allocData) QJSValue(QJSValuePrivate::get(new QJSValuePrivate(engine, value)));
+ type = qMetaTypeId<QJSValue>();
} else if (callType == QMetaType::Int) {
intValue = quint32(value->Int32Value());
type = callType;
@@ -1939,7 +1943,7 @@ void MetaCallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8:
qvariantPtr = new (&allocData) QVariant();
type = -1;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
+ QDeclarativeEnginePrivate *ep = engine->engine() ? QDeclarativeEnginePrivate::get(engine->engine()) : 0;
QVariant v = engine->toVariant(value, -1);
if (v.userType() == callType) {
@@ -1947,7 +1951,7 @@ void MetaCallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8:
} else if (v.canConvert((QVariant::Type)callType)) {
*qvariantPtr = v;
qvariantPtr->convert((QVariant::Type)callType);
- } else if (const QMetaObject *mo = ep->rawMetaObjectForType(callType)) {
+ } else if (const QMetaObject *mo = ep ? ep->rawMetaObjectForType(callType) : 0) {
QObject *obj = ep->toQObject(v);
if (obj) {
@@ -1965,8 +1969,8 @@ void MetaCallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8:
v8::Handle<v8::Value> MetaCallArgument::toValue(QV8Engine *engine)
{
- if (type == qMetaTypeId<QScriptValue>()) {
- return v8::Undefined();
+ if (type == qMetaTypeId<QJSValue>()) {
+ return QJSValuePrivate::get(*qjsValuePtr)->asV8Value(engine);
} else if (type == QMetaType::Int) {
return v8::Integer::New(int(intValue));
} else if (type == QMetaType::UInt) {
diff --git a/src/declarative/qml/v8/qv8typewrapper.cpp b/src/declarative/qml/v8/qv8typewrapper.cpp
index 39d03dbeea..fe30670fc2 100644
--- a/src/declarative/qml/v8/qv8typewrapper.cpp
+++ b/src/declarative/qml/v8/qv8typewrapper.cpp
@@ -173,10 +173,12 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
return v8engine->typeWrapper()->newObject(object, d->type, resource->mode);
} else if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = typeNamespace->moduleApi()) {
- // XXX TODO: Currently module APIs are implemented against QScriptValues. Consequently we
- // can't do anything for script module apis here until the QtScript/V8 binding is complete.
- if (moduleApi->qobjectCallback) {
- moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), 0);
+ if (moduleApi->scriptCallback) {
+ moduleApi->scriptApi = moduleApi->scriptCallback(v8engine->engine(), v8engine->engine());
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ } else if (moduleApi->qobjectCallback) {
+ moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), v8engine->engine());
moduleApi->scriptCallback = 0;
moduleApi->qobjectCallback = 0;
}
@@ -225,10 +227,12 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
QV8QObjectWrapper::IgnoreRevision);
} else if (resource->typeNamespace) {
if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = resource->typeNamespace->moduleApi()) {
- // XXX TODO: Currently module APIs are implemented against QScriptValues. Consequently we
- // can't do anything for script module apis here until the QtScript/V8 binding is complete.
- if (moduleApi->qobjectCallback) {
- moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), 0);
+ if (moduleApi->scriptCallback) {
+ moduleApi->scriptApi = moduleApi->scriptCallback(v8engine->engine(), v8engine->engine());
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ } else if (moduleApi->qobjectCallback) {
+ moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), v8engine->engine());
moduleApi->scriptCallback = 0;
moduleApi->qobjectCallback = 0;
}
diff --git a/src/declarative/qml/v8/qv8variantwrapper.cpp b/src/declarative/qml/v8/qv8variantwrapper.cpp
index a5602fbbad..d4097d7f74 100644
--- a/src/declarative/qml/v8/qv8variantwrapper.cpp
+++ b/src/declarative/qml/v8/qv8variantwrapper.cpp
@@ -71,6 +71,7 @@ void QV8VariantWrapper::init(QV8Engine *engine)
{
m_engine = engine;
m_toString = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ToString)->GetFunction());
+ m_valueOf = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ValueOf)->GetFunction());
{
v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
@@ -80,6 +81,9 @@ void QV8VariantWrapper::init(QV8Engine *engine)
ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0,
m_toString, v8::DEFAULT,
v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("valueOf"), ValueOfGetter, 0,
+ m_valueOf, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
}
{
@@ -98,6 +102,9 @@ void QV8VariantWrapper::init(QV8Engine *engine)
ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0,
m_toString, v8::DEFAULT,
v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("valueOf"), ValueOfGetter, 0,
+ m_valueOf, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
m_scarceConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
}
@@ -105,6 +112,7 @@ void QV8VariantWrapper::init(QV8Engine *engine)
void QV8VariantWrapper::destroy()
{
+ qPersistentDispose(m_valueOf);
qPersistentDispose(m_toString);
qPersistentDispose(m_destroy);
qPersistentDispose(m_preserve);
@@ -185,6 +193,13 @@ v8::Handle<v8::Value> QV8VariantWrapper::ToStringGetter(v8::Local<v8::String> pr
return info.Data();
}
+v8::Handle<v8::Value> QV8VariantWrapper::ValueOfGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ return info.Data();
+}
+
v8::Handle<v8::Value> QV8VariantWrapper::Preserve(const v8::Arguments &args)
{
QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
@@ -217,4 +232,27 @@ v8::Handle<v8::Value> QV8VariantWrapper::ToString(const v8::Arguments &args)
}
}
+v8::Handle<v8::Value> QV8VariantWrapper::ValueOf(const v8::Arguments &args)
+{
+ QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
+ if (resource) {
+ QVariant v = resource->data;
+ switch (v.type()) {
+ case QVariant::Invalid:
+ return v8::Undefined();
+ case QVariant::String:
+ return resource->engine->toString(v.toString());
+ case QVariant::Int:
+ case QVariant::Double:
+ case QVariant::UInt:
+ return v8::Number::New(v.toDouble());
+ case QVariant::Bool:
+ return v8::Boolean::New(v.toBool());
+ default:
+ break;
+ }
+ }
+ return args.This();
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/v8/qv8variantwrapper_p.h b/src/declarative/qml/v8/qv8variantwrapper_p.h
index 9e165f37f4..de74bc9e12 100644
--- a/src/declarative/qml/v8/qv8variantwrapper_p.h
+++ b/src/declarative/qml/v8/qv8variantwrapper_p.h
@@ -87,9 +87,12 @@ private:
const v8::AccessorInfo &info);
static v8::Handle<v8::Value> ToStringGetter(v8::Local<v8::String> property,
const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> ValueOfGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
static v8::Handle<v8::Value> Preserve(const v8::Arguments &args);
static v8::Handle<v8::Value> Destroy(const v8::Arguments &args);
static v8::Handle<v8::Value> ToString(const v8::Arguments &args);
+ static v8::Handle<v8::Value> ValueOf(const v8::Arguments &args);
QV8Engine *m_engine;
v8::Persistent<v8::Function> m_constructor;
@@ -97,6 +100,7 @@ private:
v8::Persistent<v8::Function> m_preserve;
v8::Persistent<v8::Function> m_destroy;
v8::Persistent<v8::Function> m_toString;
+ v8::Persistent<v8::Function> m_valueOf;
};
QT_END_NAMESPACE
diff --git a/src/declarative/qml/v8/script.pri b/src/declarative/qml/v8/script.pri
new file mode 100644
index 0000000000..04a23d1f2b
--- /dev/null
+++ b/src/declarative/qml/v8/script.pri
@@ -0,0 +1,20 @@
+
+INCLUDEPATH += $$PWD
+
+SOURCES += \
+ $$PWD/qjsengine.cpp \
+ $$PWD/qjsvalue.cpp \
+ $$PWD/qjsvalueiterator.cpp \
+
+HEADERS += \
+ $$PWD/qjsengine.h \
+ $$PWD/qjsvalue.h \
+ $$PWD/qjsvalue_p.h \
+ $$PWD/qjsvalueiterator.h \
+ $$PWD/qjsvalue_impl_p.h \
+ $$PWD/qjsconverter_p.h \
+ $$PWD/qscriptisolate_p.h \
+ $$PWD/qscriptshareddata_p.h \
+ $$PWD/qscripttools_p.h \
+ $$PWD/qscript_impl_p.h \
+ $$PWD/qscriptoriginalglobalobject_p.h
diff --git a/src/declarative/qml/v8/v8.pri b/src/declarative/qml/v8/v8.pri
index 61e0184884..97b3d679df 100644
--- a/src/declarative/qml/v8/v8.pri
+++ b/src/declarative/qml/v8/v8.pri
@@ -1,6 +1,8 @@
INCLUDEPATH += $$PWD/../../../3rdparty/javascriptcore
INCLUDEPATH += $$PWD
+include(script.pri)
+
HEADERS += \
$$PWD/qv8_p.h \
$$PWD/qv8stringwrapper_p.h \
@@ -16,6 +18,7 @@ HEADERS += \
$$PWD/qv8worker_p.h \
$$PWD/qv8bindings_p.h \
$$PWD/../../../3rdparty/javascriptcore/DateMath.h \
+ $$PWD/qv8engine_impl_p.h
SOURCES += \
$$PWD/qv8stringwrapper.cpp \
@@ -31,4 +34,3 @@ SOURCES += \
$$PWD/qv8worker.cpp \
$$PWD/qv8bindings.cpp \
$$PWD/../../../3rdparty/javascriptcore/DateMath.cpp \
-
diff --git a/src/declarative/util/qdeclarativebind.cpp b/src/declarative/util/qdeclarativebind.cpp
index 6038aca8d5..726adf96d4 100644
--- a/src/declarative/util/qdeclarativebind.cpp
+++ b/src/declarative/util/qdeclarativebind.cpp
@@ -52,9 +52,8 @@
#include <QtCore/qfile.h>
#include <QtCore/qdebug.h>
-#include <QtScript/qscriptvalue.h>
-#include <QtScript/qscriptcontext.h>
-#include <QtScript/qscriptengine.h>
+#include <QtDeclarative/qjsvalue.h>
+#include <QtDeclarative/qjsengine.h>
#include <private/qobject_p.h>
diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp
index d1496fc886..035502140b 100644
--- a/src/declarative/util/qdeclarativelistmodel.cpp
+++ b/src/declarative/util/qdeclarativelistmodel.cpp
@@ -485,7 +485,7 @@ ModelObject *ModelNode::object(const NestedListModel *model)
{
if (!objectCache) {
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(qmlEngine(model->m_listModel));
- objectCache = new ModelObject(this, const_cast<NestedListModel*>(model), &ep->v8engine);
+ objectCache = new ModelObject(this, const_cast<NestedListModel*>(model), ep->v8engine());
QHash<QString, ModelNode *>::iterator it;
for (it = properties.begin(); it != properties.end(); ++it) {
@@ -1451,7 +1451,7 @@ v8::Handle<v8::Value> NestedListModel::get(int index) const
if (!node)
return v8::Undefined();;
- return QDeclarativeEnginePrivate::get(eng)->v8engine.newQObject(node->object(this));
+ return QDeclarativeEnginePrivate::get(eng)->v8engine()->newQObject(node->object(this));
}
void NestedListModel::set(int index, v8::Handle<v8::Value> valuemap, QList<int> *roles)
diff --git a/src/imports/folderlistmodel/folderlistmodel.pro b/src/imports/folderlistmodel/folderlistmodel.pro
index e55a5b2a29..31192fd764 100644
--- a/src/imports/folderlistmodel/folderlistmodel.pro
+++ b/src/imports/folderlistmodel/folderlistmodel.pro
@@ -2,7 +2,7 @@ TARGET = qmlfolderlistmodelplugin
TARGETPATH = Qt/labs/folderlistmodel
include(../qimportbase.pri)
-QT += declarative script
+QT += declarative
SOURCES += qdeclarativefolderlistmodel.cpp plugin.cpp
HEADERS += qdeclarativefolderlistmodel.h
diff --git a/src/imports/gestures/gestures.pro b/src/imports/gestures/gestures.pro
index 5c009dde51..d94b402f4c 100644
--- a/src/imports/gestures/gestures.pro
+++ b/src/imports/gestures/gestures.pro
@@ -2,7 +2,7 @@ TARGET = qmlgesturesplugin
TARGETPATH = Qt/labs/gestures
include(../qimportbase.pri)
-QT += core-private gui-private declarative-private script-private qtquick1 qtquick1-private
+QT += core-private gui-private declarative-private qtquick1 qtquick1-private
SOURCES += qdeclarativegesturearea.cpp plugin.cpp
HEADERS += qdeclarativegesturearea_p.h
diff --git a/src/imports/inputcontext/inputcontext.pro b/src/imports/inputcontext/inputcontext.pro
index 9c7ddf4e8b..cbad82c5b1 100755
--- a/src/imports/inputcontext/inputcontext.pro
+++ b/src/imports/inputcontext/inputcontext.pro
@@ -2,7 +2,7 @@ TARGET = qmlinputcontextplugin
TARGETPATH = Qt/labs/inputcontext
include(../qimportbase.pri)
-QT += declarative script
+QT += declarative
SOURCES += \
declarativeinputcontext.cpp \
diff --git a/src/imports/inputcontext/plugin.cpp b/src/imports/inputcontext/plugin.cpp
index 36de469f1f..5ce9e5b475 100644
--- a/src/imports/inputcontext/plugin.cpp
+++ b/src/imports/inputcontext/plugin.cpp
@@ -48,7 +48,7 @@
QT_BEGIN_NAMESPACE
-static QObject *createContext(QDeclarativeEngine *, QScriptEngine *)
+static QObject *createContext(QDeclarativeEngine *, QJSEngine *)
{
return new InputContextModule;
}
diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp
index 5781b3ddf1..db0a029a9a 100644
--- a/src/imports/testlib/main.cpp
+++ b/src/imports/testlib/main.cpp
@@ -41,10 +41,8 @@
#include <QtDeclarative/qdeclarativeextensionplugin.h>
#include <QtDeclarative/qdeclarative.h>
-#include <QtScript/qscriptvalue.h>
-#include <QtScript/qscriptcontext.h>
-#include <QtScript/qscriptcontextinfo.h>
-#include <QtScript/qscriptengine.h>
+#include <QtDeclarative/qjsvalue.h>
+#include <QtDeclarative/qjsengine.h>
#include "QtQuickTest/private/quicktestresult_p.h"
#include "QtQuickTest/private/quicktestevent_p.h"
#include "private/qtestoptions_p.h"
diff --git a/src/imports/testlib/testlib.pro b/src/imports/testlib/testlib.pro
index 9980a7551f..5adde2ae85 100644
--- a/src/imports/testlib/testlib.pro
+++ b/src/imports/testlib/testlib.pro
@@ -21,7 +21,7 @@ symbian {
}
-QT += declarative script qmltest qmltest-private declarative-private script-private core-private testlib
+QT += declarative qmltest qmltest-private declarative-private core-private testlib
SOURCES += main.cpp
HEADERS +=
diff --git a/src/qmltest/qmltest.pro b/src/qmltest/qmltest.pro
index 6e79be0b09..418136aa0a 100644
--- a/src/qmltest/qmltest.pro
+++ b/src/qmltest/qmltest.pro
@@ -7,7 +7,7 @@ CONFIG += module
CONFIG += dll warn_on
MODULE_PRI += ../../modules/qt_qmltest.pri
-QT += testlib-private declarative script testlib qtquick1
+QT += testlib-private declarative testlib qtquick1
DEFINES += QT_BUILD_QUICK_TEST_LIB QT_NO_URL_CAST_FROM_STRING
diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp
index a2c494513b..3f0c5325ed 100644
--- a/src/qmltest/quicktest.cpp
+++ b/src/qmltest/quicktest.cpp
@@ -52,9 +52,8 @@
#include <QtDeclarative/qsgview.h>
#define QUICK_TEST_SCENEGRAPH 1
#endif
-#include <QtScript/qscriptvalue.h>
-#include <QtScript/qscriptcontext.h>
-#include <QtScript/qscriptengine.h>
+#include <QtDeclarative/qjsvalue.h>
+#include <QtDeclarative/qjsengine.h>
#include <QtOpenGL/qgl.h>
#include <QtCore/qurl.h>
#include <QtCore/qfileinfo.h>
@@ -73,7 +72,7 @@ QT_BEGIN_NAMESPACE
class Q_DECLARATIVE_EXPORT QDeclarativeDebugHelper
{
public:
- static QScriptEngine *getScriptEngine(QDeclarativeEngine *engine);
+ static QJSEngine *getScriptEngine(QDeclarativeEngine *engine);
static void setAnimationSlowDownFactor(qreal factor);
static void enableDebugging();
};
diff --git a/src/qtquick1/graphicsitems/qdeclarativeitem.cpp b/src/qtquick1/graphicsitems/qdeclarativeitem.cpp
index d2bfc578dd..494ed46ad5 100644
--- a/src/qtquick1/graphicsitems/qdeclarativeitem.cpp
+++ b/src/qtquick1/graphicsitems/qdeclarativeitem.cpp
@@ -59,7 +59,7 @@
#include <QEvent>
#include <QGraphicsSceneMouseEvent>
#include <QtCore/qnumeric.h>
-#include <QtScript/qscriptengine.h>
+#include <QtDeclarative/qjsengine.h>
#include <QtGui/qgraphicstransform.h>
#include <private/qv8engine_p.h>
diff --git a/src/qtquick1/qtquick1.pro b/src/qtquick1/qtquick1.pro
index e3dd0298cd..7fc670f801 100644
--- a/src/qtquick1/qtquick1.pro
+++ b/src/qtquick1/qtquick1.pro
@@ -7,7 +7,7 @@ CONFIG += module
CONFIG += dll warn_on
MODULE_PRI += ../../modules/qt_qtquick1.pri
-QT += testlib-private declarative script testlib declarative-private core-private gui-private script-private network
+QT += testlib-private declarative testlib declarative-private core-private gui-private network
DEFINES += QT_NO_URL_CAST_FROM_STRING
load(qt_module_config)
diff --git a/src/qtquick1/util/qdeclarativebind.cpp b/src/qtquick1/util/qdeclarativebind.cpp
index f6463be05d..50514234a3 100644
--- a/src/qtquick1/util/qdeclarativebind.cpp
+++ b/src/qtquick1/util/qdeclarativebind.cpp
@@ -49,9 +49,8 @@
#include <QtCore/qfile.h>
#include <QtCore/qdebug.h>
-#include <QtScript/qscriptvalue.h>
-#include <QtScript/qscriptcontext.h>
-#include <QtScript/qscriptengine.h>
+#include <QtDeclarative/qjsvalue.h>
+#include <QtDeclarative/qjsengine.h>
#include <private/qobject_p.h>
diff --git a/src/qtquick1/util/qdeclarativelistmodel.cpp b/src/qtquick1/util/qdeclarativelistmodel.cpp
index 5d60ed9658..520d9ac388 100644
--- a/src/qtquick1/util/qdeclarativelistmodel.cpp
+++ b/src/qtquick1/util/qdeclarativelistmodel.cpp
@@ -52,7 +52,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qstack.h>
#include <QXmlStreamReader>
-#include <QtScript/qscriptvalueiterator.h>
+#include <QtDeclarative/qscriptvalueiterator.h>
Q_DECLARE_METATYPE(QListModelInterface *)
diff --git a/src/qtquick1/util/qdeclarativelistmodel_p.h b/src/qtquick1/util/qdeclarativelistmodel_p.h
index 21398f7213..1be5e6001a 100644
--- a/src/qtquick1/util/qdeclarativelistmodel_p.h
+++ b/src/qtquick1/util/qdeclarativelistmodel_p.h
@@ -51,7 +51,7 @@
#include <QtCore/QList>
#include <QtCore/QVariant>
#include <QtQuick1/private/qlistmodelinterface_p.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
QT_BEGIN_HEADER
diff --git a/src/qtquick1/util/qdeclarativelistmodel_p_p.h b/src/qtquick1/util/qdeclarativelistmodel_p_p.h
index e34f6d850d..ee39ba45b1 100644
--- a/src/qtquick1/util/qdeclarativelistmodel_p_p.h
+++ b/src/qtquick1/util/qdeclarativelistmodel_p_p.h
@@ -58,7 +58,7 @@
#include "QtQuick1/private/qdeclarativeopenmetaobject_p.h"
#include <QtDeclarative/qdeclarative.h>
-#include <QtScript/private/qscriptdeclarativeclass_p.h>
+#include <QtDeclarative/private/qscriptdeclarativeclass_p.h>
QT_BEGIN_HEADER
diff --git a/src/qtquick1/util/qdeclarativelistmodelworkeragent_p.h b/src/qtquick1/util/qdeclarativelistmodelworkeragent_p.h
index f0979c4b31..a769185607 100644
--- a/src/qtquick1/util/qdeclarativelistmodelworkeragent_p.h
+++ b/src/qtquick1/util/qdeclarativelistmodelworkeragent_p.h
@@ -55,7 +55,7 @@
#include <QtDeclarative/qdeclarative.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
#include <QtGui/qevent.h>
#include <QMutex>
#include <QWaitCondition>
diff --git a/src/qtquick1/util/qdeclarativeview.cpp b/src/qtquick1/util/qdeclarativeview.cpp
index 32f2183cad..d10d34fcd1 100644
--- a/src/qtquick1/util/qdeclarativeview.cpp
+++ b/src/qtquick1/util/qdeclarativeview.cpp
@@ -51,7 +51,6 @@
#include <QtDeclarative/private/qdeclarativedebugtrace_p.h>
#include <QtDeclarative/private/qdeclarativeinspectorservice_p.h>
-#include <qscriptvalueiterator.h>
#include <qdebug.h>
#include <qtimer.h>
#include <qevent.h>
diff --git a/src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch b/src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch
new file mode 100644
index 0000000000..6cd9294d31
--- /dev/null
+++ b/src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch
@@ -0,0 +1,286 @@
+From 5719ba59309e85f3ca47da6b64df66e710f3016f Mon Sep 17 00:00:00 2001
+From: "ager@chromium.org" <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
+Date: Wed, 4 May 2011 13:03:08 +0000
+Subject: [PATCH] Add CallAsFunction method to the Object class in the API
+
+Patch by Peter Varga.
+
+BUG=v8:1336
+TEST=cctest/test-api/CallAsFunction
+
+Review URL: http://codereview.chromium.org/6883045
+
+git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@7781 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
+---
+ include/v8.h | 8 +++
+ src/api.cc | 31 +++++++++++
+ src/execution.cc | 24 ++++++++
+ src/execution.h | 2 +
+ test/cctest/test-api.cc | 135 ++++++++++++++++++++++++++++++++++-------------
+ 5 files changed, 163 insertions(+), 37 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index 4dcbf28..78ee7e6 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -1606,6 +1606,14 @@ class Object : public Value {
+ V8EXPORT ExternalArrayType GetIndexedPropertiesExternalArrayDataType();
+ V8EXPORT int GetIndexedPropertiesExternalArrayDataLength();
+
++ /**
++ * Call an Object as a function if a callback is set by the
++ * ObjectTemplate::SetCallAsFunctionHandler method.
++ */
++ V8EXPORT Local<Value> CallAsFunction(Handle<Object> recv,
++ int argc,
++ Handle<Value> argv[]);
++
+ V8EXPORT static Local<Object> New();
+ static inline Object* Cast(Value* obj);
+ private:
+diff --git a/src/api.cc b/src/api.cc
+index 792e488..c72857d 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -3255,6 +3255,37 @@ int v8::Object::GetIndexedPropertiesExternalArrayDataLength() {
+ }
+
+
++Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc,
++ v8::Handle<v8::Value> argv[]) {
++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
++ ON_BAILOUT(isolate, "v8::Object::CallAsFunction()",
++ return Local<v8::Value>());
++ LOG_API(isolate, "Object::CallAsFunction");
++ ENTER_V8(isolate);
++ HandleScope scope;
++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
++ i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv);
++ STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
++ i::Object*** args = reinterpret_cast<i::Object***>(argv);
++ i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>();
++ if (obj->IsJSFunction()) {
++ fun = i::Handle<i::JSFunction>::cast(obj);
++ } else {
++ EXCEPTION_PREAMBLE(isolate);
++ i::Handle<i::Object> delegate =
++ i::Execution::TryGetFunctionDelegate(obj, &has_pending_exception);
++ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
++ fun = i::Handle<i::JSFunction>::cast(delegate);
++ recv_obj = obj;
++ }
++ EXCEPTION_PREAMBLE(isolate);
++ i::Handle<i::Object> returned =
++ i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception);
++ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
++ return scope.Close(Utils::ToLocal(returned));
++}
++
++
+ Local<v8::Object> Function::NewInstance() const {
+ return NewInstance(0, NULL);
+ }
+diff --git a/src/execution.cc b/src/execution.cc
+index eb26438..850dec5 100644
+--- a/src/execution.cc
++++ b/src/execution.cc
+@@ -234,6 +234,30 @@ Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) {
+ }
+
+
++Handle<Object> Execution::TryGetFunctionDelegate(Handle<Object> object,
++ bool* has_pending_exception) {
++ ASSERT(!object->IsJSFunction());
++ Isolate* isolate = Isolate::Current();
++
++ // Objects created through the API can have an instance-call handler
++ // that should be used when calling the object as a function.
++ if (object->IsHeapObject() &&
++ HeapObject::cast(*object)->map()->has_instance_call_handler()) {
++ return Handle<JSFunction>(
++ isolate->global_context()->call_as_function_delegate());
++ }
++
++ // If the Object doesn't have an instance-call handler we should
++ // throw a non-callable exception.
++ i::Handle<i::Object> error_obj = isolate->factory()->NewTypeError(
++ "called_non_callable", i::HandleVector<i::Object>(&object, 1));
++ isolate->Throw(*error_obj);
++ *has_pending_exception = true;
++
++ return isolate->factory()->undefined_value();
++}
++
++
+ Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) {
+ ASSERT(!object->IsJSFunction());
+ Isolate* isolate = Isolate::Current();
+diff --git a/src/execution.h b/src/execution.h
+index d4b80d2..e89d6ba 100644
+--- a/src/execution.h
++++ b/src/execution.h
+@@ -138,6 +138,8 @@ class Execution : public AllStatic {
+ // Get a function delegate (or undefined) for the given non-function
+ // object. Used for support calling objects as functions.
+ static Handle<Object> GetFunctionDelegate(Handle<Object> object);
++ static Handle<Object> TryGetFunctionDelegate(Handle<Object> object,
++ bool* has_pending_exception);
+
+ // Get a function delegate (or undefined) for the given non-function
+ // object. Used for support calling objects as constructors.
+diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
+index e2a7fb1..c6affe5 100644
+--- a/test/cctest/test-api.cc
++++ b/test/cctest/test-api.cc
+@@ -6962,50 +6962,111 @@ THREADED_TEST(CallAsFunction) {
+ v8::HandleScope scope;
+ LocalContext context;
+
+- Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+- Local<ObjectTemplate> instance_template = t->InstanceTemplate();
+- instance_template->SetCallAsFunctionHandler(call_as_function);
+- Local<v8::Object> instance = t->GetFunction()->NewInstance();
+- context->Global()->Set(v8_str("obj"), instance);
+- v8::TryCatch try_catch;
+- Local<Value> value;
+- CHECK(!try_catch.HasCaught());
++ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
++ Local<ObjectTemplate> instance_template = t->InstanceTemplate();
++ instance_template->SetCallAsFunctionHandler(call_as_function);
++ Local<v8::Object> instance = t->GetFunction()->NewInstance();
++ context->Global()->Set(v8_str("obj"), instance);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
+
+- value = CompileRun("obj(42)");
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(42, value->Int32Value());
++ value = CompileRun("obj(42)");
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(42, value->Int32Value());
+
+- value = CompileRun("(function(o){return o(49)})(obj)");
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(49, value->Int32Value());
++ value = CompileRun("(function(o){return o(49)})(obj)");
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(49, value->Int32Value());
+
+- // test special case of call as function
+- value = CompileRun("[obj]['0'](45)");
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(45, value->Int32Value());
++ // test special case of call as function
++ value = CompileRun("[obj]['0'](45)");
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(45, value->Int32Value());
+
+- value = CompileRun("obj.call = Function.prototype.call;"
+- "obj.call(null, 87)");
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(87, value->Int32Value());
++ value = CompileRun("obj.call = Function.prototype.call;"
++ "obj.call(null, 87)");
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(87, value->Int32Value());
+
+- // Regression tests for bug #1116356: Calling call through call/apply
+- // must work for non-function receivers.
+- const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
+- value = CompileRun(apply_99);
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(99, value->Int32Value());
++ // Regression tests for bug #1116356: Calling call through call/apply
++ // must work for non-function receivers.
++ const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
++ value = CompileRun(apply_99);
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(99, value->Int32Value());
+
+- const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
+- value = CompileRun(call_17);
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(17, value->Int32Value());
++ const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
++ value = CompileRun(call_17);
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(17, value->Int32Value());
+
+- // Check that the call-as-function handler can be called through
+- // new.
+- value = CompileRun("new obj(43)");
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(-43, value->Int32Value());
++ // Check that the call-as-function handler can be called through
++ // new.
++ value = CompileRun("new obj(43)");
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(-43, value->Int32Value());
++
++ // Check that the call-as-function handler can be called through
++ // the API.
++ v8::Handle<Value> args[] = { v8_num(28) };
++ value = instance->CallAsFunction(instance, 1, args);
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(28, value->Int32Value());
++ }
++
++ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
++ Local<ObjectTemplate> instance_template = t->InstanceTemplate();
++ Local<v8::Object> instance = t->GetFunction()->NewInstance();
++ context->Global()->Set(v8_str("obj2"), instance);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
++
++ // Call an object without call-as-function handler through the JS
++ value = CompileRun("obj2(28)");
++ CHECK(value.IsEmpty());
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value1(try_catch.Exception());
++ CHECK_EQ(*exception_value1,
++ "TypeError: Property 'obj2' of object "
++ "#<Object> is not a function");
++ try_catch.Reset();
++
++ // Call an object without call-as-function handler through the API
++ value = CompileRun("obj2(28)");
++ v8::Handle<Value> args[] = { v8_num(28) };
++ value = instance->CallAsFunction(instance, 1, args);
++ CHECK(value.IsEmpty());
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value2(try_catch.Exception());
++ CHECK_EQ(*exception_value2, "TypeError: [object Object] is not a function");
++ try_catch.Reset();
++ }
++
++ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
++ Local<ObjectTemplate> instance_template = t->InstanceTemplate();
++ instance_template->SetCallAsFunctionHandler(ThrowValue);
++ Local<v8::Object> instance = t->GetFunction()->NewInstance();
++ context->Global()->Set(v8_str("obj3"), instance);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
++
++ // Catch the exception which is thrown by call-as-function handler
++ value = CompileRun("obj3(22)");
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value1(try_catch.Exception());
++ CHECK_EQ(*exception_value1, "22");
++ try_catch.Reset();
++
++ v8::Handle<Value> args[] = { v8_num(23) };
++ value = instance->CallAsFunction(instance, 1, args);
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value2(try_catch.Exception());
++ CHECK_EQ(*exception_value2, "23");
++ try_catch.Reset();
++ }
+ }
+
+
+--
+1.7.5.4
+
diff --git a/src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch b/src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch
new file mode 100644
index 0000000000..7d90f0dfbd
--- /dev/null
+++ b/src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch
@@ -0,0 +1,397 @@
+From fd2cc52576e8c89f3dffc2b4b5a9cc9c48a96f32 Mon Sep 17 00:00:00 2001
+From: "ager@chromium.org" <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
+Date: Fri, 6 May 2011 11:07:52 +0000
+Subject: [PATCH] Implement CallAsConstructor method for Object in the API
+
+Patch by Peter Varga.
+
+BUG=v8:1348
+TEST=cctest/test-api/ConstructorForObject
+
+Review URL: http://codereview.chromium.org/6902108
+
+git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@7803 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
+---
+ include/v8.h | 8 ++
+ src/api.cc | 41 +++++++++-
+ src/execution.cc | 28 +++++++
+ src/execution.h | 2 +
+ test/cctest/test-api.cc | 205 +++++++++++++++++++++++++++++++++++++++++++++--
+ 5 files changed, 276 insertions(+), 8 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index 4921823..5fc8059 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -1614,6 +1614,14 @@ class Object : public Value {
+ int argc,
+ Handle<Value> argv[]);
+
++ /**
++ * Call an Object as a consturctor if a callback is set by the
++ * ObjectTemplate::SetCallAsFunctionHandler method.
++ * Note: This method behaves like the Function::NewInstance method.
++ */
++ V8EXPORT Local<Value> CallAsConstructor(int argc,
++ Handle<Value> argv[]);
++
+ V8EXPORT static Local<Object> New();
+ static inline Object* Cast(Value* obj);
+ private:
+diff --git a/src/api.cc b/src/api.cc
+index c5c66a7..9194641 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -3262,7 +3262,7 @@ Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc,
+ return Local<v8::Value>());
+ LOG_API(isolate, "Object::CallAsFunction");
+ ENTER_V8(isolate);
+- HandleScope scope;
++ i::HandleScope scope(isolate);
+ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv);
+ STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
+@@ -3282,7 +3282,44 @@ Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc,
+ i::Handle<i::Object> returned =
+ i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception);
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
+- return scope.Close(Utils::ToLocal(returned));
++ return Utils::ToLocal(scope.CloseAndEscape(returned));
++}
++
++
++Local<v8::Value> Object::CallAsConstructor(int argc,
++ v8::Handle<v8::Value> argv[]) {
++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
++ ON_BAILOUT(isolate, "v8::Object::CallAsConstructor()",
++ return Local<v8::Object>());
++ LOG_API(isolate, "Object::CallAsConstructor");
++ ENTER_V8(isolate);
++ i::HandleScope scope(isolate);
++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
++ STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
++ i::Object*** args = reinterpret_cast<i::Object***>(argv);
++ if (obj->IsJSFunction()) {
++ i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(obj);
++ EXCEPTION_PREAMBLE(isolate);
++ i::Handle<i::Object> returned =
++ i::Execution::New(fun, argc, args, &has_pending_exception);
++ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
++ return Utils::ToLocal(scope.CloseAndEscape(
++ i::Handle<i::JSObject>::cast(returned)));
++ }
++ EXCEPTION_PREAMBLE(isolate);
++ i::Handle<i::Object> delegate =
++ i::Execution::TryGetConstructorDelegate(obj, &has_pending_exception);
++ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
++ if (!delegate->IsUndefined()) {
++ i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(delegate);
++ EXCEPTION_PREAMBLE(isolate);
++ i::Handle<i::Object> returned =
++ i::Execution::Call(fun, obj, argc, args, &has_pending_exception);
++ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
++ ASSERT(!delegate->IsUndefined());
++ return Utils::ToLocal(scope.CloseAndEscape(returned));
++ }
++ return Local<v8::Object>();
+ }
+
+
+diff --git a/src/execution.cc b/src/execution.cc
+index 4ab3e78..db74492 100644
+--- a/src/execution.cc
++++ b/src/execution.cc
+@@ -277,6 +277,34 @@ Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) {
+ }
+
+
++Handle<Object> Execution::TryGetConstructorDelegate(
++ Handle<Object> object,
++ bool* has_pending_exception) {
++ ASSERT(!object->IsJSFunction());
++ Isolate* isolate = Isolate::Current();
++
++ // If you return a function from here, it will be called when an
++ // attempt is made to call the given object as a constructor.
++
++ // Objects created through the API can have an instance-call handler
++ // that should be used when calling the object as a function.
++ if (object->IsHeapObject() &&
++ HeapObject::cast(*object)->map()->has_instance_call_handler()) {
++ return Handle<JSFunction>(
++ isolate->global_context()->call_as_constructor_delegate());
++ }
++
++ // If the Object doesn't have an instance-call handler we should
++ // throw a non-callable exception.
++ i::Handle<i::Object> error_obj = isolate->factory()->NewTypeError(
++ "called_non_callable", i::HandleVector<i::Object>(&object, 1));
++ isolate->Throw(*error_obj);
++ *has_pending_exception = true;
++
++ return isolate->factory()->undefined_value();
++}
++
++
+ bool StackGuard::IsStackOverflow() {
+ ExecutionAccess access(isolate_);
+ return (thread_local_.jslimit_ != kInterruptLimit &&
+diff --git a/src/execution.h b/src/execution.h
+index 74189a2..7b6a48c 100644
+--- a/src/execution.h
++++ b/src/execution.h
+@@ -146,6 +146,8 @@ class Execution : public AllStatic {
+ // Get a function delegate (or undefined) for the given non-function
+ // object. Used for support calling objects as constructors.
+ static Handle<Object> GetConstructorDelegate(Handle<Object> object);
++ static Handle<Object> TryGetConstructorDelegate(Handle<Object> object,
++ bool* has_pending_exception);
+ };
+
+
+diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
+index 1bcc232..f48d5b4 100644
+--- a/test/cctest/test-api.cc
++++ b/test/cctest/test-api.cc
+@@ -6747,6 +6747,200 @@ THREADED_TEST(Constructor) {
+ CHECK(value->BooleanValue());
+ }
+
++
++static Handle<Value> ConstructorCallback(const Arguments& args) {
++ ApiTestFuzzer::Fuzz();
++ Local<Object> This;
++
++ if (args.IsConstructCall()) {
++ Local<Object> Holder = args.Holder();
++ This = Object::New();
++ Local<Value> proto = Holder->GetPrototype();
++ if (proto->IsObject()) {
++ This->SetPrototype(proto);
++ }
++ } else {
++ This = args.This();
++ }
++
++ This->Set(v8_str("a"), args[0]);
++ return This;
++}
++
++
++static Handle<Value> FakeConstructorCallback(const Arguments& args) {
++ ApiTestFuzzer::Fuzz();
++ return args[0];
++}
++
++
++THREADED_TEST(ConstructorForObject) {
++ v8::HandleScope handle_scope;
++ LocalContext context;
++
++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
++ instance_template->SetCallAsFunctionHandler(ConstructorCallback);
++ Local<Object> instance = instance_template->NewInstance();
++ context->Global()->Set(v8_str("obj"), instance);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
++
++ // Call the Object's constructor with a 32-bit signed integer.
++ value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsInt32());
++ CHECK_EQ(28, value->Int32Value());
++
++ Local<Value> args1[] = { v8_num(28) };
++ Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
++ CHECK(value_obj1->IsObject());
++ Local<Object> object1 = Local<Object>::Cast(value_obj1);
++ value = object1->Get(v8_str("a"));
++ CHECK(value->IsInt32());
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(28, value->Int32Value());
++
++ // Call the Object's constructor with a String.
++ value = CompileRun(
++ "(function() { var o = new obj('tipli'); return o.a; })()");
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsString());
++ String::AsciiValue string_value1(value->ToString());
++ CHECK_EQ("tipli", *string_value1);
++
++ Local<Value> args2[] = { v8_str("tipli") };
++ Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
++ CHECK(value_obj2->IsObject());
++ Local<Object> object2 = Local<Object>::Cast(value_obj2);
++ value = object2->Get(v8_str("a"));
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsString());
++ String::AsciiValue string_value2(value->ToString());
++ CHECK_EQ("tipli", *string_value2);
++
++ // Call the Object's constructor with a Boolean.
++ value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsBoolean());
++ CHECK_EQ(true, value->BooleanValue());
++
++ Handle<Value> args3[] = { v8::Boolean::New(true) };
++ Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
++ CHECK(value_obj3->IsObject());
++ Local<Object> object3 = Local<Object>::Cast(value_obj3);
++ value = object3->Get(v8_str("a"));
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsBoolean());
++ CHECK_EQ(true, value->BooleanValue());
++
++ // Call the Object's constructor with undefined.
++ Handle<Value> args4[] = { v8::Undefined() };
++ Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
++ CHECK(value_obj4->IsObject());
++ Local<Object> object4 = Local<Object>::Cast(value_obj4);
++ value = object4->Get(v8_str("a"));
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsUndefined());
++
++ // Call the Object's constructor with null.
++ Handle<Value> args5[] = { v8::Null() };
++ Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
++ CHECK(value_obj5->IsObject());
++ Local<Object> object5 = Local<Object>::Cast(value_obj5);
++ value = object5->Get(v8_str("a"));
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsNull());
++ }
++
++ // Check exception handling when there is no constructor set for the Object.
++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
++ Local<Object> instance = instance_template->NewInstance();
++ context->Global()->Set(v8_str("obj2"), instance);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
++
++ value = CompileRun("new obj2(28)");
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value1(try_catch.Exception());
++ CHECK_EQ("TypeError: object is not a function", *exception_value1);
++ try_catch.Reset();
++
++ Local<Value> args[] = { v8_num(29) };
++ value = instance->CallAsConstructor(1, args);
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value2(try_catch.Exception());
++ CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
++ try_catch.Reset();
++ }
++
++ // Check the case when constructor throws exception.
++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
++ instance_template->SetCallAsFunctionHandler(ThrowValue);
++ Local<Object> instance = instance_template->NewInstance();
++ context->Global()->Set(v8_str("obj3"), instance);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
++
++ value = CompileRun("new obj3(22)");
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value1(try_catch.Exception());
++ CHECK_EQ("22", *exception_value1);
++ try_catch.Reset();
++
++ Local<Value> args[] = { v8_num(23) };
++ value = instance->CallAsConstructor(1, args);
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value2(try_catch.Exception());
++ CHECK_EQ("23", *exception_value2);
++ try_catch.Reset();
++ }
++
++ // Check whether constructor returns with an object or non-object.
++ { Local<FunctionTemplate> function_template =
++ FunctionTemplate::New(FakeConstructorCallback);
++ Local<Function> function = function_template->GetFunction();
++ Local<Object> instance1 = function;
++ context->Global()->Set(v8_str("obj4"), instance1);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
++
++ CHECK(instance1->IsObject());
++ CHECK(instance1->IsFunction());
++
++ value = CompileRun("new obj4(28)");
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsObject());
++
++ Local<Value> args1[] = { v8_num(28) };
++ value = instance1->CallAsConstructor(1, args1);
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsObject());
++
++ Local<ObjectTemplate> instance_template = ObjectTemplate::New();
++ instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
++ Local<Object> instance2 = instance_template->NewInstance();
++ context->Global()->Set(v8_str("obj5"), instance2);
++ CHECK(!try_catch.HasCaught());
++
++ CHECK(instance2->IsObject());
++ CHECK(!instance2->IsFunction());
++
++ value = CompileRun("new obj5(28)");
++ CHECK(!try_catch.HasCaught());
++ CHECK(!value->IsObject());
++
++ Local<Value> args2[] = { v8_num(28) };
++ value = instance2->CallAsConstructor(1, args2);
++ CHECK(!try_catch.HasCaught());
++ CHECK(!value->IsObject());
++ }
++}
++
++
+ THREADED_TEST(FunctionDescriptorException) {
+ v8::HandleScope handle_scope;
+ LocalContext context;
+@@ -7029,9 +7223,8 @@ THREADED_TEST(CallAsFunction) {
+ CHECK(value.IsEmpty());
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value1(try_catch.Exception());
+- CHECK_EQ(*exception_value1,
+- "TypeError: Property 'obj2' of object "
+- "#<Object> is not a function");
++ CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
++ *exception_value1);
+ try_catch.Reset();
+
+ // Call an object without call-as-function handler through the API
+@@ -7041,7 +7234,7 @@ THREADED_TEST(CallAsFunction) {
+ CHECK(value.IsEmpty());
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value2(try_catch.Exception());
+- CHECK_EQ(*exception_value2, "TypeError: [object Object] is not a function");
++ CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
+ try_catch.Reset();
+ }
+
+@@ -7058,14 +7251,14 @@ THREADED_TEST(CallAsFunction) {
+ value = CompileRun("obj3(22)");
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value1(try_catch.Exception());
+- CHECK_EQ(*exception_value1, "22");
++ CHECK_EQ("22", *exception_value1);
+ try_catch.Reset();
+
+ v8::Handle<Value> args[] = { v8_num(23) };
+ value = instance->CallAsFunction(instance, 1, args);
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value2(try_catch.Exception());
+- CHECK_EQ(*exception_value2, "23");
++ CHECK_EQ("23", *exception_value2);
+ try_catch.Reset();
+ }
+ }
+--
+1.7.5.4
+
diff --git a/src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch b/src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch
new file mode 100644
index 0000000000..0558ce19f6
--- /dev/null
+++ b/src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch
@@ -0,0 +1,63 @@
+From 859c452847317efe1131e337fcd51514de616ea2 Mon Sep 17 00:00:00 2001
+From: Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
+Date: Tue, 7 Dec 2010 11:56:42 +0100
+Subject: [PATCH] QtScript/V8: Add new v8 api to check if a value is an error.
+
+New function v8::Value::IsError was created.
+
+This API is experimental and added only for the purposes of our
+research.
+---
+ include/v8.h | 5 +++++
+ src/api.cc | 6 ++++++
+ src/heap.h | 1 +
+ 3 files changed, 12 insertions(+), 0 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index 303cb7a..f992cb2 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -937,6 +937,11 @@ class Value : public Data {
+ */
+ V8EXPORT bool IsRegExp() const;
+
++ /**
++ * Returns true if this value is an Error.
++ */
++ V8EXPORT bool IsError() const;
++
+ V8EXPORT Local<Boolean> ToBoolean() const;
+ V8EXPORT Local<Number> ToNumber() const;
+ V8EXPORT Local<String> ToString() const;
+diff --git a/src/api.cc b/src/api.cc
+index fd4a76b..5ada246 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -2108,6 +2108,12 @@ bool Value::IsRegExp() const {
+ return obj->IsJSRegExp();
+ }
+
++bool Value::IsError() const {
++ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsError()")) return false;
++ i::Handle<i::Object> obj = Utils::OpenHandle(this);
++ return obj->HasSpecificClassOf(HEAP->Error_symbol());
++}
++
+
+ Local<String> Value::ToString() const {
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+diff --git a/src/heap.h b/src/heap.h
+index 8cbf378..db90bb9 100644
+--- a/src/heap.h
++++ b/src/heap.h
+@@ -169,6 +169,7 @@ inline Heap* _inline_get_heap_();
+ V(string_symbol, "string") \
+ V(String_symbol, "String") \
+ V(Date_symbol, "Date") \
++ V(Error_symbol, "Error") \
+ V(this_symbol, "this") \
+ V(to_string_symbol, "toString") \
+ V(char_at_symbol, "CharAt") \
+--
+1.7.4.15.g7811d
+
diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro
index 43a2a682de..a99656a3ee 100644
--- a/tests/auto/declarative/declarative.pro
+++ b/tests/auto/declarative/declarative.pro
@@ -20,7 +20,10 @@ PUBLICTESTS += \
qdeclarativepixmapcache \
qdeclarativeqt \
qdeclarativetranslation \
- qdeclarativexmlhttprequest
+ qdeclarativexmlhttprequest \
+ qjsvalue \
+ qjsvalueiterator \
+ qjsengine
PRIVATETESTS += \
qdeclarativeanimations \
diff --git a/tests/auto/declarative/qdeclarativecomponent/qdeclarativecomponent.pro b/tests/auto/declarative/qdeclarativecomponent/qdeclarativecomponent.pro
index 7109f2da65..50d63fea42 100644
--- a/tests/auto/declarative/qdeclarativecomponent/qdeclarativecomponent.pro
+++ b/tests/auto/declarative/qdeclarativecomponent/qdeclarativecomponent.pro
@@ -1,6 +1,6 @@
load(qttest_p4)
contains(QT_CONFIG,declarative): QT += declarative
-QT += script network
+QT += network
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativecomponent.cpp
diff --git a/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro b/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro
index 564b088817..49150c8481 100644
--- a/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro
+++ b/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private opengl-private
+QT += core-private gui-private declarative-private opengl-private
diff --git a/tests/auto/declarative/qdeclarativedebug/qdeclarativedebug.pro b/tests/auto/declarative/qdeclarativedebug/qdeclarativedebug.pro
index 430224e1e8..cd5577219d 100644
--- a/tests/auto/declarative/qdeclarativedebug/qdeclarativedebug.pro
+++ b/tests/auto/declarative/qdeclarativedebug/qdeclarativedebug.pro
@@ -8,4 +8,4 @@ SOURCES += tst_qdeclarativedebug.cpp \
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativedebugclient/qdeclarativedebugclient.pro b/tests/auto/declarative/qdeclarativedebugclient/qdeclarativedebugclient.pro
index 880255b6b2..189133a526 100644
--- a/tests/auto/declarative/qdeclarativedebugclient/qdeclarativedebugclient.pro
+++ b/tests/auto/declarative/qdeclarativedebugclient/qdeclarativedebugclient.pro
@@ -5,4 +5,4 @@ macx:CONFIG -= app_bundle
HEADERS += ../shared/debugutil_p.h
SOURCES += tst_qdeclarativedebugclient.cpp \
../shared/debugutil.cpp
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativedebughelper/private_headers/qdeclarativedebughelper_p.h b/tests/auto/declarative/qdeclarativedebughelper/private_headers/qdeclarativedebughelper_p.h
index 84956d0bb7..c08f6fd639 100644
--- a/tests/auto/declarative/qdeclarativedebughelper/private_headers/qdeclarativedebughelper_p.h
+++ b/tests/auto/declarative/qdeclarativedebughelper/private_headers/qdeclarativedebughelper_p.h
@@ -48,7 +48,7 @@ QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
-class QScriptEngine;
+class QJSEngine;
class QDeclarativeEngine;
// Helper methods to access private API through a stable interface
@@ -56,7 +56,7 @@ class QDeclarativeEngine;
class Q_DECLARATIVE_EXPORT QDeclarativeDebugHelper
{
public:
- static QScriptEngine *getScriptEngine(QDeclarativeEngine *engine);
+ static QJSEngine *getScriptEngine(QDeclarativeEngine *engine);
static void setAnimationSlowDownFactor(qreal factor);
// Enables remote debugging functionality
diff --git a/tests/auto/declarative/qdeclarativedebughelper/qdeclarativedebughelper.pro b/tests/auto/declarative/qdeclarativedebughelper/qdeclarativedebughelper.pro
index e9e8e73319..1e62c12363 100644
--- a/tests/auto/declarative/qdeclarativedebughelper/qdeclarativedebughelper.pro
+++ b/tests/auto/declarative/qdeclarativedebughelper/qdeclarativedebughelper.pro
@@ -1,6 +1,6 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += network declarative script
+contains(QT_CONFIG,declarative): QT += network declarative
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativedebughelper.cpp
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativedebugservice/qdeclarativedebugservice.pro b/tests/auto/declarative/qdeclarativedebugservice/qdeclarativedebugservice.pro
index 55ddeb28a3..785e8a7bf1 100644
--- a/tests/auto/declarative/qdeclarativedebugservice/qdeclarativedebugservice.pro
+++ b/tests/auto/declarative/qdeclarativedebugservice/qdeclarativedebugservice.pro
@@ -8,4 +8,4 @@ SOURCES += tst_qdeclarativedebugservice.cpp \
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro b/tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro
index 03834ed428..4b7aff339c 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro
+++ b/tests/auto/declarative/qdeclarativeecmascript/qdeclarativeecmascript.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script network
+contains(QT_CONFIG,declarative): QT += declarative network
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativeecmascript.cpp \
@@ -22,4 +22,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp
index ea8d2c01c7..160a57215b 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp
@@ -42,7 +42,7 @@
#include <QWidget>
#include <QPlainTextEdit>
#include <QDeclarativeEngine>
-#include <QScriptEngine>
+#include <QJSEngine>
class BaseExtensionObject : public QObject
{
@@ -101,17 +101,17 @@ public:
void setWidth(int) { }
};
-static QScriptValue script_api(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+static QJSValue script_api(QDeclarativeEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
static int testProperty = 13;
- QScriptValue v = scriptEngine->newObject();
+ QJSValue v = scriptEngine->newObject();
v.setProperty("scriptTestProperty", testProperty++);
return v;
}
-static QObject *qobject_api(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+static QObject *qobject_api(QDeclarativeEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
@@ -122,7 +122,7 @@ static QObject *qobject_api(QDeclarativeEngine *engine, QScriptEngine *scriptEng
return o;
}
-static QObject *qobject_api_engine_parent(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+static QObject *qobject_api_engine_parent(QDeclarativeEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(scriptEngine)
diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
index aebfb22b7c..afb361e2d7 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
+++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
@@ -53,7 +53,7 @@
#include <QtGui/qvector3d.h>
#include <QtGui/QPixmap>
#include <QtCore/qdatetime.h>
-#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qjsvalue.h>
#include <QtDeclarative/qdeclarativescriptstring.h>
#include <QtDeclarative/qdeclarativecomponent.h>
@@ -581,7 +581,7 @@ public:
}
};
-Q_DECLARE_METATYPE(QScriptValue);
+Q_DECLARE_METATYPE(QJSValue);
class MyInvokableBaseObject : public QObject
{
Q_OBJECT
@@ -614,7 +614,7 @@ public:
Q_INVOKABLE QPointF method_NoArgs_QPointF() { invoke(3); return QPointF(123, 4.5); }
Q_INVOKABLE QObject *method_NoArgs_QObject() { invoke(4); return this; }
Q_INVOKABLE MyInvokableObject *method_NoArgs_unknown() { invoke(5); return this; }
- Q_INVOKABLE QScriptValue method_NoArgs_QScriptValue() { invoke(6); return QScriptValue("Hello world"); }
+ Q_INVOKABLE QJSValue method_NoArgs_QScriptValue() { invoke(6); return QJSValue("Hello world"); }
Q_INVOKABLE QVariant method_NoArgs_QVariant() { invoke(7); return QVariant("QML rocks"); }
Q_INVOKABLE void method_int(int a) { invoke(8); m_actuals << a; }
@@ -623,8 +623,8 @@ public:
Q_INVOKABLE void method_QString(QString a) { invoke(11); m_actuals << a; }
Q_INVOKABLE void method_QPointF(QPointF a) { invoke(12); m_actuals << a; }
Q_INVOKABLE void method_QObject(QObject *a) { invoke(13); m_actuals << qVariantFromValue(a); }
- Q_INVOKABLE void method_QScriptValue(QScriptValue a) { invoke(14); m_actuals << qVariantFromValue(a); }
- Q_INVOKABLE void method_intQScriptValue(int a, QScriptValue b) { invoke(15); m_actuals << a << qVariantFromValue(b); }
+ Q_INVOKABLE void method_QScriptValue(QJSValue a) { invoke(14); m_actuals << qVariantFromValue(a); }
+ Q_INVOKABLE void method_intQScriptValue(int a, QJSValue b) { invoke(15); m_actuals << a << qVariantFromValue(b); }
Q_INVOKABLE void method_overload(int a) { invoke(16); m_actuals << a; }
Q_INVOKABLE void method_overload(int a, int b) { invoke(17); m_actuals << a << b; }
diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
index b1bc5bda2b..6c629a80f7 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
@@ -49,7 +49,6 @@
#include <QtCore/qdir.h>
#include <QtCore/qnumeric.h>
#include <private/qdeclarativeengine_p.h>
-#include <private/qscriptdeclarativeclass_p.h>
#include "testtypes.h"
#include "testhttpserver.h"
#include "../../../shared/util.h"
@@ -1600,7 +1599,7 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QDeclarativeEngine qmlengine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
- QV8Engine *engine = &ep->v8engine;
+ QV8Engine *engine = ep->v8engine();
v8::HandleScope handle_scope;
v8::Context::Scope scope(engine->context());
@@ -1693,8 +1692,6 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.invoked(), 5);
QCOMPARE(o.actuals().count(), 0);
- // XXX enable once qml/qtscript integration is implemented
-#if 0
o.reset();
{
v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
@@ -1704,7 +1701,6 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.invoked(), 6);
QCOMPARE(o.actuals().count(), 0);
}
-#endif
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
@@ -1920,35 +1916,33 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
- // XXX enable once qml/qtscript integration is implemented
-#if 0
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 14);
QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isNull());
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 14);
QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isUndefined());
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 14);
QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).strictlyEquals(QScriptValue(engine, 19)));
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 14);
QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isArray());
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
@@ -1956,7 +1950,7 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.invoked(), 15);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(0), QVariant(4));
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isNull());
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
@@ -1964,7 +1958,7 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.invoked(), 15);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(0), QVariant(8));
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isUndefined());
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
@@ -1972,7 +1966,7 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.invoked(), 15);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(0), QVariant(3));
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).strictlyEquals(QScriptValue(engine, 19)));
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
o.reset();
QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
@@ -1980,8 +1974,7 @@ void tst_qdeclarativeecmascript::callQtInvokables()
QCOMPARE(o.invoked(), 15);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(0), QVariant(44));
- QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isArray());
-#endif
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
o.reset();
QVERIFY(EVALUATE_ERROR("object.method_overload()"));
diff --git a/tests/auto/declarative/qdeclarativeinstruction/qdeclarativeinstruction.pro b/tests/auto/declarative/qdeclarativeinstruction/qdeclarativeinstruction.pro
index a3ca541485..a4cdd81266 100644
--- a/tests/auto/declarative/qdeclarativeinstruction/qdeclarativeinstruction.pro
+++ b/tests/auto/declarative/qdeclarativeinstruction/qdeclarativeinstruction.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script
+contains(QT_CONFIG,declarative): QT += declarative
SOURCES += tst_qdeclarativeinstruction.cpp
macx:CONFIG -= app_bundle
@@ -9,4 +9,4 @@ macx:CONFIG -= app_bundle
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro b/tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro
index 88dc6128ed..71d2066608 100644
--- a/tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro
+++ b/tests/auto/declarative/qdeclarativelanguage/qdeclarativelanguage.pro
@@ -1,6 +1,6 @@
load(qttest_p4)
contains(QT_CONFIG,declarative): QT += declarative
-QT += script network
+QT += network
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativelanguage.cpp \
@@ -20,4 +20,4 @@ symbian: {
}
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro b/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro
index 85340e70e6..83ea7992ed 100644
--- a/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro
+++ b/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro
@@ -1,6 +1,5 @@
load(qttest_p4)
contains(QT_CONFIG,declarative): QT += declarative
-QT += script
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativelistmodel.cpp
@@ -15,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private opengl-private
+QT += core-private gui-private declarative-private opengl-private
diff --git a/tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro b/tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro
index d96b26aee9..fd55ed5160 100644
--- a/tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro
+++ b/tests/auto/declarative/qdeclarativeproperty/qdeclarativeproperty.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro b/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro
index cd9dabf3bd..304e168e00 100644
--- a/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro
+++ b/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script
+contains(QT_CONFIG,declarative): QT += declarative
SOURCES += tst_qdeclarativeqt.cpp
macx:CONFIG -= app_bundle
@@ -16,4 +16,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro b/tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro
index 9187bea10b..cedb92743e 100644
--- a/tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro
+++ b/tests/auto/declarative/qdeclarativescriptdebugging/qdeclarativescriptdebugging.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script
+contains(QT_CONFIG,declarative): QT += declarative
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativescriptdebugging.cpp
@@ -18,4 +18,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro b/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro
index 5bc4261a28..c8f8e9139b 100644
--- a/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro
+++ b/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro b/tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro
index 9885c6521e..f2b5928915 100644
--- a/tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro
+++ b/tests/auto/declarative/qdeclarativespringanimation/qdeclarativespringanimation.pro
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro b/tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro
index c48cdf7b55..a51eaf34de 100644
--- a/tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro
+++ b/tests/auto/declarative/qdeclarativesqldatabase/qdeclarativesqldatabase.pro
@@ -1,6 +1,6 @@
load(qttest_p4)
contains(QT_CONFIG,declarative): QT += declarative
-QT += sql script
+QT += sql
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativesqldatabase.cpp
@@ -15,4 +15,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro b/tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro
index c34b8d8319..9823c21836 100644
--- a/tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro
+++ b/tests/auto/declarative/qdeclarativestates/qdeclarativestates.pro
@@ -13,4 +13,4 @@ symbian: {
}
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private opengl-private
+QT += core-private gui-private declarative-private opengl-private
diff --git a/tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro b/tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro
index 0a2005d15d..9b66edff41 100644
--- a/tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro
+++ b/tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script network
+contains(QT_CONFIG,declarative): QT += declarative network
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativev4.cpp \
@@ -16,4 +16,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro b/tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro
index f5567e96ed..f1c64398e9 100644
--- a/tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro
+++ b/tests/auto/declarative/qdeclarativevaluetypes/qdeclarativevaluetypes.pro
@@ -17,4 +17,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro b/tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro
index 08ae7c164c..d7dfe96c65 100644
--- a/tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro
+++ b/tests/auto/declarative/qdeclarativeworkerscript/qdeclarativeworkerscript.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script
+contains(QT_CONFIG,declarative): QT += declarative
macx:CONFIG -= app_bundle
SOURCES += tst_qdeclarativeworkerscript.cpp
@@ -14,4 +14,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp
index cbf152bf8b..5e67360e15 100644
--- a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp
+++ b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp
@@ -43,7 +43,7 @@
#include <QtCore/qtimer.h>
#include <QtCore/qdir.h>
#include <QtCore/qfileinfo.h>
-#include <QtScript/qscriptengine.h>
+#include <QtDeclarative/qjsengine.h>
#include <QtDeclarative/qdeclarativecomponent.h>
#include <QtDeclarative/qdeclarativeengine.h>
diff --git a/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro b/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro
index bedd0a4602..139d4b4e0b 100644
--- a/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro
+++ b/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative script gui network
+contains(QT_CONFIG,declarative): QT += declarative gui network
contains(QT_CONFIG,xmlpatterns) {
QT += xmlpatterns
DEFINES += QTEST_XMLPATTERNS
@@ -18,4 +18,4 @@ symbian: {
CONFIG += parallel_test
-QT += core-private gui-private declarative-private script-private
+QT += core-private gui-private declarative-private
diff --git a/tests/auto/declarative/qjsengine/qjsengine.pro b/tests/auto/declarative/qjsengine/qjsengine.pro
new file mode 100644
index 0000000000..87e52ce25d
--- /dev/null
+++ b/tests/auto/declarative/qjsengine/qjsengine.pro
@@ -0,0 +1,21 @@
+load(qttest_p4)
+QT += declarative
+macx:CONFIG -= app_bundle
+SOURCES += tst_qjsengine.cpp
+
+wince* {
+ DEFINES += SRCDIR=\\\"./\\\"
+} else:!symbian {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+wince*|symbian: {
+ addFiles.files = script
+ addFiles.path = .
+ DEPLOYMENT += addFiles
+}
+
+symbian: {
+ TARGET.UID3 = 0xE0340006
+ DEFINES += SYMBIAN_SRCDIR_UID=$$lower($$replace(TARGET.UID3,"0x",""))
+}
diff --git a/tests/auto/declarative/qjsengine/script/com/__init__.js b/tests/auto/declarative/qjsengine/script/com/__init__.js
new file mode 100644
index 0000000000..7db3ee4cac
--- /dev/null
+++ b/tests/auto/declarative/qjsengine/script/com/__init__.js
@@ -0,0 +1,9 @@
+var wasDefinedAlready = (this["com"] != undefined);
+__setupPackage__("com");
+com.wasDefinedAlready = wasDefinedAlready;
+com.name = __extension__;
+com.level = 1;
+
+com.postInitCallCount = 0;
+com.originalPostInit = __postInit__;
+__postInit__ = function() { ++com.postInitCallCount; };
diff --git a/tests/auto/declarative/qjsengine/script/com/trolltech/__init__.js b/tests/auto/declarative/qjsengine/script/com/trolltech/__init__.js
new file mode 100644
index 0000000000..a55b1328ba
--- /dev/null
+++ b/tests/auto/declarative/qjsengine/script/com/trolltech/__init__.js
@@ -0,0 +1,9 @@
+var wasDefinedAlready = (com["trolltech"] != undefined);
+__setupPackage__("com.trolltech");
+com.trolltech.wasDefinedAlready = wasDefinedAlready;
+com.trolltech.name = __extension__;
+com.trolltech.level = com.level + 1;
+
+com.trolltech.postInitCallCount = 0;
+com.trolltech.originalPostInit = __postInit__;
+__postInit__ = function() { ++com.trolltech.postInitCallCount; };
diff --git a/tests/auto/declarative/qjsengine/script/com/trolltech/recursive/__init__.js b/tests/auto/declarative/qjsengine/script/com/trolltech/recursive/__init__.js
new file mode 100644
index 0000000000..2f4cad48da
--- /dev/null
+++ b/tests/auto/declarative/qjsengine/script/com/trolltech/recursive/__init__.js
@@ -0,0 +1 @@
+__import__("com.trolltech.recursive");
diff --git a/tests/auto/declarative/qjsengine/script/com/trolltech/syntaxerror/__init__.js b/tests/auto/declarative/qjsengine/script/com/trolltech/syntaxerror/__init__.js
new file mode 100644
index 0000000000..55bc35b5f2
--- /dev/null
+++ b/tests/auto/declarative/qjsengine/script/com/trolltech/syntaxerror/__init__.js
@@ -0,0 +1,5 @@
+function () {
+}
+
+0 = 1;
+
diff --git a/tests/auto/declarative/qjsengine/tst_qjsengine.cpp b/tests/auto/declarative/qjsengine/tst_qjsengine.cpp
new file mode 100644
index 0000000000..49febdbf5e
--- /dev/null
+++ b/tests/auto/declarative/qjsengine/tst_qjsengine.cpp
@@ -0,0 +1,6491 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qjsengine.h>
+#include <qgraphicsitem.h>
+#include <qstandarditemmodel.h>
+#include <QtCore/qnumeric.h>
+#include <stdlib.h>
+
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QObjectList)
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+#if defined(Q_OS_SYMBIAN)
+# define STRINGIFY(x) #x
+# define TOSTRING(x) STRINGIFY(x)
+# define SRCDIR "C:/Private/" TOSTRING(SYMBIAN_SRCDIR_UID)
+#endif
+
+// The JavaScriptCore GC marks the C stack. To try to ensure that there is
+// no JSObject* left in stack memory by the compiler, we call this function
+// to zap some bytes of memory before calling collectGarbage().
+static void zapSomeStack()
+{
+ char buf[4096];
+ memset(buf, 0, sizeof(buf));
+}
+
+static void collectGarbage_helper(QJSEngine &eng)
+{
+ zapSomeStack();
+ eng.collectGarbage();
+}
+
+class tst_QJSEngine : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QJSEngine();
+ virtual ~tst_QJSEngine();
+
+private slots:
+ void constructWithParent();
+#if 0 // FIXME: no QScriptContext
+ void currentContext();
+ void pushPopContext();
+#endif
+#if 0 // FIXME: No prototype API in QScriptEngine
+ void getSetDefaultPrototype_int();
+ void getSetDefaultPrototype_customType();
+#endif
+#if 0 // FIXME: no QScriptContext
+ void newFunction();
+ void newFunctionWithArg();
+ void newFunctionWithProto();
+#endif
+ void newObject();
+ void newArray();
+ void newArray_HooliganTask218092();
+ void newArray_HooliganTask233836();
+ void newVariant();
+#if 0 // FIXME: No prototype API in QScriptEngine
+ void newVariant_defaultPrototype();
+#endif
+#if 0 // ###FIXME: No QVariant object promotion API
+ void newVariant_promoteObject();
+ void newVariant_replaceValue();
+#endif
+ void newVariant_valueOfToString();
+#if 0 // ###FIXME: No QVariant object promotion API
+ void newVariant_promoteNonObject();
+ void newVariant_promoteNonQScriptObject();
+#endif
+ void newRegExp();
+ void jsRegExp();
+ void newDate();
+ void jsParseDate();
+ void newQObject();
+ void newQObject_ownership();
+ void newQObject_promoteObject();
+ void newQObject_sameQObject();
+#if 0 // FIXME: No prototype API in QScriptEngine
+ void newQObject_defaultPrototype();
+#endif
+ void newQObject_promoteNonObject();
+ void newQObject_promoteNonQScriptObject();
+#if 0 // ### FIXME: No QScript Metaobject support right now
+ void newQMetaObject();
+ void newActivationObject();
+#endif
+#if 0 // ###FIXME: No setGlobalObject support - yay
+ void getSetGlobalObjectSimple();
+ void getSetGlobalObject();
+#endif
+ void globalObjectProperties();
+ void globalObjectEquals();
+#if 0 // ###FIXME: No QScriptValueIterator API
+ void globalObjectProperties_enumerate();
+#endif
+ void createGlobalObjectProperty();
+ void globalObjectGetterSetterProperty();
+#if 0 // ###FIXME: No support for setting the global object
+ void customGlobalObjectWithPrototype();
+#endif
+ void globalObjectWithCustomPrototype();
+ void builtinFunctionNames_data();
+ void builtinFunctionNames();
+#if 0 // ###FIXME: No syntax checking result
+ void checkSyntax_data();
+ void checkSyntax();
+#endif
+#if 0 // ###FIXME: No support for canEvaluate
+ void canEvaluate_data();
+ void canEvaluate();
+#endif
+ void evaluate_data();
+ void evaluate();
+#if 0 // ###FIXME: no support for c-style callbacks
+ void nestedEvaluate();
+#endif
+#if 0 // ### FIXME: No c-style callbacks
+ void uncaughtException();
+#endif
+ void errorMessage_QT679();
+ void valueConversion_basic();
+#if 0 // FIXME: No API for custom types
+ void valueConversion_customType();
+ void valueConversion_sequence();
+#endif
+ void valueConversion_QVariant();
+#if 0 // FIXME: No support for custom types
+ void valueConversion_hooliganTask248802();
+#endif
+ void valueConversion_basic2();
+ void valueConversion_dateTime();
+ void valueConversion_regExp();
+#if 0 // FIXME: No qScriptValueFromValue
+ void qScriptValueFromValue_noEngine();
+#endif
+#if 0 // ###FIXME: No QScriptContext
+ void importExtension();
+ void infiniteRecursion();
+#endif
+#if 0 // FIXME: No support for default prototypes
+ void castWithPrototypeChain();
+#endif
+ void castWithMultipleInheritance();
+#if 0 // ###FIXME: ScriptOwnership
+ void collectGarbage();
+#endif
+#if 0 // ###FIXME: no reportAdditionalMemoryCost API
+ void reportAdditionalMemoryCost();
+#endif
+ void gcWithNestedDataStructure();
+#if 0 // ###FIXME: No processEvents handling
+ void processEventsWhileRunning();
+ void processEventsWhileRunning_function();
+ void throwErrorFromProcessEvents_data();
+ void throwErrorFromProcessEvents();
+ void disableProcessEventsInterval();
+#endif
+#if 0 // ###FIXME: No QScriptValueIterator API
+ void stacktrace();
+#endif
+ void numberParsing_data();
+ void numberParsing();
+ void automaticSemicolonInsertion();
+#if 0 // ###FIXME: no abortEvaluation API
+ void abortEvaluation_notEvaluating();
+ void abortEvaluation_data();
+ void abortEvaluation();
+ void abortEvaluation_tryCatch();
+ void abortEvaluation_fromNative();
+ void abortEvaluation_QTBUG9433();
+#endif
+#if 0 // ###FIXME: no QScriptEngine::isEvaluating
+ void isEvaluating_notEvaluating();
+ void isEvaluating_fromNative();
+ void isEvaluating_fromEvent();
+#endif
+#if 0 // ###FIXME: depracated
+ void printFunctionWithCustomHandler();
+ void printThrowsException();
+#endif
+ void errorConstructors();
+ void argumentsProperty_globalContext();
+ void argumentsProperty_JS();
+#if 0 // ###FIXME: no QScriptContext API
+ void argumentsProperty_evaluateInNativeFunction();
+#endif
+ void jsNumberClass();
+ void jsForInStatement_simple();
+ void jsForInStatement_prototypeProperties();
+ void jsForInStatement_mutateWhileIterating();
+ void jsForInStatement_arrays();
+ void jsForInStatement_nullAndUndefined();
+ void jsFunctionDeclarationAsStatement();
+ void stringObjects();
+ void jsStringPrototypeReplaceBugs();
+ void getterSetterThisObject_global();
+ void getterSetterThisObject_plain();
+ void getterSetterThisObject_prototypeChain();
+#if 0 // ###FIXME: no QScriptContext API
+ void getterSetterThisObject_activation();
+#endif
+ void jsContinueInSwitch();
+ void jsShadowReadOnlyPrototypeProperty();
+ void toObject();
+ void jsReservedWords_data();
+ void jsReservedWords();
+ void jsFutureReservedWords_data();
+ void jsFutureReservedWords();
+ void jsThrowInsideWithStatement();
+#if 0 // ###FIXME: No QScriptEngineAgent API
+ void getSetAgent_ownership();
+ void getSetAgent_deleteAgent();
+ void getSetAgent_differentEngine();
+#endif
+#if 0 // ###FIXME: No QScriptString API
+ void reentrancy_stringHandles();
+#endif
+#if 0 // ###FIXME: No processEventsInterval API
+ void reentrancy_processEventsInterval();
+#endif
+#if 0 // FIXME: No support for custom types
+ void reentrancy_typeConversion();
+#endif
+ void reentrancy_globalObjectProperties();
+ void reentrancy_Array();
+ void reentrancy_objectCreation();
+ void jsIncDecNonObjectProperty();
+#if 0 // ###FIXME: no installTranslatorFunctions API
+ void installTranslatorFunctions();
+ void translateScript_data();
+ void translateScript();
+ void translateScript_crossScript();
+ void translateScript_callQsTrFromNative();
+ void translateScript_trNoOp();
+ void translateScript_callQsTrFromCpp();
+ void translateWithInvalidArgs_data();
+ void translateWithInvalidArgs();
+ void translationContext_data();
+ void translationContext();
+ void translateScriptIdBased();
+ void translateScriptUnicode_data();
+ void translateScriptUnicode();
+ void translateScriptUnicodeIdBased_data();
+ void translateScriptUnicodeIdBased();
+ void translateFromBuiltinCallback();
+#endif
+#if 0 // ###FIXME: No QScriptValue::scope API
+ void functionScopes();
+#endif
+#if 0 // ###FIXME: No QScriptContext API
+ void nativeFunctionScopes();
+#endif
+#if 0 // ###FIXME: No QScriptProgram API
+ void evaluateProgram();
+ void evaluateProgram_customScope();
+ void evaluateProgram_closure();
+ void evaluateProgram_executeLater();
+ void evaluateProgram_multipleEngines();
+ void evaluateProgram_empty();
+#endif
+#if 0 // ###FIXME: No QScriptContext API
+ void collectGarbageAfterConnect();
+ void collectGarbageAfterNativeArguments();
+ void promoteThisObjectToQObjectInConstructor();
+#endif
+#if 0 // ###FIXME: No QScript MetaObject API
+ void scriptValueFromQMetaObject();
+#endif
+
+ void qRegExpInport_data();
+ void qRegExpInport();
+#if 0 // ###FIXME: No QScriptContext API
+ void reentrency();
+#endif
+#if 0 // ###FIXME: No QSCriptDeclarativeClass API
+ void newFixedStaticScopeObject();
+ void newGrowingStaticScopeObject();
+#endif
+ void dateRoundtripJSQtJS();
+ void dateRoundtripQtJSQt();
+ void dateConversionJSQt();
+ void dateConversionQtJS();
+};
+
+tst_QJSEngine::tst_QJSEngine()
+{
+}
+
+tst_QJSEngine::~tst_QJSEngine()
+{
+}
+
+void tst_QJSEngine::constructWithParent()
+{
+ QPointer<QJSEngine> ptr;
+ {
+ QObject obj;
+ QJSEngine *engine = new QJSEngine(&obj);
+ ptr = engine;
+ }
+ QVERIFY(ptr == 0);
+}
+
+#if 0 // FIXME: no QScriptContext
+void tst_QJSEngine::currentContext()
+{
+ QScriptEngine eng;
+ QScriptContext *globalCtx = eng.currentContext();
+ QVERIFY(globalCtx != 0);
+ QVERIFY(globalCtx->parentContext() == 0);
+ QCOMPARE(globalCtx->engine(), &eng);
+ QCOMPARE(globalCtx->argumentCount(), 0);
+ QCOMPARE(globalCtx->backtrace().size(), 1);
+ QVERIFY(!globalCtx->isCalledAsConstructor());
+ QVERIFY(!globalCtx->callee().isValid());
+ QCOMPARE(globalCtx->state(), QScriptContext::NormalState);
+ QVERIFY(globalCtx->thisObject().strictlyEquals(eng.globalObject()));
+ QVERIFY(globalCtx->activationObject().strictlyEquals(eng.globalObject()));
+ QVERIFY(globalCtx->argumentsObject().isObject());
+}
+
+void tst_QJSEngine::pushPopContext()
+{
+ QScriptEngine eng;
+ QScriptContext *globalCtx = eng.currentContext();
+ QScriptContext *ctx = eng.pushContext();
+ QVERIFY(ctx != 0);
+ QCOMPARE(ctx->parentContext(), globalCtx);
+ QVERIFY(!ctx->isCalledAsConstructor());
+ QVERIFY(!ctx->callee().isValid());
+ QVERIFY(ctx->thisObject().strictlyEquals(eng.globalObject()));
+ QCOMPARE(ctx->argumentCount(), 0);
+ QCOMPARE(ctx->backtrace().size(), 2);
+ QCOMPARE(ctx->engine(), &eng);
+ QCOMPARE(ctx->state(), QScriptContext::NormalState);
+ QVERIFY(ctx->activationObject().isObject());
+ QVERIFY(ctx->argumentsObject().isObject());
+
+ QScriptContext *ctx2 = eng.pushContext();
+ QVERIFY(ctx2 != 0);
+ QCOMPARE(ctx2->parentContext(), ctx);
+ QVERIFY(!ctx2->activationObject().strictlyEquals(ctx->activationObject()));
+ QVERIFY(!ctx2->argumentsObject().strictlyEquals(ctx->argumentsObject()));
+
+ eng.popContext();
+ eng.popContext();
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::popContext() doesn't match with pushContext()");
+ eng.popContext(); // ignored
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::popContext() doesn't match with pushContext()");
+ eng.popContext(); // ignored
+}
+
+static QScriptValue myFunction(QScriptContext *, QScriptEngine *eng)
+{
+ return eng->nullValue();
+}
+
+static QScriptValue myFunctionWithVoidArg(QScriptContext *, QScriptEngine *eng, void *)
+{
+ return eng->nullValue();
+}
+
+static QScriptValue myThrowingFunction(QScriptContext *ctx, QScriptEngine *)
+{
+ return ctx->throwError("foo");
+}
+
+static QScriptValue myFunctionThatReturns(QScriptContext *, QScriptEngine *eng)
+{
+ return QScriptValue(eng, 42);
+}
+
+static QScriptValue myFunctionThatReturnsWithoutEngine(QScriptContext *, QScriptEngine *)
+{
+ return QScriptValue(1024);
+}
+
+static QScriptValue myFunctionThatReturnsWrongEngine(QScriptContext *, QScriptEngine *, void *arg)
+{
+ QScriptEngine* wrongEngine = reinterpret_cast<QScriptEngine*>(arg);
+ return QScriptValue(wrongEngine, 42);
+}
+
+static QScriptValue sumFunction(QScriptContext *context, QScriptEngine *engine)
+{
+ int sum = 0;
+
+ for (int i = 0; i < context->argumentCount(); i++) {
+ QScriptValue n = context->argument(i);
+ if (n.isNumber())
+ sum += n.toInteger();
+ }
+
+ return QScriptValue(engine, sum);
+}
+
+void tst_QJSEngine::newFunction()
+{
+ QScriptEngine eng;
+ {
+ QScriptValue fun = eng.newFunction(myFunction);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+ QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
+ // a prototype property is automatically constructed
+ {
+ QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal);
+ QVERIFY(prot.isObject());
+ QVERIFY(prot.property("constructor").strictlyEquals(fun));
+ QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::SkipInEnumeration);
+ }
+ // prototype should be Function.prototype
+ QCOMPARE(fun.prototype().isValid(), true);
+ QCOMPARE(fun.prototype().isFunction(), true);
+ QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
+
+ QCOMPARE(fun.call().isNull(), true);
+ QCOMPARE(fun.construct().isObject(), true);
+ }
+}
+
+void tst_QJSEngine::newFunctionWithArg()
+{
+ QScriptEngine eng;
+ {
+ QScriptValue fun = eng.newFunction(myFunctionWithVoidArg, (void*)this);
+ QVERIFY(fun.isFunction());
+ QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
+ // a prototype property is automatically constructed
+ {
+ QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal);
+ QVERIFY(prot.isObject());
+ QVERIFY(prot.property("constructor").strictlyEquals(fun));
+ QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::SkipInEnumeration);
+ }
+ // prototype should be Function.prototype
+ QCOMPARE(fun.prototype().isValid(), true);
+ QCOMPARE(fun.prototype().isFunction(), true);
+ QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
+
+ QCOMPARE(fun.call().isNull(), true);
+ QCOMPARE(fun.construct().isObject(), true);
+ }
+}
+
+void tst_QJSEngine::newFunctionWithProto()
+{
+ QScriptEngine eng;
+ {
+ QScriptValue proto = eng.newObject();
+ QScriptValue fun = eng.newFunction(myFunction, proto);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+ // internal prototype should be Function.prototype
+ QCOMPARE(fun.prototype().isValid(), true);
+ QCOMPARE(fun.prototype().isFunction(), true);
+ QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
+ // public prototype should be the one we passed
+ QCOMPARE(fun.property("prototype").strictlyEquals(proto), true);
+ QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ QCOMPARE(proto.property("constructor").strictlyEquals(fun), true);
+ QCOMPARE(proto.propertyFlags("constructor"), QScriptValue::SkipInEnumeration);
+
+ QCOMPARE(fun.call().isNull(), true);
+ QCOMPARE(fun.construct().isObject(), true);
+ }
+ // whether the return value is correct
+ {
+ QScriptValue fun = eng.newFunction(myFunctionThatReturns);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+
+ QScriptValue result = fun.call();
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 42);
+ }
+ // whether the return value is assigned to the correct engine
+ {
+ QScriptValue fun = eng.newFunction(myFunctionThatReturnsWithoutEngine);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+
+ QScriptValue result = fun.call();
+ QCOMPARE(result.engine(), &eng);
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 1024);
+ }
+ // whether the return value is undefined when returning a value with wrong engine
+ {
+ QScriptEngine wrongEngine;
+
+ QScriptValue fun = eng.newFunction(myFunctionThatReturnsWrongEngine, reinterpret_cast<void *>(&wrongEngine));
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+
+ QTest::ignoreMessage(QtWarningMsg, "QScriptValue::call(): Value from different engine returned from native function, returning undefined value instead.");
+ QScriptValue result = fun.call();
+ QCOMPARE(result.isValid(), true);
+ QCOMPARE(result.isUndefined(), true);
+ }
+ // checking if arguments are passed correctly
+ {
+ QScriptEngine wrongEngine;
+
+ QScriptValue fun = eng.newFunction(sumFunction);
+ QCOMPARE(fun.isValid(), true);
+ QCOMPARE(fun.isFunction(), true);
+ QCOMPARE(fun.isObject(), true);
+
+ QScriptValue result = fun.call();
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 0);
+
+ result = fun.call(QScriptValue(), QScriptValueList() << 1);
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 1);
+
+ result = fun.call(QScriptValue(), QScriptValueList() << 1 << 2 << 3);
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 6);
+
+ result = fun.call(QScriptValue(), QScriptValueList() << 1 << 2 << 3 << 4);
+ QCOMPARE(result.isNumber(), true);
+ QCOMPARE(result.toInt32(), 10);
+ }
+}
+#endif
+
+void tst_QJSEngine::newObject()
+{
+ QJSEngine eng;
+ QJSValue object = eng.newObject();
+ QCOMPARE(object.isValid(), true);
+ QCOMPARE(object.isObject(), true);
+ QCOMPARE(object.isFunction(), false);
+// ###FIXME: No QScriptClass QCOMPARE(object.scriptClass(), (QScriptClass*)0);
+ // prototype should be Object.prototype
+ QCOMPARE(object.prototype().isValid(), true);
+ QCOMPARE(object.prototype().isObject(), true);
+ QCOMPARE(object.prototype().strictlyEquals(eng.evaluate("Object.prototype")), true);
+}
+
+void tst_QJSEngine::newArray()
+{
+ QJSEngine eng;
+ QJSValue array = eng.newArray();
+ QCOMPARE(array.isValid(), true);
+ QCOMPARE(array.isArray(), true);
+ QCOMPARE(array.isObject(), true);
+ QVERIFY(!array.isFunction());
+// ###FIXME: No QScriptClass QCOMPARE(array.scriptClass(), (QScriptClass*)0);
+ // prototype should be Array.prototype
+ QCOMPARE(array.prototype().isValid(), true);
+ QCOMPARE(array.prototype().isArray(), true);
+ QCOMPARE(array.prototype().strictlyEquals(eng.evaluate("Array.prototype")), true);
+}
+
+void tst_QJSEngine::newArray_HooliganTask218092()
+{
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("[].splice(0, 0, 'a')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 0);
+ }
+ {
+ QJSValue ret = eng.evaluate("['a'].splice(0, 1, 'b')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 1);
+ }
+ {
+ QJSValue ret = eng.evaluate("['a', 'b'].splice(0, 1, 'c')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 1);
+ }
+ {
+ QJSValue ret = eng.evaluate("['a', 'b', 'c'].splice(0, 2, 'd')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 2);
+ }
+ {
+ QJSValue ret = eng.evaluate("['a', 'b', 'c'].splice(1, 2, 'd', 'e', 'f')");
+ QVERIFY(ret.isArray());
+ QCOMPARE(ret.property("length").toInt32(), 2);
+ }
+}
+
+void tst_QJSEngine::newArray_HooliganTask233836()
+{
+ QJSEngine eng;
+ {
+ // According to ECMA-262, this should cause a RangeError.
+ QJSValue ret = eng.evaluate("a = new Array(4294967295); a.push('foo')");
+ QVERIFY(ret.isError() && ret.toString().contains(QLatin1String("RangeError")));
+ }
+ {
+ QJSValue ret = eng.newArray(0xFFFFFFFF);
+ QEXPECT_FAIL("", "The maximum length of arrays is defined by v8 currently and differs from QtScript", Abort);
+ QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF));
+ ret.setProperty(0xFFFFFFFF, 123);
+ QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF));
+ QVERIFY(ret.property(0xFFFFFFFF).isNumber());
+ QCOMPARE(ret.property(0xFFFFFFFF).toInt32(), 123);
+ ret.setProperty(123, 456);
+ QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF));
+ QVERIFY(ret.property(123).isNumber());
+ QCOMPARE(ret.property(123).toInt32(), 456);
+ }
+}
+
+void tst_QJSEngine::newVariant()
+{
+ QJSEngine eng;
+ {
+ QJSValue opaque = eng.newVariant(QVariant());
+ QCOMPARE(opaque.isValid(), true);
+ QCOMPARE(opaque.isVariant(), true);
+ QVERIFY(!opaque.isFunction());
+ QCOMPARE(opaque.isObject(), true);
+ QCOMPARE(opaque.prototype().isValid(), true);
+ QEXPECT_FAIL("", "FIXME: newly created QObject's prototype is an JS Object", Continue);
+ QCOMPARE(opaque.prototype().isVariant(), true);
+ QVERIFY(opaque.property("valueOf").call(opaque).isUndefined());
+ }
+}
+
+#if 0 // FIXME: No prototype API in QScriptEngine
+void tst_QJSEngine::newVariant_defaultPrototype()
+{
+ // default prototype should be set automatically
+ QScriptEngine eng;
+ {
+ QScriptValue proto = eng.newObject();
+ eng.setDefaultPrototype(qMetaTypeId<QString>(), proto);
+ QScriptValue ret = eng.newVariant(QVariant(QString::fromLatin1("hello")));
+ QVERIFY(ret.isVariant());
+// ###FIXME: No QScriptClass QCOMPARE(ret.scriptClass(), (QScriptClass*)0);
+ QVERIFY(ret.prototype().strictlyEquals(proto));
+ eng.setDefaultPrototype(qMetaTypeId<QString>(), QScriptValue());
+ QScriptValue ret2 = eng.newVariant(QVariant(QString::fromLatin1("hello")));
+ QVERIFY(ret2.isVariant());
+ QVERIFY(!ret2.prototype().strictlyEquals(proto));
+ }
+}
+#endif
+
+#if 0 // ###FIXME: No QVariant object promotion API
+void tst_QJSEngine::newVariant_promoteObject()
+{
+ // "promote" plain object to variant
+ QScriptEngine eng;
+ {
+ QScriptValue object = eng.newObject();
+ object.setProperty("foo", eng.newObject());
+ object.setProperty("bar", object.property("foo"));
+ QVERIFY(object.property("foo").isObject());
+ QVERIFY(!object.property("foo").isVariant());
+ QScriptValue originalProto = object.property("foo").prototype();
+ QSKIP("It is not possible to promote plain object to a wrapper", SkipAll);
+ QScriptValue ret = eng.newVariant(object.property("foo"), QVariant(123));
+ QVERIFY(ret.isValid());
+ QVERIFY(ret.strictlyEquals(object.property("foo")));
+ QVERIFY(ret.isVariant());
+ QVERIFY(object.property("foo").isVariant());
+ QVERIFY(object.property("bar").isVariant());
+ QCOMPARE(ret.toVariant(), QVariant(123));
+ QVERIFY(ret.prototype().strictlyEquals(originalProto));
+ }
+}
+
+void tst_QJSEngine::newVariant_replaceValue()
+{
+ // replace value of existing object
+ QScriptEngine eng;
+ {
+ QScriptValue object = eng.newVariant(QVariant(123));
+ for (int x = 0; x < 2; ++x) {
+ QScriptValue ret = eng.newVariant(object, QVariant(456));
+ QVERIFY(ret.isValid());
+ QVERIFY(ret.strictlyEquals(object));
+ QVERIFY(ret.isVariant());
+ QCOMPARE(ret.toVariant(), QVariant(456));
+ }
+ }
+}
+#endif
+
+void tst_QJSEngine::newVariant_valueOfToString()
+{
+ // valueOf() and toString()
+ QJSEngine eng;
+ {
+ QJSValue object = eng.newVariant(QVariant(123));
+ QJSValue value = object.property("valueOf").call(object);
+ QVERIFY(value.isNumber());
+ QCOMPARE(value.toInt32(), 123);
+ QCOMPARE(object.toString(), QString::fromLatin1("123"));
+ QCOMPARE(object.toVariant().toString(), object.toString());
+ }
+ {
+ QJSValue object = eng.newVariant(QVariant(QString::fromLatin1("hello")));
+ QJSValue value = object.property("valueOf").call(object);
+ QVERIFY(value.isString());
+ QCOMPARE(value.toString(), QString::fromLatin1("hello"));
+ QCOMPARE(object.toString(), QString::fromLatin1("hello"));
+ QCOMPARE(object.toVariant().toString(), object.toString());
+ }
+ {
+ QJSValue object = eng.newVariant(QVariant(false));
+ QJSValue value = object.property("valueOf").call(object);
+ QVERIFY(value.isBoolean());
+ QCOMPARE(value.toBoolean(), false);
+ QCOMPARE(object.toString(), QString::fromLatin1("false"));
+ QCOMPARE(object.toVariant().toString(), object.toString());
+ }
+ {
+ QJSValue object = eng.newVariant(QVariant(QPoint(10, 20)));
+ QJSValue value = object.property("valueOf").call(object);
+ QVERIFY(value.isObject());
+ QVERIFY(value.strictlyEquals(object));
+ QCOMPARE(object.toString(), QString::fromLatin1("QVariant(QPoint)"));
+ }
+}
+
+#if 0 // ###FIXME: No QVariant object promotion API
+void tst_QJSEngine::newVariant_promoteNonObject()
+{
+ QScriptEngine eng;
+ {
+ QVariant var(456);
+ QScriptValue ret = eng.newVariant(123, var);
+ QVERIFY(ret.isVariant());
+ QCOMPARE(ret.toVariant(), var);
+ }
+}
+
+void tst_QJSEngine::newVariant_promoteNonQScriptObject()
+{
+ QSKIP("This test relay on limitation of QtScript JSC implementation", SkipAll);
+ QScriptEngine eng;
+ {
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::newVariant(): changing class of non-QScriptObject not supported");
+ QScriptValue ret = eng.newVariant(eng.newArray(), 123);
+ QVERIFY(!ret.isValid());
+ }
+}
+#endif
+
+void tst_QJSEngine::newRegExp()
+{
+ QJSEngine eng;
+ for (int x = 0; x < 2; ++x) {
+ QJSValue rexp;
+ if (x == 0)
+ rexp = eng.newRegExp("foo", "bar");
+ else
+ rexp = eng.newRegExp(QRegExp("foo"));
+ QCOMPARE(rexp.isValid(), true);
+ QCOMPARE(rexp.isRegExp(), true);
+ QCOMPARE(rexp.isObject(), true);
+ QVERIFY(rexp.isFunction()); // in JSC, RegExp objects are callable
+ // prototype should be RegExp.prototype
+ QCOMPARE(rexp.prototype().isValid(), true);
+ QCOMPARE(rexp.prototype().isObject(), true);
+ QCOMPARE(rexp.prototype().isRegExp(), false);
+ QCOMPARE(rexp.prototype().strictlyEquals(eng.evaluate("RegExp.prototype")), true);
+
+ QCOMPARE(rexp.toRegExp().pattern(), QRegExp("foo").pattern());
+ }
+}
+
+void tst_QJSEngine::jsRegExp()
+{
+ // See ECMA-262 Section 15.10, "RegExp Objects".
+ // These should really be JS-only tests, as they test the implementation's
+ // ECMA-compliance, not the C++ API. Compliance should already be covered
+ // by the Mozilla tests (qscriptjstestsuite).
+ // We can consider updating the expected results of this test if the
+ // RegExp implementation changes.
+
+ QJSEngine eng;
+ QJSValue r = eng.evaluate("/foo/gim");
+ QVERIFY(r.isRegExp());
+ QCOMPARE(r.toString(), QString::fromLatin1("/foo/gim"));
+
+ QJSValue rxCtor = eng.globalObject().property("RegExp");
+ QJSValue r2 = rxCtor.call(QJSValue(), QJSValueList() << r);
+ QVERIFY(r2.isRegExp());
+ QVERIFY(r2.strictlyEquals(r));
+
+ QJSValue r3 = rxCtor.call(QJSValue(), QJSValueList() << r << "gim");
+ QVERIFY(r3.isError());
+ QVERIFY(r3.toString().contains(QString::fromLatin1("TypeError"))); // Cannot supply flags when constructing one RegExp from another
+
+ QJSValue r4 = rxCtor.call(QJSValue(), QJSValueList() << "foo" << "gim");
+ QVERIFY(r4.isRegExp());
+
+ QJSValue r5 = rxCtor.construct(QJSValueList() << r);
+ QVERIFY(r5.isRegExp());
+ QCOMPARE(r5.toString(), QString::fromLatin1("/foo/gim"));
+ // In JSC, constructing a RegExp from another produces the same identical object.
+ // This is different from SpiderMonkey and old back-end.
+ QVERIFY(!r5.strictlyEquals(r));
+
+ QEXPECT_FAIL("", "V8 and jsc ignores invalid flags", Continue); //https://bugs.webkit.org/show_bug.cgi?id=41614
+ QJSValue r6 = rxCtor.construct(QJSValueList() << "foo" << "bar");
+ QVERIFY(r6.isError());
+ // QVERIFY(r6.toString().contains(QString::fromLatin1("SyntaxError"))); // Invalid regular expression flag
+
+
+ QJSValue r7 = eng.evaluate("/foo/gimp");
+ /* v8 and jsc ignores invalid flags
+ QVERIFY(r7.isError());
+ QVERIFY(r7.toString().contains(QString::fromLatin1("SyntaxError"))); // Invalid regular expression flag
+ */
+
+ // JSC doesn't complain about duplicate flags.
+ QJSValue r8 = eng.evaluate("/foo/migmigmig");
+ QVERIFY(r8.isRegExp());
+ QCOMPARE(r8.toString(), QString::fromLatin1("/foo/gim"));
+
+ QJSValue r9 = rxCtor.construct();
+ QVERIFY(r9.isRegExp());
+ QCOMPARE(r9.toString(), QString::fromLatin1("/(?:)/"));
+
+ QJSValue r10 = rxCtor.construct(QJSValueList() << "" << "gim");
+ QVERIFY(r10.isRegExp());
+ QCOMPARE(r10.toString(), QString::fromLatin1("/(?:)/gim"));
+
+ QJSValue r11 = rxCtor.construct(QJSValueList() << "{1.*}" << "g");
+ QVERIFY(r11.isRegExp());
+ QCOMPARE(r11.toString(), QString::fromLatin1("/{1.*}/g"));
+}
+
+void tst_QJSEngine::newDate()
+{
+ QJSEngine eng;
+
+ {
+ QJSValue date = eng.newDate(0);
+ QCOMPARE(date.isValid(), true);
+ QCOMPARE(date.isDate(), true);
+ QCOMPARE(date.isObject(), true);
+ QVERIFY(!date.isFunction());
+ // prototype should be Date.prototype
+ QCOMPARE(date.prototype().isValid(), true);
+ QCOMPARE(date.prototype().isDate(), true);
+ QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true);
+ }
+
+ {
+ QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::LocalTime);
+ QJSValue date = eng.newDate(dt);
+ QCOMPARE(date.isValid(), true);
+ QCOMPARE(date.isDate(), true);
+ QCOMPARE(date.isObject(), true);
+ // prototype should be Date.prototype
+ QCOMPARE(date.prototype().isValid(), true);
+ QCOMPARE(date.prototype().isDate(), true);
+ QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true);
+
+ QCOMPARE(date.toDateTime(), dt);
+ }
+
+ {
+ QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::UTC);
+ QJSValue date = eng.newDate(dt);
+ // toDateTime() result should be in local time
+ QCOMPARE(date.toDateTime(), dt.toLocalTime());
+ }
+}
+
+void tst_QJSEngine::jsParseDate()
+{
+ QJSEngine eng;
+ // Date.parse() should return NaN when it fails
+ {
+ QJSValue ret = eng.evaluate("Date.parse()");
+ QVERIFY(ret.isNumber());
+ QVERIFY(qIsNaN(ret.toNumber()));
+ }
+
+ // Date.parse() should be able to parse the output of Date().toString()
+#ifndef Q_WS_WIN // TODO: Test and remove this since 169701 has been fixed
+ {
+ QJSValue ret = eng.evaluate("var x = new Date(); var s = x.toString(); s == new Date(Date.parse(s)).toString()");
+ QVERIFY(ret.isBoolean());
+ QCOMPARE(ret.toBoolean(), true);
+ }
+#endif
+}
+
+void tst_QJSEngine::newQObject()
+{
+ QJSEngine eng;
+
+ {
+ QJSValue qobject = eng.newQObject(0);
+ QCOMPARE(qobject.isValid(), true);
+ QCOMPARE(qobject.isNull(), true);
+ QCOMPARE(qobject.isObject(), false);
+ QCOMPARE(qobject.toQObject(), (QObject *)0);
+ }
+ {
+ QJSValue qobject = eng.newQObject(this);
+ QCOMPARE(qobject.isValid(), true);
+ QCOMPARE(qobject.isQObject(), true);
+ QCOMPARE(qobject.isObject(), true);
+ QCOMPARE(qobject.toQObject(), (QObject *)this);
+ QVERIFY(!qobject.isFunction());
+ // prototype should be QObject.prototype
+ QCOMPARE(qobject.prototype().isValid(), true);
+ QEXPECT_FAIL("", "FIXME: newly created QObject's prototype is an JS Object", Continue);
+ QCOMPARE(qobject.prototype().isQObject(), true);
+// ###FIXME: No QScriptClass QCOMPARE(qobject.scriptClass(), (QScriptClass*)0);
+ }
+}
+
+void tst_QJSEngine::newQObject_ownership()
+{
+#if 0 // FIXME: ownership tests need to be revivewed
+ QScriptEngine eng;
+ {
+ QPointer<QObject> ptr = new QObject();
+ QVERIFY(ptr != 0);
+ {
+ QScriptValue v = eng.newQObject(ptr, QScriptEngine::ScriptOwnership);
+ }
+ eng.evaluate("gc()");
+ if (ptr)
+ QEXPECT_FAIL("", "In the JSC-based back-end, script-owned QObjects are not always deleted immediately during GC", Continue);
+ QVERIFY(ptr == 0);
+ }
+ {
+ QPointer<QObject> ptr = new QObject();
+ QVERIFY(ptr != 0);
+ {
+ QScriptValue v = eng.newQObject(ptr, QScriptEngine::QtOwnership);
+ }
+ QObject *before = ptr;
+ eng.evaluate("gc()");
+ QVERIFY(ptr == before);
+ delete ptr;
+ }
+ {
+ QObject *parent = new QObject();
+ QObject *child = new QObject(parent);
+ QScriptValue v = eng.newQObject(child, QScriptEngine::QtOwnership);
+ QCOMPARE(v.toQObject(), child);
+ delete parent;
+ QCOMPARE(v.toQObject(), (QObject *)0);
+ }
+ {
+ QPointer<QObject> ptr = new QObject();
+ QVERIFY(ptr != 0);
+ {
+ QScriptValue v = eng.newQObject(ptr, QScriptEngine::AutoOwnership);
+ }
+ eng.evaluate("gc()");
+ // no parent, so it should be like ScriptOwnership
+ if (ptr)
+ QEXPECT_FAIL("", "In the JSC-based back-end, script-owned QObjects are not always deleted immediately during GC", Continue);
+ QVERIFY(ptr == 0);
+ }
+ {
+ QObject *parent = new QObject();
+ QPointer<QObject> child = new QObject(parent);
+ QVERIFY(child != 0);
+ {
+ QScriptValue v = eng.newQObject(child, QScriptEngine::AutoOwnership);
+ }
+ eng.evaluate("gc()");
+ // has parent, so it should be like QtOwnership
+ QVERIFY(child != 0);
+ delete parent;
+ }
+#endif
+}
+
+void tst_QJSEngine::newQObject_promoteObject()
+{
+#if 0 // ### FIXME: object promotion is not supported
+ QScriptEngine eng;
+ // "promote" plain object to QObject
+ {
+ QScriptValue obj = eng.newObject();
+ QScriptValue originalProto = obj.prototype();
+ QScriptValue ret = eng.newQObject(obj, this);
+ QVERIFY(ret.isValid());
+ QVERIFY(ret.isQObject());
+ QVERIFY(ret.strictlyEquals(obj));
+ QVERIFY(obj.isQObject());
+ QCOMPARE(ret.toQObject(), (QObject *)this);
+ QVERIFY(ret.prototype().strictlyEquals(originalProto));
+ QScriptValue val = ret.property("objectName");
+ QVERIFY(val.isString());
+ }
+ // "promote" variant object to QObject
+ {
+ QScriptValue obj = eng.newVariant(123);
+ QVERIFY(obj.isVariant());
+ QScriptValue originalProto = obj.prototype();
+ QScriptValue ret = eng.newQObject(obj, this);
+ QVERIFY(ret.isQObject());
+ QVERIFY(ret.strictlyEquals(obj));
+ QVERIFY(obj.isQObject());
+ QCOMPARE(ret.toQObject(), (QObject *)this);
+ QVERIFY(ret.prototype().strictlyEquals(originalProto));
+ }
+ // replace QObject* of existing object
+ {
+ QScriptValue object = eng.newVariant(123);
+ QScriptValue originalProto = object.prototype();
+ QObject otherQObject;
+ for (int x = 0; x < 2; ++x) {
+ QScriptValue ret = eng.newQObject(object, &otherQObject);
+ QVERIFY(ret.isValid());
+ QVERIFY(ret.isQObject());
+ QVERIFY(ret.strictlyEquals(object));
+ QCOMPARE(ret.toQObject(), (QObject *)&otherQObject);
+ QVERIFY(ret.prototype().strictlyEquals(originalProto));
+ }
+ }
+#endif
+}
+
+void tst_QJSEngine::newQObject_sameQObject()
+{
+#if 0 // ###FIXME: No QObjectWrapOptions API
+ QSKIP("This test stongly relay on strictlyEquals feature that would change in near future", SkipAll);
+ QScriptEngine eng;
+ // calling newQObject() several times with same object
+ for (int x = 0; x < 2; ++x) {
+ QObject qobj;
+ // the default is to create a new wrapper object
+ QScriptValue obj1 = eng.newQObject(&qobj);
+ QScriptValue obj2 = eng.newQObject(&qobj);
+ QVERIFY(!obj2.strictlyEquals(obj1));
+
+ QScriptEngine::QObjectWrapOptions opt = 0;
+ bool preferExisting = (x != 0);
+ if (preferExisting)
+ opt |= QScriptEngine::PreferExistingWrapperObject;
+
+ QScriptValue obj3 = eng.newQObject(&qobj, QScriptEngine::AutoOwnership, opt);
+ QVERIFY(!obj3.strictlyEquals(obj2));
+ QScriptValue obj4 = eng.newQObject(&qobj, QScriptEngine::AutoOwnership, opt);
+ QCOMPARE(obj4.strictlyEquals(obj3), preferExisting);
+
+ QScriptValue obj5 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership, opt);
+ QVERIFY(!obj5.strictlyEquals(obj4));
+ QScriptValue obj6 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership, opt);
+ QCOMPARE(obj6.strictlyEquals(obj5), preferExisting);
+
+ QScriptValue obj7 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership,
+ QScriptEngine::ExcludeSuperClassMethods | opt);
+ QVERIFY(!obj7.strictlyEquals(obj6));
+ QScriptValue obj8 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership,
+ QScriptEngine::ExcludeSuperClassMethods | opt);
+ QCOMPARE(obj8.strictlyEquals(obj7), preferExisting);
+ }
+#endif
+}
+
+#if 0 // FIXME: No prototype API in QScriptEngine
+void tst_QJSEngine::newQObject_defaultPrototype()
+{
+ QScriptEngine eng;
+ // newQObject() should set the default prototype, if one has been registered
+ {
+ QScriptValue oldQObjectProto = eng.defaultPrototype(qMetaTypeId<QObject*>());
+
+ QScriptValue qobjectProto = eng.newObject();
+ eng.setDefaultPrototype(qMetaTypeId<QObject*>(), qobjectProto);
+ {
+ QScriptValue ret = eng.newQObject(this);
+ QVERIFY(ret.prototype().equals(qobjectProto));
+ }
+ QScriptValue tstProto = eng.newObject();
+ int typeId = qRegisterMetaType<tst_QJSEngine*>("tst_QJSEngine*");
+ eng.setDefaultPrototype(typeId, tstProto);
+ {
+ QScriptValue ret = eng.newQObject(this);
+ QVERIFY(ret.prototype().equals(tstProto));
+ }
+
+ eng.setDefaultPrototype(qMetaTypeId<QObject*>(), oldQObjectProto);
+ eng.setDefaultPrototype(typeId, QScriptValue());
+ }
+}
+#endif
+
+void tst_QJSEngine::newQObject_promoteNonObject()
+{
+#if 0 // ### FIXME: object promotion is not supported
+ QScriptEngine eng;
+ {
+ QScriptValue ret = eng.newQObject(123, this);
+ QVERIFY(ret.isQObject());
+ QCOMPARE(ret.toQObject(), this);
+ }
+#endif
+}
+
+void tst_QJSEngine::newQObject_promoteNonQScriptObject()
+{
+#if 0 // ### FIXME: object promotion is not supported
+ QSKIP("Promotion of non QScriptObjects kind of works (there is not difference between Object and Array, look at comments in newQObject implementation).", SkipAll);
+ QScriptEngine eng;
+ {
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::newQObject(): changing class of non-QScriptObject not supported");
+ QScriptValue ret = eng.newQObject(eng.newArray(), this);
+ QVERIFY(!ret.isValid());
+ }
+#endif
+}
+
+#if 0 // ### FIXME: No QScript Metaobject support right now
+QT_BEGIN_NAMESPACE
+Q_SCRIPT_DECLARE_QMETAOBJECT(QObject, QObject*)
+Q_SCRIPT_DECLARE_QMETAOBJECT(QWidget, QWidget*)
+QT_END_NAMESPACE
+
+static QScriptValue myConstructor(QScriptContext *ctx, QScriptEngine *eng)
+{
+ QScriptValue obj;
+ if (ctx->isCalledAsConstructor()) {
+ obj = ctx->thisObject();
+ } else {
+ obj = eng->newObject();
+ obj.setPrototype(ctx->callee().property("prototype"));
+ }
+ obj.setProperty("isCalledAsConstructor", QScriptValue(eng, ctx->isCalledAsConstructor()));
+ return obj;
+}
+
+static QScriptValue instanceofJS(const QScriptValue &inst, const QScriptValue &ctor)
+{
+ return inst.engine()->evaluate("(function(inst, ctor) { return inst instanceof ctor; })")
+ .call(QScriptValue(), QScriptValueList() << inst << ctor);
+}
+
+void tst_QJSEngine::newQMetaObject()
+{
+ QScriptEngine eng;
+#if 0
+ QScriptValue qclass = eng.newQMetaObject<QObject>();
+ QScriptValue qclass2 = eng.newQMetaObject<QWidget>();
+#else
+ QScriptValue qclass = qScriptValueFromQMetaObject<QObject>(&eng);
+ QScriptValue qclass2 = qScriptValueFromQMetaObject<QWidget>(&eng);
+#endif
+ QCOMPARE(qclass.isValid(), true);
+ QCOMPARE(qclass.isQMetaObject(), true);
+ QCOMPARE(qclass.toQMetaObject(), &QObject::staticMetaObject);
+ QCOMPARE(qclass.isFunction(), true);
+ QVERIFY(qclass.property("prototype").isObject());
+
+ QCOMPARE(qclass2.isValid(), true);
+ QCOMPARE(qclass2.isQMetaObject(), true);
+ QCOMPARE(qclass2.toQMetaObject(), &QWidget::staticMetaObject);
+ QCOMPARE(qclass2.isFunction(), true);
+ QVERIFY(qclass2.property("prototype").isObject());
+
+ // prototype should be QMetaObject.prototype
+ QCOMPARE(qclass.prototype().isObject(), true);
+ QCOMPARE(qclass2.prototype().isObject(), true);
+
+ QScriptValue instance = qclass.construct();
+ QCOMPARE(instance.isQObject(), true);
+ QCOMPARE(instance.toQObject()->metaObject(), qclass.toQMetaObject());
+ QEXPECT_FAIL("", "FIXME: newQMetaObject not implemented properly yet", Abort);
+ QVERIFY(instance.instanceOf(qclass));
+ QVERIFY(instanceofJS(instance, qclass).strictlyEquals(true));
+
+ QScriptValue instance2 = qclass2.construct();
+ QCOMPARE(instance2.isQObject(), true);
+ QCOMPARE(instance2.toQObject()->metaObject(), qclass2.toQMetaObject());
+ QVERIFY(instance2.instanceOf(qclass2));
+ QVERIFY(instanceofJS(instance2, qclass2).strictlyEquals(true));
+ QVERIFY(!instance2.instanceOf(qclass));
+ QVERIFY(instanceofJS(instance2, qclass).strictlyEquals(false));
+
+ QScriptValueList args;
+ args << instance;
+ QScriptValue instance3 = qclass.construct(args);
+ QCOMPARE(instance3.isQObject(), true);
+ QCOMPARE(instance3.toQObject()->parent(), instance.toQObject());
+ QVERIFY(instance3.instanceOf(qclass));
+ QVERIFY(instanceofJS(instance3, qclass).strictlyEquals(true));
+ QVERIFY(!instance3.instanceOf(qclass2));
+ QVERIFY(instanceofJS(instance3, qclass2).strictlyEquals(false));
+ args.clear();
+
+ QPointer<QObject> qpointer1 = instance.toQObject();
+ QPointer<QObject> qpointer2 = instance2.toQObject();
+ QPointer<QObject> qpointer3 = instance3.toQObject();
+
+ QVERIFY(qpointer1);
+ QVERIFY(qpointer2);
+ QVERIFY(qpointer3);
+
+ // verify that AutoOwnership is in effect
+ instance = QScriptValue();
+ collectGarbage_helper(eng);
+
+ QVERIFY(!qpointer1);
+ QVERIFY(qpointer2);
+ QVERIFY(!qpointer3); // was child of instance
+
+ QVERIFY(instance.toQObject() == 0);
+ QVERIFY(instance3.toQObject() == 0); // was child of instance
+ QVERIFY(instance2.toQObject() != 0);
+ instance2 = QScriptValue();
+ collectGarbage_helper(eng);
+ QVERIFY(instance2.toQObject() == 0);
+
+ // with custom constructor
+ QScriptValue ctor = eng.newFunction(myConstructor);
+ QScriptValue qclass3 = eng.newQMetaObject(&QObject::staticMetaObject, ctor);
+ QVERIFY(qclass3.property("prototype").equals(ctor.property("prototype")));
+ {
+ QScriptValue ret = qclass3.call();
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.property("isCalledAsConstructor").isBoolean());
+ QVERIFY(!ret.property("isCalledAsConstructor").toBoolean());
+ QVERIFY(ret.instanceOf(qclass3));
+ QVERIFY(instanceofJS(ret, qclass3).strictlyEquals(true));
+ QVERIFY(!ret.instanceOf(qclass));
+ QVERIFY(instanceofJS(ret, qclass).strictlyEquals(false));
+ }
+ {
+ QScriptValue ret = qclass3.construct();
+ QVERIFY(ret.isObject());
+ QVERIFY(ret.property("isCalledAsConstructor").isBoolean());
+ QVERIFY(ret.property("isCalledAsConstructor").toBoolean());
+ QVERIFY(ret.instanceOf(qclass3));
+ QVERIFY(instanceofJS(ret, qclass3).strictlyEquals(true));
+ QVERIFY(!ret.instanceOf(qclass2));
+ QVERIFY(instanceofJS(ret, qclass2).strictlyEquals(false));
+ }
+
+ // subclassing
+ qclass2.setProperty("prototype", qclass.construct());
+ QVERIFY(qclass2.construct().instanceOf(qclass));
+ QVERIFY(instanceofJS(qclass2.construct(), qclass).strictlyEquals(true));
+
+ // with meta-constructor
+ QScriptValue qclass4 = eng.newQMetaObject(&QObject::staticMetaObject);
+ {
+ QScriptValue inst = qclass4.construct();
+ QVERIFY(inst.isQObject());
+ QVERIFY(inst.toQObject() != 0);
+ QCOMPARE(inst.toQObject()->parent(), (QObject*)0);
+ QVERIFY(inst.instanceOf(qclass4));
+ QVERIFY(instanceofJS(inst, qclass4).strictlyEquals(true));
+ QVERIFY(!inst.instanceOf(qclass3));
+ QVERIFY(instanceofJS(inst, qclass3).strictlyEquals(false));
+ }
+ {
+ QScriptValue inst = qclass4.construct(QScriptValueList() << eng.newQObject(this));
+ QVERIFY(inst.isQObject());
+ QVERIFY(inst.toQObject() != 0);
+ QCOMPARE(inst.toQObject()->parent(), (QObject*)this);
+ QVERIFY(inst.instanceOf(qclass4));
+ QVERIFY(instanceofJS(inst, qclass4).strictlyEquals(true));
+ QVERIFY(!inst.instanceOf(qclass2));
+ QVERIFY(instanceofJS(inst, qclass2).strictlyEquals(false));
+ }
+}
+#endif
+
+#if 0 // ###FIXME: No activation object support
+void tst_QJSEngine::newActivationObject()
+{
+ QSKIP("internal function not implemented in JSC-based back-end", SkipAll);
+ QScriptEngine eng;
+ QScriptValue act = eng.newActivationObject();
+ QEXPECT_FAIL("", "", Continue);
+ QCOMPARE(act.isValid(), true);
+ QEXPECT_FAIL("", "", Continue);
+ QCOMPARE(act.isObject(), true);
+ QVERIFY(!act.isFunction());
+ QScriptValue v(&eng, 123);
+ act.setProperty("prop", v);
+ QEXPECT_FAIL("", "", Continue);
+ QCOMPARE(act.property("prop").strictlyEquals(v), true);
+ QCOMPARE(act.scope().isValid(), false);
+ QEXPECT_FAIL("", "", Continue);
+ QVERIFY(act.prototype().isNull());
+}
+#endif
+
+#if 0 // ###FIXME: No setGlobalObject support - yay
+void tst_QJSEngine::getSetGlobalObjectSimple()
+{
+ QScriptEngine engine;
+ QScriptValue object = engine.newObject();
+ object.setProperty("foo", 123);
+ engine.evaluate("var bar = 100");
+ engine.setGlobalObject(object);
+ engine.evaluate("rab = 100");
+ QVERIFY(engine.globalObject().property("rab").isValid());
+ QVERIFY(engine.globalObject().property("foo").isValid());
+ QVERIFY(!engine.globalObject().property("bar").isValid());
+}
+
+void tst_QJSEngine::getSetGlobalObject()
+{
+ QScriptEngine eng;
+ QScriptValue glob = eng.globalObject();
+ glob = QScriptValue(); // kill reference to old global object
+ collectGarbage_helper(eng);
+
+ glob = eng.globalObject();
+ QCOMPARE(glob.isValid(), true);
+ QCOMPARE(glob.isObject(), true);
+ QVERIFY(!glob.isFunction());
+ QVERIFY(eng.currentContext()->thisObject().strictlyEquals(glob));
+ QVERIFY(eng.currentContext()->activationObject().strictlyEquals(glob));
+ QEXPECT_FAIL("", "FIXME: Do we really want to enforce this? ECMA standard says that it is implementation dependent, skipping for now", Continue);
+ QCOMPARE(glob.toString(), QString::fromLatin1("[object global]"));
+ // prototype should be Object.prototype
+ QCOMPARE(glob.prototype().isValid(), true);
+ QCOMPARE(glob.prototype().isObject(), true);
+ QEXPECT_FAIL("", "FIXME: Do we really want to enforce this? ECMA standard says that it is implementation dependent, skipping for now", Continue);
+ QCOMPARE(glob.prototype().strictlyEquals(eng.evaluate("Object.prototype")), true);
+
+ eng.setGlobalObject(glob);
+ QVERIFY(eng.globalObject().equals(glob));
+ eng.setGlobalObject(123);
+ QVERIFY(eng.globalObject().equals(glob));
+
+ QScriptValue obj = eng.newObject();
+ eng.setGlobalObject(obj);
+ QVERIFY(eng.globalObject().strictlyEquals(obj));
+ QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj));
+ QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj));
+ QVERIFY(eng.evaluate("this").strictlyEquals(obj));
+ QEXPECT_FAIL("", "FIXME: Do we really want to enforce this? ECMA standard says that it is implementation dependent, skipping for now", Continue);
+ QCOMPARE(eng.globalObject().toString(), QString::fromLatin1("[object global]"));
+
+ collectGarbage_helper(eng);
+ glob = QScriptValue(); // kill reference to old global object
+ collectGarbage_helper(eng);
+ obj = eng.newObject();
+ eng.setGlobalObject(obj);
+ QVERIFY(eng.globalObject().strictlyEquals(obj));
+ QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj));
+ QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj));
+
+ collectGarbage_helper(eng);
+ QVERIFY(eng.globalObject().strictlyEquals(obj));
+ QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj));
+ QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj));
+
+ QVERIFY(!obj.property("foo").isValid());
+ eng.evaluate("var foo = 123");
+ {
+ QScriptValue ret = obj.property("foo");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+
+ QVERIFY(!obj.property("bar").isValid());
+ eng.evaluate("bar = 456");
+ {
+ QScriptValue ret = obj.property("bar");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 456);
+ }
+
+ QVERIFY(!obj.property("baz").isValid());
+ eng.evaluate("this['baz'] = 789");
+ {
+ QScriptValue ret = obj.property("baz");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 789);
+ }
+
+ {
+ QScriptValue ret = eng.evaluate("(function() { return this; })()");
+ QVERIFY(ret.strictlyEquals(obj));
+ }
+
+ // Delete property.
+ {
+ QScriptValue ret = eng.evaluate("delete foo");
+ QVERIFY(ret.isBool());
+ QVERIFY(ret.toBool());
+ QVERIFY(!obj.property("foo").isValid());
+ }
+
+ // Getter/setter property.
+ //the custom global object have an interceptor
+ QVERIFY(eng.evaluate("this.__defineGetter__('oof', function() { return this.bar; })").isUndefined());
+ QVERIFY(eng.evaluate("this.__defineSetter__('oof', function(v) { this.bar = v; })").isUndefined());
+ QVERIFY(eng.evaluate("this.__lookupGetter__('oof')").isFunction());
+ QVERIFY(eng.evaluate("this.__lookupSetter__('oof')").isFunction());
+ eng.evaluate("oof = 123");
+ QVERIFY(eng.evaluate("oof").equals(obj.property("bar")));
+
+ // Enumeration.
+ {
+ QScriptValue ret = eng.evaluate("a = []; for (var p in this) a.push(p); a");
+ QCOMPARE(ret.toString(), QString::fromLatin1("bar,baz,oof,p,a"));
+ }
+}
+#endif
+
+#if 0 // ###FIXME: no c-style callbacks
+static QScriptValue getSetFoo(QScriptContext *ctx, QScriptEngine *)
+{
+ if (ctx->argumentCount() > 0)
+ ctx->thisObject().setProperty("foo", ctx->argument(0));
+ return ctx->thisObject().property("foo");
+}
+#endif
+
+void tst_QJSEngine::globalObjectProperties()
+{
+ // See ECMA-262 Section 15.1, "The Global Object".
+
+ QJSEngine eng;
+ QJSValue global = eng.globalObject();
+
+ QVERIFY(global.property("NaN").isNumber());
+ QVERIFY(qIsNaN(global.property("NaN").toNumber()));
+ QCOMPARE(global.propertyFlags("NaN"), QJSValue::SkipInEnumeration | QJSValue::Undeletable);
+
+ QVERIFY(global.property("Infinity").isNumber());
+ QVERIFY(qIsInf(global.property("Infinity").toNumber()));
+ QCOMPARE(global.propertyFlags("NaN"), QJSValue::SkipInEnumeration | QJSValue::Undeletable);
+
+ QVERIFY(global.property("undefined").isUndefined());
+ QCOMPARE(global.propertyFlags("undefined"), QJSValue::SkipInEnumeration | QJSValue::Undeletable);
+
+ QVERIFY(global.property("eval").isFunction());
+ QCOMPARE(global.propertyFlags("eval"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("parseInt").isFunction());
+ QCOMPARE(global.propertyFlags("parseInt"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("parseFloat").isFunction());
+ QCOMPARE(global.propertyFlags("parseFloat"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("isNaN").isFunction());
+ QCOMPARE(global.propertyFlags("isNaN"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("isFinite").isFunction());
+ QCOMPARE(global.propertyFlags("isFinite"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("decodeURI").isFunction());
+ QCOMPARE(global.propertyFlags("decodeURI"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("decodeURIComponent").isFunction());
+ QCOMPARE(global.propertyFlags("decodeURIComponent"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("encodeURI").isFunction());
+ QCOMPARE(global.propertyFlags("encodeURI"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("encodeURIComponent").isFunction());
+ QCOMPARE(global.propertyFlags("encodeURIComponent"), QJSValue::SkipInEnumeration);
+
+ QVERIFY(global.property("Object").isFunction());
+ QCOMPARE(global.propertyFlags("Object"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Function").isFunction());
+ QCOMPARE(global.propertyFlags("Function"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Array").isFunction());
+ QCOMPARE(global.propertyFlags("Array"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("String").isFunction());
+ QCOMPARE(global.propertyFlags("String"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Boolean").isFunction());
+ QCOMPARE(global.propertyFlags("Boolean"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Number").isFunction());
+ QCOMPARE(global.propertyFlags("Number"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Date").isFunction());
+ QCOMPARE(global.propertyFlags("Date"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("RegExp").isFunction());
+ QCOMPARE(global.propertyFlags("RegExp"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Error").isFunction());
+ QCOMPARE(global.propertyFlags("Error"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("EvalError").isFunction());
+ QCOMPARE(global.propertyFlags("EvalError"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("RangeError").isFunction());
+ QCOMPARE(global.propertyFlags("RangeError"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("ReferenceError").isFunction());
+ QCOMPARE(global.propertyFlags("ReferenceError"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("SyntaxError").isFunction());
+ QCOMPARE(global.propertyFlags("SyntaxError"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("TypeError").isFunction());
+ QCOMPARE(global.propertyFlags("TypeError"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("URIError").isFunction());
+ QCOMPARE(global.propertyFlags("URIError"), QJSValue::SkipInEnumeration);
+ QVERIFY(global.property("Math").isObject());
+ QVERIFY(!global.property("Math").isFunction());
+ QCOMPARE(global.propertyFlags("Math"), QJSValue::SkipInEnumeration);
+}
+
+void tst_QJSEngine::globalObjectEquals()
+{
+ QJSEngine eng;
+ QJSValue o = eng.globalObject();
+ QVERIFY(o.strictlyEquals(eng.globalObject()));
+ QVERIFY(o.equals(eng.globalObject()));
+}
+
+#if 0 // ###FIXME: No QScriptValueIterator API
+void tst_QJSEngine::globalObjectProperties_enumerate()
+{
+ QScriptEngine eng;
+ QScriptValue global = eng.globalObject();
+
+ QSet<QString> expectedNames;
+ expectedNames
+ << "isNaN"
+ << "parseFloat"
+ << "String"
+ << "EvalError"
+ << "URIError"
+ << "Math"
+ << "encodeURIComponent"
+ << "RangeError"
+ << "eval"
+ << "isFinite"
+ << "ReferenceError"
+ << "Infinity"
+ << "Function"
+ << "RegExp"
+ << "Number"
+ << "parseInt"
+ << "Object"
+ << "decodeURI"
+ << "TypeError"
+ << "Boolean"
+ << "encodeURI"
+ << "NaN"
+ << "Error"
+ << "decodeURIComponent"
+ << "Date"
+ << "Array"
+ << "escape"
+ << "unescape"
+ << "SyntaxError"
+ << "undefined"
+ // non-standard
+ << "gc"
+ << "version"
+ << "print"
+ // JavaScriptCore
+ << "JSON"
+ // V8
+ << "execScript" //execScript for IE compatibility.
+ ;
+ QSet<QString> actualNames;
+ {
+ QScriptValueIterator it(global);
+ while (it.hasNext()) {
+ it.next();
+ actualNames.insert(it.name());
+ }
+ }
+
+ QSet<QString> remainingNames = actualNames;
+ {
+ QSet<QString>::const_iterator it;
+ for (it = expectedNames.constBegin(); it != expectedNames.constEnd(); ++it) {
+ QString name = *it;
+ QVERIFY(actualNames.contains(name));
+ remainingNames.remove(name);
+ }
+ }
+ QVERIFY(remainingNames.isEmpty());
+}
+#endif
+
+void tst_QJSEngine::createGlobalObjectProperty()
+{
+ QJSEngine eng;
+ QJSValue global = eng.globalObject();
+ // create property with no attributes
+ {
+ QString name = QString::fromLatin1("foo");
+ QVERIFY(!global.property(name).isValid());
+ QJSValue val(123);
+ global.setProperty(name, val);
+ QVERIFY(global.property(name).equals(val));
+ QVERIFY(global.propertyFlags(name) == 0);
+ global.setProperty(name, QJSValue());
+ QVERIFY(!global.property(name).isValid());
+ }
+ // create property with attributes
+#if 0 // ###FIXME: setProperty with flags is not supported
+ {
+ QString name = QString::fromLatin1("bar");
+ QVERIFY(!global.property(name).isValid());
+ QScriptValue val(QString::fromLatin1("ciao"));
+ QScriptValue::PropertyFlags flags = QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration;
+ global.setProperty(name, val, flags);
+ QVERIFY(global.property(name).equals(val));
+ //QEXPECT_FAIL("", "QTBUG-6134: custom Global Object properties don't retain attributes", Continue);
+ QCOMPARE(global.propertyFlags(name), flags);
+ global.setProperty(name, QScriptValue());
+ QVERIFY(!global.property(name).isValid());
+ }
+#endif
+}
+
+void tst_QJSEngine::globalObjectGetterSetterProperty()
+{
+#if 0 // ###FIXME: No c-style callbacks
+ QScriptEngine engine;
+ QScriptValue global = engine.globalObject();
+ global.setProperty("bar", engine.newFunction(getSetFoo),
+ QScriptValue::PropertySetter | QScriptValue::PropertyGetter);
+ global.setProperty("foo", 123);
+ QVERIFY(global.property("bar").equals(global.property("foo")));
+ QVERIFY(engine.evaluate("bar").equals(global.property("foo")));
+ global.setProperty("bar", 456);
+ QVERIFY(global.property("bar").equals(global.property("foo")));
+
+ engine.evaluate("__defineGetter__('baz', function() { return 789; })");
+ QVERIFY(engine.evaluate("baz").equals(789));
+ QVERIFY(global.property("baz").equals(789));
+#endif
+}
+
+#if 0 // ###FIXME: No support for setting the global object
+void tst_QJSEngine::customGlobalObjectWithPrototype()
+{
+ for (int x = 0; x < 2; ++x) {
+ QScriptEngine engine;
+ QScriptValue wrap = engine.newObject();
+ QScriptValue global = engine.globalObject();
+ QScriptValue originalGlobalProto = global.prototype();
+ if (!x) {
+ // Set prototype before setting global object
+ wrap.setPrototype(global);
+ QVERIFY(wrap.prototype().strictlyEquals(global));
+ engine.setGlobalObject(wrap);
+ } else {
+ // Set prototype after setting global object
+ engine.setGlobalObject(wrap);
+ wrap.setPrototype(global);
+ QVERIFY(wrap.prototype().strictlyEquals(global));
+ }
+ {
+ QScriptValue ret = engine.evaluate("print");
+ QVERIFY(ret.isFunction());
+ QVERIFY(ret.strictlyEquals(wrap.property("print")));
+ }
+ {
+ QScriptValue ret = engine.evaluate("this.print");
+ QVERIFY(ret.isFunction());
+ QVERIFY(ret.strictlyEquals(wrap.property("print")));
+ }
+ {
+ QScriptValue ret = engine.evaluate("hasOwnProperty('print')");
+ QVERIFY(ret.isBool());
+ if (x) QEXPECT_FAIL("", "Why?", Continue);
+ QVERIFY(!ret.toBool());
+ }
+ {
+ QScriptValue ret = engine.evaluate("this.hasOwnProperty('print')");
+ QVERIFY(ret.isBool());
+ if (x) QEXPECT_FAIL("", "Why?", Continue);
+ QVERIFY(!ret.toBool());
+ }
+
+ QScriptValue anotherProto = engine.newObject();
+ anotherProto.setProperty("anotherProtoProperty", 123);
+ global.setPrototype(anotherProto);
+ {
+ QScriptValue ret = engine.evaluate("print");
+ QVERIFY(ret.isFunction());
+ QVERIFY(ret.strictlyEquals(wrap.property("print")));
+ }
+ {
+ QScriptValue ret = engine.evaluate("anotherProtoProperty");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(wrap.property("anotherProtoProperty")));
+ }
+ {
+ QScriptValue ret = engine.evaluate("this.anotherProtoProperty");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(wrap.property("anotherProtoProperty")));
+ }
+
+ wrap.setPrototype(anotherProto);
+ {
+ QScriptValue ret = engine.evaluate("print");
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: print is not defined"));
+ }
+ {
+ QScriptValue ret = engine.evaluate("anotherProtoProperty");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(wrap.property("anotherProtoProperty")));
+ }
+ QVERIFY(global.prototype().strictlyEquals(anotherProto));
+
+ global.setPrototype(originalGlobalProto);
+ engine.setGlobalObject(global);
+ {
+ QScriptValue ret = engine.evaluate("anotherProtoProperty");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().startsWith("ReferenceError: "));
+ }
+ {
+ QScriptValue ret = engine.evaluate("print");
+ QVERIFY(ret.isFunction());
+ QVERIFY(ret.strictlyEquals(global.property("print")));
+ }
+ QVERIFY(!anotherProto.property("print").isValid());
+ }
+}
+#endif
+
+void tst_QJSEngine::globalObjectWithCustomPrototype()
+{
+ QJSEngine engine;
+ QJSValue proto = engine.newObject();
+ proto.setProperty("protoProperty", 123);
+ QJSValue global = engine.globalObject();
+ QJSValue originalProto = global.prototype();
+ global.setPrototype(proto);
+ {
+ QJSValue ret = engine.evaluate("protoProperty");
+ QEXPECT_FAIL("", "Replacing the prototype of the global object is currently unsupported (see also v8 issue 1078)", Abort);
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(global.property("protoProperty")));
+ }
+ {
+ QJSValue ret = engine.evaluate("this.protoProperty");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(global.property("protoProperty")));
+ }
+ {
+ QJSValue ret = engine.evaluate("hasOwnProperty('protoProperty')");
+ QVERIFY(ret.isBool());
+ QVERIFY(!ret.toBool());
+ }
+ {
+ QJSValue ret = engine.evaluate("this.hasOwnProperty('protoProperty')");
+ QVERIFY(ret.isBool());
+ QVERIFY(!ret.toBool());
+ }
+
+ // Custom prototype set from JS
+ {
+ QJSValue ret = engine.evaluate("this.__proto__ = { 'a': 123 }; a");
+ QVERIFY(ret.isNumber());
+ QVERIFY(ret.strictlyEquals(global.property("a")));
+ }
+}
+
+void tst_QJSEngine::builtinFunctionNames_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("expectedName");
+
+ // See ECMA-262 Chapter 15, "Standard Built-in ECMAScript Objects".
+
+ QTest::newRow("parseInt") << QString("parseInt") << QString("parseInt");
+ QTest::newRow("parseFloat") << QString("parseFloat") << QString("parseFloat");
+ QTest::newRow("isNaN") << QString("isNaN") << QString("isNaN");
+ QTest::newRow("isFinite") << QString("isFinite") << QString("isFinite");
+ QTest::newRow("decodeURI") << QString("decodeURI") << QString("decodeURI");
+ QTest::newRow("decodeURIComponent") << QString("decodeURIComponent") << QString("decodeURIComponent");
+ QTest::newRow("encodeURI") << QString("encodeURI") << QString("encodeURI");
+ QTest::newRow("encodeURIComponent") << QString("encodeURIComponent") << QString("encodeURIComponent");
+ QTest::newRow("escape") << QString("escape") << QString("escape");
+ QTest::newRow("unescape") << QString("unescape") << QString("unescape");
+
+ QTest::newRow("Array") << QString("Array") << QString("Array");
+ QTest::newRow("Array.prototype.toString") << QString("Array.prototype.toString") << QString("toString");
+ QTest::newRow("Array.prototype.toLocaleString") << QString("Array.prototype.toLocaleString") << QString("toLocaleString");
+ QTest::newRow("Array.prototype.concat") << QString("Array.prototype.concat") << QString("concat");
+ QTest::newRow("Array.prototype.join") << QString("Array.prototype.join") << QString("join");
+ QTest::newRow("Array.prototype.pop") << QString("Array.prototype.pop") << QString("pop");
+ QTest::newRow("Array.prototype.push") << QString("Array.prototype.push") << QString("push");
+ QTest::newRow("Array.prototype.reverse") << QString("Array.prototype.reverse") << QString("reverse");
+ QTest::newRow("Array.prototype.shift") << QString("Array.prototype.shift") << QString("shift");
+ QTest::newRow("Array.prototype.slice") << QString("Array.prototype.slice") << QString("slice");
+ QTest::newRow("Array.prototype.sort") << QString("Array.prototype.sort") << QString("sort");
+ QTest::newRow("Array.prototype.splice") << QString("Array.prototype.splice") << QString("splice");
+ QTest::newRow("Array.prototype.unshift") << QString("Array.prototype.unshift") << QString("unshift");
+
+ QTest::newRow("Boolean") << QString("Boolean") << QString("Boolean");
+ QTest::newRow("Boolean.prototype.toString") << QString("Boolean.prototype.toString") << QString("toString");
+
+ QTest::newRow("Date") << QString("Date") << QString("Date");
+ QTest::newRow("Date.prototype.toString") << QString("Date.prototype.toString") << QString("toString");
+ QTest::newRow("Date.prototype.toDateString") << QString("Date.prototype.toDateString") << QString("toDateString");
+ QTest::newRow("Date.prototype.toTimeString") << QString("Date.prototype.toTimeString") << QString("toTimeString");
+ QTest::newRow("Date.prototype.toLocaleString") << QString("Date.prototype.toLocaleString") << QString("toLocaleString");
+ QTest::newRow("Date.prototype.toLocaleDateString") << QString("Date.prototype.toLocaleDateString") << QString("toLocaleDateString");
+ QTest::newRow("Date.prototype.toLocaleTimeString") << QString("Date.prototype.toLocaleTimeString") << QString("toLocaleTimeString");
+ QTest::newRow("Date.prototype.valueOf") << QString("Date.prototype.valueOf") << QString("valueOf");
+ QTest::newRow("Date.prototype.getTime") << QString("Date.prototype.getTime") << QString("getTime");
+ QTest::newRow("Date.prototype.getYear") << QString("Date.prototype.getYear") << QString("getYear");
+ QTest::newRow("Date.prototype.getFullYear") << QString("Date.prototype.getFullYear") << QString("getFullYear");
+ QTest::newRow("Date.prototype.getUTCFullYear") << QString("Date.prototype.getUTCFullYear") << QString("getUTCFullYear");
+ QTest::newRow("Date.prototype.getMonth") << QString("Date.prototype.getMonth") << QString("getMonth");
+ QTest::newRow("Date.prototype.getUTCMonth") << QString("Date.prototype.getUTCMonth") << QString("getUTCMonth");
+ QTest::newRow("Date.prototype.getDate") << QString("Date.prototype.getDate") << QString("getDate");
+ QTest::newRow("Date.prototype.getUTCDate") << QString("Date.prototype.getUTCDate") << QString("getUTCDate");
+ QTest::newRow("Date.prototype.getDay") << QString("Date.prototype.getDay") << QString("getDay");
+ QTest::newRow("Date.prototype.getUTCDay") << QString("Date.prototype.getUTCDay") << QString("getUTCDay");
+ QTest::newRow("Date.prototype.getHours") << QString("Date.prototype.getHours") << QString("getHours");
+ QTest::newRow("Date.prototype.getUTCHours") << QString("Date.prototype.getUTCHours") << QString("getUTCHours");
+ QTest::newRow("Date.prototype.getMinutes") << QString("Date.prototype.getMinutes") << QString("getMinutes");
+ QTest::newRow("Date.prototype.getUTCMinutes") << QString("Date.prototype.getUTCMinutes") << QString("getUTCMinutes");
+ QTest::newRow("Date.prototype.getSeconds") << QString("Date.prototype.getSeconds") << QString("getSeconds");
+ QTest::newRow("Date.prototype.getUTCSeconds") << QString("Date.prototype.getUTCSeconds") << QString("getUTCSeconds");
+ QTest::newRow("Date.prototype.getMilliseconds") << QString("Date.prototype.getMilliseconds") << QString("getMilliseconds");
+ QTest::newRow("Date.prototype.getUTCMilliseconds") << QString("Date.prototype.getUTCMilliseconds") << QString("getUTCMilliseconds");
+ QTest::newRow("Date.prototype.getTimezoneOffset") << QString("Date.prototype.getTimezoneOffset") << QString("getTimezoneOffset");
+ QTest::newRow("Date.prototype.setTime") << QString("Date.prototype.setTime") << QString("setTime");
+ QTest::newRow("Date.prototype.setMilliseconds") << QString("Date.prototype.setMilliseconds") << QString("setMilliseconds");
+ QTest::newRow("Date.prototype.setUTCMilliseconds") << QString("Date.prototype.setUTCMilliseconds") << QString("setUTCMilliseconds");
+ QTest::newRow("Date.prototype.setSeconds") << QString("Date.prototype.setSeconds") << QString("setSeconds");
+ QTest::newRow("Date.prototype.setUTCSeconds") << QString("Date.prototype.setUTCSeconds") << QString("setUTCSeconds");
+ QTest::newRow("Date.prototype.setMinutes") << QString("Date.prototype.setMinutes") << QString("setMinutes");
+ QTest::newRow("Date.prototype.setUTCMinutes") << QString("Date.prototype.setUTCMinutes") << QString("setUTCMinutes");
+ QTest::newRow("Date.prototype.setHours") << QString("Date.prototype.setHours") << QString("setHours");
+ QTest::newRow("Date.prototype.setUTCHours") << QString("Date.prototype.setUTCHours") << QString("setUTCHours");
+ QTest::newRow("Date.prototype.setDate") << QString("Date.prototype.setDate") << QString("setDate");
+ QTest::newRow("Date.prototype.setUTCDate") << QString("Date.prototype.setUTCDate") << QString("setUTCDate");
+ QTest::newRow("Date.prototype.setMonth") << QString("Date.prototype.setMonth") << QString("setMonth");
+ QTest::newRow("Date.prototype.setUTCMonth") << QString("Date.prototype.setUTCMonth") << QString("setUTCMonth");
+ QTest::newRow("Date.prototype.setYear") << QString("Date.prototype.setYear") << QString("setYear");
+ QTest::newRow("Date.prototype.setFullYear") << QString("Date.prototype.setFullYear") << QString("setFullYear");
+ QTest::newRow("Date.prototype.setUTCFullYear") << QString("Date.prototype.setUTCFullYear") << QString("setUTCFullYear");
+ QTest::newRow("Date.prototype.toUTCString") << QString("Date.prototype.toUTCString") << QString("toUTCString");
+ QTest::newRow("Date.prototype.toGMTString") << QString("Date.prototype.toGMTString") << QString("toGMTString");
+
+ QTest::newRow("Error") << QString("Error") << QString("Error");
+// QTest::newRow("Error.prototype.backtrace") << QString("Error.prototype.backtrace") << QString("backtrace");
+ QTest::newRow("Error.prototype.toString") << QString("Error.prototype.toString") << QString("toString");
+
+ QTest::newRow("EvalError") << QString("EvalError") << QString("EvalError");
+ QTest::newRow("RangeError") << QString("RangeError") << QString("RangeError");
+ QTest::newRow("ReferenceError") << QString("ReferenceError") << QString("ReferenceError");
+ QTest::newRow("SyntaxError") << QString("SyntaxError") << QString("SyntaxError");
+ QTest::newRow("TypeError") << QString("TypeError") << QString("TypeError");
+ QTest::newRow("URIError") << QString("URIError") << QString("URIError");
+
+ QTest::newRow("Function") << QString("Function") << QString("Function");
+ QTest::newRow("Function.prototype.toString") << QString("Function.prototype.toString") << QString("toString");
+ QTest::newRow("Function.prototype.apply") << QString("Function.prototype.apply") << QString("apply");
+ QTest::newRow("Function.prototype.call") << QString("Function.prototype.call") << QString("call");
+/* In V8, those function are only there for signals
+ QTest::newRow("Function.prototype.connect") << QString("Function.prototype.connect") << QString("connect");
+ QTest::newRow("Function.prototype.disconnect") << QString("Function.prototype.disconnect") << QString("disconnect");*/
+
+ QTest::newRow("Math.abs") << QString("Math.abs") << QString("abs");
+ QTest::newRow("Math.acos") << QString("Math.acos") << QString("acos");
+ QTest::newRow("Math.asin") << QString("Math.asin") << QString("asin");
+ QTest::newRow("Math.atan") << QString("Math.atan") << QString("atan");
+ QTest::newRow("Math.atan2") << QString("Math.atan2") << QString("atan2");
+ QTest::newRow("Math.ceil") << QString("Math.ceil") << QString("ceil");
+ QTest::newRow("Math.cos") << QString("Math.cos") << QString("cos");
+ QTest::newRow("Math.exp") << QString("Math.exp") << QString("exp");
+ QTest::newRow("Math.floor") << QString("Math.floor") << QString("floor");
+ QTest::newRow("Math.log") << QString("Math.log") << QString("log");
+ QTest::newRow("Math.max") << QString("Math.max") << QString("max");
+ QTest::newRow("Math.min") << QString("Math.min") << QString("min");
+ QTest::newRow("Math.pow") << QString("Math.pow") << QString("pow");
+ QTest::newRow("Math.random") << QString("Math.random") << QString("random");
+ QTest::newRow("Math.round") << QString("Math.round") << QString("round");
+ QTest::newRow("Math.sin") << QString("Math.sin") << QString("sin");
+ QTest::newRow("Math.sqrt") << QString("Math.sqrt") << QString("sqrt");
+ QTest::newRow("Math.tan") << QString("Math.tan") << QString("tan");
+
+ QTest::newRow("Number") << QString("Number") << QString("Number");
+ QTest::newRow("Number.prototype.toString") << QString("Number.prototype.toString") << QString("toString");
+ QTest::newRow("Number.prototype.toLocaleString") << QString("Number.prototype.toLocaleString") << QString("toLocaleString");
+ QTest::newRow("Number.prototype.valueOf") << QString("Number.prototype.valueOf") << QString("valueOf");
+ QTest::newRow("Number.prototype.toFixed") << QString("Number.prototype.toFixed") << QString("toFixed");
+ QTest::newRow("Number.prototype.toExponential") << QString("Number.prototype.toExponential") << QString("toExponential");
+ QTest::newRow("Number.prototype.toPrecision") << QString("Number.prototype.toPrecision") << QString("toPrecision");
+
+ QTest::newRow("Object") << QString("Object") << QString("Object");
+ QTest::newRow("Object.prototype.toString") << QString("Object.prototype.toString") << QString("toString");
+ QTest::newRow("Object.prototype.toLocaleString") << QString("Object.prototype.toLocaleString") << QString("toLocaleString");
+ QTest::newRow("Object.prototype.valueOf") << QString("Object.prototype.valueOf") << QString("valueOf");
+ QTest::newRow("Object.prototype.hasOwnProperty") << QString("Object.prototype.hasOwnProperty") << QString("hasOwnProperty");
+ QTest::newRow("Object.prototype.isPrototypeOf") << QString("Object.prototype.isPrototypeOf") << QString("isPrototypeOf");
+ QTest::newRow("Object.prototype.propertyIsEnumerable") << QString("Object.prototype.propertyIsEnumerable") << QString("propertyIsEnumerable");
+ QTest::newRow("Object.prototype.__defineGetter__") << QString("Object.prototype.__defineGetter__") << QString("__defineGetter__");
+ QTest::newRow("Object.prototype.__defineSetter__") << QString("Object.prototype.__defineSetter__") << QString("__defineSetter__");
+
+ QTest::newRow("RegExp") << QString("RegExp") << QString("RegExp");
+ QTest::newRow("RegExp.prototype.exec") << QString("RegExp.prototype.exec") << QString("exec");
+ QTest::newRow("RegExp.prototype.test") << QString("RegExp.prototype.test") << QString("test");
+ QTest::newRow("RegExp.prototype.toString") << QString("RegExp.prototype.toString") << QString("toString");
+
+ QTest::newRow("String") << QString("String") << QString("String");
+ QTest::newRow("String.prototype.toString") << QString("String.prototype.toString") << QString("toString");
+ QTest::newRow("String.prototype.valueOf") << QString("String.prototype.valueOf") << QString("valueOf");
+ QTest::newRow("String.prototype.charAt") << QString("String.prototype.charAt") << QString("charAt");
+ QTest::newRow("String.prototype.charCodeAt") << QString("String.prototype.charCodeAt") << QString("charCodeAt");
+ QTest::newRow("String.prototype.concat") << QString("String.prototype.concat") << QString("concat");
+ QTest::newRow("String.prototype.indexOf") << QString("String.prototype.indexOf") << QString("indexOf");
+ QTest::newRow("String.prototype.lastIndexOf") << QString("String.prototype.lastIndexOf") << QString("lastIndexOf");
+ QTest::newRow("String.prototype.localeCompare") << QString("String.prototype.localeCompare") << QString("localeCompare");
+ QTest::newRow("String.prototype.match") << QString("String.prototype.match") << QString("match");
+ QTest::newRow("String.prototype.replace") << QString("String.prototype.replace") << QString("replace");
+ QTest::newRow("String.prototype.search") << QString("String.prototype.search") << QString("search");
+ QTest::newRow("String.prototype.slice") << QString("String.prototype.slice") << QString("slice");
+ QTest::newRow("String.prototype.split") << QString("String.prototype.split") << QString("split");
+ QTest::newRow("String.prototype.substring") << QString("String.prototype.substring") << QString("substring");
+ QTest::newRow("String.prototype.toLowerCase") << QString("String.prototype.toLowerCase") << QString("toLowerCase");
+ QTest::newRow("String.prototype.toLocaleLowerCase") << QString("String.prototype.toLocaleLowerCase") << QString("toLocaleLowerCase");
+ QTest::newRow("String.prototype.toUpperCase") << QString("String.prototype.toUpperCase") << QString("toUpperCase");
+ QTest::newRow("String.prototype.toLocaleUpperCase") << QString("String.prototype.toLocaleUpperCase") << QString("toLocaleUpperCase");
+}
+
+void tst_QJSEngine::builtinFunctionNames()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, expectedName);
+ QJSEngine eng;
+ // The "name" property is actually non-standard, but JSC supports it.
+ QJSValue ret = eng.evaluate(QString::fromLatin1("%0.name").arg(expression));
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), expectedName);
+}
+
+#if 0 // ###FIXME: No syntax checking result
+void tst_QJSEngine::checkSyntax_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<int>("expectedState");
+ QTest::addColumn<int>("errorLineNumber");
+ QTest::addColumn<int>("errorColumnNumber");
+ QTest::addColumn<QString>("errorMessage");
+
+ QTest::newRow("0")
+ << QString("0") << int(QScriptSyntaxCheckResult::Valid)
+ << -1 << -1 << "";
+ QTest::newRow("if (")
+ << QString("if (\n") << int(QScriptSyntaxCheckResult::Intermediate)
+ << 0 << -1 << "Uncaught SyntaxError: Unexpected end of input";
+ QTest::newRow("if else")
+ << QString("\nif else") << int(QScriptSyntaxCheckResult::Error)
+ << 2 << 3 << "Uncaught SyntaxError: Unexpected token else";
+ QTest::newRow("foo[")
+ << QString("foo[") << int(QScriptSyntaxCheckResult::Intermediate)
+ << 1 << 4 << "Uncaught SyntaxError: Unexpected end of input";
+ QTest::newRow("foo['bar']")
+ << QString("foo['bar']") << int(QScriptSyntaxCheckResult::Valid)
+ << -1 << -1 << "";
+
+ QTest::newRow("/*")
+ << QString("/*") << int(QScriptSyntaxCheckResult::Error)
+ << 1 << 0 << "Uncaught SyntaxError: Unexpected token ILLEGAL";
+ QTest::newRow("/*\nMy comment")
+ << QString("/*\nMy comment") << int(QScriptSyntaxCheckResult::Error)
+ << 1 << 0 << "Uncaught SyntaxError: Unexpected token ILLEGAL";
+ QTest::newRow("/*\nMy comment */\nfoo = 10")
+ << QString("/*\nMy comment */\nfoo = 10") << int(QScriptSyntaxCheckResult::Valid)
+ << -1 << -1 << "";
+ QTest::newRow("foo = 10 /*")
+ << QString("foo = 10 /*") << int(QScriptSyntaxCheckResult::Error)
+ << 1 << 9 << "Uncaught SyntaxError: Unexpected token ILLEGAL";
+ QTest::newRow("foo = 10; /*")
+ << QString("foo = 10; /*") << int(QScriptSyntaxCheckResult::Error)
+ << 1 << 10 << "Uncaught SyntaxError: Unexpected token ILLEGAL";
+ QTest::newRow("foo = 10 /* My comment */")
+ << QString("foo = 10 /* My comment */") << int(QScriptSyntaxCheckResult::Valid)
+ << -1 << -1 << "";
+
+ QTest::newRow("/=/")
+ << QString("/=/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
+ QTest::newRow("/=/g")
+ << QString("/=/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
+ QTest::newRow("/a/")
+ << QString("/a/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
+ QTest::newRow("/a/g")
+ << QString("/a/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
+}
+
+void tst_QJSEngine::checkSyntax()
+{
+ QFETCH(QString, code);
+ QFETCH(int, expectedState);
+ QFETCH(int, errorLineNumber);
+ QFETCH(int, errorColumnNumber);
+ QFETCH(QString, errorMessage);
+
+ QScriptSyntaxCheckResult result = QScriptEngine::checkSyntax(code);
+ QCOMPARE(int(result.state()), expectedState);
+ QCOMPARE(result.errorLineNumber(), errorLineNumber);
+ QCOMPARE(result.errorColumnNumber(), errorColumnNumber);
+ QCOMPARE(result.errorMessage(), errorMessage);
+
+ // assignment
+ {
+ QScriptSyntaxCheckResult copy = result;
+ QCOMPARE(copy.state(), result.state());
+ QCOMPARE(copy.errorLineNumber(), result.errorLineNumber());
+ QCOMPARE(copy.errorColumnNumber(), result.errorColumnNumber());
+ QCOMPARE(copy.errorMessage(), result.errorMessage());
+ }
+ {
+ QScriptSyntaxCheckResult copy(result);
+ QCOMPARE(copy.state(), result.state());
+ QCOMPARE(copy.errorLineNumber(), result.errorLineNumber());
+ QCOMPARE(copy.errorColumnNumber(), result.errorColumnNumber());
+ QCOMPARE(copy.errorMessage(), result.errorMessage());
+ }
+}
+#endif
+
+#if 0 // ###FIXME: No support for canEvaluate
+void tst_QJSEngine::canEvaluate_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<bool>("expectSuccess");
+
+ QTest::newRow("") << QString("") << true;
+ QTest::newRow("0") << QString("0") << true;
+ QTest::newRow("!") << QString("!\n") << false;
+ QTest::newRow("if (") << QString("if (\n") << false;
+ QTest::newRow("if (10) //") << QString("if (10) //\n") << false;
+ QTest::newRow("a = 1; if (") << QString("a = 1;\nif (\n") << false;
+ QTest::newRow("./test.js") << QString("./test.js\n") << true;
+ QTest::newRow("if (0) print(1)") << QString("if (0)\nprint(1)\n") << true;
+ QTest::newRow("0 = ") << QString("0 = \n") << false;
+ QTest::newRow("0 = 0") << QString("0 = 0\n") << true;
+ QTest::newRow("foo[") << QString("foo[") << false;
+ QTest::newRow("foo[") << QString("foo[\n") << false;
+ QTest::newRow("foo['bar']") << QString("foo['bar']") << true;
+
+ //v8 does thinks unterminated comments are error rather than unfinished
+// QTest::newRow("/*") << QString("/*") << false;
+// QTest::newRow("/*\nMy comment") << QString("/*\nMy comment") << false;
+ QTest::newRow("/*\nMy comment */\nfoo = 10") << QString("/*\nMy comment */\nfoo = 10") << true;
+// QTest::newRow("foo = 10 /*") << QString("foo = 10 /*") << false;
+// QTest::newRow("foo = 10; /*") << QString("foo = 10; /*") << false;
+ QTest::newRow("foo = 10 /* My comment */") << QString("foo = 10 /* My comment */") << true;
+
+ QTest::newRow("/=/") << QString("/=/") << true;
+ QTest::newRow("/=/g") << QString("/=/g") << true;
+ QTest::newRow("/a/") << QString("/a/") << true;
+ QTest::newRow("/a/g") << QString("/a/g") << true;
+}
+
+void tst_QJSEngine::canEvaluate()
+{
+ QFETCH(QString, code);
+ QFETCH(bool, expectSuccess);
+
+ QScriptEngine eng;
+ QCOMPARE(eng.canEvaluate(code), expectSuccess);
+}
+#endif
+
+void tst_QJSEngine::evaluate_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<int>("lineNumber");
+ QTest::addColumn<bool>("expectHadError");
+ QTest::addColumn<int>("expectErrorLineNumber");
+
+ QTest::newRow("(newline)") << QString("\n") << -1 << false << -1;
+ QTest::newRow("0 //") << QString("0 //") << -1 << false << -1;
+ QTest::newRow("/* */") << QString("/* */") << -1 << false << -1;
+ QTest::newRow("//") << QString("//") << -1 << false << -1;
+ QTest::newRow("(spaces)") << QString(" ") << -1 << false << -1;
+ QTest::newRow("(empty)") << QString("") << -1 << false << -1;
+ QTest::newRow("0") << QString("0") << -1 << false << -1;
+ QTest::newRow("0=1") << QString("\n0=1;\n") << -1 << true << 2;
+ QTest::newRow("a=1") << QString("a=1\n") << -1 << false << -1;
+ QTest::newRow("a=1;K") << QString("a=1;\nK") << -1 << true << 2;
+
+ QTest::newRow("f()") << QString("function f()\n"
+ "{\n"
+ " var a;\n"
+ " var b=\";\n" // here's the error
+ "}\n"
+ "f();\n")
+ << -1 << true << 4;
+
+ QTest::newRow("0") << QString("0") << 10 << false << -1;
+ QTest::newRow("0=1") << QString("\n\n0=1\n") << 10 << true << 12;
+ QTest::newRow("a=1") << QString("a=1\n") << 10 << false << -1;
+ QTest::newRow("a=1;K") << QString("a=1;\n\nK") << 10 << true << 12;
+
+ QTest::newRow("f()") << QString("function f()\n"
+ "{\n"
+ " var a;\n"
+ "\n\n"
+ " var b=\";\n" // here's the error
+ "}\n"
+ "f();\n")
+ << 10 << true << 15;
+ QTest::newRow("functionThatDoesntExist()")
+ << QString(";\n;\n;\nfunctionThatDoesntExist()")
+ << -1 << true << 4;
+ QTest::newRow("for (var p in this) { continue labelThatDoesntExist; }")
+ << QString("for (var p in this) {\ncontinue labelThatDoesntExist; }")
+ << 4 << true << 5;
+ QTest::newRow("duplicateLabel: { duplicateLabel: ; }")
+ << QString("duplicateLabel: { duplicateLabel: ; }")
+ << 12 << true << 12;
+
+ QTest::newRow("/=/") << QString("/=/") << -1 << false << -1;
+ QTest::newRow("/=/g") << QString("/=/g") << -1 << false << -1;
+ QTest::newRow("/a/") << QString("/a/") << -1 << false << -1;
+ QTest::newRow("/a/g") << QString("/a/g") << -1 << false << -1;
+ QTest::newRow("/a/gim") << QString("/a/gim") << -1 << false << -1;
+ QTest::newRow("/a/gimp") << QString("/a/gimp") << 1 << true << 1;
+}
+
+void tst_QJSEngine::evaluate()
+{
+ QFETCH(QString, code);
+ QFETCH(int, lineNumber);
+ QFETCH(bool, expectHadError);
+ QFETCH(int, expectErrorLineNumber);
+
+ QJSEngine eng;
+ QJSValue ret;
+ if (lineNumber != -1)
+ ret = eng.evaluate(code, /*fileName =*/QString(), lineNumber);
+ else
+ ret = eng.evaluate(code);
+ QEXPECT_FAIL("/a/gimp", "v8 ignore invalid flags", Abort);
+ QCOMPARE(eng.hasUncaughtException(), expectHadError);
+#if 0 // ###FIXME: No support for the line number of an uncaught exception
+ QEXPECT_FAIL("f()", "SyntaxError do not report line number", Continue);
+ QEXPECT_FAIL("duplicateLabel: { duplicateLabel: ; }", "SyntaxError do not report line number", Continue);
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), expectErrorLineNumber);
+#endif
+ if (eng.hasUncaughtException() && ret.isError()) {
+ QEXPECT_FAIL("", "we have no more lineNumber property ", Continue);
+ QVERIFY(ret.property("lineNumber").strictlyEquals(QJSValue(&eng, expectErrorLineNumber)));
+ } else {
+#if 0 // ###FIXME: No support for the backtrace of an uncaught exception
+ QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty());
+#endif
+ }
+}
+
+#if 0 // ###FIXME: no support for c-style callbacks
+static QScriptValue eval_nested(QScriptContext *ctx, QScriptEngine *eng)
+{
+ QScriptValue result = eng->newObject();
+ eng->evaluate("var bar = 'local';");
+ result.setProperty("thisObjectIdBefore", ctx->thisObject().property("id"));
+ QScriptValue evaluatedThisObject = eng->evaluate("this");
+ result.setProperty("thisObjectIdAfter", ctx->thisObject().property("id"));
+ result.setProperty("evaluatedThisObjectId", evaluatedThisObject.property("id"));
+ result.setProperty("local_bar", eng->evaluate("bar"));
+
+ return result;
+}
+
+// Tests that nested evaluate uses the "this" that was passed.
+void tst_QJSEngine::nestedEvaluate()
+{
+ QScriptEngine eng;
+ QScriptValue fun = eng.newFunction(eval_nested);
+ eng.globalObject().setProperty("fun", fun);
+ // From JS function call
+ {
+ QScriptValue result = eng.evaluate("o = { id:'foo'}; o.fun = fun; o.fun()");
+ QCOMPARE(result.property("local_bar").toString(), QString("local"));
+ QCOMPARE(result.property("thisObjectIdBefore").toString(), QString("foo"));
+ QCOMPARE(result.property("thisObjectIdAfter").toString(), QString("foo"));
+ QCOMPARE(result.property("evaluatedThisObjectId").toString(), QString("foo"));
+ QScriptValue bar = eng.evaluate("bar"); // Was introduced in local scope.
+ QVERIFY(bar.isError());
+ QVERIFY(bar.toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+ // From QScriptValue::call()
+ {
+ QScriptValue result = fun.call(eng.evaluate("p = { id:'foo' }") , QScriptValueList() );
+ QCOMPARE(result.property("local_bar").toString(), QString("local"));
+ QCOMPARE(result.property("thisObjectIdBefore").toString(), QString("foo"));
+ QCOMPARE(result.property("thisObjectIdAfter").toString(), QString("foo"));
+ QCOMPARE(result.property("evaluatedThisObjectId").toString(), QString("foo"));
+ QScriptValue bar = eng.evaluate("bar");
+ QVERIFY(bar.isError());
+ QVERIFY(bar.toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+}
+#endif
+
+#if 0 // ### FIXME: No c-style callbacks
+void tst_QJSEngine::uncaughtException()
+{
+ QScriptEngine eng;
+ QScriptValue fun = eng.newFunction(myFunction);
+ QScriptValue throwFun = eng.newFunction(myThrowingFunction);
+ for (int x = -1; x < 2; ++x) {
+ {
+ QScriptValue ret = eng.evaluate("a = 10;\nb = 20;\n0 = 0;\n", /*fileName=*/QString(), /*lineNumber=*/x);
+ QVERIFY(eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), x+2);
+ QVERIFY(eng.uncaughtException().strictlyEquals(ret));
+ (void)ret.toString();
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(eng.uncaughtException().strictlyEquals(ret));
+ QVERIFY(fun.call().isNull());
+ QVERIFY(eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), x+2);
+ QVERIFY(eng.uncaughtException().strictlyEquals(ret));
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), -1);
+ QVERIFY(!eng.uncaughtException().isValid());
+
+ eng.evaluate("2 = 3");
+ QVERIFY(eng.hasUncaughtException());
+ QScriptValue ret2 = throwFun.call();
+ QVERIFY(ret2.isError());
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(eng.uncaughtException().strictlyEquals(ret2));
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), 0);
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ eng.evaluate("1 + 2");
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ {
+ QScriptValue ret = eng.evaluate("a = 10");
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(!eng.uncaughtException().isValid());
+ }
+ {
+ QScriptValue ret = eng.evaluate("1 = 2");
+ QVERIFY(eng.hasUncaughtException());
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ {
+ eng.globalObject().setProperty("throwFun", throwFun);
+ eng.evaluate("1;\nthrowFun();");
+ QVERIFY(eng.hasUncaughtException());
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), 2);
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ }
+}
+#endif
+
+void tst_QJSEngine::errorMessage_QT679()
+{
+ QJSEngine engine;
+ engine.globalObject().setProperty("foo", 15);
+ QJSValue error = engine.evaluate("'hello world';\nfoo.bar.blah");
+ QVERIFY(error.isError());
+ QVERIFY(error.toString().startsWith(QString::fromLatin1("TypeError: ")));
+}
+
+struct Foo {
+public:
+ int x, y;
+ Foo() : x(-1), y(-1) { }
+};
+
+Q_DECLARE_METATYPE(Foo)
+Q_DECLARE_METATYPE(Foo*)
+
+#if 0 // FIXME: No prototype API in QScriptEngine
+void tst_QJSEngine::getSetDefaultPrototype_int()
+{
+ QScriptEngine eng;
+
+ QScriptValue object = eng.newObject();
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false);
+ eng.setDefaultPrototype(qMetaTypeId<int>(), object);
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).strictlyEquals(object), true);
+ QScriptValue value = eng.newVariant(int(123));
+ QCOMPARE(value.prototype().isObject(), true);
+ QCOMPARE(value.prototype().strictlyEquals(object), true);
+
+ eng.setDefaultPrototype(qMetaTypeId<int>(), QScriptValue());
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false);
+ QScriptValue value2 = eng.newVariant(int(123));
+ QCOMPARE(value2.prototype().strictlyEquals(object), false);
+}
+
+void tst_QJSEngine::getSetDefaultPrototype_customType()
+{
+ QScriptEngine eng;
+
+ QScriptValue object = eng.newObject();
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false);
+ eng.setDefaultPrototype(qMetaTypeId<Foo>(), object);
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(object), true);
+ QScriptValue value = eng.newVariant(qVariantFromValue(Foo()));
+ QCOMPARE(value.prototype().isObject(), true);
+ QCOMPARE(value.prototype().strictlyEquals(object), true);
+
+ eng.setDefaultPrototype(qMetaTypeId<Foo>(), QScriptValue());
+ QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false);
+ QScriptValue value2 = eng.newVariant(qVariantFromValue(Foo()));
+ QCOMPARE(value2.prototype().strictlyEquals(object), false);
+}
+#endif
+
+static QJSValue fooToScriptValue(QJSEngine *eng, const Foo &foo)
+{
+ QJSValue obj = eng->newObject();
+ obj.setProperty("x", QJSValue(eng, foo.x));
+ obj.setProperty("y", QJSValue(eng, foo.y));
+ return obj;
+}
+
+static void fooFromScriptValue(const QJSValue &value, Foo &foo)
+{
+ foo.x = value.property("x").toInt32();
+ foo.y = value.property("y").toInt32();
+}
+
+static QJSValue fooToScriptValueV2(QJSEngine *eng, const Foo &foo)
+{
+ return QJSValue(eng, foo.x);
+}
+
+static void fooFromScriptValueV2(const QJSValue &value, Foo &foo)
+{
+ foo.x = value.toInt32();
+}
+
+Q_DECLARE_METATYPE(QLinkedList<QString>)
+Q_DECLARE_METATYPE(QList<Foo>)
+Q_DECLARE_METATYPE(QVector<QChar>)
+Q_DECLARE_METATYPE(QStack<int>)
+Q_DECLARE_METATYPE(QQueue<char>)
+Q_DECLARE_METATYPE(QLinkedList<QStack<int> >)
+
+void tst_QJSEngine::valueConversion_basic()
+{
+ QJSEngine eng;
+ {
+ QJSValue num = eng.toScriptValue(123);
+ QCOMPARE(num.isNumber(), true);
+ QCOMPARE(num.strictlyEquals(QJSValue(&eng, 123)), true);
+
+ int inum = eng.fromScriptValue<int>(num);
+ QCOMPARE(inum, 123);
+
+ QString snum = eng.fromScriptValue<QString>(num);
+ QCOMPARE(snum, QLatin1String("123"));
+ }
+ {
+ QJSValue num = eng.toScriptValue(123);
+ QCOMPARE(num.isNumber(), true);
+ QCOMPARE(num.strictlyEquals(QJSValue(&eng, 123)), true);
+
+ int inum = eng.fromScriptValue<int>(num);
+ QCOMPARE(inum, 123);
+
+ QString snum = eng.fromScriptValue<QString>(num);
+ QCOMPARE(snum, QLatin1String("123"));
+ }
+ {
+ QJSValue num(&eng, 123);
+ QCOMPARE(eng.fromScriptValue<char>(num), char(123));
+ QCOMPARE(eng.fromScriptValue<unsigned char>(num), (unsigned char)(123));
+ QCOMPARE(eng.fromScriptValue<short>(num), short(123));
+ QCOMPARE(eng.fromScriptValue<unsigned short>(num), (unsigned short)(123));
+ QCOMPARE(eng.fromScriptValue<float>(num), float(123));
+ QCOMPARE(eng.fromScriptValue<double>(num), double(123));
+ QCOMPARE(eng.fromScriptValue<qlonglong>(num), qlonglong(123));
+ QCOMPARE(eng.fromScriptValue<qulonglong>(num), qulonglong(123));
+ }
+ {
+ QJSValue num(123);
+ QCOMPARE(eng.fromScriptValue<char>(num), char(123));
+ QCOMPARE(eng.fromScriptValue<unsigned char>(num), (unsigned char)(123));
+ QCOMPARE(eng.fromScriptValue<short>(num), short(123));
+ QCOMPARE(eng.fromScriptValue<unsigned short>(num), (unsigned short)(123));
+ QCOMPARE(eng.fromScriptValue<float>(num), float(123));
+ QCOMPARE(eng.fromScriptValue<double>(num), double(123));
+ QCOMPARE(eng.fromScriptValue<qlonglong>(num), qlonglong(123));
+ QCOMPARE(eng.fromScriptValue<qulonglong>(num), qulonglong(123));
+ }
+
+ {
+ QJSValue num = eng.toScriptValue(Q_INT64_C(0x100000000));
+ QCOMPARE(eng.fromScriptValue<qlonglong>(num), Q_INT64_C(0x100000000));
+ QCOMPARE(eng.fromScriptValue<qulonglong>(num), Q_UINT64_C(0x100000000));
+ }
+
+ {
+ QChar c = QLatin1Char('c');
+ QJSValue str = QJSValue(&eng, QLatin1String("ciao"));
+ QCOMPARE(eng.fromScriptValue<QChar>(str), c);
+ QJSValue code = QJSValue(&eng, c.unicode());
+ QCOMPARE(eng.fromScriptValue<QChar>(code), c);
+ QCOMPARE(eng.fromScriptValue<QChar>(eng.toScriptValue(c)), c);
+ }
+}
+
+#if 0 // FIXME: No API for custom types
+void tst_QJSEngine::valueConversion_customType()
+{
+ QScriptEngine eng;
+ {
+ // a type that we don't have built-in conversion of
+ // (it's stored as a variant)
+ QTime tm(1, 2, 3, 4);
+ QScriptValue val = eng.toScriptValue(tm);
+ QCOMPARE(eng.fromScriptValue<QTime>(val), tm);
+ }
+
+ {
+ Foo foo;
+ foo.x = 12;
+ foo.y = 34;
+ QScriptValue fooVal = eng.toScriptValue(foo);
+ QCOMPARE(fooVal.isVariant(), true);
+
+ Foo foo2 = eng.fromScriptValue<Foo>(fooVal);
+ QCOMPARE(foo2.x, foo.x);
+ QCOMPARE(foo2.y, foo.y);
+ }
+
+ qScriptRegisterMetaType<Foo>(&eng, fooToScriptValue, fooFromScriptValue);
+
+ {
+ Foo foo;
+ foo.x = 12;
+ foo.y = 34;
+ QScriptValue fooVal = eng.toScriptValue(foo);
+ QCOMPARE(fooVal.isObject(), true);
+ QVERIFY(fooVal.prototype().strictlyEquals(eng.evaluate("Object.prototype")));
+ QCOMPARE(fooVal.property("x").strictlyEquals(QScriptValue(&eng, 12)), true);
+ QCOMPARE(fooVal.property("y").strictlyEquals(QScriptValue(&eng, 34)), true);
+ fooVal.setProperty("x", QScriptValue(&eng, 56));
+ fooVal.setProperty("y", QScriptValue(&eng, 78));
+
+ Foo foo2 = eng.fromScriptValue<Foo>(fooVal);
+ QCOMPARE(foo2.x, 56);
+ QCOMPARE(foo2.y, 78);
+
+ QScriptValue fooProto = eng.newObject();
+ eng.setDefaultPrototype(qMetaTypeId<Foo>(), fooProto);
+ QScriptValue fooVal2 = eng.toScriptValue(foo2);
+ QVERIFY(fooVal2.prototype().strictlyEquals(fooProto));
+ QVERIFY(fooVal2.property("x").strictlyEquals(QScriptValue(&eng, 56)));
+ QVERIFY(fooVal2.property("y").strictlyEquals(QScriptValue(&eng, 78)));
+ }
+}
+
+void tst_QJSEngine::valueConversion_sequence()
+{
+ QScriptEngine eng;
+ qScriptRegisterSequenceMetaType<QLinkedList<QString> >(&eng);
+
+ {
+ QLinkedList<QString> lst;
+ lst << QLatin1String("foo") << QLatin1String("bar");
+ QScriptValue lstVal = eng.toScriptValue(lst);
+ QCOMPARE(lstVal.isArray(), true);
+ QCOMPARE(lstVal.property("length").toInt32(), 2);
+ QCOMPARE(lstVal.property("0").isString(), true);
+ QCOMPARE(lstVal.property("0").toString(), QLatin1String("foo"));
+ QCOMPARE(lstVal.property("1").isString(), true);
+ QCOMPARE(lstVal.property("1").toString(), QLatin1String("bar"));
+ }
+
+ qScriptRegisterSequenceMetaType<QList<Foo> >(&eng);
+ qScriptRegisterSequenceMetaType<QStack<int> >(&eng);
+ qScriptRegisterSequenceMetaType<QVector<QChar> >(&eng);
+ qScriptRegisterSequenceMetaType<QQueue<char> >(&eng);
+ qScriptRegisterSequenceMetaType<QLinkedList<QStack<int> > >(&eng);
+
+ {
+ QLinkedList<QStack<int> > lst;
+ QStack<int> first; first << 13 << 49; lst << first;
+ QStack<int> second; second << 99999;lst << second;
+ QScriptValue lstVal = eng.toScriptValue(lst);
+ QCOMPARE(lstVal.isArray(), true);
+ QCOMPARE(lstVal.property("length").toInt32(), 2);
+ QCOMPARE(lstVal.property("0").isArray(), true);
+ QCOMPARE(lstVal.property("0").property("length").toInt32(), 2);
+ QCOMPARE(lstVal.property("0").property("0").toInt32(), first.at(0));
+ QCOMPARE(lstVal.property("0").property("1").toInt32(), first.at(1));
+ QCOMPARE(lstVal.property("1").isArray(), true);
+ QCOMPARE(lstVal.property("1").property("length").toInt32(), 1);
+ QCOMPARE(lstVal.property("1").property("0").toInt32(), second.at(0));
+ QCOMPARE(qscriptvalue_cast<QStack<int> >(lstVal.property("0")), first);
+ QCOMPARE(qscriptvalue_cast<QStack<int> >(lstVal.property("1")), second);
+ QCOMPARE(qscriptvalue_cast<QLinkedList<QStack<int> > >(lstVal), lst);
+ }
+
+ // pointers
+ {
+ Foo foo;
+ {
+ QScriptValue v = eng.toScriptValue(&foo);
+ Foo *pfoo = qscriptvalue_cast<Foo*>(v);
+ QCOMPARE(pfoo, &foo);
+ }
+ {
+ Foo *pfoo = 0;
+ QScriptValue v = eng.toScriptValue(pfoo);
+ QCOMPARE(v.isNull(), true);
+ QVERIFY(qscriptvalue_cast<Foo*>(v) == 0);
+ }
+ }
+
+ // QList<int> and QObjectList should be converted from/to arrays by default
+ {
+ QList<int> lst;
+ lst << 1 << 2 << 3;
+ QScriptValue val = eng.toScriptValue(lst);
+ QVERIFY(val.isArray());
+ QCOMPARE(val.property("length").toInt32(), lst.size());
+ QCOMPARE(val.property(0).toInt32(), lst.at(0));
+ QCOMPARE(val.property(1).toInt32(), lst.at(1));
+ QCOMPARE(val.property(2).toInt32(), lst.at(2));
+
+ QCOMPARE(qscriptvalue_cast<QList<int> >(val), lst);
+ }
+ {
+ QObjectList lst;
+ lst << this;
+ QScriptValue val = eng.toScriptValue(lst);
+ QVERIFY(val.isArray());
+ QCOMPARE(val.property("length").toInt32(), lst.size());
+ QCOMPARE(val.property(0).toQObject(), (QObject *)this);
+
+ QCOMPARE(qscriptvalue_cast<QObjectList>(val), lst);
+ }
+}
+#endif
+
+void tst_QJSEngine::valueConversion_QVariant()
+{
+ QJSEngine eng;
+ // qScriptValueFromValue() should be "smart" when the argument is a QVariant
+ {
+ QJSValue val = eng.toScriptValue(QVariant());
+ QVERIFY(!val.isVariant());
+ QVERIFY(val.isUndefined());
+ }
+ // Checking nested QVariants
+ {
+ QVariant tmp1;
+ QVariant tmp2(QMetaType::QVariant, &tmp1);
+ QVERIFY(QMetaType::Type(tmp2.type()) == QMetaType::QVariant);
+
+ QJSValue val1 = eng.toScriptValue(tmp1);
+ QJSValue val2 = eng.toScriptValue(tmp2);
+ QVERIFY(val1.isValid());
+ QVERIFY(val2.isValid());
+ QVERIFY(val1.isUndefined());
+ QEXPECT_FAIL("", "Variant are unrwapped, maybe we should not...", Continue);
+ QVERIFY(!val2.isUndefined());
+ QVERIFY(!val1.isVariant());
+ QEXPECT_FAIL("", "Variant are unrwapped, maybe we should not...", Continue);
+ QVERIFY(val2.isVariant());
+ }
+ {
+ QVariant tmp1(123);
+ QVariant tmp2(QMetaType::QVariant, &tmp1);
+ QVariant tmp3(QMetaType::QVariant, &tmp2);
+ QVERIFY(QMetaType::Type(tmp1.type()) == QMetaType::Int);
+ QVERIFY(QMetaType::Type(tmp2.type()) == QMetaType::QVariant);
+ QVERIFY(QMetaType::Type(tmp3.type()) == QMetaType::QVariant);
+
+ QJSValue val1 = eng.toScriptValue(tmp2);
+ QJSValue val2 = eng.toScriptValue(tmp3);
+ QVERIFY(val1.isValid());
+ QVERIFY(val2.isValid());
+ QEXPECT_FAIL("", "Variant are unrwapped, maybe we should not...", Continue);
+ QVERIFY(val1.isVariant());
+ QEXPECT_FAIL("", "Variant are unrwapped, maybe we should not...", Continue);
+ QVERIFY(val2.isVariant());
+ QVERIFY(val1.toVariant().toInt() == 123);
+ QVERIFY(eng.toScriptValue(val2.toVariant()).toVariant().toInt() == 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(QVariant(true));
+ QVERIFY(!val.isVariant());
+ QVERIFY(val.isBoolean());
+ QCOMPARE(val.toBoolean(), true);
+ }
+ {
+ QJSValue val = eng.toScriptValue(QVariant(int(123)));
+ QVERIFY(!val.isVariant());
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toNumber(), qreal(123));
+ }
+ {
+ QJSValue val = eng.toScriptValue(QVariant(qreal(1.25)));
+ QVERIFY(!val.isVariant());
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toNumber(), qreal(1.25));
+ }
+ {
+ QString str = QString::fromLatin1("ciao");
+ QJSValue val = eng.toScriptValue(QVariant(str));
+ QVERIFY(!val.isVariant());
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), str);
+ }
+ {
+ QJSValue val = eng.toScriptValue(qVariantFromValue((QObject*)this));
+ QVERIFY(!val.isVariant());
+ QVERIFY(val.isQObject());
+ QCOMPARE(val.toQObject(), (QObject*)this);
+ }
+ {
+ QVariant var = qVariantFromValue(QPoint(123, 456));
+ QJSValue val = eng.toScriptValue(var);
+ QVERIFY(val.isVariant());
+ QCOMPARE(val.toVariant(), var);
+ }
+
+ QCOMPARE(qjsvalue_cast<QVariant>(QJSValue(123)), QVariant(123));
+}
+
+#if 0 // FIXME: No support for custom types
+void tst_QJSEngine::valueConversion_hooliganTask248802()
+{
+ QScriptEngine eng;
+ qScriptRegisterMetaType<Foo>(&eng, fooToScriptValueV2, fooFromScriptValueV2);
+ {
+ QScriptValue num(&eng, 123);
+ Foo foo = eng.fromScriptValue<Foo>(num);
+ QCOMPARE(foo.x, 123);
+ }
+ {
+ QScriptValue num(123);
+ Foo foo = eng.fromScriptValue<Foo>(num);
+ QCOMPARE(foo.x, -1);
+ }
+ {
+ QScriptValue str(&eng, QLatin1String("123"));
+ Foo foo = eng.fromScriptValue<Foo>(str);
+ QCOMPARE(foo.x, 123);
+ }
+
+}
+#endif
+
+void tst_QJSEngine::valueConversion_basic2()
+{
+ QJSEngine eng;
+ // more built-in types
+ {
+ QJSValue val = eng.toScriptValue(uint(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(qulonglong(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(float(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(short(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(ushort(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(char(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+ {
+ QJSValue val = eng.toScriptValue(uchar(123));
+ QVERIFY(val.isNumber());
+ QCOMPARE(val.toInt32(), 123);
+ }
+}
+
+void tst_QJSEngine::valueConversion_dateTime()
+{
+ QJSEngine eng;
+ {
+ QDateTime in = QDateTime::currentDateTime();
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isDate());
+ QCOMPARE(val.toDateTime(), in);
+ }
+ {
+ QDate in = QDate::currentDate();
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isDate());
+ QCOMPARE(val.toDateTime().date(), in);
+ }
+}
+
+void tst_QJSEngine::valueConversion_regExp()
+{
+ QJSEngine eng;
+ {
+ QRegExp in = QRegExp("foo");
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isRegExp());
+ QRegExp out = val.toRegExp();
+ QEXPECT_FAIL("", "QTBUG-6136: JSC-based back-end doesn't preserve QRegExp::patternSyntax (always uses RegExp2)", Continue);
+ QCOMPARE(out.patternSyntax(), in.patternSyntax());
+ QCOMPARE(out.pattern(), in.pattern());
+ QCOMPARE(out.caseSensitivity(), in.caseSensitivity());
+ QCOMPARE(out.isMinimal(), in.isMinimal());
+ }
+ {
+ QRegExp in = QRegExp("foo", Qt::CaseSensitive, QRegExp::RegExp2);
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isRegExp());
+ QCOMPARE(val.toRegExp(), in);
+ }
+ {
+ QRegExp in = QRegExp("foo");
+ in.setMinimal(true);
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isRegExp());
+ QEXPECT_FAIL("", "QTBUG-6136: JSC-based back-end doesn't preserve QRegExp::minimal (always false)", Continue);
+ QCOMPARE(val.toRegExp().isMinimal(), in.isMinimal());
+ }
+}
+
+#if 0 // FIXME: No qScriptValueFromValue
+void tst_QJSEngine::qScriptValueFromValue_noEngine()
+{
+ QVERIFY(!qScriptValueFromValue(0, 123).isValid());
+ QVERIFY(!qScriptValueFromValue(0, QVariant(123)).isValid());
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptContext
+static QScriptValue __import__(QScriptContext *ctx, QScriptEngine *eng)
+{
+ return eng->importExtension(ctx->argument(0).toString());
+}
+
+void tst_QJSEngine::importExtension()
+{
+ QStringList libPaths = QCoreApplication::instance()->libraryPaths();
+ QCoreApplication::instance()->setLibraryPaths(QStringList() << SRCDIR);
+
+ QStringList availableExtensions;
+ {
+ QScriptEngine eng;
+ QVERIFY(eng.importedExtensions().isEmpty());
+ QStringList ret = eng.availableExtensions();
+ QCOMPARE(ret.size(), 4);
+ QCOMPARE(ret.at(0), QString::fromLatin1("com"));
+ QCOMPARE(ret.at(1), QString::fromLatin1("com.trolltech"));
+ QCOMPARE(ret.at(2), QString::fromLatin1("com.trolltech.recursive"));
+ QCOMPARE(ret.at(3), QString::fromLatin1("com.trolltech.syntaxerror"));
+ availableExtensions = ret;
+ }
+
+ // try to import something that doesn't exist
+ {
+ QScriptEngine eng;
+ QScriptValue ret = eng.importExtension("this.extension.does.not.exist");
+ QCOMPARE(eng.hasUncaughtException(), true);
+ QCOMPARE(ret.isError(), true);
+ QCOMPARE(ret.toString(), QString::fromLatin1("Error: Unable to import this.extension.does.not.exist: no such extension"));
+ }
+
+ {
+ QScriptEngine eng;
+ for (int x = 0; x < 2; ++x) {
+ QCOMPARE(eng.globalObject().property("com").isValid(), x == 1);
+ QScriptValue ret = eng.importExtension("com.trolltech");
+ QCOMPARE(eng.hasUncaughtException(), false);
+ QCOMPARE(ret.isUndefined(), true);
+
+ QScriptValue com = eng.globalObject().property("com");
+ QCOMPARE(com.isObject(), true);
+ QCOMPARE(com.property("wasDefinedAlready")
+ .strictlyEquals(QScriptValue(&eng, false)), true);
+ QCOMPARE(com.property("name")
+ .strictlyEquals(QScriptValue(&eng, "com")), true);
+ QCOMPARE(com.property("level")
+ .strictlyEquals(QScriptValue(&eng, 1)), true);
+ QVERIFY(com.property("originalPostInit").isUndefined());
+ QVERIFY(com.property("postInitCallCount").strictlyEquals(1));
+
+ QScriptValue trolltech = com.property("trolltech");
+ QCOMPARE(trolltech.isObject(), true);
+ QCOMPARE(trolltech.property("wasDefinedAlready")
+ .strictlyEquals(QScriptValue(&eng, false)), true);
+ QCOMPARE(trolltech.property("name")
+ .strictlyEquals(QScriptValue(&eng, "com.trolltech")), true);
+ QCOMPARE(trolltech.property("level")
+ .strictlyEquals(QScriptValue(&eng, 2)), true);
+ QVERIFY(trolltech.property("originalPostInit").isUndefined());
+ QVERIFY(trolltech.property("postInitCallCount").strictlyEquals(1));
+ }
+ QStringList imp = eng.importedExtensions();
+ QCOMPARE(imp.size(), 2);
+ QCOMPARE(imp.at(0), QString::fromLatin1("com"));
+ QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech"));
+ QCOMPARE(eng.availableExtensions(), availableExtensions);
+ }
+
+ // recursive import should throw an error
+ {
+ QScriptEngine eng;
+ QVERIFY(eng.importedExtensions().isEmpty());
+ eng.globalObject().setProperty("__import__", eng.newFunction(__import__));
+ QScriptValue ret = eng.importExtension("com.trolltech.recursive");
+ QCOMPARE(eng.hasUncaughtException(), true);
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("Error: recursive import of com.trolltech.recursive"));
+ QStringList imp = eng.importedExtensions();
+ QCOMPARE(imp.size(), 2);
+ QCOMPARE(imp.at(0), QString::fromLatin1("com"));
+ QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech"));
+ QCOMPARE(eng.availableExtensions(), availableExtensions);
+ }
+
+ {
+ QScriptEngine eng;
+ eng.globalObject().setProperty("__import__", eng.newFunction(__import__));
+ for (int x = 0; x < 2; ++x) {
+ if (x == 0)
+ QVERIFY(eng.importedExtensions().isEmpty());
+ QScriptValue ret = eng.importExtension("com.trolltech.syntaxerror");
+ QVERIFY(eng.hasUncaughtException());
+ QEXPECT_FAIL("", "JSC throws syntax error eagerly", Continue);
+ QCOMPARE(eng.uncaughtExceptionLineNumber(), 4);
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QLatin1String("SyntaxError")));
+ }
+ QStringList imp = eng.importedExtensions();
+ QCOMPARE(imp.size(), 2);
+ QCOMPARE(imp.at(0), QString::fromLatin1("com"));
+ QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech"));
+ QCOMPARE(eng.availableExtensions(), availableExtensions);
+ }
+
+ QCoreApplication::instance()->setLibraryPaths(libPaths);
+}
+
+static QScriptValue recurse(QScriptContext *ctx, QScriptEngine *eng)
+{
+ Q_UNUSED(eng);
+ return ctx->callee().call();
+}
+
+static QScriptValue recurse2(QScriptContext *ctx, QScriptEngine *eng)
+{
+ Q_UNUSED(eng);
+ return ctx->callee().construct();
+}
+
+void tst_QJSEngine::infiniteRecursion()
+{
+ // Infinite recursion in JS should cause the VM to throw an error
+ // when the JS stack is exhausted.
+ // The exact error is back-end specific and subject to change.
+ const QString stackOverflowError = QString::fromLatin1("RangeError: Maximum call stack size exceeded");
+ QScriptEngine eng;
+ {
+ QScriptValue ret = eng.evaluate("function foo() { foo(); }; foo();");
+ QCOMPARE(ret.isError(), true);
+ QVERIFY(ret.toString().startsWith(stackOverflowError));
+ }
+#if 0 //The native C++ stack overflow before the JS stack
+ {
+ QScriptValue fun = eng.newFunction(recurse);
+ QScriptValue ret = fun.call();
+ QCOMPARE(ret.isError(), true);
+ QCOMPARE(ret.toString(), stackOverflowError);
+ }
+ {
+ QScriptValue fun = eng.newFunction(recurse2);
+ QScriptValue ret = fun.construct();
+ QCOMPARE(ret.isError(), true);
+ QCOMPARE(ret.toString(), stackOverflowError);
+ }
+#endif
+}
+#endif
+
+struct Bar {
+ int a;
+};
+
+struct Baz : public Bar {
+ int b;
+};
+
+Q_DECLARE_METATYPE(Bar*)
+Q_DECLARE_METATYPE(Baz*)
+
+Q_DECLARE_METATYPE(QGradient)
+Q_DECLARE_METATYPE(QGradient*)
+Q_DECLARE_METATYPE(QLinearGradient)
+
+#if 0 // FIXME: No support for default prototypes
+class Zoo : public QObject
+{
+ Q_OBJECT
+public:
+ Zoo() { }
+public slots:
+ Baz *toBaz(Bar *b) { return reinterpret_cast<Baz*>(b); }
+};
+
+void tst_QJSEngine::castWithPrototypeChain()
+{
+ QScriptEngine eng;
+ Bar bar;
+ Baz baz;
+ QScriptValue barProto = eng.toScriptValue(&bar);
+ QScriptValue bazProto = eng.toScriptValue(&baz);
+ eng.setDefaultPrototype(qMetaTypeId<Bar*>(), barProto);
+ eng.setDefaultPrototype(qMetaTypeId<Baz*>(), bazProto);
+
+ Baz baz2;
+ baz2.a = 123;
+ baz2.b = 456;
+ QScriptValue baz2Value = eng.toScriptValue(&baz2);
+ {
+ // qscriptvalue_cast() does magic; if the QScriptValue contains
+ // t of type T, and the target type is T*, &t is returned.
+ Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value);
+ QVERIFY(pbaz != 0);
+ QCOMPARE(pbaz->b, baz2.b);
+
+ Zoo zoo;
+ QScriptValue scriptZoo = eng.newQObject(&zoo);
+ QScriptValue toBaz = scriptZoo.property("toBaz");
+ QVERIFY(toBaz.isFunction());
+
+ // no relation between Bar and Baz's proto --> casting fails
+ {
+ Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
+ QVERIFY(pbar == 0);
+ }
+
+ {
+ QScriptValue ret = toBaz.call(scriptZoo, QScriptValueList() << baz2Value);
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: incompatible type of argument(s) in call to toBaz(); candidates were\n toBaz(Bar*)"));
+ }
+
+ // establish chain -- now casting should work
+ // Why? because qscriptvalue_cast() does magic again.
+ // It the instance itself is not of type T, qscriptvalue_cast()
+ // searches the prototype chain for T, and if it finds one, it infers
+ // that the instance can also be casted to that type. This cast is
+ // _not_ safe and thus relies on the developer doing the right thing.
+ // This is an undocumented feature to enable qscriptvalue_cast() to
+ // be used by prototype functions to cast the JS this-object to C++.
+ bazProto.setPrototype(barProto);
+
+ {
+ Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
+ QVERIFY(pbar != 0);
+ QCOMPARE(pbar->a, baz2.a);
+ }
+
+ {
+ QScriptValue ret = toBaz.call(scriptZoo, QScriptValueList() << baz2Value);
+ QEXPECT_FAIL("", "Cannot convert Baz* to Bar*", Continue);
+ QVERIFY(!ret.isError());
+ QEXPECT_FAIL("", "Cannot convert Baz* to Bar*", Continue);
+ QCOMPARE(qscriptvalue_cast<Baz*>(ret), pbaz);
+ }
+ }
+
+ bazProto.setPrototype(barProto.prototype()); // kill chain
+ {
+ Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value);
+ QVERIFY(pbaz != 0);
+ // should not work anymore
+ Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
+ QVERIFY(pbar == 0);
+ }
+
+ bazProto.setPrototype(eng.newQObject(this));
+ {
+ Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value);
+ QVERIFY(pbaz != 0);
+ // should not work now either
+ Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
+ QVERIFY(pbar == 0);
+ }
+
+ {
+ QScriptValue b = eng.toScriptValue(QBrush());
+ b.setPrototype(barProto);
+ // this shows that a "wrong" cast is possible, if you
+ // don't play by the rules (the pointer is actually a QBrush*)...
+ Bar *pbar = qscriptvalue_cast<Bar*>(b);
+ QVERIFY(pbar != 0);
+ }
+
+ {
+ QScriptValue gradientProto = eng.toScriptValue(QGradient());
+ QScriptValue linearGradientProto = eng.toScriptValue(QLinearGradient());
+ linearGradientProto.setPrototype(gradientProto);
+ QLinearGradient lg(10, 20, 30, 40);
+ QScriptValue linearGradient = eng.toScriptValue(lg);
+ {
+ QGradient *pgrad = qscriptvalue_cast<QGradient*>(linearGradient);
+ QVERIFY(pgrad == 0);
+ }
+ linearGradient.setPrototype(linearGradientProto);
+ {
+ QGradient *pgrad = qscriptvalue_cast<QGradient*>(linearGradient);
+ QVERIFY(pgrad != 0);
+ QCOMPARE(pgrad->type(), QGradient::LinearGradient);
+ QLinearGradient *plingrad = static_cast<QLinearGradient*>(pgrad);
+ QCOMPARE(plingrad->start(), lg.start());
+ QCOMPARE(plingrad->finalStop(), lg.finalStop());
+ }
+ }
+}
+#endif
+
+class Klazz : public QWidget,
+ public QStandardItem,
+ public QGraphicsItem
+{
+ Q_OBJECT
+public:
+ Klazz(QWidget *parent = 0) : QWidget(parent) { }
+ virtual QRectF boundingRect() const { return QRectF(); }
+ virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) { }
+};
+
+Q_DECLARE_METATYPE(Klazz*)
+Q_DECLARE_METATYPE(QStandardItem*)
+
+void tst_QJSEngine::castWithMultipleInheritance()
+{
+ QJSEngine eng;
+ Klazz klz;
+ QJSValue v = eng.newQObject(&klz);
+
+ QCOMPARE(qjsvalue_cast<Klazz*>(v), &klz);
+ QCOMPARE(qjsvalue_cast<QWidget*>(v), (QWidget *)&klz);
+ QCOMPARE(qjsvalue_cast<QObject*>(v), (QObject *)&klz);
+ QCOMPARE(qjsvalue_cast<QStandardItem*>(v), (QStandardItem *)&klz);
+ QCOMPARE(qjsvalue_cast<QGraphicsItem*>(v), (QGraphicsItem *)&klz);
+}
+
+#if 0 // ###FIXME: ScriptOwnership
+void tst_QJSEngine::collectGarbage()
+{
+ QScriptEngine eng;
+ eng.evaluate("a = new Object(); a = new Object(); a = new Object()");
+ QScriptValue a = eng.newObject();
+ a = eng.newObject();
+ a = eng.newObject();
+ QPointer<QObject> ptr = new QObject();
+ QVERIFY(ptr != 0);
+ (void)eng.newQObject(ptr, QScriptEngine::ScriptOwnership);
+ collectGarbage_helper(eng);
+ QVERIFY(ptr == 0);
+}
+#endif
+
+#if 0 // ###FIXME: no reportAdditionalMemoryCost API
+void tst_QJSEngine::reportAdditionalMemoryCost()
+{
+ QScriptEngine eng;
+ // There isn't any reliable way to test whether calling
+ // this function affects garbage collection responsiveness;
+ // the best we can do is call it with a few different values.
+ for (int x = 0; x < 100; ++x) {
+ eng.reportAdditionalMemoryCost(0);
+ eng.reportAdditionalMemoryCost(10);
+ eng.reportAdditionalMemoryCost(1000);
+ eng.reportAdditionalMemoryCost(10000);
+ eng.reportAdditionalMemoryCost(100000);
+ eng.reportAdditionalMemoryCost(1000000);
+ eng.reportAdditionalMemoryCost(10000000);
+ eng.reportAdditionalMemoryCost(-1);
+ eng.reportAdditionalMemoryCost(-1000);
+ QScriptValue obj = eng.newObject();
+ eng.collectGarbage();
+ }
+}
+#endif
+
+void tst_QJSEngine::gcWithNestedDataStructure()
+{
+ // The GC must be able to traverse deeply nested objects, otherwise this
+ // test would crash.
+ QJSEngine eng;
+ eng.evaluate(
+ "function makeList(size)"
+ "{"
+ " var head = { };"
+ " var l = head;"
+ " for (var i = 0; i < size; ++i) {"
+ " l.data = i + \"\";"
+ " l.next = { }; l = l.next;"
+ " }"
+ " l.next = null;"
+ " return head;"
+ "}");
+ QCOMPARE(eng.hasUncaughtException(), false);
+ const int size = 200;
+ QJSValue head = eng.evaluate(QString::fromLatin1("makeList(%0)").arg(size));
+ QCOMPARE(eng.hasUncaughtException(), false);
+ for (int x = 0; x < 2; ++x) {
+ if (x == 1)
+ eng.evaluate("gc()");
+ QJSValue l = head;
+ // Make sure all the nodes are still alive.
+ for (int i = 0; i < 200; ++i) {
+ QCOMPARE(l.property("data").toString(), QString::number(i));
+ l = l.property("next");
+ }
+ }
+}
+
+#if 0 // ###FIXME: No processEvents handling
+class EventReceiver : public QObject
+{
+public:
+ EventReceiver() {
+ received = false;
+ }
+
+ bool event(QEvent *e) {
+ received |= (e->type() == QEvent::User + 1);
+ return QObject::event(e);
+ }
+
+ bool received;
+};
+
+void tst_QJSEngine::processEventsWhileRunning()
+{
+ for (int x = 0; x < 2; ++x) {
+ QScriptEngine eng;
+ if (x == 0)
+ eng.pushContext();
+
+ // This is running for a silly amount of time just to make sure
+ // the script doesn't finish before event processing is triggered.
+ QString script = QString::fromLatin1(
+ "var end = Number(new Date()) + 2000;"
+ "var x = 0;"
+ "while (Number(new Date()) < end) {"
+ " ++x;"
+ "}");
+
+ EventReceiver receiver;
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
+
+ eng.evaluate(script);
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(!receiver.received);
+
+ QCOMPARE(eng.processEventsInterval(), -1);
+ eng.setProcessEventsInterval(100);
+ eng.evaluate(script);
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(receiver.received);
+
+ if (x == 0)
+ eng.popContext();
+ }
+}
+
+void tst_QJSEngine::processEventsWhileRunning_function()
+{
+ QScriptEngine eng;
+ QScriptValue script = eng.evaluate(QString::fromLatin1(
+ "(function() { var end = Number(new Date()) + 2000;"
+ "var x = 0;"
+ "while (Number(new Date()) < end) {"
+ " ++x;"
+ "} })"));
+
+ eng.setProcessEventsInterval(100);
+
+ for (int x = 0; x < 2; ++x) {
+ EventReceiver receiver;
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(!receiver.received);
+ QCOMPARE(eng.processEventsInterval(), 100);
+
+ if (x) script.call();
+ else script.construct();
+
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(receiver.received);
+ }
+}
+
+
+class EventReceiver2 : public QObject
+{
+public:
+ EventReceiver2(QScriptEngine *eng) {
+ engine = eng;
+ }
+
+ bool event(QEvent *e) {
+ if (e->type() == QEvent::User + 1) {
+ engine->currentContext()->throwError("Killed");
+ }
+ return QObject::event(e);
+ }
+
+ QScriptEngine *engine;
+};
+
+void tst_QJSEngine::throwErrorFromProcessEvents_data()
+{
+ QTest::addColumn<QString>("script");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("while (1)")
+ << QString::fromLatin1("while (1) { }")
+ << QString::fromLatin1("Error: Killed");
+ QTest::newRow("while (1) i++")
+ << QString::fromLatin1("i = 0; while (1) { i++; }")
+ << QString::fromLatin1("Error: Killed");
+ // Unlike abortEvaluation(), scripts should be able to catch the
+ // exception.
+ QTest::newRow("try catch")
+ << QString::fromLatin1("try {"
+ " while (1) { }"
+ "} catch(e) {"
+ " throw new Error('Caught');"
+ "}")
+ << QString::fromLatin1("Error: Caught");
+}
+
+void tst_QJSEngine::throwErrorFromProcessEvents()
+{
+ QFETCH(QString, script);
+ QFETCH(QString, error);
+
+ QScriptEngine eng;
+
+ EventReceiver2 receiver(&eng);
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
+
+ eng.setProcessEventsInterval(100);
+ QScriptValue ret = eng.evaluate(script);
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), error);
+}
+
+void tst_QJSEngine::disableProcessEventsInterval()
+{
+ QScriptEngine eng;
+ eng.setProcessEventsInterval(100);
+ QCOMPARE(eng.processEventsInterval(), 100);
+ eng.setProcessEventsInterval(0);
+ QCOMPARE(eng.processEventsInterval(), 0);
+ eng.setProcessEventsInterval(-1);
+ QCOMPARE(eng.processEventsInterval(), -1);
+ eng.setProcessEventsInterval(-100);
+ QCOMPARE(eng.processEventsInterval(), -100);
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptValueIterator API
+void tst_QJSEngine::stacktrace()
+{
+ QString script = QString::fromLatin1(
+ "function foo(counter) {\n"
+ " switch (counter) {\n"
+ " case 0: foo(counter+1); break;\n"
+ " case 1: foo(counter+1); break;\n"
+ " case 2: foo(counter+1); break;\n"
+ " case 3: foo(counter+1); break;\n"
+ " case 4: foo(counter+1); break;\n"
+ " default:\n"
+ " throw new Error('blah');\n"
+ " }\n"
+ "}\n"
+ "foo(0);");
+
+ const QString fileName("testfile");
+
+ QStringList backtrace;
+ backtrace << "foo(5)@testfile:9"
+ << "foo(4)@testfile:7"
+ << "foo(3)@testfile:6"
+ << "foo(2)@testfile:5"
+ << "foo(1)@testfile:4"
+ << "foo(0)@testfile:3"
+ << "<global>()@testfile:12";
+
+ QScriptEngine eng;
+ QScriptValue result = eng.evaluate(script, fileName);
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(result.isError());
+
+ QEXPECT_FAIL("", "QTBUG-6139: uncaughtExceptionBacktrace() doesn't give the full backtrace", Abort);
+ // ###FIXME: no uncahgutExceptionBacktrace: QCOMPARE(eng.uncaughtExceptionBacktrace(), backtrace);
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(result.strictlyEquals(eng.uncaughtException()));
+
+ QCOMPARE(result.property("fileName").toString(), fileName);
+ QCOMPARE(result.property("lineNumber").toInt32(), 9);
+
+ QScriptValue stack = result.property("stack");
+ QVERIFY(stack.isArray());
+
+ QCOMPARE(stack.property("length").toInt32(), 7);
+
+ QScriptValueIterator it(stack);
+ int counter = 5;
+ while (it.hasNext()) {
+ it.next();
+ QScriptValue obj = it.value();
+ QScriptValue frame = obj.property("frame");
+
+ QCOMPARE(obj.property("fileName").toString(), fileName);
+ if (counter >= 0) {
+ QScriptValue callee = frame.property("arguments").property("callee");
+ QVERIFY(callee.strictlyEquals(eng.globalObject().property("foo")));
+ QCOMPARE(obj.property("functionName").toString(), QString("foo"));
+ int line = obj.property("lineNumber").toInt32();
+ if (counter == 5)
+ QCOMPARE(line, 9);
+ else
+ QCOMPARE(line, 3 + counter);
+ } else {
+ QVERIFY(frame.strictlyEquals(eng.globalObject()));
+ QVERIFY(obj.property("functionName").toString().isEmpty());
+ }
+
+ --counter;
+ }
+
+ {
+ QScriptValue bt = result.property("backtrace").call(result);
+ QCOMPARE(qscriptvalue_cast<QStringList>(bt), backtrace);
+ }
+
+ // throw something that isn't an Error object
+ eng.clearExceptions();
+ // ###FIXME: No uncaughtExceptionBacktrace: QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty());
+ QString script2 = QString::fromLatin1(
+ "function foo(counter) {\n"
+ " switch (counter) {\n"
+ " case 0: foo(counter+1); break;\n"
+ " case 1: foo(counter+1); break;\n"
+ " case 2: foo(counter+1); break;\n"
+ " case 3: foo(counter+1); break;\n"
+ " case 4: foo(counter+1); break;\n"
+ " default:\n"
+ " throw 'just a string';\n"
+ " }\n"
+ "}\n"
+ "foo(0);");
+
+ QScriptValue result2 = eng.evaluate(script2, fileName);
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(!result2.isError());
+ QVERIFY(result2.isString());
+
+ // ###FIXME: No uncaughtExceptionBacktrace: QCOMPARE(eng.uncaughtExceptionBacktrace(), backtrace);
+ QVERIFY(eng.hasUncaughtException());
+
+ eng.clearExceptions();
+ QVERIFY(!eng.hasUncaughtException());
+ // ###FIXME: No uncaughtExceptionBacktrace: QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty());
+}
+#endif
+
+void tst_QJSEngine::numberParsing_data()
+{
+ QTest::addColumn<QString>("string");
+ QTest::addColumn<qreal>("expect");
+
+ QTest::newRow("decimal 0") << QString("0") << qreal(0);
+ QTest::newRow("octal 0") << QString("00") << qreal(00);
+ QTest::newRow("hex 0") << QString("0x0") << qreal(0x0);
+ QTest::newRow("decimal 100") << QString("100") << qreal(100);
+ QTest::newRow("hex 100") << QString("0x100") << qreal(0x100);
+ QTest::newRow("octal 100") << QString("0100") << qreal(0100);
+ QTest::newRow("decimal 4G") << QString("4294967296") << qreal(Q_UINT64_C(4294967296));
+ QTest::newRow("hex 4G") << QString("0x100000000") << qreal(Q_UINT64_C(0x100000000));
+ QTest::newRow("octal 4G") << QString("040000000000") << qreal(Q_UINT64_C(040000000000));
+ QTest::newRow("0.5") << QString("0.5") << qreal(0.5);
+ QTest::newRow("1.5") << QString("1.5") << qreal(1.5);
+ QTest::newRow("1e2") << QString("1e2") << qreal(100);
+}
+
+void tst_QJSEngine::numberParsing()
+{
+ QFETCH(QString, string);
+ QFETCH(qreal, expect);
+
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate(string);
+ QVERIFY(ret.isNumber());
+ qreal actual = ret.toNumber();
+ QCOMPARE(actual, expect);
+}
+
+// see ECMA-262, section 7.9
+// This is testing ECMA compliance, not our C++ API, but it's important that
+// the back-end is conformant in this regard.
+void tst_QJSEngine::automaticSemicolonInsertion()
+{
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("{ 1 2 } 3");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains("SyntaxError"));
+ }
+ {
+ QJSValue ret = eng.evaluate("{ 1\n2 } 3");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+ {
+ QJSValue ret = eng.evaluate("for (a; b\n)");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains("SyntaxError"));
+ }
+ {
+ QJSValue ret = eng.evaluate("(function() { return\n1 + 2 })()");
+ QVERIFY(ret.isUndefined());
+ }
+ {
+ eng.evaluate("c = 2; b = 1");
+ QJSValue ret = eng.evaluate("a = b\n++c");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+ {
+ QJSValue ret = eng.evaluate("if (a > b)\nelse c = d");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains("SyntaxError"));
+ }
+ {
+ eng.evaluate("function c() { return { foo: function() { return 5; } } }");
+ eng.evaluate("b = 1; d = 2; e = 3");
+ QJSValue ret = eng.evaluate("a = b + c\n(d + e).foo()");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 6);
+ }
+ {
+ QJSValue ret = eng.evaluate("throw\n1");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains("SyntaxError"));
+ }
+ {
+ QJSValue ret = eng.evaluate("a = Number(1)\n++a");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 2);
+ }
+
+ // "a semicolon is never inserted automatically if the semicolon
+ // would then be parsed as an empty statement"
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if (0)\n ++a; a");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if (0)\n --a; a");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if ((0))\n ++a; a");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if ((0))\n --a; a");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if (0\n)\n ++a; a");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if (0\n ++a; a");
+ QVERIFY(ret.isError());
+ }
+ {
+ eng.evaluate("a = 123");
+ QJSValue ret = eng.evaluate("if (0))\n ++a; a");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 0; for (i = 0; i < 10; ++i)\n ++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 10);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 30; for (i = 0; i < 10; ++i)\n --n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 20);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 0; for (var i = 0; i < 10; ++i)\n ++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 10);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 30; for (var i = 0; i < 10; ++i)\n --n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 20);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 0; i = 0; while (i++ < 10)\n ++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 10);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 30; i = 0; while (i++ < 10)\n --n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 20);
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 0; for (i in o)\n ++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 9; for (i in o)\n --n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 6);
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 0; for (var i in o)\n ++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 9; for (var i in o)\n --n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 6);
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { n: 3 }; n = 5; with (o)\n ++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 5);
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { n: 3 }; n = 10; with (o)\n --n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 10);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 5; i = 0; do\n ++n; while (++i < 10); n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 15);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 20; i = 0; do\n --n; while (++i < 10); n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 10);
+ }
+
+ {
+ QJSValue ret = eng.evaluate("n = 1; i = 0; if (n) i\n++n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 2);
+ }
+ {
+ QJSValue ret = eng.evaluate("n = 1; i = 0; if (n) i\n--n; n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 0);
+ }
+
+ {
+ QJSValue ret = eng.evaluate("if (0)");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("while (0)");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("for (;;)");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("for (p in this)");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("with (this)");
+ QVERIFY(ret.isError());
+ }
+ {
+ QJSValue ret = eng.evaluate("do");
+ QVERIFY(ret.isError());
+ }
+}
+
+#if 0 // ###FIXME: no abortEvaluation API
+class EventReceiver3 : public QObject
+{
+public:
+ enum AbortionResult {
+ None = 0,
+ String = 1,
+ Error = 2,
+ Number = 3
+ };
+
+ EventReceiver3(QScriptEngine *eng) {
+ engine = eng;
+ resultType = None;
+ }
+
+ bool event(QEvent *e) {
+ if (e->type() == QEvent::User + 1) {
+ switch (resultType) {
+ case None:
+ engine->abortEvaluation();
+ break;
+ case String:
+ engine->abortEvaluation(QScriptValue(engine, QString::fromLatin1("Aborted")));
+ break;
+ case Error:
+ engine->abortEvaluation(engine->currentContext()->throwError("AbortedWithError"));
+ break;
+ case Number:
+ engine->abortEvaluation(QScriptValue(1234));
+ }
+ }
+ return QObject::event(e);
+ }
+
+ AbortionResult resultType;
+ QScriptEngine *engine;
+};
+
+static QScriptValue myFunctionAbortingEvaluation(QScriptContext *, QScriptEngine *eng)
+{
+ eng->abortEvaluation();
+ return eng->nullValue(); // should be ignored
+}
+
+void tst_QJSEngine::abortEvaluation_notEvaluating()
+{
+ QScriptEngine eng;
+
+ eng.abortEvaluation();
+ QVERIFY(!eng.hasUncaughtException());
+
+ eng.abortEvaluation(123);
+ {
+ QScriptValue ret = eng.evaluate("'ciao'");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
+ }
+}
+
+void tst_QJSEngine::abortEvaluation_data()
+{
+ QTest::addColumn<QString>("script");
+
+ QTest::newRow("while (1)")
+ << QString::fromLatin1("while (1) { }");
+ QTest::newRow("while (1) i++")
+ << QString::fromLatin1("i = 0; while (1) { i++; }");
+ QTest::newRow("try catch")
+ << QString::fromLatin1("try {"
+ " while (1) { }"
+ "} catch(e) {"
+ " throw new Error('Caught');"
+ "}");
+}
+
+void tst_QJSEngine::abortEvaluation()
+{
+ QFETCH(QString, script);
+
+ QScriptEngine eng;
+ EventReceiver3 receiver(&eng);
+
+ eng.setProcessEventsInterval(100);
+ for (int x = 0; x < 4; ++x) {
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
+ receiver.resultType = EventReceiver3::AbortionResult(x);
+ QScriptValue ret = eng.evaluate(script);
+ switch (receiver.resultType) {
+ case EventReceiver3::None:
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(!ret.isValid());
+ break;
+ case EventReceiver3::Number:
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 1234);
+ break;
+ case EventReceiver3::String:
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("Aborted"));
+ break;
+ case EventReceiver3::Error:
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("Error: AbortedWithError"));
+ break;
+ }
+ }
+
+}
+
+void tst_QJSEngine::abortEvaluation_tryCatch()
+{
+ QSKIP("It crashes", SkipAll);
+ QScriptEngine eng;
+ EventReceiver3 receiver(&eng);
+ eng.setProcessEventsInterval(100);
+ // scripts cannot intercept the abortion with try/catch
+ for (int y = 0; y < 4; ++y) {
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
+ receiver.resultType = EventReceiver3::AbortionResult(y);
+ QScriptValue ret = eng.evaluate(QString::fromLatin1(
+ "while (1) {\n"
+ " try {\n"
+ " (function() { while (1) { } })();\n"
+ " } catch (e) {\n"
+ " ;\n"
+ " }\n"
+ "}"));
+ switch (receiver.resultType) {
+ case EventReceiver3::None:
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(!ret.isValid());
+ break;
+ case EventReceiver3::Number:
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 1234);
+ break;
+ case EventReceiver3::String:
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("Aborted"));
+ break;
+ case EventReceiver3::Error:
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(ret.isError());
+ break;
+ }
+ }
+}
+
+void tst_QJSEngine::abortEvaluation_fromNative()
+{
+ QScriptEngine eng;
+ QScriptValue fun = eng.newFunction(myFunctionAbortingEvaluation);
+ eng.globalObject().setProperty("myFunctionAbortingEvaluation", fun);
+ QScriptValue ret = eng.evaluate("myFunctionAbortingEvaluation()");
+ QVERIFY(!ret.isValid());
+}
+
+class ThreadedEngine : public QThread {
+ Q_OBJECT;
+
+private:
+ QScriptEngine* m_engine;
+protected:
+ void run() {
+ m_engine = new QScriptEngine();
+ m_engine->setGlobalObject(m_engine->newQObject(this));
+ m_engine->evaluate("while (1) { sleep(); }");
+ delete m_engine;
+ }
+
+public slots:
+ void sleep()
+ {
+ QTest::qSleep(25);
+ m_engine->abortEvaluation();
+ }
+};
+
+void tst_QJSEngine::abortEvaluation_QTBUG9433()
+{
+ ThreadedEngine engine;
+ engine.start();
+ QVERIFY(engine.isRunning());
+ QTest::qSleep(50);
+ for (uint i = 0; i < 50; ++i) { // up to ~2500 ms
+ if (engine.isFinished())
+ return;
+ QTest::qSleep(50);
+ }
+ if (!engine.isFinished()) {
+ engine.terminate();
+ engine.wait(7000);
+ QFAIL("abortEvaluation doesn't work");
+ }
+
+}
+#endif
+
+#if 0 // ###FIXME: no QScriptEngine::isEvaluating
+static QScriptValue myFunctionReturningIsEvaluating(QScriptContext *, QScriptEngine *eng)
+{
+ return QScriptValue(eng, eng->isEvaluating());
+}
+
+class EventReceiver4 : public QObject
+{
+public:
+ EventReceiver4(QScriptEngine *eng) {
+ engine = eng;
+ wasEvaluating = false;
+ }
+
+ bool event(QEvent *e) {
+ if (e->type() == QEvent::User + 1) {
+ wasEvaluating = engine->isEvaluating();
+ }
+ return QObject::event(e);
+ }
+
+ QScriptEngine *engine;
+ bool wasEvaluating;
+};
+
+void tst_QJSEngine::isEvaluating_notEvaluating()
+{
+ QScriptEngine eng;
+
+ QVERIFY(!eng.isEvaluating());
+
+ eng.evaluate("");
+ QVERIFY(!eng.isEvaluating());
+ eng.evaluate("123");
+ QVERIFY(!eng.isEvaluating());
+ eng.evaluate("0 = 0");
+ QVERIFY(!eng.isEvaluating());
+}
+
+void tst_QJSEngine::isEvaluating_fromNative()
+{
+ QScriptEngine eng;
+ QScriptValue fun = eng.newFunction(myFunctionReturningIsEvaluating);
+ eng.globalObject().setProperty("myFunctionReturningIsEvaluating", fun);
+ QScriptValue ret = eng.evaluate("myFunctionReturningIsEvaluating()");
+ QVERIFY(ret.isBoolean());
+ QVERIFY(ret.toBoolean());
+ ret = fun.call();
+ QVERIFY(ret.isBoolean());
+ QVERIFY(ret.toBoolean());
+ ret = myFunctionReturningIsEvaluating(eng.currentContext(), &eng);
+ QVERIFY(ret.isBoolean());
+ QVERIFY(!ret.toBoolean());
+}
+
+void tst_QJSEngine::isEvaluating_fromEvent()
+{
+ QScriptEngine eng;
+ EventReceiver4 receiver(&eng);
+ QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
+
+ QString script = QString::fromLatin1(
+ "var end = Number(new Date()) + 1000;"
+ "var x = 0;"
+ "while (Number(new Date()) < end) {"
+ " ++x;"
+ "}");
+
+ eng.setProcessEventsInterval(100);
+ eng.evaluate(script);
+ QVERIFY(receiver.wasEvaluating);
+}
+#endif
+
+static QtMsgType theMessageType;
+static QString theMessage;
+
+static void myMsgHandler(QtMsgType type, const char *msg)
+{
+ theMessageType = type;
+ theMessage = QString::fromLatin1(msg);
+}
+
+#if 0
+void tst_QJSEngine::printFunctionWithCustomHandler()
+{
+ // The built-in print() function passes the output to Qt's message
+ // handler. By installing a custom message handler, the output can be
+ // redirected without changing the print() function itself.
+ // This behavior is not documented.
+ QJSEngine eng;
+ QtMsgHandler oldHandler = qInstallMsgHandler(myMsgHandler);
+ QVERIFY(eng.globalObject().property("print").isFunction());
+
+ theMessageType = QtSystemMsg;
+ QVERIFY(theMessage.isEmpty());
+ QVERIFY(eng.evaluate("print('test')").isUndefined());
+ QCOMPARE(theMessageType, QtDebugMsg);
+ QCOMPARE(theMessage, QString::fromLatin1("test"));
+
+ theMessageType = QtSystemMsg;
+ theMessage.clear();
+ QVERIFY(eng.evaluate("print(3, true, 'little pigs')").isUndefined());
+ QCOMPARE(theMessageType, QtDebugMsg);
+ QCOMPARE(theMessage, QString::fromLatin1("3 true little pigs"));
+
+ qInstallMsgHandler(oldHandler);
+}
+
+void tst_QJSEngine::printThrowsException()
+{
+ // If an argument to print() causes an exception to be thrown when
+ // it's converted to a string, print() should propagate the exception.
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("print({ toString: function() { throw 'foo'; } });");
+ QVERIFY(eng.hasUncaughtException());
+ QVERIFY(ret.strictlyEquals(QJSValue(&eng, QLatin1String("foo"))));
+}
+#endif
+
+void tst_QJSEngine::errorConstructors()
+{
+ QJSEngine eng;
+ QStringList prefixes;
+ prefixes << "" << "Eval" << "Range" << "Reference" << "Syntax" << "Type" << "URI";
+ for (int x = 0; x < 3; ++x) {
+ for (int i = 0; i < prefixes.size(); ++i) {
+ QString name = prefixes.at(i) + QLatin1String("Error");
+ QString code = QString(i+1, QLatin1Char('\n'));
+ if (x == 0)
+ code += QLatin1String("throw ");
+ else if (x == 1)
+ code += QLatin1String("new ");
+ code += name + QLatin1String("()");
+ QJSValue ret = eng.evaluate(code);
+ QVERIFY(ret.isError());
+ QCOMPARE(eng.hasUncaughtException(), x == 0);
+ eng.clearExceptions();
+ QVERIFY(ret.toString().startsWith(name));
+ //QTBUG-6138: JSC doesn't assign lineNumber when errors are not thrown
+ QEXPECT_FAIL("", "we have no more lineNumber property ", Continue);
+ QCOMPARE(ret.property("lineNumber").toInt32(), i+2);
+ }
+ }
+}
+
+void tst_QJSEngine::argumentsProperty_globalContext()
+{
+ QJSEngine eng;
+ {
+ // Unlike function calls, the global context doesn't have an
+ // arguments property.
+ QJSValue ret = eng.evaluate("arguments");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+ eng.evaluate("arguments = 10");
+ {
+ QJSValue ret = eng.evaluate("arguments");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 10);
+ }
+ QVERIFY(eng.evaluate("delete arguments").toBoolean());
+ QVERIFY(!eng.globalObject().property("arguments").isValid());
+}
+
+void tst_QJSEngine::argumentsProperty_JS()
+{
+ {
+ QJSEngine eng;
+ eng.evaluate("o = { arguments: 123 }");
+ QJSValue ret = eng.evaluate("with (o) { arguments; }");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ {
+ QJSEngine eng;
+ QVERIFY(!eng.globalObject().property("arguments").isValid());
+ // This is testing ECMA-262 compliance. In function calls, "arguments"
+ // appears like a local variable, and it can be replaced.
+ QJSValue ret = eng.evaluate("(function() { arguments = 456; return arguments; })()");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 456);
+ QVERIFY(!eng.globalObject().property("arguments").isValid());
+ }
+}
+
+#if 0 // ###FIXME: no QScriptContext API
+static QScriptValue argumentsProperty_fun(QScriptContext *, QScriptEngine *eng)
+{
+ // Since evaluate() is done in the current context, "arguments" should
+ // refer to currentContext()->argumentsObject().
+ // This is for consistency with the built-in JS eval() function.
+ eng->evaluate("var a = arguments[0];");
+ eng->evaluate("arguments[0] = 200;");
+ return eng->evaluate("a + arguments[0]");
+}
+
+void tst_QJSEngine::argumentsProperty_evaluateInNativeFunction()
+{
+ QScriptEngine eng;
+ QScriptValue fun = eng.newFunction(argumentsProperty_fun);
+ eng.globalObject().setProperty("fun", eng.newFunction(argumentsProperty_fun));
+ QScriptValue result = eng.evaluate("fun(18)");
+ QVERIFY(result.isNumber());
+ QCOMPARE(result.toInt32(), 200+18);
+}
+#endif
+
+void tst_QJSEngine::jsNumberClass()
+{
+ // See ECMA-262 Section 15.7, "Number Objects".
+
+ QJSEngine eng;
+
+ QJSValue ctor = eng.globalObject().property("Number");
+ QVERIFY(ctor.property("length").isNumber());
+ QCOMPARE(ctor.property("length").toNumber(), qreal(1));
+ QJSValue proto = ctor.property("prototype");
+ QVERIFY(proto.isObject());
+ {
+ QJSValue::PropertyFlags flags = QJSValue::SkipInEnumeration
+ | QJSValue::Undeletable
+ | QJSValue::ReadOnly;
+ QCOMPARE(ctor.propertyFlags("prototype"), flags);
+ QVERIFY(ctor.property("MAX_VALUE").isNumber());
+ QCOMPARE(ctor.propertyFlags("MAX_VALUE"), flags);
+ QVERIFY(ctor.property("MIN_VALUE").isNumber());
+ QCOMPARE(ctor.propertyFlags("MIN_VALUE"), flags);
+ QVERIFY(ctor.property("NaN").isNumber());
+ QCOMPARE(ctor.propertyFlags("NaN"), flags);
+ QVERIFY(ctor.property("NEGATIVE_INFINITY").isNumber());
+ QCOMPARE(ctor.propertyFlags("NEGATIVE_INFINITY"), flags);
+ QVERIFY(ctor.property("POSITIVE_INFINITY").isNumber());
+ QCOMPARE(ctor.propertyFlags("POSITIVE_INFINITY"), flags);
+ }
+ QVERIFY(proto.instanceOf(eng.globalObject().property("Object")));
+ QCOMPARE(proto.toNumber(), qreal(0));
+ QVERIFY(proto.property("constructor").strictlyEquals(ctor));
+
+ {
+ QJSValue ret = eng.evaluate("Number()");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), qreal(0));
+ }
+ {
+ QJSValue ret = eng.evaluate("Number(123)");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), qreal(123));
+ }
+ {
+ QJSValue ret = eng.evaluate("Number('456')");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), qreal(456));
+ }
+ {
+ QJSValue ret = eng.evaluate("new Number()");
+ QVERIFY(!ret.isNumber());
+ QVERIFY(ret.isObject());
+ QCOMPARE(ret.toNumber(), qreal(0));
+ }
+ {
+ QJSValue ret = eng.evaluate("new Number(123)");
+ QVERIFY(!ret.isNumber());
+ QVERIFY(ret.isObject());
+ QCOMPARE(ret.toNumber(), qreal(123));
+ }
+ {
+ QJSValue ret = eng.evaluate("new Number('456')");
+ QVERIFY(!ret.isNumber());
+ QVERIFY(ret.isObject());
+ QCOMPARE(ret.toNumber(), qreal(456));
+ }
+
+ QVERIFY(proto.property("toString").isFunction());
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toString()");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("123"));
+ }
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toString(8)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("173"));
+ }
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toString(16)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("7b"));
+ }
+ QVERIFY(proto.property("toLocaleString").isFunction());
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toLocaleString()");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("123"));
+ }
+ QVERIFY(proto.property("valueOf").isFunction());
+ {
+ QJSValue ret = eng.evaluate("new Number(123).valueOf()");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toNumber(), qreal(123));
+ }
+ QVERIFY(proto.property("toExponential").isFunction());
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toExponential()");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("1.23e+2"));
+ }
+ QVERIFY(proto.property("toFixed").isFunction());
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toFixed()");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("123"));
+ }
+ QVERIFY(proto.property("toPrecision").isFunction());
+ {
+ QJSValue ret = eng.evaluate("new Number(123).toPrecision()");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("123"));
+ }
+}
+
+void tst_QJSEngine::jsForInStatement_simple()
+{
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("o = { }; r = []; for (var p in o) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QVERIFY(lst.isEmpty());
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { p: 123 }; r = [];"
+ "for (var p in o) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 1);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { p: 123, q: 456 }; r = [];"
+ "for (var p in o) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 2);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ QCOMPARE(lst.at(1), QString::fromLatin1("q"));
+ }
+}
+
+void tst_QJSEngine::jsForInStatement_prototypeProperties()
+{
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("o = { }; o.__proto__ = { p: 123 }; r = [];"
+ "for (var p in o) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 1);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { p: 123 }; o.__proto__ = { q: 456 }; r = [];"
+ "for (var p in o) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 2);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ QCOMPARE(lst.at(1), QString::fromLatin1("q"));
+ }
+ {
+ // shadowed property
+ QJSValue ret = eng.evaluate("o = { p: 123 }; o.__proto__ = { p: 456 }; r = [];"
+ "for (var p in o) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 1);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ }
+
+}
+
+void tst_QJSEngine::jsForInStatement_mutateWhileIterating()
+{
+ QJSEngine eng;
+ // deleting property during enumeration
+ {
+ QJSValue ret = eng.evaluate("o = { p: 123 }; r = [];"
+ "for (var p in o) { r[r.length] = p; delete r[p]; } r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 1);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ }
+ {
+ QJSValue ret = eng.evaluate("o = { p: 123, q: 456 }; r = [];"
+ "for (var p in o) { r[r.length] = p; delete o.q; } r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 1);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ }
+
+ // adding property during enumeration
+ {
+ QJSValue ret = eng.evaluate("o = { p: 123 }; r = [];"
+ "for (var p in o) { r[r.length] = p; o.q = 456; } r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 1);
+ QCOMPARE(lst.at(0), QString::fromLatin1("p"));
+ }
+
+}
+
+void tst_QJSEngine::jsForInStatement_arrays()
+{
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("a = [123, 456]; r = [];"
+ "for (var p in a) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 2);
+ QCOMPARE(lst.at(0), QString::fromLatin1("0"));
+ QCOMPARE(lst.at(1), QString::fromLatin1("1"));
+ }
+ {
+ QJSValue ret = eng.evaluate("a = [123, 456]; a.foo = 'bar'; r = [];"
+ "for (var p in a) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 3);
+ QCOMPARE(lst.at(0), QString::fromLatin1("0"));
+ QCOMPARE(lst.at(1), QString::fromLatin1("1"));
+ QCOMPARE(lst.at(2), QString::fromLatin1("foo"));
+ }
+ {
+ QJSValue ret = eng.evaluate("a = [123, 456]; a.foo = 'bar';"
+ "b = [111, 222, 333]; b.bar = 'baz';"
+ "a.__proto__ = b; r = [];"
+ "for (var p in a) r[r.length] = p; r");
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), 5);
+ QCOMPARE(lst.at(0), QString::fromLatin1("0"));
+ QCOMPARE(lst.at(1), QString::fromLatin1("1"));
+ QCOMPARE(lst.at(2), QString::fromLatin1("foo"));
+ QCOMPARE(lst.at(3), QString::fromLatin1("2"));
+ QCOMPARE(lst.at(4), QString::fromLatin1("bar"));
+ }
+}
+
+void tst_QJSEngine::jsForInStatement_nullAndUndefined()
+{
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("r = true; for (var p in undefined) r = false; r");
+ QVERIFY(ret.isBool());
+ QVERIFY(ret.toBool());
+ }
+ {
+ QJSValue ret = eng.evaluate("r = true; for (var p in null) r = false; r");
+ QVERIFY(ret.isBool());
+ QVERIFY(ret.toBool());
+ }
+}
+
+void tst_QJSEngine::jsFunctionDeclarationAsStatement()
+{
+ // ECMA-262 does not allow function declarations to be used as statements,
+ // but several popular implementations (including JSC) do. See the NOTE
+ // at the beginning of chapter 12 in ECMA-262 5th edition, where it's
+ // recommended that implementations either disallow this usage or issue
+ // a warning.
+ // Since we had a bug report long ago about QtScript not supporting this
+ // "feature" (and thus deviating from other implementations), we still
+ // check this behavior.
+
+ QJSEngine eng;
+ QVERIFY(!eng.globalObject().property("bar").isValid());
+ eng.evaluate("function foo(arg) {\n"
+ " if (arg == 'bar')\n"
+ " function bar() { return 'bar'; }\n"
+ " else\n"
+ " function baz() { return 'baz'; }\n"
+ " return (arg == 'bar') ? bar : baz;\n"
+ "}");
+ QVERIFY(!eng.globalObject().property("bar").isValid());
+ QVERIFY(!eng.globalObject().property("baz").isValid());
+ QVERIFY(eng.evaluate("foo").isFunction());
+ {
+ QJSValue ret = eng.evaluate("foo('bar')");
+ QVERIFY(ret.isFunction());
+ QJSValue ret2 = ret.call(QJSValue());
+ QCOMPARE(ret2.toString(), QString::fromLatin1("bar"));
+ QVERIFY(!eng.globalObject().property("bar").isValid());
+ QVERIFY(!eng.globalObject().property("baz").isValid());
+ }
+ {
+ QJSValue ret = eng.evaluate("foo('baz')");
+ QVERIFY(ret.isFunction());
+ QJSValue ret2 = ret.call(QJSValue());
+ QCOMPARE(ret2.toString(), QString::fromLatin1("baz"));
+ QVERIFY(!eng.globalObject().property("bar").isValid());
+ QVERIFY(!eng.globalObject().property("baz").isValid());
+ }
+}
+
+void tst_QJSEngine::stringObjects()
+{
+ // See ECMA-262 Section 15.5, "String Objects".
+
+ QJSEngine eng;
+ QString str("ciao");
+ // in C++
+ {
+ QJSValue obj = QJSValue(&eng, str).toObject();
+ QCOMPARE(obj.property("length").toInt32(), str.length());
+ QCOMPARE(obj.propertyFlags("length"), QJSValue::PropertyFlags(QJSValue::Undeletable | QJSValue::SkipInEnumeration | QJSValue::ReadOnly));
+ for (int i = 0; i < str.length(); ++i) {
+ QString pname = QString::number(i);
+ QVERIFY(obj.property(pname).isString());
+ QCOMPARE(obj.property(pname).toString(), QString(str.at(i)));
+ QEXPECT_FAIL("", "FIXME: This is V8 issue 862. ECMA script standard 15.5.5.2 compliance.", Continue);
+ QCOMPARE(obj.propertyFlags(pname), QJSValue::PropertyFlags(QJSValue::Undeletable | QJSValue::ReadOnly));
+ obj.setProperty(pname, QJSValue());
+ obj.setProperty(pname, QJSValue(&eng, 123));
+ QVERIFY(obj.property(pname).isString());
+ QCOMPARE(obj.property(pname).toString(), QString(str.at(i)));
+ }
+ QVERIFY(!obj.property("-1").isValid());
+ QVERIFY(!obj.property(QString::number(str.length())).isValid());
+
+ QJSValue val(&eng, 123);
+ obj.setProperty("-1", val);
+ QVERIFY(obj.property("-1").strictlyEquals(val));
+ obj.setProperty("100", val);
+ QVERIFY(obj.property("100").strictlyEquals(val));
+ }
+
+ // in script
+ {
+ QJSValue ret = eng.evaluate("s = new String('ciao'); r = []; for (var p in s) r.push(p); r");
+ QVERIFY(ret.isArray());
+ QStringList lst = qjsvalue_cast<QStringList>(ret);
+ QCOMPARE(lst.size(), str.length());
+ for (int i = 0; i < str.length(); ++i)
+ QCOMPARE(lst.at(i), QString::number(i));
+
+ QJSValue ret2 = eng.evaluate("s[0] = 123; s[0]");
+ QVERIFY(ret2.isString());
+ QCOMPARE(ret2.toString().length(), 1);
+ QCOMPARE(ret2.toString().at(0), str.at(0));
+
+ QJSValue ret3 = eng.evaluate("s[-1] = 123; s[-1]");
+ QVERIFY(ret3.isNumber());
+ QCOMPARE(ret3.toInt32(), 123);
+
+ QJSValue ret4 = eng.evaluate("s[s.length] = 456; s[s.length]");
+ QVERIFY(ret4.isNumber());
+ QCOMPARE(ret4.toInt32(), 456);
+
+ QJSValue ret5 = eng.evaluate("delete s[0]");
+ QVERIFY(ret5.isBoolean());
+ QEXPECT_FAIL("", "FIXME: This is V8 bug, please report it! ECMA script standard 15.5.5.2", Abort);
+ QVERIFY(!ret5.toBoolean());
+
+ QJSValue ret6 = eng.evaluate("delete s[-1]");
+ QVERIFY(ret6.isBoolean());
+ QVERIFY(ret6.toBoolean());
+
+ QJSValue ret7 = eng.evaluate("delete s[s.length]");
+ QVERIFY(ret7.isBoolean());
+ QVERIFY(ret7.toBoolean());
+ }
+}
+
+void tst_QJSEngine::jsStringPrototypeReplaceBugs()
+{
+ QJSEngine eng;
+ // task 212440
+ {
+ QJSValue ret = eng.evaluate("replace_args = []; \"a a a\".replace(/(a)/g, function() { replace_args.push(arguments); }); replace_args");
+ QVERIFY(ret.isArray());
+ int len = ret.property("length").toInt32();
+ QCOMPARE(len, 3);
+ for (int i = 0; i < len; ++i) {
+ QJSValue args = ret.property(i);
+ QCOMPARE(args.property("length").toInt32(), 4);
+ QCOMPARE(args.property(0).toString(), QString::fromLatin1("a")); // matched string
+ QCOMPARE(args.property(1).toString(), QString::fromLatin1("a")); // capture
+ QVERIFY(args.property(2).isNumber());
+ QCOMPARE(args.property(2).toInt32(), i*2); // index of match
+ QCOMPARE(args.property(3).toString(), QString::fromLatin1("a a a"));
+ }
+ }
+ // task 212501
+ {
+ QJSValue ret = eng.evaluate("\"foo\".replace(/a/g, function() {})");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+}
+
+void tst_QJSEngine::getterSetterThisObject_global()
+{
+ {
+ QJSEngine eng;
+ // read
+ eng.evaluate("__defineGetter__('x', function() { return this; });");
+ {
+ QJSValue ret = eng.evaluate("x");
+ QVERIFY(ret.equals(eng.globalObject()));
+ }
+ {
+ QJSValue ret = eng.evaluate("(function() { return x; })()");
+ QVERIFY(ret.equals(eng.globalObject()));
+ }
+ {
+ QJSValue ret = eng.evaluate("with (this) x");
+ QVERIFY(ret.equals(eng.globalObject()));
+ }
+ {
+ QJSValue ret = eng.evaluate("with ({}) x");
+ QVERIFY(ret.equals(eng.globalObject()));
+ }
+ {
+ QJSValue ret = eng.evaluate("(function() { with ({}) return x; })()");
+ QVERIFY(ret.equals(eng.globalObject()));
+ }
+ // write
+ eng.evaluate("__defineSetter__('x', function() { return this; });");
+ {
+ QJSValue ret = eng.evaluate("x = 'foo'");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QJSValue ret = eng.evaluate("(function() { return x = 'foo'; })()");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QJSValue ret = eng.evaluate("with (this) x = 'foo'");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QJSValue ret = eng.evaluate("with ({}) x = 'foo'");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QJSValue ret = eng.evaluate("(function() { with ({}) return x = 'foo'; })()");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ }
+}
+
+void tst_QJSEngine::getterSetterThisObject_plain()
+{
+ {
+ QJSEngine eng;
+ eng.evaluate("o = {}");
+ // read
+ eng.evaluate("o.__defineGetter__('x', function() { return this; })");
+ QVERIFY(eng.evaluate("o.x === o").toBoolean());
+ QVERIFY(eng.evaluate("with (o) x").equals(eng.evaluate("o")));
+ QVERIFY(eng.evaluate("(function() { with (o) return x; })() === o").toBoolean());
+ eng.evaluate("q = {}; with (o) with (q) x").equals(eng.evaluate("o"));
+ // write
+ eng.evaluate("o.__defineSetter__('x', function() { return this; });");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(eng.evaluate("(o.x = 'foo') === 'foo'").toBoolean());
+ QVERIFY(eng.evaluate("with (o) x = 'foo'").equals("foo"));
+ QVERIFY(eng.evaluate("with (o) with (q) x = 'foo'").equals("foo"));
+ }
+}
+
+void tst_QJSEngine::getterSetterThisObject_prototypeChain()
+{
+ {
+ QJSEngine eng;
+ eng.evaluate("o = {}; p = {}; o.__proto__ = p");
+ // read
+ eng.evaluate("p.__defineGetter__('x', function() { return this; })");
+ QVERIFY(eng.evaluate("o.x === o").toBoolean());
+ QVERIFY(eng.evaluate("with (o) x").equals(eng.evaluate("o")));
+ QVERIFY(eng.evaluate("(function() { with (o) return x; })() === o").toBoolean());
+ eng.evaluate("q = {}; with (o) with (q) x").equals(eng.evaluate("o"));
+ eng.evaluate("with (q) with (o) x").equals(eng.evaluate("o"));
+ // write
+ eng.evaluate("o.__defineSetter__('x', function() { return this; });");
+ // SpiderMonkey says setter return value, JSC says RHS.
+ QVERIFY(eng.evaluate("(o.x = 'foo') === 'foo'").toBoolean());
+ QVERIFY(eng.evaluate("with (o) x = 'foo'").equals("foo"));
+ QVERIFY(eng.evaluate("with (o) with (q) x = 'foo'").equals("foo"));
+ }
+}
+
+#if 0 // ###FIXME: no QScriptContext API
+void tst_QJSEngine::getterSetterThisObject_activation()
+{
+ {
+ QScriptEngine eng;
+ QScriptContext *ctx = eng.pushContext();
+ QVERIFY(ctx != 0);
+ QScriptValue act = ctx->activationObject();
+ act.setProperty("act", act);
+ // read
+ eng.evaluate("act.__defineGetter__('x', function() { return this; })");
+ QVERIFY(eng.evaluate("x === act").toBoolean());
+ QEXPECT_FAIL("", "QTBUG-17605: Not possible to implement local variables as getter/setter properties", Abort);
+ QVERIFY(!eng.hasUncaughtException());
+ QVERIFY(eng.evaluate("with (act) x").equals("foo"));
+ QVERIFY(eng.evaluate("(function() { with (act) return x; })() === act").toBoolean());
+ eng.evaluate("q = {}; with (act) with (q) x").equals(eng.evaluate("act"));
+ eng.evaluate("with (q) with (act) x").equals(eng.evaluate("act"));
+ // write
+ eng.evaluate("act.__defineSetter__('x', function() { return this; });");
+ QVERIFY(eng.evaluate("(x = 'foo') === 'foo'").toBoolean());
+ QVERIFY(eng.evaluate("with (act) x = 'foo'").equals("foo"));
+ QVERIFY(eng.evaluate("with (act) with (q) x = 'foo'").equals("foo"));
+ eng.popContext();
+ }
+}
+#endif
+
+void tst_QJSEngine::jsContinueInSwitch()
+{
+ // This is testing ECMA-262 compliance, not C++ API.
+
+ QJSEngine eng;
+ // switch - continue
+ {
+ QJSValue ret = eng.evaluate("switch (1) { default: continue; }");
+ QVERIFY(ret.isError());
+ }
+ // for - switch - case - continue
+ {
+ QJSValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n"
+ " switch (i) {\n"
+ " case 1: ++j; continue;\n"
+ " case 100: ++j; continue;\n"
+ " case 1000: ++j; continue;\n"
+ " }\n"
+ "}; j");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+ // for - switch - case - default - continue
+ {
+ QJSValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n"
+ " switch (i) {\n"
+ " case 1: ++j; continue;\n"
+ " case 100: ++j; continue;\n"
+ " case 1000: ++j; continue;\n"
+ " default: if (i < 50000) break; else continue;\n"
+ " }\n"
+ "}; j");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+ // switch - for - continue
+ {
+ QJSValue ret = eng.evaluate("j = 123; switch (j) {\n"
+ " case 123:\n"
+ " for (i = 0; i < 100000; ++i) {\n"
+ " continue;\n"
+ " }\n"
+ "}; i\n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 100000);
+ }
+ // switch - switch - continue
+ {
+ QJSValue ret = eng.evaluate("i = 1; switch (i) { default: switch (i) { case 1: continue; } }");
+ QVERIFY(ret.isError());
+ }
+ // for - switch - switch - continue
+ {
+ QJSValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n"
+ " switch (i) {\n"
+ " case 1:\n"
+ " switch (i) {\n"
+ " case 1: ++j; continue;\n"
+ " }\n"
+ " }\n"
+ "}; j");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 1);
+ }
+ // switch - for - switch - continue
+ {
+ QJSValue ret = eng.evaluate("j = 123; switch (j) {\n"
+ " case 123:\n"
+ " for (i = 0; i < 100000; ++i) {\n"
+ " switch (i) {\n"
+ " case 1:\n"
+ " ++j; continue;\n"
+ " }\n"
+ " }\n"
+ "}; i\n");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 100000);
+ }
+}
+
+void tst_QJSEngine::jsShadowReadOnlyPrototypeProperty()
+{
+ // SpiderMonkey has different behavior than JSC and V8; it disallows
+ // creating a property on the instance if there's a property with the
+ // same name in the prototype, and that property is read-only. We
+ // adopted that behavior in the old (4.5) QtScript back-end, but it
+ // just seems weird -- and non-compliant. Adopt the JSC behavior instead.
+ QJSEngine eng;
+ QVERIFY(eng.evaluate("o = {}; o.__proto__ = parseInt; o.length").isNumber());
+ QCOMPARE(eng.evaluate("o.length = 123; o.length").toInt32(), 123);
+ QVERIFY(eng.evaluate("o.hasOwnProperty('length')").toBoolean());
+}
+
+void tst_QJSEngine::toObject()
+{
+ QJSEngine eng;
+
+ QVERIFY(!eng.toObject(eng.undefinedValue()).isValid());
+
+ QVERIFY(!eng.toObject(eng.nullValue()).isValid());
+
+ QJSValue falskt(false);
+ {
+ QJSValue tmp = eng.toObject(falskt);
+ QVERIFY(tmp.isObject());
+ QCOMPARE(tmp.toNumber(), falskt.toNumber());
+ }
+ QVERIFY(falskt.isBool());
+
+ QJSValue sant(true);
+ {
+ QJSValue tmp = eng.toObject(sant);
+ QVERIFY(tmp.isObject());
+ QCOMPARE(tmp.toNumber(), sant.toNumber());
+ }
+ QVERIFY(sant.isBool());
+
+ QJSValue number(123.0);
+ {
+ QJSValue tmp = eng.toObject(number);
+ QVERIFY(tmp.isObject());
+ QCOMPARE(tmp.toNumber(), number.toNumber());
+ }
+ QVERIFY(number.isNumber());
+
+ QJSValue str = QJSValue(&eng, QString("ciao"));
+ {
+ QJSValue tmp = eng.toObject(str);
+ QVERIFY(tmp.isObject());
+ QCOMPARE(tmp.toString(), str.toString());
+ }
+ QVERIFY(str.isString());
+
+ QJSValue object = eng.newObject();
+ {
+ QJSValue tmp = eng.toObject(object);
+ QVERIFY(tmp.isObject());
+ QVERIFY(tmp.strictlyEquals(object));
+ }
+
+ QJSValue qobject = eng.newQObject(this);
+ QVERIFY(eng.toObject(qobject).strictlyEquals(qobject));
+
+ QVERIFY(!eng.toObject(QJSValue()).isValid());
+
+ // v1 constructors
+
+ QJSValue boolValue(&eng, true);
+ {
+ QJSValue ret = eng.toObject(boolValue);
+ QVERIFY(ret.isObject());
+ QCOMPARE(ret.toBool(), boolValue.toBool());
+ }
+ QVERIFY(boolValue.isBool());
+
+ QJSValue numberValue(&eng, 123.0);
+ {
+ QJSValue ret = eng.toObject(numberValue);
+ QVERIFY(ret.isObject());
+ QCOMPARE(ret.toNumber(), numberValue.toNumber());
+ }
+ QVERIFY(numberValue.isNumber());
+
+ QJSValue stringValue(&eng, QString::fromLatin1("foo"));
+ {
+ QJSValue ret = eng.toObject(stringValue);
+ QVERIFY(ret.isObject());
+ QCOMPARE(ret.toString(), stringValue.toString());
+ }
+ QVERIFY(stringValue.isString());
+}
+
+void tst_QJSEngine::jsReservedWords_data()
+{
+ QTest::addColumn<QString>("word");
+ QTest::newRow("break") << QString("break");
+ QTest::newRow("case") << QString("case");
+ QTest::newRow("catch") << QString("catch");
+ QTest::newRow("continue") << QString("continue");
+ QTest::newRow("default") << QString("default");
+ QTest::newRow("delete") << QString("delete");
+ QTest::newRow("do") << QString("do");
+ QTest::newRow("else") << QString("else");
+ QTest::newRow("false") << QString("false");
+ QTest::newRow("finally") << QString("finally");
+ QTest::newRow("for") << QString("for");
+ QTest::newRow("function") << QString("function");
+ QTest::newRow("if") << QString("if");
+ QTest::newRow("in") << QString("in");
+ QTest::newRow("instanceof") << QString("instanceof");
+ QTest::newRow("new") << QString("new");
+ QTest::newRow("null") << QString("null");
+ QTest::newRow("return") << QString("return");
+ QTest::newRow("switch") << QString("switch");
+ QTest::newRow("this") << QString("this");
+ QTest::newRow("throw") << QString("throw");
+ QTest::newRow("true") << QString("true");
+ QTest::newRow("try") << QString("try");
+ QTest::newRow("typeof") << QString("typeof");
+ QTest::newRow("var") << QString("var");
+ QTest::newRow("void") << QString("void");
+ QTest::newRow("while") << QString("while");
+ QTest::newRow("with") << QString("with");
+}
+
+void tst_QJSEngine::jsReservedWords()
+{
+ // See ECMA-262 Section 7.6.1, "Reserved Words".
+ // We prefer that the implementation is less strict than the spec; e.g.
+ // it's good to allow reserved words as identifiers in object literals,
+ // and when accessing properties using dot notation.
+
+ QFETCH(QString, word);
+ {
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate(word + " = 123");
+ QVERIFY(ret.isError());
+ QString str = ret.toString();
+ QVERIFY(str.startsWith("SyntaxError") || str.startsWith("ReferenceError"));
+ }
+ {
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("var " + word + " = 123");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().startsWith("SyntaxError"));
+ }
+ {
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("o = {}; o." + word + " = 123");
+ // in the old back-end, in SpiderMonkey and in v8, this is allowed, but not in JSC
+ QVERIFY(!ret.isError());
+ QVERIFY(ret.strictlyEquals(eng.evaluate("o." + word)));
+ }
+ {
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("o = { " + word + ": 123 }");
+ // in the old back-end, in SpiderMonkey and in v8, this is allowed, but not in JSC
+ QVERIFY(!ret.isError());
+ QVERIFY(ret.property(word).isNumber());
+ }
+ {
+ // SpiderMonkey allows this, but we don't
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("function " + word + "() {}");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().startsWith("SyntaxError"));
+ }
+}
+
+void tst_QJSEngine::jsFutureReservedWords_data()
+{
+ QTest::addColumn<QString>("word");
+ QTest::addColumn<bool>("allowed");
+ QTest::newRow("abstract") << QString("abstract") << true;
+ QTest::newRow("boolean") << QString("boolean") << true;
+ QTest::newRow("byte") << QString("byte") << true;
+ QTest::newRow("char") << QString("char") << true;
+ QTest::newRow("class") << QString("class") << false;
+ QTest::newRow("const") << QString("const") << false;
+ QTest::newRow("debugger") << QString("debugger") << false;
+ QTest::newRow("double") << QString("double") << true;
+ QTest::newRow("enum") << QString("enum") << false;
+ QTest::newRow("export") << QString("export") << false;
+ QTest::newRow("extends") << QString("extends") << false;
+ QTest::newRow("final") << QString("final") << true;
+ QTest::newRow("float") << QString("float") << true;
+ QTest::newRow("goto") << QString("goto") << true;
+ QTest::newRow("implements") << QString("implements") << true;
+ QTest::newRow("import") << QString("import") << false;
+ QTest::newRow("int") << QString("int") << true;
+ QTest::newRow("interface") << QString("interface") << true;
+ QTest::newRow("long") << QString("long") << true;
+ QTest::newRow("native") << QString("native") << true;
+ QTest::newRow("package") << QString("package") << true;
+ QTest::newRow("private") << QString("private") << true;
+ QTest::newRow("protected") << QString("protected") << true;
+ QTest::newRow("public") << QString("public") << true;
+ QTest::newRow("short") << QString("short") << true;
+ QTest::newRow("static") << QString("static") << true;
+ QTest::newRow("super") << QString("super") << false;
+ QTest::newRow("synchronized") << QString("synchronized") << true;
+ QTest::newRow("throws") << QString("throws") << true;
+ QTest::newRow("transient") << QString("transient") << true;
+ QTest::newRow("volatile") << QString("volatile") << true;
+}
+
+void tst_QJSEngine::jsFutureReservedWords()
+{
+ QSKIP("Fails", SkipAll);
+ // See ECMA-262 Section 7.6.1.2, "Future Reserved Words".
+ // In real-world implementations, most of these words are
+ // actually allowed as normal identifiers.
+
+ QFETCH(QString, word);
+ QFETCH(bool, allowed);
+ {
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate(word + " = 123");
+ QCOMPARE(!ret.isError(), allowed);
+ }
+ {
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("var " + word + " = 123");
+ QCOMPARE(!ret.isError(), allowed);
+ }
+ {
+ // this should probably be allowed (see task 162567)
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("o = {}; o." + word + " = 123");
+ QCOMPARE(ret.isNumber(), allowed);
+ QCOMPARE(!ret.isError(), allowed);
+ }
+ {
+ // this should probably be allowed (see task 162567)
+ QJSEngine eng;
+ QJSValue ret = eng.evaluate("o = { " + word + ": 123 }");
+ QCOMPARE(!ret.isError(), allowed);
+ }
+}
+
+void tst_QJSEngine::jsThrowInsideWithStatement()
+{
+ // This is testing ECMA-262 compliance, not C++ API.
+
+ // task 209988
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate(
+ "try {"
+ " o = { bad : \"bug\" };"
+ " with (o) {"
+ " throw 123;"
+ " }"
+ "} catch (e) {"
+ " bad;"
+ "}");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+ {
+ QJSValue ret = eng.evaluate(
+ "try {"
+ " o = { bad : \"bug\" };"
+ " with (o) {"
+ " throw 123;"
+ " }"
+ "} finally {"
+ " bad;"
+ "}");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+ {
+ eng.clearExceptions();
+ QJSValue ret = eng.evaluate(
+ "o = { bug : \"no bug\" };"
+ "with (o) {"
+ " try {"
+ " throw 123;"
+ " } finally {"
+ " bug;"
+ " }"
+ "}");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ QVERIFY(eng.hasUncaughtException());
+ }
+ {
+ eng.clearExceptions();
+ QJSValue ret = eng.evaluate(
+ "o = { bug : \"no bug\" };"
+ "with (o) {"
+ " throw 123;"
+ "}");
+ QVERIFY(ret.isNumber());
+ QJSValue ret2 = eng.evaluate("bug");
+ QVERIFY(ret2.isError());
+ QVERIFY(ret2.toString().contains(QString::fromLatin1("ReferenceError")));
+ }
+}
+
+#if 0 // ###FIXME: No QScriptEngineAgent API
+class TestAgent : public QScriptEngineAgent
+{
+public:
+ TestAgent(QScriptEngine *engine) : QScriptEngineAgent(engine) {}
+};
+
+void tst_QJSEngine::getSetAgent_ownership()
+{
+ // engine deleted before agent --> agent deleted too
+ QScriptEngine *eng = new QScriptEngine;
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
+ TestAgent *agent = new TestAgent(eng);
+ eng->setAgent(agent);
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent);
+ eng->setAgent(0); // the engine maintains ownership of the old agent
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
+ delete eng;
+}
+
+void tst_QJSEngine::getSetAgent_deleteAgent()
+{
+ // agent deleted before engine --> engine's agent should become 0
+ QScriptEngine *eng = new QScriptEngine;
+ TestAgent *agent = new TestAgent(eng);
+ eng->setAgent(agent);
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent);
+ delete agent;
+ QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
+ eng->evaluate("(function(){ return 123; })()");
+ delete eng;
+}
+
+void tst_QJSEngine::getSetAgent_differentEngine()
+{
+ QScriptEngine eng;
+ QScriptEngine eng2;
+ TestAgent *agent = new TestAgent(&eng);
+ QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::setAgent(): cannot set agent belonging to different engine");
+ eng2.setAgent(agent);
+ QCOMPARE(eng2.agent(), (QScriptEngineAgent*)0);
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptString API
+void tst_QJSEngine::reentrancy_stringHandles()
+{
+ QScriptEngine eng1;
+ QScriptEngine eng2;
+ QScriptString s1 = eng1.toStringHandle("foo");
+ QScriptString s2 = eng2.toStringHandle("foo");
+ QVERIFY(s1 != s2);
+}
+#endif
+
+#if 0 // ###FIXME: No processEventsInterval API
+void tst_QJSEngine::reentrancy_processEventsInterval()
+{
+ QScriptEngine eng1;
+ QScriptEngine eng2;
+ eng1.setProcessEventsInterval(123);
+ QCOMPARE(eng2.processEventsInterval(), -1);
+ eng2.setProcessEventsInterval(456);
+ QCOMPARE(eng1.processEventsInterval(), 123);
+}
+#endif
+
+#if 0 // FIXME: No support for custom types
+void tst_QJSEngine::reentrancy_typeConversion()
+{
+ QScriptEngine eng1;
+ QScriptEngine eng2;
+ qScriptRegisterMetaType<Foo>(&eng1, fooToScriptValue, fooFromScriptValue);
+ Foo foo;
+ foo.x = 12;
+ foo.y = 34;
+ {
+ QScriptValue fooVal = qScriptValueFromValue(&eng1, foo);
+ QVERIFY(fooVal.isObject());
+ QVERIFY(!fooVal.isVariant());
+ QCOMPARE(fooVal.property("x").toInt32(), 12);
+ QCOMPARE(fooVal.property("y").toInt32(), 34);
+ fooVal.setProperty("x", 56);
+ fooVal.setProperty("y", 78);
+
+ Foo foo2 = eng.fromScriptValue<Foo>(fooVal);
+ QCOMPARE(foo2.x, 56);
+ QCOMPARE(foo2.y, 78);
+ }
+ {
+ QScriptValue fooVal = qScriptValueFromValue(&eng2, foo);
+ QVERIFY(fooVal.isVariant());
+
+ Foo foo2 = eng.fromScriptValue<Foo>(fooVal);
+ QCOMPARE(foo2.x, 12);
+ QCOMPARE(foo2.y, 34);
+ }
+ QVERIFY(!eng1.defaultPrototype(qMetaTypeId<Foo>()).isValid());
+ QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
+ QScriptValue proto1 = eng1.newObject();
+ eng1.setDefaultPrototype(qMetaTypeId<Foo>(), proto1);
+ QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
+ QScriptValue proto2 = eng2.newObject();
+ eng2.setDefaultPrototype(qMetaTypeId<Foo>(), proto2);
+ QVERIFY(eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
+ QVERIFY(eng1.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(proto1));
+}
+#endif
+
+void tst_QJSEngine::reentrancy_globalObjectProperties()
+{
+ QJSEngine eng1;
+ QJSEngine eng2;
+ QVERIFY(!eng2.globalObject().property("a").isValid());
+ eng1.evaluate("a = 10");
+ QVERIFY(eng1.globalObject().property("a").isNumber());
+ QVERIFY(!eng2.globalObject().property("a").isValid());
+ eng2.evaluate("a = 20");
+ QVERIFY(eng2.globalObject().property("a").isNumber());
+ QCOMPARE(eng1.globalObject().property("a").toInt32(), 10);
+}
+
+void tst_QJSEngine::reentrancy_Array()
+{
+ // weird bug with JSC backend
+ {
+ QJSEngine eng;
+ QCOMPARE(eng.evaluate("Array()").toString(), QString());
+ eng.evaluate("Array.prototype.toString");
+ QCOMPARE(eng.evaluate("Array()").toString(), QString());
+ }
+ {
+ QJSEngine eng;
+ QCOMPARE(eng.evaluate("Array()").toString(), QString());
+ }
+}
+
+void tst_QJSEngine::reentrancy_objectCreation()
+{
+ QJSEngine eng1;
+ QJSEngine eng2;
+ {
+ QJSValue d1 = eng1.newDate(0);
+ QJSValue d2 = eng2.newDate(0);
+ QCOMPARE(d1.toDateTime(), d2.toDateTime());
+ QCOMPARE(d2.toDateTime(), d1.toDateTime());
+ }
+ {
+ QJSValue r1 = eng1.newRegExp("foo", "gim");
+ QJSValue r2 = eng2.newRegExp("foo", "gim");
+ QCOMPARE(r1.toRegExp(), r2.toRegExp());
+ QCOMPARE(r2.toRegExp(), r1.toRegExp());
+ }
+ {
+ QJSValue o1 = eng1.newQObject(this);
+ QJSValue o2 = eng2.newQObject(this);
+ QCOMPARE(o1.toQObject(), o2.toQObject());
+ QCOMPARE(o2.toQObject(), o1.toQObject());
+ }
+#if 0 // ###FIXME: No QScriptEngine::newQMetaObject API
+ {
+ QScriptValue mo1 = eng1.newQMetaObject(&staticMetaObject);
+ QScriptValue mo2 = eng2.newQMetaObject(&staticMetaObject);
+ QCOMPARE(mo1.toQMetaObject(), mo2.toQMetaObject());
+ QCOMPARE(mo2.toQMetaObject(), mo1.toQMetaObject());
+ }
+#endif
+}
+
+void tst_QJSEngine::jsIncDecNonObjectProperty()
+{
+ // This is testing ECMA-262 compliance, not C++ API.
+
+ QJSEngine eng;
+ {
+ QJSValue ret = eng.evaluate("var a; a.n++");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a; a.n--");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a = null; a.n++");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a = null; a.n--");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a; ++a.n");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a; --a.n");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a; a.n += 1");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a; a.n -= 1");
+ QVERIFY(ret.isError());
+ QVERIFY(ret.toString().contains(QString::fromLatin1("TypeError")));
+ }
+ {
+ QJSValue ret = eng.evaluate("var a = 'ciao'; a.length++");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 4);
+ }
+ {
+ QJSValue ret = eng.evaluate("var a = 'ciao'; a.length--");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 4);
+ }
+ {
+ QJSValue ret = eng.evaluate("var a = 'ciao'; ++a.length");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 5);
+ }
+ {
+ QJSValue ret = eng.evaluate("var a = 'ciao'; --a.length");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 3);
+ }
+}
+
+#if 0 // ###FIXME: no installTranslatorFunctions API
+void tst_QJSEngine::installTranslatorFunctions()
+{
+ QScriptEngine eng;
+ QScriptValue global = eng.globalObject();
+ QVERIFY(!global.property("qsTranslate").isValid());
+ QVERIFY(!global.property("QT_TRANSLATE_NOOP").isValid());
+ QVERIFY(!global.property("qsTr").isValid());
+ QVERIFY(!global.property("QT_TR_NOOP").isValid());
+ QVERIFY(!global.property("qsTrId").isValid());
+ QVERIFY(!global.property("QT_TRID_NOOP").isValid());
+ QVERIFY(!global.property("String").property("prototype").property("arg").isValid());
+
+ eng.installTranslatorFunctions();
+ QVERIFY(global.property("qsTranslate").isFunction());
+ QVERIFY(global.property("QT_TRANSLATE_NOOP").isFunction());
+ QVERIFY(global.property("qsTr").isFunction());
+ QVERIFY(global.property("QT_TR_NOOP").isFunction());
+ QVERIFY(global.property("qsTrId").isFunction());
+ QVERIFY(global.property("QT_TRID_NOOP").isFunction());
+ QVERIFY(global.property("String").property("prototype").property("arg").isFunction());
+
+ {
+ QScriptValue ret = eng.evaluate("qsTr('foo')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("qsTranslate('foo', 'bar')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("bar"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("QT_TR_NOOP('foo')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("QT_TRANSLATE_NOOP('foo', 'bar')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("bar"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("'foo%0'.arg('bar')");
+ QEXPECT_FAIL("Custom global object", "FIXME: why we expect that String prototype exists?", Abort);
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foobar"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("'foo%0'.arg(123)");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo123"));
+ }
+ {
+ // Maybe this should throw an error?
+ QScriptValue ret = eng.evaluate("'foo%0'.arg()");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString());
+ }
+
+ {
+ QScriptValue ret = eng.evaluate("qsTrId('foo')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ {
+ QScriptValue ret = eng.evaluate("QT_TRID_NOOP('foo')");
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
+ }
+ QVERIFY(eng.evaluate("QT_TRID_NOOP()").isUndefined());
+}
+
+class TranslationScope
+{
+public:
+ TranslationScope(const QString &fileName)
+ {
+ translator.load(fileName);
+ QCoreApplication::instance()->installTranslator(&translator);
+ }
+ ~TranslationScope()
+ {
+ QCoreApplication::instance()->removeTranslator(&translator);
+ }
+
+private:
+ QTranslator translator;
+};
+
+void tst_QJSEngine::translateScript_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QString>("expectedTranslation");
+
+ QString fileName = QString::fromLatin1("translatable.js");
+ // Top-level
+ QTest::newRow("qsTr('One')@translatable.js")
+ << QString::fromLatin1("qsTr('One')") << fileName << QString::fromLatin1("En");
+ QTest::newRow("qsTr('Hello')@translatable.js")
+ << QString::fromLatin1("qsTr('Hello')") << fileName << QString::fromLatin1("Hallo");
+ // From function
+ QTest::newRow("(function() { return qsTr('One'); })()@translatable.js")
+ << QString::fromLatin1("(function() { return qsTr('One'); })()") << fileName << QString::fromLatin1("En");
+ QTest::newRow("(function() { return qsTr('Hello'); })()@translatable.js")
+ << QString::fromLatin1("(function() { return qsTr('Hello'); })()") << fileName << QString::fromLatin1("Hallo");
+ // From eval
+ QTest::newRow("eval('qsTr(\\'One\\')')@translatable.js")
+ << QString::fromLatin1("eval('qsTr(\\'One\\')')") << fileName << QString::fromLatin1("En");
+ QTest::newRow("eval('qsTr(\\'Hello\\')')@translatable.js")
+ << QString::fromLatin1("eval('qsTr(\\'Hello\\')')") << fileName << QString::fromLatin1("Hallo");
+ // Plural
+ QTest::newRow("qsTr('%n message(s) saved', '', 1)@translatable.js")
+ << QString::fromLatin1("qsTr('%n message(s) saved', '', 1)") << fileName << QString::fromLatin1("1 melding lagret");
+ QTest::newRow("qsTr('%n message(s) saved', '', 3).arg@translatable.js")
+ << QString::fromLatin1("qsTr('%n message(s) saved', '', 3)") << fileName << QString::fromLatin1("3 meldinger lagret");
+
+ // Top-level
+ QTest::newRow("qsTranslate('FooContext', 'Two')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Two')") << fileName << QString::fromLatin1("To");
+ QTest::newRow("qsTranslate('FooContext', 'Goodbye')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye')") << fileName << QString::fromLatin1("Farvel");
+ // From eval
+ QTest::newRow("eval('qsTranslate(\\'FooContext\\', \\'Two\\')')@translatable.js")
+ << QString::fromLatin1("eval('qsTranslate(\\'FooContext\\', \\'Two\\')')") << fileName << QString::fromLatin1("To");
+ QTest::newRow("eval('qsTranslate(\\'FooContext\\', \\'Goodbye\\')')@translatable.js")
+ << QString::fromLatin1("eval('qsTranslate(\\'FooContext\\', \\'Goodbye\\')')") << fileName << QString::fromLatin1("Farvel");
+
+ QTest::newRow("qsTranslate('FooContext', 'Goodbye', '', 'UnicodeUTF8')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye', '', 'UnicodeUTF8')") << fileName << QString::fromLatin1("Farvel");
+ QTest::newRow("qsTranslate('FooContext', 'Goodbye', '', 'CodecForTr')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye', '', 'CodecForTr')") << fileName << QString::fromLatin1("Farvel");
+
+ QTest::newRow("qsTranslate('FooContext', 'Goodbye', '', 'UnicodeUTF8', 42)@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye', '', 'UnicodeUTF8', 42)") << fileName << QString::fromLatin1("Goodbye");
+
+ QTest::newRow("qsTr('One', 'not the same one')@translatable.js")
+ << QString::fromLatin1("qsTr('One', 'not the same one')") << fileName << QString::fromLatin1("Enda en");
+
+ QTest::newRow("qsTr('One', 'not the same one', 42)@translatable.js")
+ << QString::fromLatin1("qsTr('One', 'not the same one', 42)") << fileName << QString::fromLatin1("One");
+
+ // Plural
+ QTest::newRow("qsTranslate('FooContext', '%n fooish bar(s) found', '', 'UnicodeUTF8', 1)@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', '%n fooish bar(s) found', '', 'UnicodeUTF8', 1)") << fileName << QString::fromLatin1("1 fooaktig bar funnet");
+ QTest::newRow("qsTranslate('FooContext', '%n fooish bar(s) found', '', 'UnicodeUTF8', 2)@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', '%n fooish bar(s) found', '', 'UnicodeUTF8', 2)") << fileName << QString::fromLatin1("2 fooaktige barer funnet");
+
+ // Don't exist in translation
+ QTest::newRow("qsTr('Three')@translatable.js")
+ << QString::fromLatin1("qsTr('Three')") << fileName << QString::fromLatin1("Three");
+ QTest::newRow("qsTranslate('FooContext', 'So long')@translatable.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'So long')") << fileName << QString::fromLatin1("So long");
+ QTest::newRow("qsTranslate('BarContext', 'Goodbye')@translatable.js")
+ << QString::fromLatin1("qsTranslate('BarContext', 'Goodbye')") << fileName << QString::fromLatin1("Goodbye");
+
+ // Translate strings from the second script (translatable2.js)
+
+ QString fileName2 = QString::fromLatin1("translatable2.js");
+ QTest::newRow("qsTr('Three')@translatable2.js")
+ << QString::fromLatin1("qsTr('Three')") << fileName2 << QString::fromLatin1("Tre");
+ QTest::newRow("qsTr('Happy birthday!')@translatable2.js")
+ << QString::fromLatin1("qsTr('Happy birthday!')") << fileName2 << QString::fromLatin1("Gratulerer med dagen!");
+
+ // Not translated because translation is only in translatable.js
+ QTest::newRow("qsTr('One')@translatable2.js")
+ << QString::fromLatin1("qsTr('One')") << fileName2 << QString::fromLatin1("One");
+ QTest::newRow("(function() { return qsTr('One'); })()@translatable2.js")
+ << QString::fromLatin1("(function() { return qsTr('One'); })()") << fileName2 << QString::fromLatin1("One");
+
+ // For qsTranslate() the filename shouldn't matter
+ QTest::newRow("qsTranslate('FooContext', 'Two')@translatable2.js")
+ << QString::fromLatin1("qsTranslate('FooContext', 'Two')") << fileName2 << QString::fromLatin1("To");
+ QTest::newRow("qsTranslate('BarContext', 'Congratulations!')@translatable.js")
+ << QString::fromLatin1("qsTranslate('BarContext', 'Congratulations!')") << fileName << QString::fromLatin1("Gratulerer!");
+}
+
+void tst_QJSEngine::translateScript()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, fileName);
+ QFETCH(QString, expectedTranslation);
+
+ QScriptEngine engine;
+
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ QCOMPARE(engine.evaluate(expression, fileName).toString(), expectedTranslation);
+ QVERIFY(!engine.hasUncaughtException());
+}
+
+void tst_QJSEngine::translateScript_crossScript()
+{
+ QScriptEngine engine;
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ QString fileName = QString::fromLatin1("translatable.js");
+ QString fileName2 = QString::fromLatin1("translatable2.js");
+ // qsTr() should use the innermost filename as context
+ engine.evaluate("function foo(s) { return bar(s); }", fileName);
+ engine.evaluate("function bar(s) { return qsTr(s); }", fileName2);
+ QCOMPARE(engine.evaluate("bar('Three')", fileName2).toString(), QString::fromLatin1("Tre"));
+ QCOMPARE(engine.evaluate("bar('Three')", fileName).toString(), QString::fromLatin1("Tre"));
+ QCOMPARE(engine.evaluate("bar('One')", fileName2).toString(), QString::fromLatin1("One"));
+
+ engine.evaluate("function foo(s) { return bar(s); }", fileName2);
+ engine.evaluate("function bar(s) { return qsTr(s); }", fileName);
+ QCOMPARE(engine.evaluate("bar('Three')", fileName2).toString(), QString::fromLatin1("Three"));
+ QCOMPARE(engine.evaluate("bar('One')", fileName).toString(), QString::fromLatin1("En"));
+ QCOMPARE(engine.evaluate("bar('One')", fileName2).toString(), QString::fromLatin1("En"));
+}
+
+static QScriptValue callQsTr(QScriptContext *ctx, QScriptEngine *eng)
+{
+ return eng->globalObject().property("qsTr").call(ctx->thisObject(), ctx->argumentsObject());
+}
+
+void tst_QJSEngine::translateScript_callQsTrFromNative()
+{
+ QScriptEngine engine;
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ QString fileName = QString::fromLatin1("translatable.js");
+ QString fileName2 = QString::fromLatin1("translatable2.js");
+ // Calling qsTr() from a native function
+ engine.globalObject().setProperty("qsTrProxy", engine.newFunction(callQsTr));
+ QCOMPARE(engine.evaluate("qsTrProxy('One')", fileName).toString(), QString::fromLatin1("En"));
+ QCOMPARE(engine.evaluate("qsTrProxy('One')", fileName2).toString(), QString::fromLatin1("One"));
+ QCOMPARE(engine.evaluate("qsTrProxy('Three')", fileName).toString(), QString::fromLatin1("Three"));
+ QCOMPARE(engine.evaluate("qsTrProxy('Three')", fileName2).toString(), QString::fromLatin1("Tre"));
+}
+
+void tst_QJSEngine::translateScript_trNoOp()
+{
+ QScriptEngine engine;
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ QVERIFY(engine.evaluate("QT_TR_NOOP()").isUndefined());
+ QCOMPARE(engine.evaluate("QT_TR_NOOP('One')").toString(), QString::fromLatin1("One"));
+
+ QVERIFY(engine.evaluate("QT_TRANSLATE_NOOP()").isUndefined());
+ QVERIFY(engine.evaluate("QT_TRANSLATE_NOOP('FooContext')").isUndefined());
+ QCOMPARE(engine.evaluate("QT_TRANSLATE_NOOP('FooContext', 'Two')").toString(), QString::fromLatin1("Two"));
+}
+
+void tst_QJSEngine::translateScript_callQsTrFromCpp()
+{
+ QScriptEngine engine;
+ TranslationScope tranScope(":/translations/translatable_la");
+ engine.installTranslatorFunctions();
+
+ // There is no context, but it shouldn't crash
+ QCOMPARE(engine.globalObject().property("qsTr").call(
+ QScriptValue(), QScriptValueList() << "One").toString(), QString::fromLatin1("One"));
+}
+
+void tst_QJSEngine::translateWithInvalidArgs_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("expectedError");
+
+ QTest::newRow("qsTr()") << "qsTr()" << "Error: qsTr() requires at least one argument";
+ QTest::newRow("qsTr(123)") << "qsTr(123)" << "Error: qsTr(): first argument (text) must be a string";
+ QTest::newRow("qsTr('foo', 123)") << "qsTr('foo', 123)" << "Error: qsTr(): second argument (comment) must be a string";
+ QTest::newRow("qsTr('foo', 'bar', 'baz')") << "qsTr('foo', 'bar', 'baz')" << "Error: qsTr(): third argument (n) must be a number";
+ QTest::newRow("qsTr('foo', 'bar', true)") << "qsTr('foo', 'bar', true)" << "Error: qsTr(): third argument (n) must be a number";
+
+ QTest::newRow("qsTranslate()") << "qsTranslate()" << "Error: qsTranslate() requires at least two arguments";
+ QTest::newRow("qsTranslate('foo')") << "qsTranslate('foo')" << "Error: qsTranslate() requires at least two arguments";
+ QTest::newRow("qsTranslate(123, 'foo')") << "qsTranslate(123, 'foo')" << "Error: qsTranslate(): first argument (context) must be a string";
+ QTest::newRow("qsTranslate('foo', 123)") << "qsTranslate('foo', 123)" << "Error: qsTranslate(): second argument (text) must be a string";
+ QTest::newRow("qsTranslate('foo', 'bar', 123)") << "qsTranslate('foo', 'bar', 123)" << "Error: qsTranslate(): third argument (comment) must be a string";
+ QTest::newRow("qsTranslate('foo', 'bar', 'baz', 123)") << "qsTranslate('foo', 'bar', 'baz', 123)" << "Error: qsTranslate(): fourth argument (encoding) must be a string";
+ QTest::newRow("qsTranslate('foo', 'bar', 'baz', 'zab', 'rab')") << "qsTranslate('foo', 'bar', 'baz', 'zab', 'rab')" << "Error: qsTranslate(): fifth argument (n) must be a number";
+ QTest::newRow("qsTranslate('foo', 'bar', 'baz', 'zab', 123)") << "qsTranslate('foo', 'bar', 'baz', 'zab', 123)" << "Error: qsTranslate(): invalid encoding 'zab'";
+
+ QTest::newRow("qsTrId()") << "qsTrId()" << "Error: qsTrId() requires at least one argument";
+ QTest::newRow("qsTrId(123)") << "qsTrId(123)" << "TypeError: qsTrId(): first argument (id) must be a string";
+ QTest::newRow("qsTrId('foo', 'bar')") << "qsTrId('foo', 'bar')" << "TypeError: qsTrId(): second argument (n) must be a number";
+}
+
+void tst_QJSEngine::translateWithInvalidArgs()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, expectedError);
+ QScriptEngine engine;
+ engine.installTranslatorFunctions();
+ QScriptValue result = engine.evaluate(expression);
+ QVERIFY(result.isError());
+ QCOMPARE(result.toString(), expectedError);
+}
+
+void tst_QJSEngine::translationContext_data()
+{
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<QString>("expectedTranslation");
+
+ QTest::newRow("translatable.js") << "translatable.js" << "One" << "En";
+ QTest::newRow("/translatable.js") << "/translatable.js" << "One" << "En";
+ QTest::newRow("/foo/translatable.js") << "/foo/translatable.js" << "One" << "En";
+ QTest::newRow("/foo/bar/translatable.js") << "/foo/bar/translatable.js" << "One" << "En";
+ QTest::newRow("./translatable.js") << "./translatable.js" << "One" << "En";
+ QTest::newRow("../translatable.js") << "../translatable.js" << "One" << "En";
+ QTest::newRow("foo/translatable.js") << "foo/translatable.js" << "One" << "En";
+ QTest::newRow("file:///home/qt/translatable.js") << "file:///home/qt/translatable.js" << "One" << "En";
+ QTest::newRow(":/resources/translatable.js") << ":/resources/translatable.js" << "One" << "En";
+ QTest::newRow("/translatable.js.foo") << "/translatable.js.foo" << "One" << "En";
+ QTest::newRow("/translatable.txt") << "/translatable.txt" << "One" << "En";
+ QTest::newRow("translatable") << "translatable" << "One" << "En";
+ QTest::newRow("foo/translatable") << "foo/translatable" << "One" << "En";
+
+ QTest::newRow("native separators")
+ << (QDir::toNativeSeparators(QDir::currentPath()) + QDir::separator() + "translatable.js")
+ << "One" << "En";
+
+ QTest::newRow("translatable.js/") << "translatable.js/" << "One" << "One";
+ QTest::newRow("nosuchscript.js") << "" << "One" << "One";
+ QTest::newRow("(empty)") << "" << "One" << "One";
+}
+
+void tst_QJSEngine::translationContext()
+{
+ TranslationScope tranScope(":/translations/translatable_la");
+
+ QScriptEngine engine;
+ engine.installTranslatorFunctions();
+
+ QFETCH(QString, path);
+ QFETCH(QString, text);
+ QFETCH(QString, expectedTranslation);
+ QScriptValue ret = engine.evaluate(QString::fromLatin1("qsTr('%0')").arg(text), path);
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), expectedTranslation);
+}
+
+void tst_QJSEngine::translateScriptIdBased()
+{
+ QScriptEngine engine;
+
+ TranslationScope tranScope(":/translations/idtranslatable_la");
+ engine.installTranslatorFunctions();
+
+ QString fileName = QString::fromLatin1("idtranslatable.js");
+
+ QHash<QString, QString> expectedTranslations;
+ expectedTranslations["qtn_foo_bar"] = "First string";
+ expectedTranslations["qtn_needle"] = "Second string";
+ expectedTranslations["qtn_haystack"] = "Third string";
+ expectedTranslations["qtn_bar_baz"] = "Fourth string";
+
+ QHash<QString, QString>::const_iterator it;
+ for (it = expectedTranslations.constBegin(); it != expectedTranslations.constEnd(); ++it) {
+ for (int x = 0; x < 2; ++x) {
+ QString fn;
+ if (x)
+ fn = fileName;
+ // Top-level
+ QCOMPARE(engine.evaluate(QString::fromLatin1("qsTrId('%0')")
+ .arg(it.key()), fn).toString(),
+ it.value());
+ QCOMPARE(engine.evaluate(QString::fromLatin1("QT_TRID_NOOP('%0')")
+ .arg(it.key()), fn).toString(),
+ it.key());
+ // From function
+ QCOMPARE(engine.evaluate(QString::fromLatin1("(function() { return qsTrId('%0'); })()")
+ .arg(it.key()), fn).toString(),
+ it.value());
+ QCOMPARE(engine.evaluate(QString::fromLatin1("(function() { return QT_TRID_NOOP('%0'); })()")
+ .arg(it.key()), fn).toString(),
+ it.key());
+ }
+ }
+
+ // Plural form
+ QCOMPARE(engine.evaluate("qsTrId('qtn_bar_baz', 10)").toString(),
+ QString::fromLatin1("10 fooish bar(s) found"));
+ QCOMPARE(engine.evaluate("qsTrId('qtn_foo_bar', 10)").toString(),
+ QString::fromLatin1("qtn_foo_bar")); // Doesn't have plural
+}
+
+// How to add a new test row:
+// - Find a nice list of Unicode characters to choose from
+// - Write source string/context/comment in .js using Unicode escape sequences (\uABCD)
+// - Update corresponding .ts file (e.g. lupdate foo.js -ts foo.ts -codecfortr UTF-8)
+// - Enter translation in Linguist
+// - Update corresponding .qm file (e.g. lrelease foo.ts)
+// - Evaluate script that performs translation; make sure the correct result is returned
+// (e.g. by setting the resulting string as the text of a QLabel and visually verifying
+// that it looks the same as what you entered in Linguist :-) )
+// - Generate the expectedTranslation column data using toUtf8().toHex()
+void tst_QJSEngine::translateScriptUnicode_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QString>("expectedTranslation");
+
+ QString fileName = QString::fromLatin1("translatable-unicode.js");
+ QTest::newRow("qsTr('H\\u2082O')@translatable-unicode.js")
+ << QString::fromLatin1("qsTr('H\\u2082O')") << fileName << QString::fromUtf8("\xcd\xbb\xcd\xbc\xcd\xbd");
+ QTest::newRow("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')@translatable-unicode.js")
+ << QString::fromLatin1("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')") << fileName << QString::fromUtf8("\xd7\x91\xd7\x9a\xd7\xa2");
+ QTest::newRow("qsTr('\\u0391\\u0392\\u0393')@translatable-unicode.js")
+ << QString::fromLatin1("qsTr('\\u0391\\u0392\\u0393')") << fileName << QString::fromUtf8("\xd3\x9c\xd2\xb4\xd1\xbc");
+ QTest::newRow("qsTranslate('\\u010C\\u0101\\u011F\\u0115', '\\u0414\\u0415\\u0416')@translatable-unicode.js")
+ << QString::fromLatin1("qsTranslate('\\u010C\\u0101\\u011F\\u0115', '\\u0414\\u0415\\u0416')") << fileName << QString::fromUtf8("\xd8\xae\xd8\xb3\xd8\xb3");
+ QTest::newRow("qsTr('H\\u2082O', 'not the same H\\u2082O')@translatable-unicode.js")
+ << QString::fromLatin1("qsTr('H\\u2082O', 'not the same H\\u2082O')") << fileName << QString::fromUtf8("\xd4\xb6\xd5\x8a\xd5\x92");
+ QTest::newRow("qsTr('H\\u2082O')")
+ << QString::fromLatin1("qsTr('H\\u2082O')") << QString() << QString::fromUtf8("\x48\xe2\x82\x82\x4f");
+ QTest::newRow("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')")
+ << QString::fromLatin1("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')") << QString() << QString::fromUtf8("\xd7\x91\xd7\x9a\xd7\xa2");
+}
+
+void tst_QJSEngine::translateScriptUnicode()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, fileName);
+ QFETCH(QString, expectedTranslation);
+
+ QScriptEngine engine;
+
+ TranslationScope tranScope(":/translations/translatable-unicode");
+ engine.installTranslatorFunctions();
+
+ QCOMPARE(engine.evaluate(expression, fileName).toString(), expectedTranslation);
+ QVERIFY(!engine.hasUncaughtException());
+}
+
+void tst_QJSEngine::translateScriptUnicodeIdBased_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("expectedTranslation");
+
+ QTest::newRow("qsTrId('\\u01F8\\u01D2\\u0199\\u01D0\\u01E1'')")
+ << QString::fromLatin1("qsTrId('\\u01F8\\u01D2\\u0199\\u01D0\\u01E1')") << QString::fromUtf8("\xc6\xa7\xc6\xb0\xc6\x88\xc8\xbc\xc8\x9d\xc8\xbf\xc8\x99");
+ QTest::newRow("qsTrId('\\u0191\\u01CE\\u0211\\u0229\\u019C\\u018E\\u019A\\u01D0')")
+ << QString::fromLatin1("qsTrId('\\u0191\\u01CE\\u0211\\u0229\\u019C\\u018E\\u019A\\u01D0')") << QString::fromUtf8("\xc7\xa0\xc8\xa1\xc8\x8b\xc8\x85\xc8\x95");
+ QTest::newRow("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C', 10)")
+ << QString::fromLatin1("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C', 10)") << QString::fromUtf8("\x31\x30\x20\xc6\x92\xc6\xa1\xc7\x92\x28\xc8\x99\x29");
+ QTest::newRow("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C')")
+ << QString::fromLatin1("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C')") << QString::fromUtf8("\xc6\x91\xc6\xb0\xc7\xb9");
+ QTest::newRow("qsTrId('\\u01CD\\u0180\\u01A8\\u0190\\u019E\\u01AB')")
+ << QString::fromLatin1("qsTrId('\\u01CD\\u0180\\u01A8\\u0190\\u019E\\u01AB')") << QString::fromUtf8("\xc7\x8d\xc6\x80\xc6\xa8\xc6\x90\xc6\x9e\xc6\xab");
+}
+
+void tst_QJSEngine::translateScriptUnicodeIdBased()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, expectedTranslation);
+
+ QScriptEngine engine;
+
+ TranslationScope tranScope(":/translations/idtranslatable-unicode");
+ engine.installTranslatorFunctions();
+
+ QCOMPARE(engine.evaluate(expression).toString(), expectedTranslation);
+ QVERIFY(!engine.hasUncaughtException());
+}
+
+void tst_QJSEngine::translateFromBuiltinCallback()
+{
+ QScriptEngine eng;
+ eng.installTranslatorFunctions();
+
+ // Callback has no translation context.
+ eng.evaluate("function foo() { qsTr('foo'); }");
+
+ // Stack at translation time will be:
+ // qsTr, foo, forEach, global
+ // qsTr() needs to walk to the outer-most (global) frame before it finds
+ // a translation context, and this should not crash.
+ eng.evaluate("[10,20].forEach(foo)", "script.js");
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptValue::scope API
+void tst_QJSEngine::functionScopes()
+{
+ QScriptEngine eng;
+ {
+ // top-level functions have only the global object in their scope
+ QScriptValue fun = eng.evaluate("(function() {})");
+ QVERIFY(fun.isFunction());
+ QEXPECT_FAIL("", "QScriptValue::scope() is internal, not implemented", Abort);
+ QVERIFY(fun.scope().isObject());
+ QVERIFY(fun.scope().strictlyEquals(eng.globalObject()));
+ QVERIFY(!eng.globalObject().scope().isValid());
+ }
+ {
+ QScriptValue fun = eng.globalObject().property("Object");
+ QVERIFY(fun.isFunction());
+ // native built-in functions don't have scope
+ QVERIFY(!fun.scope().isValid());
+ }
+ {
+ // closure
+ QScriptValue fun = eng.evaluate("(function(arg) { var foo = arg; return function() { return foo; }; })(123)");
+ QVERIFY(fun.isFunction());
+ {
+ QScriptValue ret = fun.call();
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ QScriptValue scope = fun.scope();
+ QVERIFY(scope.isObject());
+ {
+ QScriptValue ret = scope.property("foo");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ QCOMPARE(scope.propertyFlags("foo"), QScriptValue::Undeletable);
+ }
+ {
+ QScriptValue ret = scope.property("arg");
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ QCOMPARE(scope.propertyFlags("arg"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ }
+
+ scope.setProperty("foo", 456);
+ {
+ QScriptValue ret = fun.call();
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 456);
+ }
+
+ scope = scope.scope();
+ QVERIFY(scope.isObject());
+ QVERIFY(scope.strictlyEquals(eng.globalObject()));
+ }
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptContext API
+static QScriptValue counter_inner(QScriptContext *ctx, QScriptEngine *)
+{
+ QScriptValue outerAct = ctx->callee().scope();
+ double count = outerAct.property("count").toNumber();
+ outerAct.setProperty("count", count+1);
+ return count;
+}
+
+static QScriptValue counter(QScriptContext *ctx, QScriptEngine *eng)
+{
+ QScriptValue act = ctx->activationObject();
+ act.setProperty("count", ctx->argument(0).toInt32());
+ QScriptValue result = eng->newFunction(counter_inner);
+ result.setScope(act);
+ return result;
+}
+
+static QScriptValue counter_hybrid(QScriptContext *ctx, QScriptEngine *eng)
+{
+ QScriptValue act = ctx->activationObject();
+ act.setProperty("count", ctx->argument(0).toInt32());
+ return eng->evaluate("(function() { return count++; })");
+}
+
+void tst_QJSEngine::nativeFunctionScopes()
+{
+ QScriptEngine eng;
+ {
+ QScriptValue fun = eng.newFunction(counter);
+ QScriptValue cnt = fun.call(QScriptValue(), QScriptValueList() << 123);
+ QVERIFY(cnt.isFunction());
+ {
+ QScriptValue ret = cnt.call();
+ QVERIFY(ret.isNumber());
+ QEXPECT_FAIL("", "QScriptValue::setScope not implemented", Continue);
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ }
+ {
+ QScriptValue fun = eng.newFunction(counter_hybrid);
+ QScriptValue cnt = fun.call(QScriptValue(), QScriptValueList() << 123);
+ QVERIFY(cnt.isFunction());
+ {
+ QScriptValue ret = cnt.call();
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ }
+
+ //from http://doc.trolltech.com/latest/qtscript.html#nested-functions-and-the-scope-chain
+ {
+ QScriptEngine eng;
+ eng.evaluate("function counter() { var count = 0; return function() { return count++; } }\n"
+ "var c1 = counter(); var c2 = counter(); ");
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ {
+ QScriptEngine eng;
+ eng.globalObject().setProperty("counter", eng.newFunction(counter));
+ eng.evaluate("var c1 = counter(); var c2 = counter(); ");
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
+ QEXPECT_FAIL("", "QScriptValue::setScope not implemented", Continue);
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
+ QEXPECT_FAIL("", "QScriptValue::setScope not implemented", Continue);
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
+ QVERIFY(!eng.hasUncaughtException());
+ }
+ {
+ QScriptEngine eng;
+ eng.globalObject().setProperty("counter", eng.newFunction(counter_hybrid));
+ eng.evaluate("var c1 = counter(); var c2 = counter(); ");
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
+ QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
+ QVERIFY(!eng.hasUncaughtException());
+ }
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptProgram API
+static QScriptValue createProgram(QScriptContext *ctx, QScriptEngine *eng)
+{
+ QString code = ctx->argument(0).toString();
+ QScriptProgram result(code);
+ return qScriptValueFromValue(eng, result);
+}
+
+void tst_QJSEngine::evaluateProgram()
+{
+ QScriptEngine eng;
+
+ {
+ QString code("1 + 2");
+ QString fileName("hello.js");
+ int lineNumber(123);
+ QScriptProgram program(code, fileName, lineNumber);
+ QVERIFY(!program.isNull());
+ QCOMPARE(program.sourceCode(), code);
+ QCOMPARE(program.fileName(), fileName);
+ QCOMPARE(program.firstLineNumber(), lineNumber);
+
+ QScriptValue expected = eng.evaluate(code);
+ for (int x = 0; x < 10; ++x) {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(ret.equals(expected));
+ }
+
+ // operator=
+ QScriptProgram sameProgram = program;
+ QVERIFY(sameProgram == program);
+ QVERIFY(eng.evaluate(sameProgram).equals(expected));
+
+ // copy constructor
+ QScriptProgram sameProgram2(program);
+ QVERIFY(sameProgram2 == program);
+ QVERIFY(eng.evaluate(sameProgram2).equals(expected));
+
+ QScriptProgram differentProgram("2 + 3");
+ QVERIFY(differentProgram != program);
+ QVERIFY(!eng.evaluate(differentProgram).equals(expected));
+ }
+}
+
+void tst_QJSEngine::evaluateProgram_customScope()
+{
+ QScriptEngine eng;
+ {
+ QScriptProgram program("a");
+ QVERIFY(!program.isNull());
+ {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: a is not defined"));
+ }
+
+ QScriptValue obj = eng.newObject();
+ obj.setProperty("a", 123);
+ QScriptContext *ctx = eng.currentContext();
+ ctx->pushScope(obj);
+ {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(!ret.isError());
+ QVERIFY(ret.equals(obj.property("a")));
+ }
+
+ obj.setProperty("a", QScriptValue());
+ {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(ret.isError());
+ }
+
+ QScriptValue obj2 = eng.newObject();
+ obj2.setProperty("a", 456);
+ ctx->pushScope(obj2);
+ {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(!ret.isError());
+ QVERIFY(ret.equals(obj2.property("a")));
+ }
+
+ ctx->popScope();
+ }
+}
+
+void tst_QJSEngine::evaluateProgram_closure()
+{
+ QScriptEngine eng;
+ {
+ QScriptProgram program("(function() { var count = 0; return function() { return count++; }; })");
+ QVERIFY(!program.isNull());
+ QScriptValue createCounter = eng.evaluate(program);
+ QVERIFY(createCounter.isFunction());
+ QScriptValue counter = createCounter.call();
+ QVERIFY(counter.isFunction());
+ {
+ QScriptValue ret = counter.call();
+ QVERIFY(ret.isNumber());
+ }
+ QScriptValue counter2 = createCounter.call();
+ QVERIFY(counter2.isFunction());
+ QVERIFY(!counter2.equals(counter));
+ {
+ QScriptValue ret = counter2.call();
+ QVERIFY(ret.isNumber());
+ }
+ }
+}
+
+void tst_QJSEngine::evaluateProgram_executeLater()
+{
+ QScriptEngine eng;
+ // Program created in a function call, then executed later
+ {
+ QScriptValue fun = eng.newFunction(createProgram);
+ QScriptProgram program = qscriptvalue_cast<QScriptProgram>(
+ fun.call(QScriptValue(), QScriptValueList() << "a + 1"));
+ QVERIFY(!program.isNull());
+ eng.globalObject().setProperty("a", QScriptValue());
+ {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(ret.isError());
+ QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: a is not defined"));
+ }
+ eng.globalObject().setProperty("a", 122);
+ {
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(!ret.isError());
+ QVERIFY(ret.isNumber());
+ QCOMPARE(ret.toInt32(), 123);
+ }
+ }
+}
+
+void tst_QJSEngine::evaluateProgram_multipleEngines()
+{
+ QScriptEngine eng;
+ {
+ QString code("1 + 2");
+ QScriptProgram program(code);
+ QVERIFY(!program.isNull());
+ double expected = eng.evaluate(program).toNumber();
+ for (int x = 0; x < 2; ++x) {
+ QScriptEngine eng2;
+ for (int y = 0; y < 2; ++y) {
+ double ret = eng2.evaluate(program).toNumber();
+ QCOMPARE(ret, expected);
+ }
+ }
+ }
+}
+
+void tst_QJSEngine::evaluateProgram_empty()
+{
+ QScriptEngine eng;
+ {
+ QScriptProgram program;
+ QVERIFY(program.isNull());
+ QScriptValue ret = eng.evaluate(program);
+ QVERIFY(!ret.isValid());
+ }
+}
+#endif
+
+#if 0 // ###FIXME: No ScriptOwnership API
+void tst_QJSEngine::collectGarbageAfterConnect()
+{
+ // QTBUG-6366
+ QScriptEngine engine;
+ QPointer<QWidget> widget = new QWidget;
+ engine.globalObject().setProperty(
+ "widget", engine.newQObject(widget, QScriptEngine::ScriptOwnership));
+ QVERIFY(engine.evaluate("widget.customContextMenuRequested.connect(\n"
+ " function() { print('hello'); }\n"
+ ");")
+ .isUndefined());
+ QVERIFY(widget != 0);
+ engine.evaluate("widget = null;");
+ // The connection should not keep the widget alive.
+ collectGarbage_helper(engine);
+ QVERIFY(widget == 0);
+}
+#endif
+
+#if 0 // ###FIXME: No QScriptContext API
+void tst_QJSEngine::collectGarbageAfterNativeArguments()
+{
+ // QTBUG-17788
+ QScriptEngine eng;
+ QScriptContext *ctx = eng.pushContext();
+ QScriptValue arguments = ctx->argumentsObject();
+ // Shouldn't crash when marking the arguments object.
+ collectGarbage_helper(eng);
+}
+
+static QScriptValue constructQObjectFromThisObject(QScriptContext *ctx, QScriptEngine *eng)
+{
+ if (!ctx->isCalledAsConstructor()) {
+ qWarning("%s: ctx->isCalledAsConstructor() returned false", Q_FUNC_INFO);
+ return QScriptValue();
+ }
+ return eng->newQObject(ctx->thisObject(), new QObject, QScriptEngine::ScriptOwnership);
+}
+
+void tst_QJSEngine::promoteThisObjectToQObjectInConstructor()
+{
+ QScriptEngine engine;
+ QScriptValue ctor = engine.newFunction(constructQObjectFromThisObject);
+ engine.globalObject().setProperty("Ctor", ctor);
+ QScriptValue object = engine.evaluate("new Ctor");
+ QVERIFY(!object.isError());
+ QVERIFY(object.isQObject());
+ QVERIFY(object.toQObject() != 0);
+ QVERIFY(object.property("objectName").isString());
+ QVERIFY(object.property("deleteLater").isFunction());
+}
+#endif
+
+static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; }
+
+void tst_QJSEngine::qRegExpInport_data()
+{
+ QTest::addColumn<QRegExp>("rx");
+ QTest::addColumn<QString>("string");
+ QTest::addColumn<QString>("matched");
+
+ QTest::newRow("normal") << QRegExp("(test|foo)") << "test _ foo _ test _ Foo";
+ QTest::newRow("normal2") << QRegExp("(Test|Foo)") << "test _ foo _ test _ Foo";
+ QTest::newRow("case insensitive)") << QRegExp("(test|foo)", Qt::CaseInsensitive) << "test _ foo _ test _ Foo";
+ QTest::newRow("case insensitive2)") << QRegExp("(Test|Foo)", Qt::CaseInsensitive) << "test _ foo _ test _ Foo";
+ QTest::newRow("b(a*)(b*)") << QRegExp("b(a*)(b*)", Qt::CaseInsensitive) << "aaabbBbaAabaAaababaaabbaaab";
+ QTest::newRow("greedy") << QRegExp("a*(a*)", Qt::CaseInsensitive, QRegExp::RegExp2) << "aaaabaaba";
+ // this one will fail because we do not support the QRegExp::RegExp in JSC
+ //QTest::newRow("not_greedy") << QRegExp("a*(a*)", Qt::CaseInsensitive, QRegExp::RegExp) << "aaaabaaba";
+ QTest::newRow("willcard") << QRegExp("*.txt", Qt::CaseSensitive, QRegExp::Wildcard) << "file.txt";
+ QTest::newRow("willcard 2") << QRegExp("a?b.txt", Qt::CaseSensitive, QRegExp::Wildcard) << "ab.txt abb.rtc acb.txt";
+ QTest::newRow("slash") << QRegExp("g/.*/s", Qt::CaseInsensitive, QRegExp::RegExp2) << "string/string/string";
+ QTest::newRow("slash2") << QRegExp("g / .* / s", Qt::CaseInsensitive, QRegExp::RegExp2) << "string / string / string";
+ QTest::newRow("fixed") << QRegExp("a*aa.a(ba)*a\\ba", Qt::CaseInsensitive, QRegExp::FixedString) << "aa*aa.a(ba)*a\\ba";
+ QTest::newRow("fixed insensitive") << QRegExp("A*A", Qt::CaseInsensitive, QRegExp::FixedString) << "a*A A*a A*A a*a";
+ QTest::newRow("fixed sensitive") << QRegExp("A*A", Qt::CaseSensitive, QRegExp::FixedString) << "a*A A*a A*A a*a";
+ QTest::newRow("html") << QRegExp("<b>(.*)</b>", Qt::CaseSensitive, QRegExp::RegExp2) << "<b>bold</b><i>italic</i><b>bold</b>";
+ QTest::newRow("html minimal") << minimal(QRegExp("<b>(.*)</b>", Qt::CaseSensitive, QRegExp::RegExp2)) << "<b>bold</b><i>italic</i><b>bold</b>";
+ QTest::newRow("aaa") << QRegExp("a{2,5}") << "aAaAaaaaaAa";
+ QTest::newRow("aaa minimal") << minimal(QRegExp("a{2,5}")) << "aAaAaaaaaAa";
+ QTest::newRow("minimal") << minimal(QRegExp(".*\\} [*8]")) << "}?} ?} *";
+ QTest::newRow(".? minimal") << minimal(QRegExp(".?")) << ".?";
+ QTest::newRow(".+ minimal") << minimal(QRegExp(".+")) << ".+";
+ QTest::newRow("[.?] minimal") << minimal(QRegExp("[.?]")) << ".?";
+ QTest::newRow("[.+] minimal") << minimal(QRegExp("[.+]")) << ".+";
+}
+
+void tst_QJSEngine::qRegExpInport()
+{
+ QFETCH(QRegExp, rx);
+ QFETCH(QString, string);
+
+ QJSEngine eng;
+ QJSValue rexp;
+ rexp = eng.newRegExp(rx);
+
+ QCOMPARE(rexp.isValid(), true);
+ QCOMPARE(rexp.isRegExp(), true);
+ QVERIFY(rexp.isFunction());
+
+ QJSValue func = eng.evalu