aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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.evaluate("(function(string, regexp) { return string.match(regexp); })");
+ QJSValue result = func.call(QJSValue(), QJSValueList() << string << rexp);
+
+ rx.indexIn(string);
+ for (int i = 0; i <= rx.captureCount(); i++) {
+ QCOMPARE(result.property(i).toString(), rx.cap(i));
+ }
+}
+
+// QScriptValue::toDateTime() returns a local time, whereas JS dates
+// are always stored as UTC. QtScript must respect the current time
+// zone, and correctly adjust for daylight saving time that may be in
+// effect at a given date (QTBUG-9770).
+void tst_QJSEngine::dateRoundtripJSQtJS()
+{
+ uint secs = QDateTime(QDate(2009, 1, 1)).toUTC().toTime_t();
+ QJSEngine eng;
+ for (int i = 0; i < 8000; ++i) {
+ QJSValue jsDate = eng.evaluate(QString::fromLatin1("new Date(%0)").arg(secs * 1000.0));
+ QDateTime qtDate = jsDate.toDateTime();
+ QJSValue jsDate2 = eng.newDate(qtDate);
+ if (jsDate2.toNumber() != jsDate.toNumber())
+ QFAIL(qPrintable(jsDate.toString()));
+ secs += 2*60*60;
+ }
+}
+
+void tst_QJSEngine::dateRoundtripQtJSQt()
+{
+ QDateTime qtDate = QDateTime(QDate(2009, 1, 1));