summaryrefslogtreecommitdiff
path: root/src/script/api/qscriptengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/script/api/qscriptengine.cpp')
-rw-r--r--src/script/api/qscriptengine.cpp4456
1 files changed, 4456 insertions, 0 deletions
diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp
new file mode 100644
index 0000000..a3a965e
--- /dev/null
+++ b/src/script/api/qscriptengine.cpp
@@ -0,0 +1,4456 @@
+/****************************************************************************
+**
+** 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 "config.h"
+#include "qscriptengine.h"
+#include "qscriptsyntaxchecker_p.h"
+
+#include "qscriptengine_p.h"
+#include "qscriptengineagent_p.h"
+#include "qscriptcontext_p.h"
+#include "qscriptstring_p.h"
+#include "qscriptvalue_p.h"
+#include "qscriptvalueiterator.h"
+#include "qscriptclass.h"
+#include "qscriptcontextinfo.h"
+#include "qscriptprogram.h"
+#include "qscriptprogram_p.h"
+#include "qdebug.h"
+
+#include <QtCore/qstringlist.h>
+#include <QtCore/qmetaobject.h>
+
+#include <math.h>
+
+#include "CodeBlock.h"
+#include "Error.h"
+#include "Interpreter.h"
+
+#include "ExceptionHelpers.h"
+#include "PrototypeFunction.h"
+#include "InitializeThreading.h"
+#include "ObjectPrototype.h"
+#include "SourceCode.h"
+#include "FunctionPrototype.h"
+#include "TimeoutChecker.h"
+#include "JSFunction.h"
+#include "Parser.h"
+#include "PropertyNameArray.h"
+#include "Operations.h"
+
+#include "bridge/qscriptfunction_p.h"
+#include "bridge/qscriptclassobject_p.h"
+#include "bridge/qscriptvariant_p.h"
+#include "bridge/qscriptqobject_p.h"
+#include "bridge/qscriptglobalobject_p.h"
+#include "bridge/qscriptactivationobject_p.h"
+#include "bridge/qscriptstaticscopeobject_p.h"
+
+#ifndef QT_NO_QOBJECT
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qpluginloader.h>
+#include <QtCore/qset.h>
+#include <QtCore/qtextstream.h>
+#include "qscriptextensioninterface.h"
+#endif
+
+Q_DECLARE_METATYPE(QScriptValue)
+#ifndef QT_NO_QOBJECT
+Q_DECLARE_METATYPE(QObjectList)
+#endif
+Q_DECLARE_METATYPE(QList<int>)
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \since 4.3
+ \class QScriptEngine
+ \reentrant
+
+ \brief The QScriptEngine class provides an environment for evaluating Qt Script code.
+
+ \ingroup script
+ \mainclass
+
+ See the \l{QtScript} documentation for information about the Qt Script language,
+ and how to get started with scripting your C++ application.
+
+ \section1 Evaluating Scripts
+
+ Use evaluate() to evaluate script code; this is the C++ equivalent
+ of the built-in script function \c{eval()}.
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 0
+
+ evaluate() returns a QScriptValue that holds the result of the
+ evaluation. The QScriptValue class provides functions for converting
+ the result to various C++ types (e.g. QScriptValue::toString()
+ and QScriptValue::toNumber()).
+
+ The following code snippet shows how a script function can be
+ defined and then invoked from C++ using QScriptValue::call():
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 1
+
+ As can be seen from the above snippets, a script is provided to the
+ engine in the form of a string. One common way of loading scripts is
+ by reading the contents of a file and passing it to evaluate():
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 2
+
+ Here we pass the name of the file as the second argument to
+ evaluate(). This does not affect evaluation in any way; the second
+ argument is a general-purpose string that is used to identify the
+ script for debugging purposes (for example, our filename will now
+ show up in any uncaughtExceptionBacktrace() involving the script).
+
+ \section1 Engine Configuration
+
+ The globalObject() function returns the \bold {Global Object}
+ associated with the script engine. Properties of the Global Object
+ are accessible from any script code (i.e. they are global
+ variables). Typically, before evaluating "user" scripts, you will
+ want to configure a script engine by adding one or more properties
+ to the Global Object:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 3
+
+ Adding custom properties to the scripting environment is one of the
+ standard means of providing a scripting API that is specific to your
+ application. Usually these custom properties are objects created by
+ the newQObject() or newObject() functions, or constructor functions
+ created by newFunction().
+
+ \section1 Script Exceptions
+
+ evaluate() can throw a script exception (e.g. due to a syntax
+ error); in that case, the return value is the value that was thrown
+ (typically an \c{Error} object). You can check whether the
+ evaluation caused an exception by calling hasUncaughtException(). In
+ that case, you can call toString() on the error object to obtain an
+ error message. The current uncaught exception is also available
+ through uncaughtException().
+ Calling clearExceptions() will cause any uncaught exceptions to be
+ cleared.
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 4
+
+ The checkSyntax() function can be used to determine whether code can be
+ usefully passed to evaluate().
+
+ \section1 Script Object Creation
+
+ Use newObject() to create a standard Qt Script object; this is the
+ C++ equivalent of the script statement \c{new Object()}. You can use
+ the object-specific functionality in QScriptValue to manipulate the
+ script object (e.g. QScriptValue::setProperty()). Similarly, use
+ newArray() to create a Qt Script array object. Use newDate() to
+ create a \c{Date} object, and newRegExp() to create a \c{RegExp}
+ object.
+
+ \section1 QObject Integration
+
+ Use newQObject() to wrap a QObject (or subclass)
+ pointer. newQObject() returns a proxy script object; properties,
+ children, and signals and slots of the QObject are available as
+ properties of the proxy object. No binding code is needed because it
+ is done dynamically using the Qt meta object system.
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 5
+
+ Use qScriptConnect() to connect a C++ signal to a script function;
+ this is the Qt Script equivalent of QObject::connect(). When a
+ script function is invoked in response to a C++ signal, it can cause
+ a script exception; you can connect to the signalHandlerException()
+ signal to catch such an exception.
+
+ Use newQMetaObject() to wrap a QMetaObject; this gives you a "script
+ representation" of a QObject-based class. newQMetaObject() returns a
+ proxy script object; enum values of the class are available as
+ properties of the proxy object. You can also specify a function that
+ will be used to construct objects of the class (e.g. when the
+ constructor is invoked from a script). For classes that have a
+ "standard" Qt constructor, Qt Script can provide a default script
+ constructor for you; see scriptValueFromQMetaObject().
+
+ See the \l{QtScript} documentation for more information on
+ the QObject integration.
+
+ \section1 Support for Custom C++ Types
+
+ Use newVariant() to wrap a QVariant. This can be used to store
+ values of custom (non-QObject) C++ types that have been registered
+ with the Qt meta-type system. To make such types scriptable, you
+ typically associate a prototype (delegate) object with the C++ type
+ by calling setDefaultPrototype(); the prototype object defines the
+ scripting API for the C++ type. Unlike the QObject integration,
+ there is no automatic binding possible here; i.e. you have to create
+ the scripting API yourself, for example by using the QScriptable
+ class.
+
+ Use fromScriptValue() to cast from a QScriptValue to another type,
+ and toScriptValue() to create a QScriptValue from another value.
+ You can specify how the conversion of C++ types is to be performed
+ with qScriptRegisterMetaType() and qScriptRegisterSequenceMetaType().
+ By default, Qt Script will use QVariant to store values of custom
+ types.
+
+ \section1 Importing Extensions
+
+ Use importExtension() to import plugin-based extensions into the
+ engine. Call availableExtensions() to obtain a list naming all the
+ available extensions, and importedExtensions() to obtain a list
+ naming only those extensions that have been imported.
+
+ Call pushContext() to open up a new variable scope, and popContext()
+ to close the current scope. This is useful if you are implementing
+ an extension that evaluates script code containing temporary
+ variable definitions (e.g. \c{var foo = 123;}) that are safe to
+ discard when evaluation has completed.
+
+ \section1 Native Functions
+
+ Use newFunction() to wrap native (C++) functions, including
+ constructors for your own custom types, so that these can be invoked
+ from script code. Such functions must have the signature
+ QScriptEngine::FunctionSignature. You may then pass the function as
+ argument to newFunction(). Here is an example of a function that
+ returns the sum of its first two arguments:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 6
+
+ To expose this function to script code, you can set it as a property
+ of the Global Object:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 7
+
+ Once this is done, script code can call your function in the exact
+ same manner as a "normal" script function:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 8
+
+ \section1 Long-running Scripts
+
+ If you need to evaluate possibly long-running scripts from the main
+ (GUI) thread, you should first call setProcessEventsInterval() to
+ make sure that the GUI stays responsive. You can abort a currently
+ running script by calling abortEvaluation(). You can determine
+ whether an engine is currently running a script by calling
+ isEvaluating().
+
+ \section1 Garbage Collection
+
+ Qt Script objects may be garbage collected when they are no longer
+ referenced. There is no guarantee as to when automatic garbage
+ collection will take place.
+
+ The collectGarbage() function can be called to explicitly request
+ garbage collection.
+
+ The reportAdditionalMemoryCost() function can be called to indicate
+ that a Qt Script object occupies memory that isn't managed by the
+ scripting environment. Reporting the additional cost makes it more
+ likely that the garbage collector will be triggered. This can be
+ useful, for example, when many custom, native Qt Script objects are
+ allocated.
+
+ \section1 Core Debugging/Tracing Facilities
+
+ Since Qt 4.4, you can be notified of events pertaining to script
+ execution (e.g. script function calls and statement execution)
+ through the QScriptEngineAgent interface; see the setAgent()
+ function. This can be used to implement debugging and profiling of a
+ QScriptEngine.
+
+ \sa QScriptValue, QScriptContext, QScriptEngineAgent
+
+*/
+
+/*!
+ \enum QScriptEngine::ValueOwnership
+
+ This enum specifies the ownership when wrapping a C++ value, e.g. by using newQObject().
+
+ \value QtOwnership The standard Qt ownership rules apply, i.e. the
+ associated object will never be explicitly deleted by the script
+ engine. This is the default. (QObject ownership is explained in
+ \l{Object Trees & Ownership}.)
+
+ \value ScriptOwnership The value is owned by the script
+ environment. The associated data will be deleted when appropriate
+ (i.e. after the garbage collector has discovered that there are no
+ more live references to the value).
+
+ \value AutoOwnership If the associated object has a parent, the Qt
+ ownership rules apply (QtOwnership); otherwise, the object is
+ owned by the script environment (ScriptOwnership).
+
+*/
+
+/*!
+ \enum QScriptEngine::QObjectWrapOption
+
+ These flags specify options when wrapping a QObject pointer with newQObject().
+
+ \value ExcludeChildObjects The script object will not expose child objects as properties.
+ \value ExcludeSuperClassMethods The script object will not expose signals and slots inherited from the superclass.
+ \value ExcludeSuperClassProperties The script object will not expose properties inherited from the superclass.
+ \value ExcludeSuperClassContents Shorthand form for ExcludeSuperClassMethods | ExcludeSuperClassProperties
+ \value ExcludeDeleteLater The script object will not expose the QObject::deleteLater() slot.
+ \value ExcludeSlots The script object will not expose the QObject's slots.
+ \value AutoCreateDynamicProperties Properties that don't already exist in the QObject will be created as dynamic properties of that object, rather than as properties of the script object.
+ \value PreferExistingWrapperObject If a wrapper object with the requested configuration already exists, return that object.
+ \value SkipMethodsInEnumeration Don't include methods (signals and slots) when enumerating the object's properties.
+*/
+
+class QScriptSyntaxCheckResultPrivate
+{
+public:
+ QScriptSyntaxCheckResultPrivate() { ref = 0; }
+ ~QScriptSyntaxCheckResultPrivate() {}
+
+ QScriptSyntaxCheckResult::State state;
+ int errorColumnNumber;
+ int errorLineNumber;
+ QString errorMessage;
+ QBasicAtomicInt ref;
+};
+
+class QScriptTypeInfo
+{
+public:
+ QScriptTypeInfo() : signature(0, '\0'), marshal(0), demarshal(0)
+ { }
+
+ QByteArray signature;
+ QScriptEngine::MarshalFunction marshal;
+ QScriptEngine::DemarshalFunction demarshal;
+ JSC::JSValue prototype;
+};
+
+namespace QScript
+{
+
+static const qsreal D32 = 4294967296.0;
+
+qint32 ToInt32(qsreal n)
+{
+ if (qIsNaN(n) || qIsInf(n) || (n == 0))
+ return 0;
+
+ qsreal sign = (n < 0) ? -1.0 : 1.0;
+ qsreal abs_n = fabs(n);
+
+ n = ::fmod(sign * ::floor(abs_n), D32);
+ const double D31 = D32 / 2.0;
+
+ if (sign == -1 && n < -D31)
+ n += D32;
+
+ else if (sign != -1 && n >= D31)
+ n -= D32;
+
+ return qint32 (n);
+}
+
+quint32 ToUInt32(qsreal n)
+{
+ if (qIsNaN(n) || qIsInf(n) || (n == 0))
+ return 0;
+
+ qsreal sign = (n < 0) ? -1.0 : 1.0;
+ qsreal abs_n = fabs(n);
+
+ n = ::fmod(sign * ::floor(abs_n), D32);
+
+ if (n < 0)
+ n += D32;
+
+ return quint32 (n);
+}
+
+quint16 ToUInt16(qsreal n)
+{
+ static const qsreal D16 = 65536.0;
+
+ if (qIsNaN(n) || qIsInf(n) || (n == 0))
+ return 0;
+
+ qsreal sign = (n < 0) ? -1.0 : 1.0;
+ qsreal abs_n = fabs(n);
+
+ n = ::fmod(sign * ::floor(abs_n), D16);
+
+ if (n < 0)
+ n += D16;
+
+ return quint16 (n);
+}
+
+qsreal ToInteger(qsreal n)
+{
+ if (qIsNaN(n))
+ return 0;
+
+ if (n == 0 || qIsInf(n))
+ return n;
+
+ int sign = n < 0 ? -1 : 1;
+ return sign * ::floor(::fabs(n));
+}
+
+#ifdef Q_CC_MSVC
+// MSVC2008 crashes if these are inlined.
+
+QString ToString(qsreal value)
+{
+ return JSC::UString::from(value);
+}
+
+qsreal ToNumber(const QString &value)
+{
+ return ((JSC::UString)value).toDouble();
+}
+
+#endif
+
+static const qsreal MsPerSecond = 1000.0;
+
+static inline int MsFromTime(qsreal t)
+{
+ int r = int(::fmod(t, MsPerSecond));
+ return (r >= 0) ? r : r + int(MsPerSecond);
+}
+
+/*!
+ \internal
+ Converts a JS date value (milliseconds) to a QDateTime (local time).
+*/
+QDateTime MsToDateTime(JSC::ExecState *exec, qsreal t)
+{
+ if (qIsNaN(t))
+ return QDateTime();
+ JSC::GregorianDateTime tm;
+ JSC::msToGregorianDateTime(exec, t, /*output UTC=*/true, tm);
+ int ms = MsFromTime(t);
+ QDateTime convertedUTC = QDateTime(QDate(tm.year + 1900, tm.month + 1, tm.monthDay),
+ QTime(tm.hour, tm.minute, tm.second, ms), Qt::UTC);
+ return convertedUTC.toLocalTime();
+}
+
+/*!
+ \internal
+ Converts a QDateTime to a JS date value (milliseconds).
+*/
+qsreal DateTimeToMs(JSC::ExecState *exec, const QDateTime &dt)
+{
+ if (!dt.isValid())
+ return qSNaN();
+ QDateTime utc = dt.toUTC();
+ QDate date = utc.date();
+ QTime time = utc.time();
+ JSC::GregorianDateTime tm;
+ tm.year = date.year() - 1900;
+ tm.month = date.month() - 1;
+ tm.monthDay = date.day();
+ tm.weekDay = date.dayOfWeek();
+ tm.yearDay = date.dayOfYear();
+ tm.hour = time.hour();
+ tm.minute = time.minute();
+ tm.second = time.second();
+ return JSC::gregorianDateTimeToMS(exec, tm, time.msec(), /*inputIsUTC=*/true);
+}
+
+void GlobalClientData::mark(JSC::MarkStack& markStack)
+{
+ engine->mark(markStack);
+}
+
+class TimeoutCheckerProxy : public JSC::TimeoutChecker
+{
+public:
+ TimeoutCheckerProxy(const JSC::TimeoutChecker& originalChecker)
+ : JSC::TimeoutChecker(originalChecker)
+ , m_shouldProcessEvents(false)
+ , m_shouldAbortEvaluation(false)
+ {}
+
+ void setShouldProcessEvents(bool shouldProcess) { m_shouldProcessEvents = shouldProcess; }
+ void setShouldAbort(bool shouldAbort) { m_shouldAbortEvaluation = shouldAbort; }
+ bool shouldAbort() { return m_shouldAbortEvaluation; }
+
+ virtual bool didTimeOut(JSC::ExecState* exec)
+ {
+ if (JSC::TimeoutChecker::didTimeOut(exec))
+ return true;
+
+ if (m_shouldProcessEvents)
+ QCoreApplication::processEvents();
+
+ return m_shouldAbortEvaluation;
+ }
+
+private:
+ bool m_shouldProcessEvents;
+ bool m_shouldAbortEvaluation;
+};
+
+static int toDigit(char c)
+{
+ if ((c >= '0') && (c <= '9'))
+ return c - '0';
+ else if ((c >= 'a') && (c <= 'z'))
+ return 10 + c - 'a';
+ else if ((c >= 'A') && (c <= 'Z'))
+ return 10 + c - 'A';
+ return -1;
+}
+
+qsreal integerFromString(const char *buf, int size, int radix)
+{
+ if (size == 0)
+ return qSNaN();
+
+ qsreal sign = 1.0;
+ int i = 0;
+ if (buf[0] == '+') {
+ ++i;
+ } else if (buf[0] == '-') {
+ sign = -1.0;
+ ++i;
+ }
+
+ if (((size-i) >= 2) && (buf[i] == '0')) {
+ if (((buf[i+1] == 'x') || (buf[i+1] == 'X'))
+ && (radix < 34)) {
+ if ((radix != 0) && (radix != 16))
+ return 0;
+ radix = 16;
+ i += 2;
+ } else {
+ if (radix == 0) {
+ radix = 8;
+ ++i;
+ }
+ }
+ } else if (radix == 0) {
+ radix = 10;
+ }
+
+ int j = i;
+ for ( ; i < size; ++i) {
+ int d = toDigit(buf[i]);
+ if ((d == -1) || (d >= radix))
+ break;
+ }
+ qsreal result;
+ if (j == i) {
+ if (!qstrcmp(buf, "Infinity"))
+ result = qInf();
+ else
+ result = qSNaN();
+ } else {
+ result = 0;
+ qsreal multiplier = 1;
+ for (--i ; i >= j; --i, multiplier *= radix)
+ result += toDigit(buf[i]) * multiplier;
+ }
+ result *= sign;
+ return result;
+}
+
+qsreal integerFromString(const QString &str, int radix)
+{
+ QByteArray ba = str.trimmed().toUtf8();
+ return integerFromString(ba.constData(), ba.size(), radix);
+}
+
+bool isFunction(JSC::JSValue value)
+{
+ if (!value || !value.isObject())
+ return false;
+ JSC::CallData callData;
+ return (JSC::asObject(value)->getCallData(callData) != JSC::CallTypeNone);
+}
+
+static JSC::JSValue JSC_HOST_CALL functionConnect(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
+static JSC::JSValue JSC_HOST_CALL functionDisconnect(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
+
+JSC::JSValue JSC_HOST_CALL functionDisconnect(JSC::ExecState *exec, JSC::JSObject * /*callee*/, JSC::JSValue thisObject, const JSC::ArgList &args)
+{
+#ifndef QT_NO_QOBJECT
+ if (args.size() == 0) {
+ return JSC::throwError(exec, JSC::GeneralError, "Function.prototype.disconnect: no arguments given");
+ }
+
+ if (!JSC::asObject(thisObject)->inherits(&QScript::QtFunction::info)) {
+ return JSC::throwError(exec, JSC::TypeError, "Function.prototype.disconnect: this object is not a signal");
+ }
+
+ QScript::QtFunction *qtSignal = static_cast<QScript::QtFunction*>(JSC::asObject(thisObject));
+
+ const QMetaObject *meta = qtSignal->metaObject();
+ if (!meta) {
+ return JSC::throwError(exec, JSC::TypeError, "Function.prototype.discconnect: cannot disconnect from deleted QObject");
+ }
+
+ QMetaMethod sig = meta->method(qtSignal->initialIndex());
+ if (sig.methodType() != QMetaMethod::Signal) {
+ QString message = QString::fromLatin1("Function.prototype.disconnect: %0::%1 is not a signal")
+ .arg(QLatin1String(qtSignal->metaObject()->className()))
+ .arg(QLatin1String(sig.signature()));
+ return JSC::throwError(exec, JSC::TypeError, message);
+ }
+
+ QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
+
+ JSC::JSValue receiver;
+ JSC::JSValue slot;
+ JSC::JSValue arg0 = args.at(0);
+ if (args.size() < 2) {
+ slot = arg0;
+ } else {
+ receiver = arg0;
+ JSC::JSValue arg1 = args.at(1);
+ if (isFunction(arg1))
+ slot = arg1;
+ else {
+ QScript::SaveFrameHelper saveFrame(engine, exec);
+ JSC::UString propertyName = QScriptEnginePrivate::toString(exec, arg1);
+ slot = QScriptEnginePrivate::property(exec, arg0, propertyName, QScriptValue::ResolvePrototype);
+ }
+ }
+
+ if (!isFunction(slot)) {
+ return JSC::throwError(exec, JSC::TypeError, "Function.prototype.disconnect: target is not a function");
+ }
+
+ bool ok = engine->scriptDisconnect(thisObject, receiver, slot);
+ if (!ok) {
+ QString message = QString::fromLatin1("Function.prototype.disconnect: failed to disconnect from %0::%1")
+ .arg(QLatin1String(qtSignal->metaObject()->className()))
+ .arg(QLatin1String(sig.signature()));
+ return JSC::throwError(exec, JSC::GeneralError, message);
+ }
+ return JSC::jsUndefined();
+#else
+ Q_UNUSED(eng);
+ return context->throwError(QScriptContext::TypeError,
+ QLatin1String("Function.prototype.disconnect"));
+#endif // QT_NO_QOBJECT
+}
+
+JSC::JSValue JSC_HOST_CALL functionConnect(JSC::ExecState *exec, JSC::JSObject * /*callee*/, JSC::JSValue thisObject, const JSC::ArgList &args)
+{
+#ifndef QT_NO_QOBJECT
+ if (args.size() == 0) {
+ return JSC::throwError(exec, JSC::GeneralError,"Function.prototype.connect: no arguments given");
+ }
+
+ if (!JSC::asObject(thisObject)->inherits(&QScript::QtFunction::info)) {
+ return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: this object is not a signal");
+ }
+
+ QScript::QtFunction *qtSignal = static_cast<QScript::QtFunction*>(JSC::asObject(thisObject));
+
+ const QMetaObject *meta = qtSignal->metaObject();
+ if (!meta) {
+ return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: cannot connect to deleted QObject");
+ }
+
+ QMetaMethod sig = meta->method(qtSignal->initialIndex());
+ if (sig.methodType() != QMetaMethod::Signal) {
+ QString message = QString::fromLatin1("Function.prototype.connect: %0::%1 is not a signal")
+ .arg(QLatin1String(qtSignal->metaObject()->className()))
+ .arg(QLatin1String(sig.signature()));
+ return JSC::throwError(exec, JSC::TypeError, message);
+ }
+
+ {
+ QList<int> overloads = qtSignal->overloadedIndexes();
+ if (!overloads.isEmpty()) {
+ overloads.append(qtSignal->initialIndex());
+ QByteArray signature = sig.signature();
+ QString message = QString::fromLatin1("Function.prototype.connect: ambiguous connect to %0::%1(); candidates are\n")
+ .arg(QLatin1String(qtSignal->metaObject()->className()))
+ .arg(QLatin1String(signature.left(signature.indexOf('('))));
+ for (int i = 0; i < overloads.size(); ++i) {
+ QMetaMethod mtd = meta->method(overloads.at(i));
+ message.append(QString::fromLatin1(" %0\n").arg(QString::fromLatin1(mtd.signature())));
+ }
+ message.append(QString::fromLatin1("Use e.g. object['%0'].connect() to connect to a particular overload")
+ .arg(QLatin1String(signature)));
+ return JSC::throwError(exec, JSC::GeneralError, message);
+ }
+ }
+
+ QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
+
+ JSC::JSValue receiver;
+ JSC::JSValue slot;
+ JSC::JSValue arg0 = args.at(0);
+ if (args.size() < 2) {
+ slot = arg0;
+ } else {
+ receiver = arg0;
+ JSC::JSValue arg1 = args.at(1);
+ if (isFunction(arg1))
+ slot = arg1;
+ else {
+ QScript::SaveFrameHelper saveFrame(engine, exec);
+ JSC::UString propertyName = QScriptEnginePrivate::toString(exec, arg1);
+ slot = QScriptEnginePrivate::property(exec, arg0, propertyName, QScriptValue::ResolvePrototype);
+ }
+ }
+
+ if (!isFunction(slot)) {
+ return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: target is not a function");
+ }
+
+ bool ok = engine->scriptConnect(thisObject, receiver, slot, Qt::AutoConnection);
+ if (!ok) {
+ QString message = QString::fromLatin1("Function.prototype.connect: failed to connect to %0::%1")
+ .arg(QLatin1String(qtSignal->metaObject()->className()))
+ .arg(QLatin1String(sig.signature()));
+ return JSC::throwError(exec, JSC::GeneralError, message);
+ }
+ return JSC::jsUndefined();
+#else
+ Q_UNUSED(eng);
+ Q_UNUSED(classInfo);
+ return context->throwError(QScriptContext::TypeError,
+ QLatin1String("Function.prototype.connect"));
+#endif // QT_NO_QOBJECT
+}
+
+static JSC::JSValue JSC_HOST_CALL functionPrint(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
+static JSC::JSValue JSC_HOST_CALL functionGC(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
+static JSC::JSValue JSC_HOST_CALL functionVersion(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
+
+JSC::JSValue JSC_HOST_CALL functionPrint(JSC::ExecState* exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList& args)
+{
+ QString result;
+ for (unsigned i = 0; i < args.size(); ++i) {
+ if (i != 0)
+ result.append(QLatin1Char(' '));
+ QString s(args.at(i).toString(exec));
+ if (exec->hadException())
+ break;
+ result.append(s);
+ }
+ if (exec->hadException())
+ return exec->exception();
+ qDebug("%s", qPrintable(result));
+ return JSC::jsUndefined();
+}
+
+JSC::JSValue JSC_HOST_CALL functionGC(JSC::ExecState* exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&)
+{
+ QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
+ engine->collectGarbage();
+ return JSC::jsUndefined();
+}
+
+JSC::JSValue JSC_HOST_CALL functionVersion(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&)
+{
+ return JSC::JSValue(exec, 1);
+}
+
+#ifndef QT_NO_TRANSLATION
+
+static JSC::JSValue JSC_HOST_CALL functionQsTranslate(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
+static JSC::JSValue JSC_HOST_CALL functionQsTranslateNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
+static JSC::JSValue JSC_HOST_CALL functionQsTr(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
+static JSC::JSValue JSC_HOST_CALL functionQsTrNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
+static JSC::JSValue JSC_HOST_CALL functionQsTrId(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
+static JSC::JSValue JSC_HOST_CALL functionQsTrIdNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
+
+JSC::JSValue JSC_HOST_CALL functionQsTranslate(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
+{
+ if (args.size() < 2)
+ return JSC::throwError(exec, JSC::GeneralError, "qsTranslate() requires at least two arguments");
+ if (!args.at(0).isString())
+ return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): first argument (context) must be a string");
+ if (!args.at(1).isString())
+ return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): second argument (text) must be a string");
+ if ((args.size() > 2) && !args.at(2).isString())
+ return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): third argument (comment) must be a string");
+ if ((args.size() > 3) && !args.at(3).isString())
+ return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): fourth argument (encoding) must be a string");
+ if ((args.size() > 4) && !args.at(4).isNumber())
+ return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): fifth argument (n) must be a number");
+#ifndef QT_NO_QOBJECT
+ JSC::UString context = args.at(0).toString(exec);
+#endif
+ JSC::UString text = args.at(1).toString(exec);
+#ifndef QT_NO_QOBJECT
+ JSC::UString comment;
+ if (args.size() > 2)
+ comment = args.at(2).toString(exec);
+ QCoreApplication::Encoding encoding = QCoreApplication::UnicodeUTF8;
+ if (args.size() > 3) {
+ JSC::UString encStr = args.at(3).toString(exec);
+ if (encStr == "CodecForTr")
+ encoding = QCoreApplication::CodecForTr;
+ else if (encStr == "UnicodeUTF8")
+ encoding = QCoreApplication::UnicodeUTF8;
+ else
+ return JSC::throwError(exec, JSC::GeneralError, QString::fromLatin1("qsTranslate(): invalid encoding '%0'").arg(encStr));
+ }
+ int n = -1;
+ if (args.size() > 4)
+ n = args.at(4).toInt32(exec);
+#endif
+ JSC::UString result;
+#ifndef QT_NO_QOBJECT
+ result = QCoreApplication::translate(context.UTF8String().c_str(),
+ text.UTF8String().c_str(),
+ comment.UTF8String().c_str(),
+ encoding, n);
+#else
+ result = text;
+#endif
+ return JSC::jsString(exec, result);
+}
+
+JSC::JSValue JSC_HOST_CALL functionQsTranslateNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
+{
+ if (args.size() < 2)
+ return JSC::jsUndefined();
+ return args.at(1);
+}
+
+JSC::JSValue JSC_HOST_CALL functionQsTr(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
+{
+ if (args.size() < 1)
+ return JSC::throwError(exec, JSC::GeneralError, "qsTr() requires at least one argument");
+ if (!args.at(0).isString())
+ return JSC::throwError(exec, JSC::GeneralError, "qsTr(): first argument (text) must be a string");
+ if ((args.size() > 1) && !args.at(1).isString())
+ return JSC::throwError(exec, JSC::GeneralError, "qsTr(): second argument (comment) must be a string");
+ if ((args.size() > 2) && !args.at(2).isNumber())
+ return JSC::throwError(exec, JSC::GeneralError, "qsTr(): third argument (n) must be a number");
+#ifndef QT_NO_QOBJECT
+ QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
+ JSC::UString context;
+ // The first non-empty source URL in the call stack determines the translation context.
+ {
+ JSC::ExecState *frame = exec->callerFrame()->removeHostCallFrameFlag();
+ while (frame) {
+ if (frame->codeBlock() && QScriptEnginePrivate::hasValidCodeBlockRegister(frame)
+ && frame->codeBlock()->source()
+ && !frame->codeBlock()->source()->url().isEmpty()) {
+ context = engine->translationContextFromUrl(frame->codeBlock()->source()->url());
+ break;
+ }
+ frame = frame->callerFrame()->removeHostCallFrameFlag();
+ }
+ }
+#endif
+ JSC::UString text = args.at(0).toString(exec);
+#ifndef QT_NO_QOBJECT
+ JSC::UString comment;
+ if (args.size() > 1)
+ comment = args.at(1).toString(exec);
+ int n = -1;
+ if (args.size() > 2)
+ n = args.at(2).toInt32(exec);
+#endif
+ JSC::UString result;
+#ifndef QT_NO_QOBJECT
+ result = QCoreApplication::translate(context.UTF8String().c_str(),
+ text.UTF8String().c_str(),
+ comment.UTF8String().c_str(),
+ QCoreApplication::UnicodeUTF8, n);
+#else
+ result = text;
+#endif
+ return JSC::jsString(exec, result);
+}
+
+JSC::JSValue JSC_HOST_CALL functionQsTrNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
+{
+ if (args.size() < 1)
+ return JSC::jsUndefined();
+ return args.at(0);
+}
+
+JSC::JSValue JSC_HOST_CALL functionQsTrId(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
+{
+ if (args.size() < 1)
+ return JSC::throwError(exec, JSC::GeneralError, "qsTrId() requires at least one argument");
+ if (!args.at(0).isString())
+ return JSC::throwError(exec, JSC::TypeError, "qsTrId(): first argument (id) must be a string");
+ if ((args.size() > 1) && !args.at(1).isNumber())
+ return JSC::throwError(exec, JSC::TypeError, "qsTrId(): second argument (n) must be a number");
+ JSC::UString id = args.at(0).toString(exec);
+ int n = -1;
+ if (args.size() > 1)
+ n = args.at(1).toInt32(exec);
+ return JSC::jsString(exec, qtTrId(id.UTF8String().c_str(), n));
+}
+
+JSC::JSValue JSC_HOST_CALL functionQsTrIdNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
+{
+ if (args.size() < 1)
+ return JSC::jsUndefined();
+ return args.at(0);
+}
+#endif // QT_NO_TRANSLATION
+
+static JSC::JSValue JSC_HOST_CALL stringProtoFuncArg(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
+
+JSC::JSValue JSC_HOST_CALL stringProtoFuncArg(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisObject, const JSC::ArgList &args)
+{
+ QString value(thisObject.toString(exec));
+ JSC::JSValue arg = (args.size() != 0) ? args.at(0) : JSC::jsUndefined();
+ QString result;
+ if (arg.isString())
+ result = value.arg(arg.toString(exec));
+ else if (arg.isNumber())
+ result = value.arg(arg.toNumber(exec));
+ return JSC::jsString(exec, result);
+}
+
+
+#if !defined(QT_NO_QOBJECT) && !defined(QT_NO_LIBRARY)
+static QScriptValue __setupPackage__(QScriptContext *ctx, QScriptEngine *eng)
+{
+ QString path = ctx->argument(0).toString();
+ QStringList components = path.split(QLatin1Char('.'));
+ QScriptValue o = eng->globalObject();
+ for (int i = 0; i < components.count(); ++i) {
+ QString name = components.at(i);
+ QScriptValue oo = o.property(name);
+ if (!oo.isValid()) {
+ oo = eng->newObject();
+ o.setProperty(name, oo);
+ }
+ o = oo;
+ }
+ return o;
+}
+#endif
+
+} // namespace QScript
+
+QScriptEnginePrivate::QScriptEnginePrivate()
+ : originalGlobalObjectProxy(0), currentFrame(0),
+ qobjectPrototype(0), qmetaobjectPrototype(0), variantPrototype(0),
+ activeAgent(0), agentLineNumber(-1),
+ registeredScriptValues(0), freeScriptValues(0), freeScriptValuesCount(0),
+ registeredScriptStrings(0), processEventsInterval(-1), inEval(false)
+{
+ qMetaTypeId<QScriptValue>();
+ qMetaTypeId<QList<int> >();
+#ifndef QT_NO_QOBJECT
+ qMetaTypeId<QObjectList>();
+#endif
+
+ if (!QCoreApplication::instance()) {
+ qFatal("QScriptEngine: Must construct a Q(Core)Application before a QScriptEngine");
+ return;
+ }
+ JSC::initializeThreading();
+ JSC::IdentifierTable *oldTable = JSC::currentIdentifierTable();
+ globalData = JSC::JSGlobalData::create().releaseRef();
+ globalData->clientData = new QScript::GlobalClientData(this);
+ JSC::JSGlobalObject *globalObject = new (globalData)QScript::GlobalObject();
+
+ JSC::ExecState* exec = globalObject->globalExec();
+
+ scriptObjectStructure = QScriptObject::createStructure(globalObject->objectPrototype());
+ staticScopeObjectStructure = QScriptStaticScopeObject::createStructure(JSC::jsNull());
+
+ qobjectPrototype = new (exec) QScript::QObjectPrototype(exec, QScript::QObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
+ qobjectWrapperObjectStructure = QScriptObject::createStructure(qobjectPrototype);
+
+ qmetaobjectPrototype = new (exec) QScript::QMetaObjectPrototype(exec, QScript::QMetaObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
+ qmetaobjectWrapperObjectStructure = QScript::QMetaObjectWrapperObject::createStructure(qmetaobjectPrototype);
+
+ variantPrototype = new (exec) QScript::QVariantPrototype(exec, QScript::QVariantPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
+ variantWrapperObjectStructure = QScriptObject::createStructure(variantPrototype);
+
+ globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "print"), QScript::functionPrint));
+ globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 0, JSC::Identifier(exec, "gc"), QScript::functionGC));
+ globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 0, JSC::Identifier(exec, "version"), QScript::functionVersion));
+
+ // ### rather than extending Function.prototype, consider creating a QtSignal.prototype
+ globalObject->functionPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "disconnect"), QScript::functionDisconnect));
+ globalObject->functionPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "connect"), QScript::functionConnect));
+
+ JSC::TimeoutChecker* originalChecker = globalData->timeoutChecker;
+ globalData->timeoutChecker = new QScript::TimeoutCheckerProxy(*originalChecker);
+ delete originalChecker;
+
+ currentFrame = exec;
+
+ cachedTranslationUrl = JSC::UString();
+ cachedTranslationContext = JSC::UString();
+ JSC::setCurrentIdentifierTable(oldTable);
+}
+
+QScriptEnginePrivate::~QScriptEnginePrivate()
+{
+ QScript::APIShim shim(this);
+
+ //disconnect all loadedScripts and generate all jsc::debugger::scriptUnload events
+ QHash<intptr_t,QScript::UStringSourceProviderWithFeedback*>::const_iterator it;
+ for (it = loadedScripts.constBegin(); it != loadedScripts.constEnd(); ++it)
+ it.value()->disconnectFromEngine();
+
+ while (!ownedAgents.isEmpty())
+ delete ownedAgents.takeFirst();
+
+ detachAllRegisteredScriptPrograms();
+ detachAllRegisteredScriptValues();
+ detachAllRegisteredScriptStrings();
+ qDeleteAll(m_qobjectData);
+ qDeleteAll(m_typeInfos);
+ globalData->heap.destroy();
+ globalData->deref();
+ while (freeScriptValues) {
+ QScriptValuePrivate *p = freeScriptValues;
+ freeScriptValues = p->next;
+ qFree(p);
+ }
+}
+
+QVariant QScriptEnginePrivate::jscValueToVariant(JSC::ExecState *exec, JSC::JSValue value, int targetType)
+{
+ QVariant v(targetType, (void *)0);
+ if (convertValue(exec, value, targetType, v.data()))
+ return v;
+ if (uint(targetType) == QVariant::LastType)
+ return toVariant(exec, value);
+ if (isVariant(value)) {
+ v = variantValue(value);
+ if (v.canConvert(QVariant::Type(targetType))) {
+ v.convert(QVariant::Type(targetType));
+ return v;
+ }
+ QByteArray typeName = v.typeName();
+ if (typeName.endsWith('*')
+ && (QMetaType::type(typeName.left(typeName.size()-1)) == targetType)) {
+ return QVariant(targetType, *reinterpret_cast<void* *>(v.data()));
+ }
+ }
+ return QVariant();
+}
+
+JSC::JSValue QScriptEnginePrivate::arrayFromStringList(JSC::ExecState *exec, const QStringList &lst)
+{
+ JSC::JSValue arr = newArray(exec, lst.size());
+ for (int i = 0; i < lst.size(); ++i)
+ setProperty(exec, arr, i, JSC::jsString(exec, lst.at(i)));
+ return arr;
+}
+
+QStringList QScriptEnginePrivate::stringListFromArray(JSC::ExecState *exec, JSC::JSValue arr)
+{
+ QStringList lst;
+ uint len = toUInt32(exec, property(exec, arr, exec->propertyNames().length));
+ for (uint i = 0; i < len; ++i)
+ lst.append(toString(exec, property(exec, arr, i)));
+ return lst;
+}
+
+JSC::JSValue QScriptEnginePrivate::arrayFromVariantList(JSC::ExecState *exec, const QVariantList &lst)
+{
+ JSC::JSValue arr = newArray(exec, lst.size());
+ for (int i = 0; i < lst.size(); ++i)
+ setProperty(exec, arr, i, jscValueFromVariant(exec, lst.at(i)));
+ return arr;
+}
+
+QVariantList QScriptEnginePrivate::variantListFromArray(JSC::ExecState *exec, JSC::JSArray *arr)
+{
+ QScriptEnginePrivate *eng = QScript::scriptEngineFromExec(exec);
+ if (eng->visitedConversionObjects.contains(arr))
+ return QVariantList(); // Avoid recursion.
+ eng->visitedConversionObjects.insert(arr);
+ QVariantList lst;
+ uint len = toUInt32(exec, property(exec, arr, exec->propertyNames().length));
+ for (uint i = 0; i < len; ++i)
+ lst.append(toVariant(exec, property(exec, arr, i)));
+ eng->visitedConversionObjects.remove(arr);
+ return lst;
+}
+
+JSC::JSValue QScriptEnginePrivate::objectFromVariantMap(JSC::ExecState *exec, const QVariantMap &vmap)
+{
+ JSC::JSValue obj = JSC::constructEmptyObject(exec);
+ QVariantMap::const_iterator it;
+ for (it = vmap.constBegin(); it != vmap.constEnd(); ++it)
+ setProperty(exec, obj, it.key(), jscValueFromVariant(exec, it.value()));
+ return obj;
+}
+
+QVariantMap QScriptEnginePrivate::variantMapFromObject(JSC::ExecState *exec, JSC::JSObject *obj)
+{
+ QScriptEnginePrivate *eng = QScript::scriptEngineFromExec(exec);
+ if (eng->visitedConversionObjects.contains(obj))
+ return QVariantMap(); // Avoid recursion.
+ eng->visitedConversionObjects.insert(obj);
+ JSC::PropertyNameArray propertyNames(exec);
+ obj->getOwnPropertyNames(exec, propertyNames, JSC::IncludeDontEnumProperties);
+ QVariantMap vmap;
+ JSC::PropertyNameArray::const_iterator it = propertyNames.begin();
+ for( ; it != propertyNames.end(); ++it)
+ vmap.insert(it->ustring(), toVariant(exec, property(exec, obj, *it)));
+ eng->visitedConversionObjects.remove(obj);
+ return vmap;
+}
+
+JSC::JSValue QScriptEnginePrivate::defaultPrototype(int metaTypeId) const
+{
+ QScriptTypeInfo *info = m_typeInfos.value(metaTypeId);
+ if (!info)
+ return JSC::JSValue();
+ return info->prototype;
+}
+
+void QScriptEnginePrivate::setDefaultPrototype(int metaTypeId, JSC::JSValue prototype)
+{
+ QScriptTypeInfo *info = m_typeInfos.value(metaTypeId);
+ if (!info) {
+ info = new QScriptTypeInfo();
+ m_typeInfos.insert(metaTypeId, info);
+ }
+ info->prototype = prototype;
+}
+
+JSC::JSGlobalObject *QScriptEnginePrivate::originalGlobalObject() const
+{
+ return globalData->head;
+}
+
+JSC::JSObject *QScriptEnginePrivate::customGlobalObject() const
+{
+ QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
+ return glob->customGlobalObject;
+}
+
+JSC::JSObject *QScriptEnginePrivate::getOriginalGlobalObjectProxy()
+{
+ if (!originalGlobalObjectProxy) {
+ JSC::ExecState* exec = currentFrame;
+ originalGlobalObjectProxy = new (exec)QScript::OriginalGlobalObjectProxy(scriptObjectStructure, originalGlobalObject());
+ }
+ return originalGlobalObjectProxy;
+}
+
+JSC::JSObject *QScriptEnginePrivate::globalObject() const
+{
+ QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
+ if (glob->customGlobalObject)
+ return glob->customGlobalObject;
+ return glob;
+}
+
+void QScriptEnginePrivate::setGlobalObject(JSC::JSObject *object)
+{
+ if (object == globalObject())
+ return;
+ QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
+ if (object == originalGlobalObjectProxy) {
+ glob->customGlobalObject = 0;
+ // Sync the internal prototype, since JSObject::prototype() is not virtual.
+ glob->setPrototype(originalGlobalObjectProxy->prototype());
+ } else {
+ Q_ASSERT(object != originalGlobalObject());
+ glob->customGlobalObject = object;
+ // Sync the internal prototype, since JSObject::prototype() is not virtual.
+ glob->setPrototype(object->prototype());
+ }
+}
+
+/*!
+ \internal
+
+ If the given \a value is the original global object, returns the custom
+ global object or a proxy to the original global object; otherwise returns \a
+ value.
+*/
+JSC::JSValue QScriptEnginePrivate::toUsableValue(JSC::JSValue value)
+{
+ if (!value || !value.isObject() || !JSC::asObject(value)->isGlobalObject())
+ return value;
+ Q_ASSERT(JSC::asObject(value) == originalGlobalObject());
+ if (customGlobalObject())
+ return customGlobalObject();
+ if (!originalGlobalObjectProxy)
+ originalGlobalObjectProxy = new (currentFrame)QScript::OriginalGlobalObjectProxy(scriptObjectStructure, originalGlobalObject());
+ return originalGlobalObjectProxy;
+}
+/*!
+ \internal
+ Return the 'this' value for a given context
+*/
+JSC::JSValue QScriptEnginePrivate::thisForContext(JSC::ExecState *frame)
+{
+ if (frame->codeBlock() != 0) {
+ return frame->thisValue();
+ } else if(frame == frame->lexicalGlobalObject()->globalExec()) {
+ return frame->globalThisValue();
+ } else {
+ JSC::Register *thisRegister = thisRegisterForFrame(frame);
+ return thisRegister->jsValue();
+ }
+}
+
+JSC::Register* QScriptEnginePrivate::thisRegisterForFrame(JSC::ExecState *frame)
+{
+ Q_ASSERT(frame->codeBlock() == 0); // only for native calls
+ return frame->registers() - JSC::RegisterFile::CallFrameHeaderSize - frame->argumentCount();
+}
+
+/*! \internal
+ For native context, we use the ReturnValueRegister entry in the stackframe header to store flags.
+ We can do that because this header is not used as the native function return their value thought C++
+
+ when setting flags, NativeContext should always be set
+
+ contextFlags returns 0 for non native context
+ */
+uint QScriptEnginePrivate::contextFlags(JSC::ExecState *exec)
+{
+ if (exec->codeBlock())
+ return 0; //js function doesn't have flags
+
+ return exec->returnValueRegister();
+}
+
+void QScriptEnginePrivate::setContextFlags(JSC::ExecState *exec, uint flags)
+{
+ Q_ASSERT(!exec->codeBlock());
+ exec->registers()[JSC::RegisterFile::ReturnValueRegister] = JSC::Register::withInt(flags);
+}
+
+
+void QScriptEnginePrivate::mark(JSC::MarkStack& markStack)
+{
+ Q_Q(QScriptEngine);
+
+ if (originalGlobalObject()) {
+ markStack.append(originalGlobalObject());
+ markStack.append(globalObject());
+ if (originalGlobalObjectProxy)
+ markStack.append(originalGlobalObjectProxy);
+ }
+
+ if (qobjectPrototype)
+ markStack.append(qobjectPrototype);
+ if (qmetaobjectPrototype)
+ markStack.append(qmetaobjectPrototype);
+ if (variantPrototype)
+ markStack.append(variantPrototype);
+
+ {
+ QScriptValuePrivate *it;
+ for (it = registeredScriptValues; it != 0; it = it->next) {
+ if (it->isJSC())
+ markStack.append(it->jscValue);
+ }
+ }
+
+ {
+ QHash<int, QScriptTypeInfo*>::const_iterator it;
+ for (it = m_typeInfos.constBegin(); it != m_typeInfos.constEnd(); ++it) {
+ if ((*it)->prototype)
+ markStack.append((*it)->prototype);
+ }
+ }
+
+ if (q) {
+ QScriptContext *context = q->currentContext();
+
+ while (context) {
+ JSC::ScopeChainNode *node = frameForContext(context)->scopeChain();
+ JSC::ScopeChainIterator it(node);
+ for (it = node->begin(); it != node->end(); ++it) {
+ JSC::JSObject *object = *it;
+ if (object)
+ markStack.append(object);
+ }
+
+ context = context->parentContext();
+ }
+ }
+
+#ifndef QT_NO_QOBJECT
+ markStack.drain(); // make sure everything is marked before marking qobject data
+ {
+ QHash<QObject*, QScript::QObjectData*>::const_iterator it;
+ for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) {
+ QScript::QObjectData *qdata = it.value();
+ qdata->mark(markStack);
+ }
+ }
+#endif
+}
+
+bool QScriptEnginePrivate::isCollecting() const
+{
+ return globalData->heap.isBusy();
+}
+
+void QScriptEnginePrivate::collectGarbage()
+{
+ QScript::APIShim shim(this);
+ globalData->heap.collectAllGarbage();
+}
+
+void QScriptEnginePrivate::reportAdditionalMemoryCost(int size)
+{
+ if (size > 0)
+ globalData->heap.reportExtraMemoryCost(size);
+}
+
+QScript::TimeoutCheckerProxy *QScriptEnginePrivate::timeoutChecker() const
+{
+ return static_cast<QScript::TimeoutCheckerProxy*>(globalData->timeoutChecker);
+}
+
+void QScriptEnginePrivate::agentDeleted(QScriptEngineAgent *agent)
+{
+ ownedAgents.removeOne(agent);
+ if (activeAgent == agent) {
+ QScriptEngineAgentPrivate::get(agent)->detach();
+ activeAgent = 0;
+ }
+}
+
+JSC::JSValue QScriptEnginePrivate::evaluateHelper(JSC::ExecState *exec, intptr_t sourceId,
+ JSC::EvalExecutable *executable,
+ bool &compile)
+{
+ Q_Q(QScriptEngine);
+ QBoolBlocker inEvalBlocker(inEval, true);
+ q->currentContext()->activationObject(); //force the creation of a context for native function;
+
+ JSC::Debugger* debugger = originalGlobalObject()->debugger();
+ if (debugger)
+ debugger->evaluateStart(sourceId);
+
+ q->clearExceptions();
+ JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject);
+
+ if (compile) {
+ JSC::JSObject* error = executable->compile(exec, exec->scopeChain());
+ if (error) {
+ compile = false;
+ exec->setException(error);
+
+ if (debugger) {
+ debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, error), sourceId, false);
+ debugger->evaluateStop(error, sourceId);
+ }
+
+ return error;
+ }
+ }
+
+ JSC::JSValue thisValue = thisForContext(exec);
+ JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull())
+ ? exec->dynamicGlobalObject() : thisValue.toObject(exec);
+ JSC::JSValue exceptionValue;
+ timeoutChecker()->setShouldAbort(false);
+ if (processEventsInterval > 0)
+ timeoutChecker()->reset();
+
+ JSC::JSValue result = exec->interpreter()->execute(executable, exec, thisObject, exec->scopeChain(), &exceptionValue);
+
+ if (timeoutChecker()->shouldAbort()) {
+ if (abortResult.isError())
+ exec->setException(scriptValueToJSCValue(abortResult));
+
+ if (debugger)
+ debugger->evaluateStop(scriptValueToJSCValue(abortResult), sourceId);
+
+ return scriptValueToJSCValue(abortResult);
+ }
+
+ if (exceptionValue) {
+ exec->setException(exceptionValue);
+
+ if (debugger)
+ debugger->evaluateStop(exceptionValue, sourceId);
+
+ return exceptionValue;
+ }
+
+ if (debugger)
+ debugger->evaluateStop(result, sourceId);
+
+ Q_ASSERT(!exec->hadException());
+ return result;
+}
+
+#ifndef QT_NO_QOBJECT
+
+JSC::JSValue QScriptEnginePrivate::newQObject(
+ QObject *object, QScriptEngine::ValueOwnership ownership,
+ const QScriptEngine::QObjectWrapOptions &options)
+{
+ if (!object)
+ return JSC::jsNull();
+ JSC::ExecState* exec = currentFrame;
+ QScript::QObjectData *data = qobjectData(object);
+ bool preferExisting = (options & QScriptEngine::PreferExistingWrapperObject) != 0;
+ QScriptEngine::QObjectWrapOptions opt = options & ~QScriptEngine::PreferExistingWrapperObject;
+ QScriptObject *result = 0;
+ if (preferExisting) {
+ result = data->findWrapper(ownership, opt);
+ if (result)
+ return result;
+ }
+ result = new (exec) QScriptObject(qobjectWrapperObjectStructure);
+ if (preferExisting)
+ data->registerWrapper(result, ownership, opt);
+ result->setDelegate(new QScript::QObjectDelegate(object, ownership, options));
+ /*if (setDefaultPrototype)*/ {
+ const QMetaObject *meta = object->metaObject();
+ while (meta) {
+ QByteArray typeString = meta->className();
+ typeString.append('*');
+ int typeId = QMetaType::type(typeString);
+ if (typeId != 0) {
+ JSC::JSValue proto = defaultPrototype(typeId);
+ if (proto) {
+ result->setPrototype(proto);
+ break;
+ }
+ }
+ meta = meta->superClass();
+ }
+ }
+ return result;
+}
+
+JSC::JSValue QScriptEnginePrivate::newQMetaObject(
+ const QMetaObject *metaObject, JSC::JSValue ctor)
+{
+ if (!metaObject)
+ return JSC::jsNull();
+ JSC::ExecState* exec = currentFrame;
+ QScript::QMetaObjectWrapperObject *result = new (exec) QScript::QMetaObjectWrapperObject(exec, metaObject, ctor, qmetaobjectWrapperObjectStructure);
+ return result;
+}
+
+bool QScriptEnginePrivate::convertToNativeQObject(JSC::ExecState *exec, JSC::JSValue value,
+ const QByteArray &targetType,
+ void **result)
+{
+ if (!targetType.endsWith('*'))
+ return false;
+ if (QObject *qobject = toQObject(exec, 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;
+}
+
+QScript::QObjectData *QScriptEnginePrivate::qobjectData(QObject *object)
+{
+ QHash<QObject*, QScript::QObjectData*>::const_iterator it;
+ it = m_qobjectData.constFind(object);
+ if (it != m_qobjectData.constEnd())
+ return it.value();
+
+ QScript::QObjectData *data = new QScript::QObjectData(this);
+ m_qobjectData.insert(object, data);
+ QObject::connect(object, SIGNAL(destroyed(QObject*)),
+ q_func(), SLOT(_q_objectDestroyed(QObject*)));
+ return data;
+}
+
+void QScriptEnginePrivate::_q_objectDestroyed(QObject *object)
+{
+ QHash<QObject*, QScript::QObjectData*>::iterator it;
+ it = m_qobjectData.find(object);
+ Q_ASSERT(it != m_qobjectData.end());
+ QScript::QObjectData *data = it.value();
+ m_qobjectData.erase(it);
+ delete data;
+}
+
+void QScriptEnginePrivate::disposeQObject(QObject *object)
+{
+ // TODO
+/* if (isCollecting()) {
+ // wait until we're done with GC before deleting it
+ int index = m_qobjectsToBeDeleted.indexOf(object);
+ if (index == -1)
+ m_qobjectsToBeDeleted.append(object);
+ } else*/ {
+ delete object;
+ }
+}
+
+void QScriptEnginePrivate::emitSignalHandlerException()
+{
+ Q_Q(QScriptEngine);
+ emit q->signalHandlerException(q->uncaughtException());
+}
+
+bool QScriptEnginePrivate::scriptConnect(QObject *sender, const char *signal,
+ JSC::JSValue receiver, JSC::JSValue function,
+ Qt::ConnectionType type)
+{
+ Q_ASSERT(sender);
+ Q_ASSERT(signal);
+ const QMetaObject *meta = sender->metaObject();
+ int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
+ if (index == -1)
+ return false;
+ return scriptConnect(sender, index, receiver, function, /*wrapper=*/JSC::JSValue(), type);
+}
+
+bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, const char *signal,
+ JSC::JSValue receiver, JSC::JSValue function)
+{
+ Q_ASSERT(sender);
+ Q_ASSERT(signal);
+ const QMetaObject *meta = sender->metaObject();
+ int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
+ if (index == -1)
+ return false;
+ return scriptDisconnect(sender, index, receiver, function);
+}
+
+bool QScriptEnginePrivate::scriptConnect(QObject *sender, int signalIndex,
+ JSC::JSValue receiver, JSC::JSValue function,
+ JSC::JSValue senderWrapper,
+ Qt::ConnectionType type)
+{
+ QScript::QObjectData *data = qobjectData(sender);
+ return data->addSignalHandler(sender, signalIndex, receiver, function, senderWrapper, type);
+}
+
+bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, int signalIndex,
+ JSC::JSValue receiver, JSC::JSValue function)
+{
+ QScript::QObjectData *data = qobjectData(sender);
+ if (!data)
+ return false;
+ return data->removeSignalHandler(sender, signalIndex, receiver, function);
+}
+
+bool QScriptEnginePrivate::scriptConnect(JSC::JSValue signal, JSC::JSValue receiver,
+ JSC::JSValue function, Qt::ConnectionType type)
+{
+ QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(JSC::asObject(signal));
+ int index = fun->mostGeneralMethod();
+ return scriptConnect(fun->qobject(), index, receiver, function, fun->wrapperObject(), type);
+}
+
+bool QScriptEnginePrivate::scriptDisconnect(JSC::JSValue signal, JSC::JSValue receiver,
+ JSC::JSValue function)
+{
+ QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(JSC::asObject(signal));
+ int index = fun->mostGeneralMethod();
+ return scriptDisconnect(fun->qobject(), index, receiver, function);
+}
+
+#endif
+
+void QScriptEnginePrivate::detachAllRegisteredScriptPrograms()
+{
+ QSet<QScriptProgramPrivate*>::const_iterator it;
+ for (it = registeredScriptPrograms.constBegin(); it != registeredScriptPrograms.constEnd(); ++it)
+ (*it)->detachFromEngine();
+ registeredScriptPrograms.clear();
+}
+
+void QScriptEnginePrivate::detachAllRegisteredScriptValues()
+{
+ QScriptValuePrivate *it;
+ QScriptValuePrivate *next;
+ for (it = registeredScriptValues; it != 0; it = next) {
+ it->detachFromEngine();
+ next = it->next;
+ it->prev = 0;
+ it->next = 0;
+ }
+ registeredScriptValues = 0;
+}
+
+void QScriptEnginePrivate::detachAllRegisteredScriptStrings()
+{
+ QScriptStringPrivate *it;
+ QScriptStringPrivate *next;
+ for (it = registeredScriptStrings; it != 0; it = next) {
+ it->detachFromEngine();
+ next = it->next;
+ it->prev = 0;
+ it->next = 0;
+ }
+ registeredScriptStrings = 0;
+}
+
+#ifndef QT_NO_REGEXP
+
+Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
+
+JSC::JSValue QScriptEnginePrivate::newRegExp(JSC::ExecState *exec, const QRegExp &regexp)
+{
+ JSC::JSValue buf[2];
+ JSC::ArgList args(buf, sizeof(buf));
+
+ //convert the pattern to a ECMAScript pattern
+ QString pattern = qt_regexp_toCanonical(regexp.pattern(), regexp.patternSyntax());
+ if (regexp.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;
+ }
+
+ JSC::UString jscPattern = pattern;
+ QString flags;
+ if (regexp.caseSensitivity() == Qt::CaseInsensitive)
+ flags.append(QLatin1Char('i'));
+ JSC::UString jscFlags = flags;
+ buf[0] = JSC::jsString(exec, jscPattern);
+ buf[1] = JSC::jsString(exec, jscFlags);
+ return JSC::constructRegExp(exec, args);
+}
+
+#endif
+
+JSC::JSValue QScriptEnginePrivate::newRegExp(JSC::ExecState *exec, const QString &pattern, const QString &flags)
+{
+ JSC::JSValue buf[2];
+ JSC::ArgList args(buf, sizeof(buf));
+ JSC::UString jscPattern = pattern;
+ QString strippedFlags;
+ if (flags.contains(QLatin1Char('i')))
+ strippedFlags += QLatin1Char('i');
+ if (flags.contains(QLatin1Char('m')))
+ strippedFlags += QLatin1Char('m');
+ if (flags.contains(QLatin1Char('g')))
+ strippedFlags += QLatin1Char('g');
+ JSC::UString jscFlags = strippedFlags;
+ buf[0] = JSC::jsString(exec, jscPattern);
+ buf[1] = JSC::jsString(exec, jscFlags);
+ return JSC::constructRegExp(exec, args);
+}
+
+JSC::JSValue QScriptEnginePrivate::newVariant(const QVariant &value)
+{
+ QScriptObject *obj = new (currentFrame) QScriptObject(variantWrapperObjectStructure);
+ obj->setDelegate(new QScript::QVariantDelegate(value));
+ JSC::JSValue proto = defaultPrototype(value.userType());
+ if (proto)
+ obj->setPrototype(proto);
+ return obj;
+}
+
+JSC::JSValue QScriptEnginePrivate::newVariant(JSC::JSValue objectValue,
+ const QVariant &value)
+{
+ if (!isObject(objectValue))
+ return newVariant(value);
+ JSC::JSObject *jscObject = JSC::asObject(objectValue);
+ if (!jscObject->inherits(&QScriptObject::info)) {
+ qWarning("QScriptEngine::newVariant(): changing class of non-QScriptObject not supported");
+ return JSC::JSValue();
+ }
+ QScriptObject *jscScriptObject = static_cast<QScriptObject*>(jscObject);
+ if (!isVariant(objectValue)) {
+ jscScriptObject->setDelegate(new QScript::QVariantDelegate(value));
+ } else {
+ setVariantValue(objectValue, value);
+ }
+ return objectValue;
+}
+
+#ifndef QT_NO_REGEXP
+
+QRegExp QScriptEnginePrivate::toRegExp(JSC::ExecState *exec, JSC::JSValue value)
+{
+ if (!isRegExp(value))
+ return QRegExp();
+ QString pattern = toString(exec, property(exec, value, "source", QScriptValue::ResolvePrototype));
+ Qt::CaseSensitivity kase = Qt::CaseSensitive;
+ if (toBool(exec, property(exec, value, "ignoreCase", QScriptValue::ResolvePrototype)))
+ kase = Qt::CaseInsensitive;
+ return QRegExp(pattern, kase, QRegExp::RegExp2);
+}
+
+#endif
+
+QVariant QScriptEnginePrivate::toVariant(JSC::ExecState *exec, JSC::JSValue value)
+{
+ if (!value) {
+ return QVariant();
+ } else if (isObject(value)) {
+ if (isVariant(value))
+ return variantValue(value);
+#ifndef QT_NO_QOBJECT
+ else if (isQObject(value))
+ return QVariant::fromValue(toQObject(exec, value));
+#endif
+ else if (isDate(value))
+ return QVariant(toDateTime(exec, value));
+#ifndef QT_NO_REGEXP
+ else if (isRegExp(value))
+ return QVariant(toRegExp(exec, value));
+#endif
+ else if (isArray(value))
+ return variantListFromArray(exec, JSC::asArray(value));
+ else if (QScriptDeclarativeClass *dc = declarativeClass(value))
+ return dc->toVariant(declarativeObject(value));
+ return variantMapFromObject(exec, JSC::asObject(value));
+ } else if (value.isInt32()) {
+ return QVariant(toInt32(exec, value));
+ } else if (value.isDouble()) {
+ return QVariant(toNumber(exec, value));
+ } else if (value.isString()) {
+ return QVariant(toString(exec, value));
+ } else if (value.isBoolean()) {
+ return QVariant(toBool(exec, value));
+ }
+ return QVariant();
+}
+
+JSC::JSValue QScriptEnginePrivate::propertyHelper(JSC::ExecState *exec, JSC::JSValue value, const JSC::Identifier &id, int resolveMode)
+{
+ JSC::JSValue result;
+ if (!(resolveMode & QScriptValue::ResolvePrototype)) {
+ // Look in the object's own properties
+ JSC::JSObject *object = JSC::asObject(value);
+ JSC::PropertySlot slot(object);
+ if (object->getOwnPropertySlot(exec, id, slot))
+ result = slot.getValue(exec, id);
+ }
+ if (!result && (resolveMode & QScriptValue::ResolveScope)) {
+ // ### check if it's a function object and look in the scope chain
+ JSC::JSValue scope = property(exec, value, "__qt_scope__", QScriptValue::ResolveLocal);
+ if (isObject(scope))
+ result = property(exec, scope, id, resolveMode);
+ }
+ return result;
+}
+
+JSC::JSValue QScriptEnginePrivate::propertyHelper(JSC::ExecState *exec, JSC::JSValue value, quint32 index, int resolveMode)
+{
+ JSC::JSValue result;
+ if (!(resolveMode & QScriptValue::ResolvePrototype)) {
+ // Look in the object's own properties
+ JSC::JSObject *object = JSC::asObject(value);
+ JSC::PropertySlot slot(object);
+ if (object->getOwnPropertySlot(exec, index, slot))
+ result = slot.getValue(exec, index);
+ }
+ return result;
+}
+
+void QScriptEnginePrivate::setProperty(JSC::ExecState *exec, JSC::JSValue objectValue, const JSC::Identifier &id,
+ JSC::JSValue value, const QScriptValue::PropertyFlags &flags)
+{
+ JSC::JSObject *thisObject = JSC::asObject(objectValue);
+ JSC::JSValue setter = thisObject->lookupSetter(exec, id);
+ JSC::JSValue getter = thisObject->lookupGetter(exec, id);
+ if ((flags & QScriptValue::PropertyGetter) || (flags & QScriptValue::PropertySetter)) {
+ if (!value) {
+ // deleting getter/setter
+ if ((flags & QScriptValue::PropertyGetter) && (flags & QScriptValue::PropertySetter)) {
+ // deleting both: just delete the property
+ thisObject->deleteProperty(exec, id);
+ } else if (flags & QScriptValue::PropertyGetter) {
+ // preserve setter, if there is one
+ thisObject->deleteProperty(exec, id);
+ if (setter && setter.isObject())
+ thisObject->defineSetter(exec, id, JSC::asObject(setter));
+ } else { // flags & QScriptValue::PropertySetter
+ // preserve getter, if there is one
+ thisObject->deleteProperty(exec, id);
+ if (getter && getter.isObject())
+ thisObject->defineGetter(exec, id, JSC::asObject(getter));
+ }
+ } else {
+ if (value.isObject()) { // ### should check if it has callData()
+ // defining getter/setter
+ if (id == exec->propertyNames().underscoreProto) {
+ qWarning("QScriptValue::setProperty() failed: "
+ "cannot set getter or setter of native property `__proto__'");
+ } else {
+ if (flags & QScriptValue::PropertyGetter)
+ thisObject->defineGetter(exec, id, JSC::asObject(value));
+ if (flags & QScriptValue::PropertySetter)
+ thisObject->defineSetter(exec, id, JSC::asObject(value));
+ }
+ } else {
+ qWarning("QScriptValue::setProperty(): getter/setter must be a function");
+ }
+ }
+ } else {
+ // setting the value
+ if (getter && getter.isObject() && !(setter && setter.isObject())) {
+ qWarning("QScriptValue::setProperty() failed: "
+ "property '%s' has a getter but no setter",
+ qPrintable(QString(id.ustring())));
+ return;
+ }
+ if (!value) {
+ // ### check if it's a getter/setter property
+ thisObject->deleteProperty(exec, id);
+ } else if (flags != QScriptValue::KeepExistingFlags) {
+ if (thisObject->hasOwnProperty(exec, id))
+ thisObject->deleteProperty(exec, id); // ### hmmm - can't we just update the attributes?
+ thisObject->putWithAttributes(exec, id, value, propertyFlagsToJSCAttributes(flags));
+ } else {
+ JSC::PutPropertySlot slot;
+ thisObject->put(exec, id, value, slot);
+ }
+ }
+}
+
+void QScriptEnginePrivate::setProperty(JSC::ExecState *exec, JSC::JSValue objectValue, quint32 index,
+ JSC::JSValue value, const QScriptValue::PropertyFlags &flags)
+{
+ if (!value) {
+ JSC::asObject(objectValue)->deleteProperty(exec, index);
+ } else {
+ if ((flags & QScriptValue::PropertyGetter) || (flags & QScriptValue::PropertySetter)) {
+ // fall back to string-based setProperty(), since there is no
+ // JSC::JSObject::defineGetter(unsigned)
+ setProperty(exec, objectValue, JSC::Identifier::from(exec, index), value, flags);
+ } else {
+ if (flags != QScriptValue::KeepExistingFlags) {
+ // if (JSC::asObject(d->jscValue)->hasOwnProperty(exec, arrayIndex))
+ // JSC::asObject(d->jscValue)->deleteProperty(exec, arrayIndex);
+ unsigned attribs = 0;
+ if (flags & QScriptValue::ReadOnly)
+ attribs |= JSC::ReadOnly;
+ if (flags & QScriptValue::SkipInEnumeration)
+ attribs |= JSC::DontEnum;
+ if (flags & QScriptValue::Undeletable)
+ attribs |= JSC::DontDelete;
+ attribs |= flags & QScriptValue::UserRange;
+ JSC::asObject(objectValue)->putWithAttributes(exec, index, value, attribs);
+ } else {
+ JSC::asObject(objectValue)->put(exec, index, value);
+ }
+ }
+ }
+}
+
+QScriptValue::PropertyFlags QScriptEnginePrivate::propertyFlags(JSC::ExecState *exec, JSC::JSValue value, const JSC::Identifier &id,
+ const QScriptValue::ResolveFlags &mode)
+{
+ JSC::JSObject *object = JSC::asObject(value);
+ unsigned attribs = 0;
+ JSC::PropertyDescriptor descriptor;
+ if (object->getOwnPropertyDescriptor(exec, id, descriptor))
+ attribs = descriptor.attributes();
+ else {
+ if ((mode & QScriptValue::ResolvePrototype) && object->prototype() && object->prototype().isObject()) {
+ JSC::JSValue proto = object->prototype();
+ return propertyFlags(exec, proto, id, mode);
+ }
+ return 0;
+ }
+ QScriptValue::PropertyFlags result = 0;
+ if (attribs & JSC::ReadOnly)
+ result |= QScriptValue::ReadOnly;
+ if (attribs & JSC::DontEnum)
+ result |= QScriptValue::SkipInEnumeration;
+ if (attribs & JSC::DontDelete)
+ result |= QScriptValue::Undeletable;
+ //We cannot rely on attribs JSC::Setter/Getter because they are not necesserly set by JSC (bug?)
+ if (attribs & JSC::Getter || !object->lookupGetter(exec, id).isUndefinedOrNull())
+ result |= QScriptValue::PropertyGetter;
+ if (attribs & JSC::Setter || !object->lookupSetter(exec, id).isUndefinedOrNull())
+ result |= QScriptValue::PropertySetter;
+#ifndef QT_NO_QOBJECT
+ if (attribs & QScript::QObjectMemberAttribute)
+ result |= QScriptValue::QObjectMember;
+#endif
+ result |= QScriptValue::PropertyFlag(attribs & QScriptValue::UserRange);
+ return result;
+}
+
+QScriptString QScriptEnginePrivate::toStringHandle(const JSC::Identifier &name)
+{
+ QScriptString result;
+ QScriptStringPrivate *p = new QScriptStringPrivate(this, name, QScriptStringPrivate::HeapAllocated);
+ QScriptStringPrivate::init(result, p);
+ registerScriptString(p);
+ return result;
+}
+
+#ifdef QT_NO_QOBJECT
+
+QScriptEngine::QScriptEngine()
+ : d_ptr(new QScriptEnginePrivate)
+{
+ d_ptr->q_ptr = this;
+}
+
+/*! \internal
+*/
+QScriptEngine::QScriptEngine(QScriptEnginePrivate &dd)
+ : d_ptr(&dd)
+{
+ d_ptr->q_ptr = this;
+}
+#else
+
+/*!
+ Constructs a QScriptEngine object.
+
+ The globalObject() is initialized to have properties as described in
+ \l{ECMA-262}, Section 15.1.
+*/
+QScriptEngine::QScriptEngine()
+ : QObject(*new QScriptEnginePrivate, 0)
+{
+}
+
+/*!
+ Constructs a QScriptEngine object with the given \a parent.
+
+ The globalObject() is initialized to have properties as described in
+ \l{ECMA-262}, Section 15.1.
+*/
+
+QScriptEngine::QScriptEngine(QObject *parent)
+ : QObject(*new QScriptEnginePrivate, parent)
+{
+}
+
+/*! \internal
+*/
+QScriptEngine::QScriptEngine(QScriptEnginePrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+}
+#endif
+
+/*!
+ Destroys this QScriptEngine.
+*/
+QScriptEngine::~QScriptEngine()
+{
+#ifdef QT_NO_QOBJECT
+ delete d_ptr;
+ d_ptr = 0;
+#endif
+}
+
+/*!
+ Returns this engine's Global Object.
+
+ By default, the Global Object contains the built-in objects that are
+ part of \l{ECMA-262}, such as Math, Date and String. Additionally,
+ you can set properties of the Global Object to make your own
+ extensions available to all script code. Non-local variables in
+ script code will be created as properties of the Global Object, as
+ well as local variables in global code.
+*/
+QScriptValue QScriptEngine::globalObject() const
+{
+ Q_D(const QScriptEngine);
+ QScript::APIShim shim(const_cast<QScriptEnginePrivate*>(d));
+ JSC::JSObject *result = d->globalObject();
+ return const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(result);
+}
+
+/*!
+ \since 4.5
+
+ Sets this engine's Global Object to be the given \a object.
+ If \a object is not a valid script object, this function does
+ nothing.
+
+ When setting a custom global object, you may want to use
+ QScriptValueIterator to copy the properties of the standard Global
+ Object; alternatively, you can set the internal prototype of your
+ custom object to be the original Global Object.
+*/
+void QScriptEngine::setGlobalObject(const QScriptValue &object)
+{
+ Q_D(QScriptEngine);
+ if (!object.isObject())
+ return;
+ QScript::APIShim shim(d);
+ JSC::JSObject *jscObject = JSC::asObject(d->scriptValueToJSCValue(object));
+ d->setGlobalObject(jscObject);
+}
+
+/*!
+ Returns a QScriptValue of the primitive type Null.
+
+ \sa undefinedValue()
+*/
+QScriptValue QScriptEngine::nullValue()
+{
+ Q_D(QScriptEngine);
+ return d->scriptValueFromJSCValue(JSC::jsNull());
+}
+
+/*!
+ Returns a QScriptValue of the primitive type Undefined.
+
+ \sa nullValue()
+*/
+QScriptValue QScriptEngine::undefinedValue()
+{
+ Q_D(QScriptEngine);
+ return d->scriptValueFromJSCValue(JSC::jsUndefined());
+}
+
+/*!
+ Creates a constructor function from \a fun, with the given \a length.
+ The \c{prototype} property of the resulting function is set to be the
+ given \a prototype. The \c{constructor} property of \a prototype is
+ set to be the resulting function.
+
+ When a function is called as a constructor (e.g. \c{new Foo()}), the
+ `this' object associated with the function call is the new object
+ that the function is expected to initialize; the prototype of this
+ default constructed object will be the function's public
+ \c{prototype} property. If you always want the function to behave as
+ a constructor (e.g. \c{Foo()} should also create a new object), or
+ if you need to create your own object rather than using the default
+ `this' object, you should make sure that the prototype of your
+ object is set correctly; either by setting it manually, or, when
+ wrapping a custom type, by having registered the defaultPrototype()
+ of that type. Example:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 9
+
+ To wrap a custom type and provide a constructor for it, you'd typically
+ do something like this:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 10
+*/
+QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun,
+ const QScriptValue &prototype,
+ int length)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ JSC::ExecState* exec = d->currentFrame;
+ JSC::JSValue function = new (exec)QScript::FunctionWrapper(exec, length, JSC::Identifier(exec, ""), fun);
+ QScriptValue result = d->scriptValueFromJSCValue(function);
+ result.setProperty(QLatin1String("prototype"), prototype,
+ QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ const_cast<QScriptValue&>(prototype)
+ .setProperty(QLatin1String("constructor"), result, QScriptValue::SkipInEnumeration);
+ return result;
+}
+
+#ifndef QT_NO_REGEXP
+
+/*!
+ Creates a QtScript object of class RegExp with the given
+ \a regexp.
+
+ \sa QScriptValue::toRegExp()
+*/
+QScriptValue QScriptEngine::newRegExp(const QRegExp &regexp)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ return d->scriptValueFromJSCValue(d->newRegExp(d->currentFrame, regexp));
+}
+
+#endif // QT_NO_REGEXP
+
+/*!
+ 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(), QScriptValue::toVariant(), reportAdditionalMemoryCost()
+*/
+QScriptValue QScriptEngine::newVariant(const QVariant &value)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ return d->scriptValueFromJSCValue(d->newVariant(value));
+}
+
+/*!
+ \since 4.4
+ \overload
+
+ Initializes the given Qt Script \a object to hold the given variant
+ \a value, and returns the \a object.
+
+ This function enables you to "promote" a plain Qt Script object
+ (created by the newObject() function) to a variant, or to replace
+ the variant contained inside an object previously created by the
+ newVariant() function.
+
+ The prototype() of the \a object will remain unchanged.
+
+ If \a object is not an object, this function behaves like the normal
+ newVariant(), i.e. it creates a new script object and returns it.
+
+ This function is useful when you want to provide a script
+ constructor for a C++ type. If your constructor is invoked in a
+ \c{new} expression (QScriptContext::isCalledAsConstructor() returns
+ true), you can pass QScriptContext::thisObject() (the default
+ constructed script object) to this function to initialize the new
+ object.
+
+ \sa reportAdditionalMemoryCost()
+*/
+QScriptValue QScriptEngine::newVariant(const QScriptValue &object,
+ const QVariant &value)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ JSC::JSValue jsObject = d->scriptValueToJSCValue(object);
+ return d->scriptValueFromJSCValue(d->newVariant(jsObject, value));
+}
+
+#ifndef QT_NO_QOBJECT
+/*!
+ 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 QScriptValue. 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 QScriptValue::toQObject(), reportAdditionalMemoryCost()
+*/
+QScriptValue QScriptEngine::newQObject(QObject *object, ValueOwnership ownership,
+ const QObjectWrapOptions &options)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ JSC::JSValue jscQObject = d->newQObject(object, ownership, options);
+ return d->scriptValueFromJSCValue(jscQObject);
+}
+
+/*!
+ \since 4.4
+ \overload
+
+ Initializes the given \a scriptObject to hold the given \a qtObject,
+ and returns the \a scriptObject.
+
+ This function enables you to "promote" a plain Qt Script object
+ (created by the newObject() function) to a QObject proxy, or to
+ replace the QObject contained inside an object previously created by
+ the newQObject() function.
+
+ The prototype() of the \a scriptObject will remain unchanged.
+
+ If \a scriptObject is not an object, this function behaves like the
+ normal newQObject(), i.e. it creates a new script object and returns
+ it.
+
+ This function is useful when you want to provide a script
+ constructor for a QObject-based class. If your constructor is
+ invoked in a \c{new} expression
+ (QScriptContext::isCalledAsConstructor() returns true), you can pass
+ QScriptContext::thisObject() (the default constructed script object)
+ to this function to initialize the new object.
+
+ \sa reportAdditionalMemoryCost()
+*/
+QScriptValue QScriptEngine::newQObject(const QScriptValue &scriptObject,
+ QObject *qtObject,
+ ValueOwnership ownership,
+ const QObjectWrapOptions &options)
+{
+ Q_D(QScriptEngine);
+ if (!scriptObject.isObject())
+ return newQObject(qtObject, ownership, options);
+ QScript::APIShim shim(d);
+ JSC::JSObject *jscObject = JSC::asObject(QScriptValuePrivate::get(scriptObject)->jscValue);
+ if (!jscObject->inherits(&QScriptObject::info)) {
+ qWarning("QScriptEngine::newQObject(): changing class of non-QScriptObject not supported");
+ return QScriptValue();
+ }
+ QScriptObject *jscScriptObject = static_cast<QScriptObject*>(jscObject);
+ if (!scriptObject.isQObject()) {
+ jscScriptObject->setDelegate(new QScript::QObjectDelegate(qtObject, ownership, options));
+ } else {
+ QScript::QObjectDelegate *delegate = static_cast<QScript::QObjectDelegate*>(jscScriptObject->delegate());
+ delegate->setValue(qtObject);
+ delegate->setOwnership(ownership);
+ delegate->setOptions(options);
+ }
+ return scriptObject;
+}
+
+#endif // QT_NO_QOBJECT
+
+/*!
+ Creates a QtScript object of class Object.
+
+ The prototype of the created object will be the Object
+ prototype object.
+
+ \sa newArray(), QScriptValue::setProperty()
+*/
+QScriptValue QScriptEngine::newObject()
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ return d->scriptValueFromJSCValue(d->newObject());
+}
+
+/*!
+ \since 4.4
+ \overload
+
+ Creates a QtScript Object of the given class, \a scriptClass.
+
+ The prototype of the created object will be the Object
+ prototype object.
+
+ \a data, if specified, is set as the internal data of the
+ new object (using QScriptValue::setData()).
+
+ \sa QScriptValue::scriptClass(), reportAdditionalMemoryCost()
+*/
+QScriptValue QScriptEngine::newObject(QScriptClass *scriptClass,
+ const QScriptValue &data)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ JSC::ExecState* exec = d->currentFrame;
+ QScriptObject *result = new (exec) QScriptObject(d->scriptObjectStructure);
+ result->setDelegate(new QScript::ClassObjectDelegate(scriptClass));
+ QScriptValue scriptObject = d->scriptValueFromJSCValue(result);
+ scriptObject.setData(data);
+ QScriptValue proto = scriptClass->prototype();
+ if (proto.isValid())
+ scriptObject.setPrototype(proto);
+ return scriptObject;
+}
+
+/*!
+ \internal
+*/
+QScriptValue QScriptEngine::newActivationObject()
+{
+ qWarning("QScriptEngine::newActivationObject() not implemented");
+ // ### JSActivation or JSVariableObject?
+ return QScriptValue();
+}
+
+/*!
+ Creates a QScriptValue that wraps a native (C++) function. \a fun
+ must be a C++ function with signature QScriptEngine::FunctionSignature. \a
+ length is the number of arguments that \a fun expects; this becomes
+ the \c{length} property of the created QScriptValue.
+
+ Note that \a length only gives an indication of the number of
+ arguments that the function expects; an actual invocation of a
+ function can include any number of arguments. You can check the
+ \l{QScriptContext::argumentCount()}{argumentCount()} of the
+ QScriptContext associated with the invocation to determine the
+ actual number of arguments passed.
+
+ A \c{prototype} property is automatically created for the resulting
+ function object, to provide for the possibility that the function
+ will be used as a constructor.
+
+ By combining newFunction() and the property flags
+ QScriptValue::PropertyGetter and QScriptValue::PropertySetter, you
+ can create script object properties that behave like normal
+ properties in script code, but are in fact accessed through
+ functions (analogous to how properties work in \l{Qt's Property
+ System}). Example:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 11
+
+ When the property \c{foo} of the script object is subsequently
+ accessed in script code, \c{getSetFoo()} will be invoked to handle
+ the access. In this particular case, we chose to store the "real"
+ value of \c{foo} as a property of the accessor function itself; you
+ are of course free to do whatever you like in this function.
+
+ In the above example, a single native function was used to handle
+ both reads and writes to the property; the argument count is used to
+ determine if we are handling a read or write. You can also use two
+ separate functions; just specify the relevant flag
+ (QScriptValue::PropertyGetter or QScriptValue::PropertySetter) when
+ setting the property, e.g.:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 12
+
+ \sa QScriptValue::call()
+*/
+QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun, int length)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ JSC::ExecState* exec = d->currentFrame;
+ JSC::JSValue function = new (exec)QScript::FunctionWrapper(exec, length, JSC::Identifier(exec, ""), fun);
+ QScriptValue result = d->scriptValueFromJSCValue(function);
+ QScriptValue proto = newObject();
+ result.setProperty(QLatin1String("prototype"), proto,
+ QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ proto.setProperty(QLatin1String("constructor"), result, QScriptValue::SkipInEnumeration);
+ return result;
+}
+
+/*!
+ \internal
+ \since 4.4
+*/
+QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionWithArgSignature fun, void *arg)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ JSC::ExecState* exec = d->currentFrame;
+ JSC::JSValue function = new (exec)QScript::FunctionWithArgWrapper(exec, /*length=*/0, JSC::Identifier(exec, ""), fun, arg);
+ QScriptValue result = d->scriptValueFromJSCValue(function);
+ QScriptValue proto = newObject();
+ result.setProperty(QLatin1String("prototype"), proto,
+ QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ proto.setProperty(QLatin1String("constructor"), result, QScriptValue::SkipInEnumeration);
+ return result;
+}
+
+/*!
+ Creates a QtScript object of class Array with the given \a length.
+
+ \sa newObject()
+*/
+QScriptValue QScriptEngine::newArray(uint length)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ return d->scriptValueFromJSCValue(d->newArray(d->currentFrame, length));
+}
+
+/*!
+ 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).
+*/
+QScriptValue QScriptEngine::newRegExp(const QString &pattern, const QString &flags)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ return d->scriptValueFromJSCValue(d->newRegExp(d->currentFrame, pattern, flags));
+}
+
+/*!
+ Creates a QtScript object of class Date with the given
+ \a value (the number of milliseconds since 01 January 1970,
+ UTC).
+*/
+QScriptValue QScriptEngine::newDate(qsreal value)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ return d->scriptValueFromJSCValue(d->newDate(d->currentFrame, value));
+}
+
+/*!
+ Creates a QtScript object of class Date from the given \a value.
+
+ \sa QScriptValue::toDateTime()
+*/
+QScriptValue QScriptEngine::newDate(const QDateTime &value)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ return d->scriptValueFromJSCValue(d->newDate(d->currentFrame, value));
+}
+
+#ifndef QT_NO_QOBJECT
+/*!
+ Creates a QtScript object that represents a QObject class, using the
+ the given \a metaObject and constructor \a ctor.
+
+ Enums of \a metaObject (declared with Q_ENUMS) are available as
+ properties of the created QScriptValue. When the class is called as
+ a function, \a ctor will be called to create a new instance of the
+ class.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 27
+
+ \sa newQObject(), scriptValueFromQMetaObject()
+*/
+QScriptValue QScriptEngine::newQMetaObject(
+ const QMetaObject *metaObject, const QScriptValue &ctor)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ JSC::JSValue jscCtor = d->scriptValueToJSCValue(ctor);
+ JSC::JSValue jscQMetaObject = d->newQMetaObject(metaObject, jscCtor);
+ return d->scriptValueFromJSCValue(jscQMetaObject);
+}
+
+/*!
+ \fn QScriptValue QScriptEngine::scriptValueFromQMetaObject()
+
+ Creates a QScriptValue that represents the Qt class \c{T}.
+
+ This function is used in combination with one of the
+ Q_SCRIPT_DECLARE_QMETAOBJECT() macro. Example:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 13
+
+ \sa QScriptEngine::newQMetaObject()
+*/
+
+/*!
+ \fn QScriptValue qScriptValueFromQMetaObject(QScriptEngine *engine)
+ \since 4.3
+ \relates QScriptEngine
+ \obsolete
+
+ Uses \a engine to create a QScriptValue that represents the Qt class
+ \c{T}.
+
+ This function is equivalent to
+ QScriptEngine::scriptValueFromQMetaObject().
+
+ \note This function was provided as a workaround for MSVC 6
+ which did not support member template functions. It is advised
+ to use the other form in new code.
+
+ \sa QScriptEngine::newQMetaObject()
+*/
+#endif // QT_NO_QOBJECT
+
+/*!
+ \obsolete
+
+ Returns true if \a program can be evaluated; i.e. the code is
+ sufficient to determine whether it appears to be a syntactically
+ correct program, or contains a syntax error.
+
+ This function returns false if \a program is incomplete; i.e. the
+ input is syntactically correct up to the point where the input is
+ terminated.
+
+ Note that this function only does a static check of \a program;
+ e.g. it does not check whether references to variables are
+ valid, and so on.
+
+ A typical usage of canEvaluate() is to implement an interactive
+ interpreter for QtScript. The user is repeatedly queried for
+ individual lines of code; the lines are concatened internally, and
+ only when canEvaluate() returns true for the resulting program is it
+ passed to evaluate().
+
+ The following are some examples to illustrate the behavior of
+ canEvaluate(). (Note that all example inputs are assumed to have an
+ explicit newline as their last character, since otherwise the
+ QtScript parser would automatically insert a semi-colon character at
+ the end of the input, and this could cause canEvaluate() to produce
+ different results.)
+
+ Given the input
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 14
+ canEvaluate() will return true, since the program appears to be complete.
+
+ Given the input
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 15
+ canEvaluate() will return false, since the if-statement is not complete,
+ but is syntactically correct so far.
+
+ Given the input
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 16
+ canEvaluate() will return true, but evaluate() will throw a
+ SyntaxError given the same input.
+
+ Given the input
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 17
+ canEvaluate() will return true, even though the code is clearly not
+ syntactically valid QtScript code. evaluate() will throw a
+ SyntaxError when this code is evaluated.
+
+ Given the input
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 18
+ canEvaluate() will return true, but evaluate() will throw a
+ ReferenceError if \c{foo} is not defined in the script
+ environment.
+
+ \sa evaluate(), checkSyntax()
+*/
+bool QScriptEngine::canEvaluate(const QString &program) const
+{
+ return QScriptEnginePrivate::canEvaluate(program);
+}
+
+
+bool QScriptEnginePrivate::canEvaluate(const QString &program)
+{
+ QScript::SyntaxChecker checker;
+ QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
+ return (result.state != QScript::SyntaxChecker::Intermediate);
+}
+
+/*!
+ \since 4.5
+
+ Checks the syntax of the given \a program. Returns a
+ QScriptSyntaxCheckResult object that contains the result of the check.
+*/
+QScriptSyntaxCheckResult QScriptEngine::checkSyntax(const QString &program)
+{
+ return QScriptEnginePrivate::checkSyntax(program);
+}
+
+QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &program)
+{
+ QScript::SyntaxChecker checker;
+ QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
+ QScriptSyntaxCheckResultPrivate *p = new QScriptSyntaxCheckResultPrivate();
+ switch (result.state) {
+ case QScript::SyntaxChecker::Error:
+ p->state = QScriptSyntaxCheckResult::Error;
+ break;
+ case QScript::SyntaxChecker::Intermediate:
+ p->state = QScriptSyntaxCheckResult::Intermediate;
+ break;
+ case QScript::SyntaxChecker::Valid:
+ p->state = QScriptSyntaxCheckResult::Valid;
+ break;
+ }
+ p->errorLineNumber = result.errorLineNumber;
+ p->errorColumnNumber = result.errorColumnNumber;
+ p->errorMessage = result.errorMessage;
+ return QScriptSyntaxCheckResult(p);
+}
+
+
+
+/*!
+ 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.
+
+ \sa canEvaluate(), hasUncaughtException(), isEvaluating(), abortEvaluation()
+*/
+
+QScriptValue QScriptEngine::evaluate(const QString &program, const QString &fileName, int lineNumber)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ WTF::PassRefPtr<QScript::UStringSourceProviderWithFeedback> provider
+ = QScript::UStringSourceProviderWithFeedback::create(program, fileName, lineNumber, d);
+ intptr_t sourceId = provider->asID();
+ JSC::SourceCode source(provider, lineNumber); //after construction of SourceCode provider variable will be null.
+
+ JSC::ExecState* exec = d->currentFrame;
+ WTF::RefPtr<JSC::EvalExecutable> executable = JSC::EvalExecutable::create(exec, source);
+ bool compile = true;
+ return d->scriptValueFromJSCValue(d->evaluateHelper(exec, sourceId, executable.get(), compile));
+}
+
+/*!
+ \since 4.7
+
+ Evaluates the given \a program and returns the result of the
+ evaluation.
+*/
+QScriptValue QScriptEngine::evaluate(const QScriptProgram &program)
+{
+ Q_D(QScriptEngine);
+ QScriptProgramPrivate *program_d = QScriptProgramPrivate::get(program);
+ if (!program_d)
+ return QScriptValue();
+
+ QScript::APIShim shim(d);
+ JSC::ExecState* exec = d->currentFrame;
+ JSC::EvalExecutable *executable = program_d->executable(exec, d);
+ bool compile = !program_d->isCompiled;
+ JSC::JSValue result = d->evaluateHelper(exec, program_d->sourceId,
+ executable, compile);
+ if (compile)
+ program_d->isCompiled = true;
+ return d->scriptValueFromJSCValue(result);
+}
+
+/*!
+ Returns the current context.
+
+ The current context is typically accessed to retrieve the arguments
+ and `this' object in native functions; for convenience, it is
+ available as the first argument in QScriptEngine::FunctionSignature.
+*/
+QScriptContext *QScriptEngine::currentContext() const
+{
+ Q_D(const QScriptEngine);
+ return const_cast<QScriptEnginePrivate*>(d)->contextForFrame(d->currentFrame);
+}
+
+/*!
+ Enters a new execution context and returns the associated
+ QScriptContext object.
+
+ Once you are done with the context, you should call popContext() to
+ restore the old context.
+
+ By default, the `this' object of the new context is the Global Object.
+ The context's \l{QScriptContext::callee()}{callee}() will be invalid.
+
+ This function is useful when you want to evaluate script code
+ as if it were the body of a function. You can use the context's
+ \l{QScriptContext::activationObject()}{activationObject}() to initialize
+ local variables that will be available to scripts. Example:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 19
+
+ In the above example, the new variable "tmp" defined in the script
+ will be local to the context; in other words, the script doesn't
+ have any effect on the global environment.
+
+ Returns 0 in case of stack overflow
+
+ \sa popContext()
+*/
+QScriptContext *QScriptEngine::pushContext()
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+
+ JSC::CallFrame* newFrame = d->pushContext(d->currentFrame, d->currentFrame->globalData().dynamicGlobalObject,
+ JSC::ArgList(), /*callee = */0);
+
+ if (agent())
+ agent()->contextPush();
+
+ return d->contextForFrame(newFrame);
+}
+
+/*! \internal
+ push a context for a native function.
+ JSC native function doesn't have different stackframe or context. so we need to create one.
+
+ use popContext right after to go back to the previous context the context if no stack overflow has hapenned
+
+ exec is the current top frame.
+
+ return the new top frame. (might be the same as exec if a new stackframe was not needed) or 0 if stack overflow
+*/
+JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, JSC::JSValue _thisObject,
+ const JSC::ArgList& args, JSC::JSObject *callee, bool calledAsConstructor,
+ bool clearScopeChain)
+{
+ JSC::JSValue thisObject = _thisObject;
+ if (!callee) {
+ // callee can't be zero, as this can cause JSC to crash during GC
+ // marking phase if the context's Arguments object has been created.
+ // Fake it by using the global object. Note that this is also handled
+ // in QScriptContext::callee(), as that function should still return
+ // an invalid value.
+ callee = originalGlobalObject();
+ }
+ if (calledAsConstructor) {
+ //JSC doesn't create default created object for native functions. so we do it
+ JSC::JSValue prototype = callee->get(exec, exec->propertyNames().prototype);
+ JSC::Structure *structure = prototype.isObject() ? JSC::asObject(prototype)->inheritorID()
+ : originalGlobalObject()->emptyObjectStructure();
+ thisObject = new (exec) QScriptObject(structure);
+ }
+
+ int flags = NativeContext;
+ if (calledAsConstructor)
+ flags |= CalledAsConstructorContext;
+
+ //build a frame
+ JSC::CallFrame *newCallFrame = exec;
+ if (callee == 0 //called from public QScriptEngine::pushContext
+ || exec->returnPC() == 0 || (contextFlags(exec) & NativeContext) //called from native-native call
+ || (exec->codeBlock() && exec->callee() != callee)) { //the interpreter did not build a frame for us.
+ //We need to check if the Interpreter might have already created a frame for function called from JS.
+ JSC::Interpreter *interp = exec->interpreter();
+ JSC::Register *oldEnd = interp->registerFile().end();
+ int argc = args.size() + 1; //add "this"
+ JSC::Register *newEnd = oldEnd + argc + JSC::RegisterFile::CallFrameHeaderSize;
+ if (!interp->registerFile().grow(newEnd))
+ return 0; //### Stack overflow
+ newCallFrame = JSC::CallFrame::create(oldEnd);
+ newCallFrame[0] = thisObject;
+ int dst = 0;
+ JSC::ArgList::const_iterator it;
+ for (it = args.begin(); it != args.end(); ++it)
+ newCallFrame[++dst] = *it;
+ newCallFrame += argc + JSC::RegisterFile::CallFrameHeaderSize;
+
+ if (!clearScopeChain) {
+ newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee);
+ } else {
+ newCallFrame->init(0, /*vPC=*/0, globalExec()->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee);
+ }
+ } else {
+ setContextFlags(newCallFrame, flags);
+#if ENABLE(JIT)
+ exec->registers()[JSC::RegisterFile::Callee] = JSC::JSValue(callee); //JIT let the callee set the 'callee'
+#endif
+ if (calledAsConstructor) {
+ //update the new created this
+ JSC::Register* thisRegister = thisRegisterForFrame(newCallFrame);
+ *thisRegister = thisObject;
+ }
+ }
+ currentFrame = newCallFrame;
+ return newCallFrame;
+}
+
+
+/*!
+ Pops the current execution context and restores the previous one.
+ This function must be used in conjunction with pushContext().
+
+ \sa pushContext()
+*/
+void QScriptEngine::popContext()
+{
+ if (agent())
+ agent()->contextPop();
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ if (d->currentFrame->returnPC() != 0 || d->currentFrame->codeBlock() != 0
+ || !currentContext()->parentContext()) {
+ qWarning("QScriptEngine::popContext() doesn't match with pushContext()");
+ return;
+ }
+
+ d->popContext();
+}
+
+/*! \internal
+ counter part of QScriptEnginePrivate::pushContext
+ */
+void QScriptEnginePrivate::popContext()
+{
+ uint flags = contextFlags(currentFrame);
+ bool hasScope = flags & HasScopeContext;
+ if (flags & ShouldRestoreCallFrame) { //normal case
+ JSC::RegisterFile &registerFile = currentFrame->interpreter()->registerFile();
+ JSC::Register *const newEnd = currentFrame->registers() - JSC::RegisterFile::CallFrameHeaderSize - currentFrame->argumentCount();
+ if (hasScope)
+ currentFrame->scopeChain()->pop()->deref();
+ registerFile.shrink(newEnd);
+ } else if(hasScope) { //the stack frame was created by the Interpreter, we don't need to rewind it.
+ currentFrame->setScopeChain(currentFrame->scopeChain()->pop());
+ currentFrame->scopeChain()->deref();
+ }
+ currentFrame = currentFrame->callerFrame();
+}
+
+/*!
+ 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()
+*/
+bool QScriptEngine::hasUncaughtException() const
+{
+ Q_D(const QScriptEngine);
+ JSC::ExecState* exec = d->globalExec();
+ return exec->hadException() || d->currentException().isValid();
+}
+
+/*!
+ Returns the current uncaught exception, or an invalid QScriptValue
+ 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(),
+*/
+QScriptValue QScriptEngine::uncaughtException() const
+{
+ Q_D(const QScriptEngine);
+ QScriptValue result;
+ JSC::ExecState* exec = d->globalExec();
+ if (exec->hadException())
+ result = const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(exec->exception());
+ else
+ result = d->currentException();
+ return result;
+}
+
+/*!
+ Returns the line number where the last uncaught exception occurred.
+
+ Line numbers are 1-based, unless a different base was specified as
+ the second argument to evaluate().
+
+ \sa hasUncaughtException()
+*/
+int QScriptEngine::uncaughtExceptionLineNumber() const
+{
+ if (!hasUncaughtException())
+ return -1;
+ return uncaughtException().property(QLatin1String("lineNumber")).toInt32();
+}
+
+/*!
+ Returns a human-readable backtrace of the last uncaught exception.
+
+ It is in the form \c{<function-name>()@<file-name>:<line-number>}.
+
+ \sa uncaughtException()
+*/
+QStringList QScriptEngine::uncaughtExceptionBacktrace() const
+{
+ if (!hasUncaughtException())
+ return QStringList();
+// ### currently no way to get a full backtrace from JSC without installing a
+// debugger that reimplements exception() and store the backtrace there.
+ QScriptValue value = uncaughtException();
+ if (!value.isError())
+ return QStringList();
+ QStringList result;
+ result.append(QString::fromLatin1("<anonymous>()@%0:%1")
+ .arg(value.property(QLatin1String("fileName")).toString())
+ .arg(value.property(QLatin1String("lineNumber")).toInt32()));
+ return result;
+}
+
+/*!
+ \since 4.4
+
+ Clears any uncaught exceptions in this engine.
+
+ \sa hasUncaughtException()
+*/
+void QScriptEngine::clearExceptions()
+{
+ Q_D(QScriptEngine);
+ JSC::ExecState* exec = d->currentFrame;
+ exec->clearException();
+ d->clearCurrentException();
+}
+
+/*!
+ Returns the default prototype associated with the given \a metaTypeId,
+ or an invalid QScriptValue if no default prototype has been set.
+
+ \sa setDefaultPrototype()
+*/
+QScriptValue QScriptEngine::defaultPrototype(int metaTypeId) const
+{
+ Q_D(const QScriptEngine);
+ return const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(d->defaultPrototype(metaTypeId));
+}
+
+/*!
+ Sets the default prototype of the C++ type identified by the given
+ \a metaTypeId to \a prototype.
+
+ The default prototype provides a script interface for values of
+ type \a metaTypeId when a value of that type is accessed from script
+ code. Whenever the script engine (implicitly or explicitly) creates
+ a QScriptValue from a value of type \a metaTypeId, the default
+ prototype will be set as the QScriptValue's prototype.
+
+ The \a prototype object itself may be constructed using one of two
+ principal techniques; the simplest is to subclass QScriptable, which
+ enables you to define the scripting API of the type through QObject
+ properties and slots. Another possibility is to create a script
+ object by calling newObject(), and populate the object with the
+ desired properties (e.g. native functions wrapped with
+ newFunction()).
+
+ \sa defaultPrototype(), qScriptRegisterMetaType(), QScriptable, {Default Prototypes Example}
+*/
+void QScriptEngine::setDefaultPrototype(int metaTypeId, const QScriptValue &prototype)
+{
+ Q_D(QScriptEngine);
+ d->setDefaultPrototype(metaTypeId, d->scriptValueToJSCValue(prototype));
+}
+
+/*!
+ \typedef QScriptEngine::FunctionSignature
+ \relates QScriptEngine
+
+ The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *)}.
+
+ A function with such a signature can be passed to
+ QScriptEngine::newFunction() to wrap the function.
+*/
+
+/*!
+ \typedef QScriptEngine::FunctionWithArgSignature
+ \relates QScriptEngine
+
+ The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *, void *)}.
+
+ A function with such a signature can be passed to
+ QScriptEngine::newFunction() to wrap the function.
+*/
+
+/*!
+ \typedef QScriptEngine::MarshalFunction
+ \internal
+*/
+
+/*!
+ \typedef QScriptEngine::DemarshalFunction
+ \internal
+*/
+
+/*!
+ \internal
+*/
+QScriptValue QScriptEngine::create(int type, const void *ptr)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ return d->scriptValueFromJSCValue(d->create(d->currentFrame, type, ptr));
+}
+
+JSC::JSValue QScriptEnginePrivate::create(JSC::ExecState *exec, int type, const void *ptr)
+{
+ Q_ASSERT(ptr != 0);
+ JSC::JSValue result;
+ QScriptEnginePrivate *eng = exec ? QScript::scriptEngineFromExec(exec) : 0;
+ QScriptTypeInfo *info = eng ? eng->m_typeInfos.value(type) : 0;
+ if (info && info->marshal) {
+ result = eng->scriptValueToJSCValue(info->marshal(eng->q_func(), ptr));
+ } else {
+ // check if it's one of the types we know
+ switch (QMetaType::Type(type)) {
+ case QMetaType::Void:
+ return JSC::jsUndefined();
+ case QMetaType::Bool:
+ return JSC::jsBoolean(*reinterpret_cast<const bool*>(ptr));
+ case QMetaType::Int:
+ return JSC::jsNumber(exec, *reinterpret_cast<const int*>(ptr));
+ case QMetaType::UInt:
+ return JSC::jsNumber(exec, *reinterpret_cast<const uint*>(ptr));
+ case QMetaType::LongLong:
+ return JSC::jsNumber(exec, qsreal(*reinterpret_cast<const qlonglong*>(ptr)));
+ case QMetaType::ULongLong:
+ return JSC::jsNumber(exec, qsreal(*reinterpret_cast<const qulonglong*>(ptr)));
+ case QMetaType::Double:
+ return JSC::jsNumber(exec, qsreal(*reinterpret_cast<const double*>(ptr)));
+ case QMetaType::QString:
+ return JSC::jsString(exec, *reinterpret_cast<const QString*>(ptr));
+ case QMetaType::Float:
+ return JSC::jsNumber(exec, *reinterpret_cast<const float*>(ptr));
+ case QMetaType::Short:
+ return JSC::jsNumber(exec, *reinterpret_cast<const short*>(ptr));
+ case QMetaType::UShort:
+ return JSC::jsNumber(exec, *reinterpret_cast<const unsigned short*>(ptr));
+ case QMetaType::Char:
+ return JSC::jsNumber(exec, *reinterpret_cast<const char*>(ptr));
+ case QMetaType::UChar:
+ return JSC::jsNumber(exec, *reinterpret_cast<const unsigned char*>(ptr));
+ case QMetaType::QChar:
+ return JSC::jsNumber(exec, (*reinterpret_cast<const QChar*>(ptr)).unicode());
+ case QMetaType::QStringList:
+ result = arrayFromStringList(exec, *reinterpret_cast<const QStringList *>(ptr));
+ break;
+ case QMetaType::QVariantList:
+ result = arrayFromVariantList(exec, *reinterpret_cast<const QVariantList *>(ptr));
+ break;
+ case QMetaType::QVariantMap:
+ result = objectFromVariantMap(exec, *reinterpret_cast<const QVariantMap *>(ptr));
+ break;
+ case QMetaType::QDateTime:
+ result = newDate(exec, *reinterpret_cast<const QDateTime *>(ptr));
+ break;
+ case QMetaType::QDate:
+ result = newDate(exec, QDateTime(*reinterpret_cast<const QDate *>(ptr)));
+ break;
+#ifndef QT_NO_REGEXP
+ case QMetaType::QRegExp:
+ result = newRegExp(exec, *reinterpret_cast<const QRegExp *>(ptr));
+ break;
+#endif
+#ifndef QT_NO_QOBJECT
+ case QMetaType::QObjectStar:
+ case QMetaType::QWidgetStar:
+ result = eng->newQObject(*reinterpret_cast<QObject* const *>(ptr));
+ break;
+#endif
+ case QMetaType::QVariant:
+ result = eng->newVariant(*reinterpret_cast<const QVariant*>(ptr));
+ break;
+ default:
+ if (type == qMetaTypeId<QScriptValue>()) {
+ result = eng->scriptValueToJSCValue(*reinterpret_cast<const QScriptValue*>(ptr));
+ if (!result)
+ return JSC::jsUndefined();
+ }
+
+#ifndef QT_NO_QOBJECT
+ // lazy registration of some common list types
+ else if (type == qMetaTypeId<QObjectList>()) {
+ qScriptRegisterSequenceMetaType<QObjectList>(eng->q_func());
+ return create(exec, type, ptr);
+ }
+#endif
+ else if (type == qMetaTypeId<QList<int> >()) {
+ qScriptRegisterSequenceMetaType<QList<int> >(eng->q_func());
+ return create(exec, type, ptr);
+ }
+
+ else {
+ QByteArray typeName = QMetaType::typeName(type);
+ if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(ptr))
+ return JSC::jsNull();
+ else
+ result = eng->newVariant(QVariant(type, ptr));
+ }
+ }
+ }
+ if (result && result.isObject() && info && info->prototype
+ && JSC::JSValue::strictEqual(exec, JSC::asObject(result)->prototype(), eng->originalGlobalObject()->objectPrototype())) {
+ JSC::asObject(result)->setPrototype(info->prototype);
+ }
+ return result;
+}
+
+bool QScriptEnginePrivate::convertValue(JSC::ExecState *exec, JSC::JSValue value,
+ int type, void *ptr)
+{
+ QScriptEnginePrivate *eng = exec ? QScript::scriptEngineFromExec(exec) : 0;
+ if (eng) {
+ QScriptTypeInfo *info = eng->m_typeInfos.value(type);
+ if (info && info->demarshal) {
+ info->demarshal(eng->scriptValueFromJSCValue(value), ptr);
+ return true;
+ }
+ }
+
+ // check if it's one of the types we know
+ switch (QMetaType::Type(type)) {
+ case QMetaType::Bool:
+ *reinterpret_cast<bool*>(ptr) = toBool(exec, value);
+ return true;
+ case QMetaType::Int:
+ *reinterpret_cast<int*>(ptr) = toInt32(exec, value);
+ return true;
+ case QMetaType::UInt:
+ *reinterpret_cast<uint*>(ptr) = toUInt32(exec, value);
+ return true;
+ case QMetaType::LongLong:
+ *reinterpret_cast<qlonglong*>(ptr) = qlonglong(toInteger(exec, value));
+ return true;
+ case QMetaType::ULongLong:
+ *reinterpret_cast<qulonglong*>(ptr) = qulonglong(toInteger(exec, value));
+ return true;
+ case QMetaType::Double:
+ *reinterpret_cast<double*>(ptr) = toNumber(exec, value);
+ return true;
+ case QMetaType::QString:
+ if (value.isUndefined() || value.isNull())
+ *reinterpret_cast<QString*>(ptr) = QString();
+ else
+ *reinterpret_cast<QString*>(ptr) = toString(exec, value);
+ return true;
+ case QMetaType::Float:
+ *reinterpret_cast<float*>(ptr) = toNumber(exec, value);
+ return true;
+ case QMetaType::Short:
+ *reinterpret_cast<short*>(ptr) = short(toInt32(exec, value));
+ return true;
+ case QMetaType::UShort:
+ *reinterpret_cast<unsigned short*>(ptr) = QScript::ToUInt16(toNumber(exec, value));
+ return true;
+ case QMetaType::Char:
+ *reinterpret_cast<char*>(ptr) = char(toInt32(exec, value));
+ return true;
+ case QMetaType::UChar:
+ *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(toInt32(exec, value));
+ return true;
+ case QMetaType::QChar:
+ if (value.isString()) {
+ QString str = toString(exec, value);
+ *reinterpret_cast<QChar*>(ptr) = str.isEmpty() ? QChar() : str.at(0);
+ } else {
+ *reinterpret_cast<QChar*>(ptr) = QChar(QScript::ToUInt16(toNumber(exec, value)));
+ }
+ return true;
+ case QMetaType::QDateTime:
+ if (isDate(value)) {
+ *reinterpret_cast<QDateTime *>(ptr) = toDateTime(exec, value);
+ return true;
+ } break;
+ case QMetaType::QDate:
+ if (isDate(value)) {
+ *reinterpret_cast<QDate *>(ptr) = toDateTime(exec, value).date();
+ return true;
+ } break;
+#ifndef QT_NO_REGEXP
+ case QMetaType::QRegExp:
+ if (isRegExp(value)) {
+ *reinterpret_cast<QRegExp *>(ptr) = toRegExp(exec, value);
+ return true;
+ } break;
+#endif
+#ifndef QT_NO_QOBJECT
+ case QMetaType::QObjectStar:
+ if (isQObject(value) || value.isNull()) {
+ *reinterpret_cast<QObject* *>(ptr) = toQObject(exec, value);
+ return true;
+ } break;
+ case QMetaType::QWidgetStar:
+ if (isQObject(value) || value.isNull()) {
+ QObject *qo = toQObject(exec, value);
+ if (!qo || qo->isWidgetType()) {
+ *reinterpret_cast<QWidget* *>(ptr) = reinterpret_cast<QWidget*>(qo);
+ return true;
+ }
+ } break;
+#endif
+ case QMetaType::QStringList:
+ if (isArray(value)) {
+ *reinterpret_cast<QStringList *>(ptr) = stringListFromArray(exec, value);
+ return true;
+ } break;
+ case QMetaType::QVariantList:
+ if (isArray(value)) {
+ *reinterpret_cast<QVariantList *>(ptr) = variantListFromArray(exec, JSC::asArray(value));
+ return true;
+ } break;
+ case QMetaType::QVariantMap:
+ if (isObject(value)) {
+ *reinterpret_cast<QVariantMap *>(ptr) = variantMapFromObject(exec, JSC::asObject(value));
+ return true;
+ } break;
+ case QMetaType::QVariant:
+ *reinterpret_cast<QVariant*>(ptr) = toVariant(exec, value);
+ return true;
+ default:
+ ;
+ }
+
+ QByteArray name = QMetaType::typeName(type);
+#ifndef QT_NO_QOBJECT
+ if (convertToNativeQObject(exec, value, name, reinterpret_cast<void* *>(ptr)))
+ return true;
+#endif
+ if (isVariant(value) && name.endsWith('*')) {
+ int valueType = QMetaType::type(name.left(name.size()-1));
+ QVariant &var = variantValue(value);
+ if (valueType == var.userType()) {
+ *reinterpret_cast<void* *>(ptr) = var.data();
+ return true;
+ } else {
+ // look in the prototype chain
+ JSC::JSValue proto = JSC::asObject(value)->prototype();
+ while (proto.isObject()) {
+ bool canCast = false;
+ if (isVariant(proto)) {
+ canCast = (type == variantValue(proto).userType())
+ || (valueType && (valueType == variantValue(proto).userType()));
+ }
+#ifndef QT_NO_QOBJECT
+ else if (isQObject(proto)) {
+ QByteArray className = name.left(name.size()-1);
+ if (QObject *qobject = toQObject(exec, proto))
+ canCast = qobject->qt_metacast(className) != 0;
+ }
+#endif
+ if (canCast) {
+ QByteArray varTypeName = QMetaType::typeName(var.userType());
+ if (varTypeName.endsWith('*'))
+ *reinterpret_cast<void* *>(ptr) = *reinterpret_cast<void* *>(var.data());
+ else
+ *reinterpret_cast<void* *>(ptr) = var.data();
+ return true;
+ }
+ proto = JSC::asObject(proto)->prototype();
+ }
+ }
+ } else if (value.isNull() && name.endsWith('*')) {
+ *reinterpret_cast<void* *>(ptr) = 0;
+ return true;
+ } else if (type == qMetaTypeId<QScriptValue>()) {
+ if (!eng)
+ return false;
+ *reinterpret_cast<QScriptValue*>(ptr) = eng->scriptValueFromJSCValue(value);
+ return true;
+ }
+
+ // lazy registration of some common list types
+#ifndef QT_NO_QOBJECT
+ else if (type == qMetaTypeId<QObjectList>()) {
+ if (!eng)
+ return false;
+ qScriptRegisterSequenceMetaType<QObjectList>(eng->q_func());
+ return convertValue(exec, value, type, ptr);
+ }
+#endif
+ else if (type == qMetaTypeId<QList<int> >()) {
+ if (!eng)
+ return false;
+ qScriptRegisterSequenceMetaType<QList<int> >(eng->q_func());
+ return convertValue(exec, value, type, ptr);
+ }
+
+#if 0
+ if (!name.isEmpty()) {
+ qWarning("QScriptEngine::convert: unable to convert value to type `%s'",
+ name.constData());
+ }
+#endif
+ return false;
+}
+
+bool QScriptEnginePrivate::convertNumber(qsreal value, int type, void *ptr)
+{
+ switch (QMetaType::Type(type)) {
+ case QMetaType::Bool:
+ *reinterpret_cast<bool*>(ptr) = QScript::ToBool(value);
+ return true;
+ case QMetaType::Int:
+ *reinterpret_cast<int*>(ptr) = QScript::ToInt32(value);
+ return true;
+ case QMetaType::UInt:
+ *reinterpret_cast<uint*>(ptr) = QScript::ToUInt32(value);
+ return true;
+ case QMetaType::LongLong:
+ *reinterpret_cast<qlonglong*>(ptr) = qlonglong(QScript::ToInteger(value));
+ return true;
+ case QMetaType::ULongLong:
+ *reinterpret_cast<qulonglong*>(ptr) = qulonglong(QScript::ToInteger(value));
+ return true;
+ case QMetaType::Double:
+ *reinterpret_cast<double*>(ptr) = value;
+ return true;
+ case QMetaType::QString:
+ *reinterpret_cast<QString*>(ptr) = QScript::ToString(value);
+ return true;
+ case QMetaType::Float:
+ *reinterpret_cast<float*>(ptr) = value;
+ return true;
+ case QMetaType::Short:
+ *reinterpret_cast<short*>(ptr) = short(QScript::ToInt32(value));
+ return true;
+ case QMetaType::UShort:
+ *reinterpret_cast<unsigned short*>(ptr) = QScript::ToUInt16(value);
+ return true;
+ case QMetaType::Char:
+ *reinterpret_cast<char*>(ptr) = char(QScript::ToInt32(value));
+ return true;
+ case QMetaType::UChar:
+ *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(QScript::ToInt32(value));
+ return true;
+ case QMetaType::QChar:
+ *reinterpret_cast<QChar*>(ptr) = QChar(QScript::ToUInt16(value));
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool QScriptEnginePrivate::convertString(const QString &value, int type, void *ptr)
+{
+ switch (QMetaType::Type(type)) {
+ case QMetaType::Bool:
+ *reinterpret_cast<bool*>(ptr) = QScript::ToBool(value);
+ return true;
+ case QMetaType::Int:
+ *reinterpret_cast<int*>(ptr) = QScript::ToInt32(value);
+ return true;
+ case QMetaType::UInt:
+ *reinterpret_cast<uint*>(ptr) = QScript::ToUInt32(value);
+ return true;
+ case QMetaType::LongLong:
+ *reinterpret_cast<qlonglong*>(ptr) = qlonglong(QScript::ToInteger(value));
+ return true;
+ case QMetaType::ULongLong:
+ *reinterpret_cast<qulonglong*>(ptr) = qulonglong(QScript::ToInteger(value));
+ return true;
+ case QMetaType::Double:
+ *reinterpret_cast<double*>(ptr) = QScript::ToNumber(value);
+ return true;
+ case QMetaType::QString:
+ *reinterpret_cast<QString*>(ptr) = value;
+ return true;
+ case QMetaType::Float:
+ *reinterpret_cast<float*>(ptr) = QScript::ToNumber(value);
+ return true;
+ case QMetaType::Short:
+ *reinterpret_cast<short*>(ptr) = short(QScript::ToInt32(value));
+ return true;
+ case QMetaType::UShort:
+ *reinterpret_cast<unsigned short*>(ptr) = QScript::ToUInt16(value);
+ return true;
+ case QMetaType::Char:
+ *reinterpret_cast<char*>(ptr) = char(QScript::ToInt32(value));
+ return true;
+ case QMetaType::UChar:
+ *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(QScript::ToInt32(value));
+ return true;
+ case QMetaType::QChar:
+ *reinterpret_cast<QChar*>(ptr) = QChar(QScript::ToUInt16(value));
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool QScriptEnginePrivate::hasDemarshalFunction(int type) const
+{
+ QScriptTypeInfo *info = m_typeInfos.value(type);
+ return info && (info->demarshal != 0);
+}
+
+JSC::UString QScriptEnginePrivate::translationContextFromUrl(const JSC::UString &url)
+{
+ if (url != cachedTranslationUrl) {
+ cachedTranslationContext = QFileInfo(url).baseName();
+ cachedTranslationUrl = url;
+ }
+ return cachedTranslationContext;
+}
+
+/*!
+ \internal
+*/
+bool QScriptEngine::convert(const QScriptValue &value, int type, void *ptr)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ return QScriptEnginePrivate::convertValue(d->currentFrame, d->scriptValueToJSCValue(value), type, ptr);
+}
+
+/*!
+ \internal
+*/
+bool QScriptEngine::convertV2(const QScriptValue &value, int type, void *ptr)
+{
+ QScriptValuePrivate *vp = QScriptValuePrivate::get(value);
+ if (vp) {
+ switch (vp->type) {
+ case QScriptValuePrivate::JavaScriptCore: {
+ if (vp->engine) {
+ QScript::APIShim shim(vp->engine);
+ return QScriptEnginePrivate::convertValue(vp->engine->currentFrame, vp->jscValue, type, ptr);
+ } else {
+ return QScriptEnginePrivate::convertValue(0, vp->jscValue, type, ptr);
+ }
+ }
+ case QScriptValuePrivate::Number:
+ return QScriptEnginePrivate::convertNumber(vp->numberValue, type, ptr);
+ case QScriptValuePrivate::String:
+ return QScriptEnginePrivate::convertString(vp->stringValue, type, ptr);
+ }
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QScriptEngine::registerCustomType(int type, MarshalFunction mf,
+ DemarshalFunction df,
+ const QScriptValue &prototype)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ QScriptTypeInfo *info = d->m_typeInfos.value(type);
+ if (!info) {
+ info = new QScriptTypeInfo();
+ d->m_typeInfos.insert(type, info);
+ }
+ info->marshal = mf;
+ info->demarshal = df;
+ info->prototype = d->scriptValueToJSCValue(prototype);
+}
+
+/*!
+ \since 4.5
+
+ Installs translator functions on the given \a object, or on the Global
+ Object if no object is specified.
+
+ The relation between Qt Script translator functions and C++ translator
+ functions is described in the following table:
+
+ \table
+ \header \o Script Function \o Corresponding C++ Function
+ \row \o qsTr() \o QObject::tr()
+ \row \o QT_TR_NOOP() \o QT_TR_NOOP()
+ \row \o qsTranslate() \o QCoreApplication::translate()
+ \row \o QT_TRANSLATE_NOOP() \o QT_TRANSLATE_NOOP()
+ \row \o qsTrId() (since 4.7) \o qtTrId()
+ \row \o QT_TRID_NOOP() (since 4.7) \o QT_TRID_NOOP()
+ \endtable
+
+ \sa {Internationalization with Qt}
+*/
+void QScriptEngine::installTranslatorFunctions(const QScriptValue &object)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ JSC::ExecState* exec = d->currentFrame;
+ JSC::JSValue jscObject = d->scriptValueToJSCValue(object);
+ JSC::JSGlobalObject *glob = d->originalGlobalObject();
+ if (!jscObject || !jscObject.isObject())
+ jscObject = d->globalObject();
+// unsigned attribs = JSC::DontEnum;
+
+#ifndef QT_NO_TRANSLATION
+ JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 5, JSC::Identifier(exec, "qsTranslate"), QScript::functionQsTranslate));
+ JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 2, JSC::Identifier(exec, "QT_TRANSLATE_NOOP"), QScript::functionQsTranslateNoOp));
+ JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 3, JSC::Identifier(exec, "qsTr"), QScript::functionQsTr));
+ JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "QT_TR_NOOP"), QScript::functionQsTrNoOp));
+ JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "qsTrId"), QScript::functionQsTrId));
+ JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "QT_TRID_NOOP"), QScript::functionQsTrIdNoOp));
+#endif
+
+ glob->stringPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "arg"), QScript::stringProtoFuncArg));
+}
+
+/*!
+ Imports the given \a extension into this QScriptEngine. Returns
+ undefinedValue() if the extension was successfully imported. You
+ can call hasUncaughtException() to check if an error occurred; in
+ that case, the return value is the value that was thrown by the
+ exception (usually an \c{Error} object).
+
+ QScriptEngine ensures that a particular extension is only imported
+ once; subsequent calls to importExtension() with the same extension
+ name will do nothing and return undefinedValue().
+
+ \sa availableExtensions(), QScriptExtensionPlugin, {Creating QtScript Extensions}
+*/
+QScriptValue QScriptEngine::importExtension(const QString &extension)
+{
+#if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
+ Q_UNUSED(extension);
+#else
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ if (d->importedExtensions.contains(extension))
+ return undefinedValue(); // already imported
+
+ QScriptContext *context = currentContext();
+ QCoreApplication *app = QCoreApplication::instance();
+ if (!app)
+ return context->throwError(QLatin1String("No application object"));
+
+ QObjectList staticPlugins = QPluginLoader::staticInstances();
+ QStringList libraryPaths = app->libraryPaths();
+ QString dot = QLatin1String(".");
+ QStringList pathComponents = extension.split(dot);
+ QString initDotJs = QLatin1String("__init__.js");
+
+ QString ext;
+ for (int i = 0; i < pathComponents.count(); ++i) {
+ if (!ext.isEmpty())
+ ext.append(dot);
+ ext.append(pathComponents.at(i));
+ if (d->importedExtensions.contains(ext))
+ continue; // already imported
+
+ if (d->extensionsBeingImported.contains(ext)) {
+ return context->throwError(QString::fromLatin1("recursive import of %0")
+ .arg(extension));
+ }
+ d->extensionsBeingImported.insert(ext);
+
+ QScriptExtensionInterface *iface = 0;
+ QString initjsContents;
+ QString initjsFileName;
+
+ // look for the extension in static plugins
+ for (int j = 0; j < staticPlugins.size(); ++j) {
+ iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(j));
+ if (!iface)
+ continue;
+ if (iface->keys().contains(ext))
+ break; // use this one
+ else
+ iface = 0; // keep looking
+ }
+
+ {
+ // look for __init__.js resource
+ QString path = QString::fromLatin1(":/qtscriptextension");
+ for (int j = 0; j <= i; ++j) {
+ path.append(QLatin1Char('/'));
+ path.append(pathComponents.at(j));
+ }
+ path.append(QLatin1Char('/'));
+ path.append(initDotJs);
+ QFile file(path);
+ if (file.open(QIODevice::ReadOnly)) {
+ QTextStream ts(&file);
+ initjsContents = ts.readAll();
+ initjsFileName = path;
+ file.close();
+ }
+ }
+
+ if (!iface && initjsContents.isEmpty()) {
+ // look for the extension in library paths
+ for (int j = 0; j < libraryPaths.count(); ++j) {
+ QString libPath = libraryPaths.at(j) + QDir::separator() + QLatin1String("script");
+ QDir dir(libPath);
+ if (!dir.exists(dot))
+ continue;
+
+ // look for C++ plugin
+ QFileInfoList files = dir.entryInfoList(QDir::Files);
+ for (int k = 0; k < files.count(); ++k) {
+ QFileInfo entry = files.at(k);
+ QString filePath = entry.canonicalFilePath();
+ QPluginLoader loader(filePath);
+ iface = qobject_cast<QScriptExtensionInterface*>(loader.instance());
+ if (iface) {
+ if (iface->keys().contains(ext))
+ break; // use this one
+ else
+ iface = 0; // keep looking
+ }
+ }
+
+ // look for __init__.js in the corresponding dir
+ QDir dirdir(libPath);
+ bool dirExists = dirdir.exists();
+ for (int k = 0; dirExists && (k <= i); ++k)
+ dirExists = dirdir.cd(pathComponents.at(k));
+ if (dirExists && dirdir.exists(initDotJs)) {
+ QFile file(dirdir.canonicalPath()
+ + QDir::separator() + initDotJs);
+ if (file.open(QIODevice::ReadOnly)) {
+ QTextStream ts(&file);
+ initjsContents = ts.readAll();
+ initjsFileName = file.fileName();
+ file.close();
+ }
+ }
+
+ if (iface || !initjsContents.isEmpty())
+ break;
+ }
+ }
+
+ if (!iface && initjsContents.isEmpty()) {
+ d->extensionsBeingImported.remove(ext);
+ return context->throwError(
+ QString::fromLatin1("Unable to import %0: no such extension")
+ .arg(extension));
+ }
+
+ // initialize the extension in a new context
+ QScriptContext *ctx = pushContext();
+ ctx->setThisObject(globalObject());
+ ctx->activationObject().setProperty(QLatin1String("__extension__"), ext,
+ QScriptValue::ReadOnly | QScriptValue::Undeletable);
+ ctx->activationObject().setProperty(QLatin1String("__setupPackage__"),
+ newFunction(QScript::__setupPackage__));
+ ctx->activationObject().setProperty(QLatin1String("__postInit__"), QScriptValue(QScriptValue::UndefinedValue));
+
+ // the script is evaluated first
+ if (!initjsContents.isEmpty()) {
+ QScriptValue ret = evaluate(initjsContents, initjsFileName);
+ if (hasUncaughtException()) {
+ popContext();
+ d->extensionsBeingImported.remove(ext);
+ return ret;
+ }
+ }
+
+ // next, the C++ plugin is called
+ if (iface) {
+ iface->initialize(ext, this);
+ if (hasUncaughtException()) {
+ QScriptValue ret = uncaughtException(); // ctx_p->returnValue();
+ popContext();
+ d->extensionsBeingImported.remove(ext);
+ return ret;
+ }
+ }
+
+ // if the __postInit__ function has been set, we call it
+ QScriptValue postInit = ctx->activationObject().property(QLatin1String("__postInit__"));
+ if (postInit.isFunction()) {
+ postInit.call(globalObject());
+ if (hasUncaughtException()) {
+ QScriptValue ret = uncaughtException(); // ctx_p->returnValue();
+ popContext();
+ d->extensionsBeingImported.remove(ext);
+ return ret;
+ }
+ }
+
+ popContext();
+
+ d->importedExtensions.insert(ext);
+ d->extensionsBeingImported.remove(ext);
+ } // for (i)
+#endif // QT_NO_QOBJECT
+ return undefinedValue();
+}
+
+/*!
+ \since 4.4
+
+ Returns a list naming the available extensions that can be
+ imported using the importExtension() function. This list includes
+ extensions that have been imported.
+
+ \sa importExtension(), importedExtensions()
+*/
+QStringList QScriptEngine::availableExtensions() const
+{
+#if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
+ return QStringList();
+#else
+ QCoreApplication *app = QCoreApplication::instance();
+ if (!app)
+ return QStringList();
+
+ QSet<QString> result;
+
+ QObjectList staticPlugins = QPluginLoader::staticInstances();
+ for (int i = 0; i < staticPlugins.size(); ++i) {
+ QScriptExtensionInterface *iface;
+ iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(i));
+ if (iface) {
+ QStringList keys = iface->keys();
+ for (int j = 0; j < keys.count(); ++j)
+ result << keys.at(j);
+ }
+ }
+
+ QStringList libraryPaths = app->libraryPaths();
+ for (int i = 0; i < libraryPaths.count(); ++i) {
+ QString libPath = libraryPaths.at(i) + QDir::separator() + QLatin1String("script");
+ QDir dir(libPath);
+ if (!dir.exists())
+ continue;
+
+ // look for C++ plugins
+ QFileInfoList files = dir.entryInfoList(QDir::Files);
+ for (int j = 0; j < files.count(); ++j) {
+ QFileInfo entry = files.at(j);
+ QString filePath = entry.canonicalFilePath();
+ QPluginLoader loader(filePath);
+ QScriptExtensionInterface *iface;
+ iface = qobject_cast<QScriptExtensionInterface*>(loader.instance());
+ if (iface) {
+ QStringList keys = iface->keys();
+ for (int k = 0; k < keys.count(); ++k)
+ result << keys.at(k);
+ }
+ }
+
+ // look for scripts
+ QString initDotJs = QLatin1String("__init__.js");
+ QList<QFileInfo> stack;
+ stack << dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
+ while (!stack.isEmpty()) {
+ QFileInfo entry = stack.takeLast();
+ QDir dd(entry.canonicalFilePath());
+ if (dd.exists(initDotJs)) {
+ QString rpath = dir.relativeFilePath(dd.canonicalPath());
+ QStringList components = rpath.split(QLatin1Char('/'));
+ result << components.join(QLatin1String("."));
+ stack << dd.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
+ }
+ }
+ }
+
+ QStringList lst = result.toList();
+ qSort(lst);
+ return lst;
+#endif
+}
+
+/*!
+ \since 4.4
+
+ Returns a list naming the extensions that have been imported
+ using the importExtension() function.
+
+ \sa availableExtensions()
+*/
+QStringList QScriptEngine::importedExtensions() const
+{
+ Q_D(const QScriptEngine);
+ QStringList lst = d->importedExtensions.toList();
+ qSort(lst);
+ return lst;
+}
+
+/*! \fn QScriptValue QScriptEngine::toScriptValue(const T &value)
+
+ Creates a QScriptValue with the given \a value.
+
+ Note that the template type \c{T} must be known to QMetaType.
+
+ See \l{Conversion Between QtScript and C++ Types} for a
+ description of the built-in type conversion provided by
+ QtScript. By default, the types that are not specially handled by
+ QtScript are represented as QVariants (e.g. the \a value is passed
+ to newVariant()); you can change this behavior by installing your
+ own type conversion functions with qScriptRegisterMetaType().
+
+ \sa fromScriptValue(), qScriptRegisterMetaType()
+*/
+
+/*! \fn T QScriptEngine::fromScriptValue(const QScriptValue &value)
+
+ Returns the given \a value converted to the template type \c{T}.
+
+ Note that \c{T} must be known to QMetaType.
+
+ See \l{Conversion Between QtScript and C++ Types} for a
+ description of the built-in type conversion provided by
+ QtScript.
+
+ \sa toScriptValue(), qScriptRegisterMetaType()
+*/
+
+/*!
+ \fn QScriptValue qScriptValueFromValue(QScriptEngine *engine, const T &value)
+ \since 4.3
+ \relates QScriptEngine
+ \obsolete
+
+ Creates a QScriptValue using the given \a engine with the given \a
+ value of template type \c{T}.
+
+ This function is equivalent to QScriptEngine::toScriptValue().
+
+ \note This function was provided as a workaround for MSVC 6
+ which did not support member template functions. It is advised
+ to use the other form in new code.
+
+ \sa QScriptEngine::toScriptValue(), qscriptvalue_cast
+*/
+
+/*!
+ \fn T qScriptValueToValue(const QScriptValue &value)
+ \since 4.3
+ \relates QScriptEngine
+ \obsolete
+
+ Returns the given \a value converted to the template type \c{T}.
+
+ This function is equivalent to QScriptEngine::fromScriptValue().
+
+ \note This function was provided as a workaround for MSVC 6
+ which did not support member template functions. It is advised
+ to use the other form in new code.
+
+ \sa QScriptEngine::fromScriptValue()
+*/
+
+/*!
+ \fn QScriptValue qScriptValueFromSequence(QScriptEngine *engine, const Container &container)
+ \since 4.3
+ \relates QScriptEngine
+
+ Creates an array in the form of a QScriptValue using the given \a engine
+ with the given \a container of template type \c{Container}.
+
+ The \c Container type must provide a \c const_iterator class to enable the
+ contents of the container to be copied into the array.
+
+ Additionally, the type of each element in the sequence should be
+ suitable for conversion to a QScriptValue. See
+ \l{Conversion Between QtScript and C++ Types} for more information
+ about the restrictions on types that can be used with QScriptValue.
+
+ \sa QScriptEngine::fromScriptValue()
+*/
+
+/*!
+ \fn void qScriptValueToSequence(const QScriptValue &value, Container &container)
+ \since 4.3
+ \relates QScriptEngine
+
+ Copies the elements in the sequence specified by \a value to the given
+ \a container of template type \c{Container}.
+
+ The \a value used is typically an array, but any container can be copied
+ as long as it provides a \c length property describing how many elements
+ it contains.
+
+ Additionally, the type of each element in the sequence must be
+ suitable for conversion to a C++ type from a QScriptValue. See
+ \l{Conversion Between QtScript and C++ Types} for more information
+ about the restrictions on types that can be used with
+ QScriptValue.
+
+ \sa qscriptvalue_cast()
+*/
+
+/*!
+ \fn T qscriptvalue_cast(const QScriptValue &value)
+ \since 4.3
+ \relates QScriptValue
+
+ Returns the given \a value converted to the template type \c{T}.
+
+ \sa qScriptRegisterMetaType(), QScriptEngine::toScriptValue()
+*/
+
+/*! \fn int qScriptRegisterMetaType(
+ QScriptEngine *engine,
+ QScriptValue (*toScriptValue)(QScriptEngine *, const T &t),
+ void (*fromScriptValue)(const QScriptValue &, T &t),
+ const QScriptValue &prototype = QScriptValue())
+ \relates QScriptEngine
+
+ Registers the type \c{T} in the given \a engine. \a toScriptValue must
+ be a function that will convert from a value of type \c{T} to a
+ QScriptValue, and \a fromScriptValue a function that does the
+ opposite. \a prototype, if valid, is the prototype that's set on
+ QScriptValues returned by \a toScriptValue.
+
+ Returns the internal ID used by QMetaType.
+
+ You only need to call this function if you want to provide custom
+ conversion of values of type \c{T}, i.e. if the default
+ QVariant-based representation and conversion is not
+ appropriate. (Note that custom QObject-derived types also fall in
+ this category; e.g. for a QObject-derived class called MyObject,
+ you probably want to define conversion functions for MyObject*
+ that utilize QScriptEngine::newQObject() and
+ QScriptValue::toQObject().)
+
+ If you only want to define a common script interface for values of
+ type \c{T}, and don't care how those values are represented
+ (i.e. storing them in QVariants is fine), use
+ \l{QScriptEngine::setDefaultPrototype()}{setDefaultPrototype}()
+ instead; this will minimize conversion costs.
+
+ You need to declare the custom type first with
+ Q_DECLARE_METATYPE().
+
+ After a type has been registered, you can convert from a
+ QScriptValue to that type using
+ \l{QScriptEngine::fromScriptValue()}{fromScriptValue}(), and
+ create a QScriptValue from a value of that type using
+ \l{QScriptEngine::toScriptValue()}{toScriptValue}(). The engine
+ will take care of calling the proper conversion function when
+ calling C++ slots, and when getting or setting a C++ property;
+ i.e. the custom type may be used seamlessly on both the C++ side
+ and the script side.
+
+ The following is an example of how to use this function. We will
+ specify custom conversion of our type \c{MyStruct}. Here's the C++
+ type:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 20
+
+ We must declare it so that the type will be known to QMetaType:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 21
+
+ Next, the \c{MyStruct} conversion functions. We represent the
+ \c{MyStruct} value as a script object and just copy the properties:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 22
+
+ Now we can register \c{MyStruct} with the engine:
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 23
+
+ Working with \c{MyStruct} values is now easy:
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 24
+
+ If you want to be able to construct values of your custom type
+ from script code, you have to register a constructor function for
+ the type. For example:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 25
+
+ \sa qScriptRegisterSequenceMetaType(), qRegisterMetaType()
+*/
+
+/*!
+ \macro Q_SCRIPT_DECLARE_QMETAOBJECT(QMetaObject, ArgType)
+ \since 4.3
+ \relates QScriptEngine
+
+ Declares the given \a QMetaObject. Used in combination with
+ QScriptEngine::scriptValueFromQMetaObject() to make enums and
+ instantiation of \a QMetaObject available to script code. The
+ constructor generated by this macro takes a single argument of
+ type \a ArgType; typically the argument is the parent type of the
+ new instance, in which case \a ArgType is \c{QWidget*} or
+ \c{QObject*}. Objects created by the constructor will have
+ QScriptEngine::AutoOwnership ownership.
+*/
+
+/*! \fn int qScriptRegisterSequenceMetaType(
+ QScriptEngine *engine,
+ const QScriptValue &prototype = QScriptValue())
+ \relates QScriptEngine
+
+ Registers the sequence type \c{T} in the given \a engine. This
+ function provides conversion functions that convert between \c{T}
+ and Qt Script \c{Array} objects. \c{T} must provide a
+ const_iterator class and begin(), end() and push_back()
+ functions. If \a prototype is valid, it will be set as the
+ prototype of \c{Array} objects due to conversion from \c{T};
+ otherwise, the standard \c{Array} prototype will be used.
+
+ Returns the internal ID used by QMetaType.
+
+ You need to declare the container type first with
+ Q_DECLARE_METATYPE(). If the element type isn't a standard Qt/C++
+ type, it must be declared using Q_DECLARE_METATYPE() as well.
+ Example:
+
+ \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 26
+
+ \sa qScriptRegisterMetaType()
+*/
+
+/*!
+ 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 QScriptEngine 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 QScriptEngine::collectGarbage()
+{
+ Q_D(QScriptEngine);
+ d->collectGarbage();
+}
+
+/*!
+ \since 4.7
+
+ Reports an additional memory cost of the given \a size, measured in
+ bytes, to the garbage collector.
+
+ This function can be called to indicate that a Qt Script object has
+ memory associated with it that isn't managed by Qt Script itself.
+ Reporting the additional cost makes it more likely that the garbage
+ collector will be triggered.
+
+ Note that if the additional memory is shared with objects outside
+ the scripting environment, the cost should not be reported, since
+ collecting the Qt Script object would not cause the memory to be
+ freed anyway.
+
+ Negative \a size values are ignored, i.e. this function can't be
+ used to report that the additional memory has been deallocated.
+
+ \sa collectGarbage()
+*/
+void QScriptEngine::reportAdditionalMemoryCost(int size)
+{
+ Q_D(QScriptEngine);
+ d->reportAdditionalMemoryCost(size);
+}
+
+/*!
+
+ Sets the interval between calls to QCoreApplication::processEvents
+ to \a interval milliseconds.
+
+ While the interpreter is running, all event processing is by default
+ blocked. This means for instance that the gui will not be updated
+ and timers will not be fired. To allow event processing during
+ interpreter execution one can specify the processing interval to be
+ a positive value, indicating the number of milliseconds between each
+ time QCoreApplication::processEvents() is called.
+
+ The default value is -1, which disables event processing during
+ interpreter execution.
+
+ You can use QCoreApplication::postEvent() to post an event that
+ performs custom processing at the next interval. For example, you
+ could keep track of the total running time of the script and call
+ abortEvaluation() when you detect that the script has been running
+ for a long time without completing.
+
+ \sa processEventsInterval()
+*/
+void QScriptEngine::setProcessEventsInterval(int interval)
+{
+ Q_D(QScriptEngine);
+ d->processEventsInterval = interval;
+
+ if (interval > 0)
+ d->globalData->timeoutChecker->setCheckInterval(interval);
+
+ d->timeoutChecker()->setShouldProcessEvents(interval > 0);
+}
+
+/*!
+
+ Returns the interval in milliseconds between calls to
+ QCoreApplication::processEvents() while the interpreter is running.
+
+ \sa setProcessEventsInterval()
+*/
+int QScriptEngine::processEventsInterval() const
+{
+ Q_D(const QScriptEngine);
+ return d->processEventsInterval;
+}
+
+/*!
+ \since 4.4
+
+ Returns true if this engine is currently evaluating a script,
+ otherwise returns false.
+
+ \sa evaluate(), abortEvaluation()
+*/
+bool QScriptEngine::isEvaluating() const
+{
+ Q_D(const QScriptEngine);
+ return (d->currentFrame != d->globalExec()) || d->inEval;
+}
+
+/*!
+ \since 4.4
+
+ Aborts any script evaluation currently taking place in this engine.
+ The given \a result is passed back as the result of the evaluation
+ (i.e. it is returned from the call to evaluate() being aborted).
+
+ If the engine isn't evaluating a script (i.e. isEvaluating() returns
+ false), this function does nothing.
+
+ Call this function if you need to abort a running script for some
+ reason, e.g. when you have detected that the script has been
+ running for several seconds without completing.
+
+ \sa evaluate(), isEvaluating(), setProcessEventsInterval()
+*/
+void QScriptEngine::abortEvaluation(const QScriptValue &result)
+{
+ Q_D(QScriptEngine);
+ if (!isEvaluating())
+ return;
+ d->abortResult = result;
+ d->timeoutChecker()->setShouldAbort(true);
+ JSC::throwError(d->currentFrame, JSC::createInterruptedExecutionException(&d->currentFrame->globalData()).toObject(d->currentFrame));
+}
+
+#ifndef QT_NO_QOBJECT
+
+/*!
+ \since 4.4
+ \relates QScriptEngine
+
+ Creates a connection from the \a signal in the \a sender to the
+ given \a function. If \a receiver is an object, it will act as the
+ `this' object when the signal handler function is invoked. Returns
+ true if the connection succeeds; otherwise returns false.
+
+ \sa qScriptDisconnect(), QScriptEngine::signalHandlerException()
+*/
+bool qScriptConnect(QObject *sender, const char *signal,
+ const QScriptValue &receiver, const QScriptValue &function)
+{
+ if (!sender || !signal)
+ return false;
+ if (!function.isFunction())
+ return false;
+ if (receiver.isObject() && (receiver.engine() != function.engine()))
+ return false;
+ QScriptEnginePrivate *engine = QScriptEnginePrivate::get(function.engine());
+ QScript::APIShim shim(engine);
+ JSC::JSValue jscReceiver = engine->scriptValueToJSCValue(receiver);
+ JSC::JSValue jscFunction = engine->scriptValueToJSCValue(function);
+ return engine->scriptConnect(sender, signal, jscReceiver, jscFunction,
+ Qt::AutoConnection);
+}
+
+/*!
+ \since 4.4
+ \relates QScriptEngine
+
+ Disconnects the \a signal in the \a sender from the given (\a
+ receiver, \a function) pair. Returns true if the connection is
+ successfully broken; otherwise returns false.
+
+ \sa qScriptConnect()
+*/
+bool qScriptDisconnect(QObject *sender, const char *signal,
+ const QScriptValue &receiver, const QScriptValue &function)
+{
+ if (!sender || !signal)
+ return false;
+ if (!function.isFunction())
+ return false;
+ if (receiver.isObject() && (receiver.engine() != function.engine()))
+ return false;
+ QScriptEnginePrivate *engine = QScriptEnginePrivate::get(function.engine());
+ QScript::APIShim shim(engine);
+ JSC::JSValue jscReceiver = engine->scriptValueToJSCValue(receiver);
+ JSC::JSValue jscFunction = engine->scriptValueToJSCValue(function);
+ return engine->scriptDisconnect(sender, signal, jscReceiver, jscFunction);
+}
+
+/*!
+ \since 4.4
+ \fn void QScriptEngine::signalHandlerException(const QScriptValue &exception)
+
+ This signal is emitted when a script function connected to a signal causes
+ an \a exception.
+
+ \sa qScriptConnect()
+*/
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "moc_qscriptengine.cpp"
+QT_END_INCLUDE_NAMESPACE
+
+#endif // QT_NO_QOBJECT
+
+/*!
+ \since 4.4
+
+ Installs the given \a agent on this engine. The agent will be
+ notified of various events pertaining to script execution. This is
+ useful when you want to find out exactly what the engine is doing,
+ e.g. when evaluate() is called. The agent interface is the basis of
+ tools like debuggers and profilers.
+
+ The engine maintains ownership of the \a agent.
+
+ Calling this function will replace the existing agent, if any.
+
+ \sa agent()
+*/
+void QScriptEngine::setAgent(QScriptEngineAgent *agent)
+{
+ Q_D(QScriptEngine);
+ if (agent && (agent->engine() != this)) {
+ qWarning("QScriptEngine::setAgent(): "
+ "cannot set agent belonging to different engine");
+ return;
+ }
+ QScript::APIShim shim(d);
+ if (d->activeAgent)
+ QScriptEngineAgentPrivate::get(d->activeAgent)->detach();
+ d->activeAgent = agent;
+ if (agent) {
+ QScriptEngineAgentPrivate::get(agent)->attach();
+ }
+}
+
+/*!
+ \since 4.4
+
+ Returns the agent currently installed on this engine, or 0 if no
+ agent is installed.
+
+ \sa setAgent()
+*/
+QScriptEngineAgent *QScriptEngine::agent() const
+{
+ Q_D(const QScriptEngine);
+ return d->activeAgent;
+}
+
+/*!
+ \since 4.4
+
+ Returns a handle that represents the given string, \a str.
+
+ QScriptString can be used to quickly look up properties, and
+ compare property names, of script objects.
+
+ \sa QScriptValue::property()
+*/
+QScriptString QScriptEngine::toStringHandle(const QString &str)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ return d->toStringHandle(JSC::Identifier(d->currentFrame, str));
+}
+
+/*!
+ \since 4.5
+
+ Converts the given \a value to an object, if such a conversion is
+ possible; otherwise returns an invalid QScriptValue. The conversion
+ is performed according to the following table:
+
+ \table
+ \header \o Input Type \o Result
+ \row \o Undefined \o An invalid QScriptValue.
+ \row \o Null \o An invalid QScriptValue.
+ \row \o Boolean \o A new Boolean object whose internal value is set to the value of the boolean.
+ \row \o Number \o A new Number object whose internal value is set to the value of the number.
+ \row \o String \o A new String object whose internal value is set to the value of the string.
+ \row \o Object \o The result is the object itself (no conversion).
+ \endtable
+
+ \sa newObject()
+*/
+QScriptValue QScriptEngine::toObject(const QScriptValue &value)
+{
+ Q_D(QScriptEngine);
+ QScript::APIShim shim(d);
+ JSC::JSValue jscValue = d->scriptValueToJSCValue(value);
+ if (!jscValue || jscValue.isUndefined() || jscValue.isNull())
+ return QScriptValue();
+ JSC::ExecState* exec = d->currentFrame;
+ JSC::JSValue result = jscValue.toObject(exec);
+ return d->scriptValueFromJSCValue(result);
+}
+
+/*!
+ \internal
+
+ Returns the object with the given \a id, or an invalid
+ QScriptValue if there is no object with that id.
+
+ \sa QScriptValue::objectId()
+*/
+QScriptValue QScriptEngine::objectById(qint64 id) const
+{
+ Q_D(const QScriptEngine);
+ // Assumes that the cell was not been garbage collected
+ return const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue((JSC::JSCell*)id);
+}
+
+/*!
+ \since 4.5
+ \class QScriptSyntaxCheckResult
+
+ \brief The QScriptSyntaxCheckResult class provides the result of a script syntax check.
+
+ \ingroup script
+ \mainclass
+
+ QScriptSyntaxCheckResult is returned by QScriptEngine::checkSyntax() to
+ provide information about the syntactical (in)correctness of a script.
+*/
+
+/*!
+ \enum QScriptSyntaxCheckResult::State
+
+ This enum specifies the state of a syntax check.
+
+ \value Error The program contains a syntax error.
+ \value Intermediate The program is incomplete.
+ \value Valid The program is a syntactically correct Qt Script program.
+*/
+
+/*!
+ Constructs a new QScriptSyntaxCheckResult from the \a other result.
+*/
+QScriptSyntaxCheckResult::QScriptSyntaxCheckResult(const QScriptSyntaxCheckResult &other)
+ : d_ptr(other.d_ptr)
+{
+}
+
+/*!
+ \internal
+*/
+QScriptSyntaxCheckResult::QScriptSyntaxCheckResult(QScriptSyntaxCheckResultPrivate *d)
+ : d_ptr(d)
+{
+}
+
+/*!
+ \internal
+*/
+QScriptSyntaxCheckResult::QScriptSyntaxCheckResult()
+ : d_ptr(0)
+{
+}
+
+/*!
+ Destroys this QScriptSyntaxCheckResult.
+*/
+QScriptSyntaxCheckResult::~QScriptSyntaxCheckResult()
+{
+}
+
+/*!
+ Returns the state of this QScriptSyntaxCheckResult.
+*/
+QScriptSyntaxCheckResult::State QScriptSyntaxCheckResult::state() const
+{
+ Q_D(const QScriptSyntaxCheckResult);
+ if (!d)
+ return Valid;
+ return d->state;
+}
+
+/*!
+ Returns the error line number of this QScriptSyntaxCheckResult, or -1 if
+ there is no error.
+
+ \sa state(), errorMessage()
+*/
+int QScriptSyntaxCheckResult::errorLineNumber() const
+{
+ Q_D(const QScriptSyntaxCheckResult);
+ if (!d)
+ return -1;
+ return d->errorLineNumber;
+}
+
+/*!
+ Returns the error column number of this QScriptSyntaxCheckResult, or -1 if
+ there is no error.
+
+ \sa state(), errorLineNumber()
+*/
+int QScriptSyntaxCheckResult::errorColumnNumber() const
+{
+ Q_D(const QScriptSyntaxCheckResult);
+ if (!d)
+ return -1;
+ return d->errorColumnNumber;
+}
+
+/*!
+ Returns the error message of this QScriptSyntaxCheckResult, or an empty
+ string if there is no error.
+
+ \sa state(), errorLineNumber()
+*/
+QString QScriptSyntaxCheckResult::errorMessage() const
+{
+ Q_D(const QScriptSyntaxCheckResult);
+ if (!d)
+ return QString();
+ return d->errorMessage;
+}
+
+/*!
+ Assigns the \a other result to this QScriptSyntaxCheckResult, and returns a
+ reference to this QScriptSyntaxCheckResult.
+*/
+QScriptSyntaxCheckResult &QScriptSyntaxCheckResult::operator=(const QScriptSyntaxCheckResult &other)
+{
+ d_ptr = other.d_ptr;
+ return *this;
+}
+
+#ifdef QT_BUILD_INTERNAL
+Q_AUTOTEST_EXPORT bool qt_script_isJITEnabled()
+{
+#if ENABLE(JIT)
+ return true;
+#else
+ return false;
+#endif
+}
+#endif
+
+#ifdef Q_CC_MSVC
+// Try to prevent compiler from crashing.
+#pragma optimize("", off)
+#endif
+
+QT_END_NAMESPACE