| /**************************************************************************** |
| ** |
| ** Copyright (C) 2015 The Qt Company Ltd. |
| ** Contact: http://www.qt.io/licensing/ |
| ** |
| ** 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 |
| ** us via http://www.qt.io/contact-us/. |
| ** |
| ** $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/qshareddata.h> |
| #include <QtCore/qmetaobject.h> |
| |
| #include <math.h> |
| #include <algorithm> |
| |
| #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 |
| |
| #include <stdlib.h> |
| |
| 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 |
| \inmodule QtScript |
| |
| \brief The QScriptEngine class provides an environment for evaluating Qt Script code. |
| |
| \ingroup script |
| |
| See the \l{Qt Script} 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 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 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 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 \b {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 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 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 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 \l{Making Applications Scriptable} 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 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 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 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 QSharedData |
| { |
| public: |
| QScriptSyntaxCheckResultPrivate() {} |
| ~QScriptSyntaxCheckResultPrivate() {} |
| |
| QScriptSyntaxCheckResult::State state; |
| int errorColumnNumber; |
| int errorLineNumber; |
| QString errorMessage; |
| }; |
| |
| 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); |
| } |
| |
| void GlobalClientData::uncaughtException(JSC::ExecState* exec, unsigned bytecodeOffset, |
| JSC::JSValue value) |
| { |
| engine->uncaughtException(exec, bytecodeOffset, value); |
| } |
| |
| 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.methodSignature().constData())); |
| 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.methodSignature().constData())); |
| 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.methodSignature().constData())); |
| return JSC::throwError(exec, JSC::TypeError, message); |
| } |
| |
| { |
| QList<int> overloads = qtSignal->overloadedIndexes(); |
| if (!overloads.isEmpty()) { |
| overloads.append(qtSignal->initialIndex()); |
| QByteArray signature = sig.methodSignature(); |
| 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.methodSignature().constData()))); |
| } |
| 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.methodSignature().constData())); |
| 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"); |
| |
| int n = -1; |
| if ((args.size() > 3)) { |
| if (args.at(3).isString()) { |
| qWarning("qsTranslate(): specifying the encoding as fourth argument is deprecated"); |
| if (args.size() > 4) { |
| if (args.at(4).isNumber()) |
| n = args.at(4).toInt32(exec); |
| else |
| return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): fifth argument (n) must be a number"); |
| } |
| } else if (args.at(3).isNumber()) { |
| n = args.at(3).toInt32(exec); |
| } else { |
| return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): fourth 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); |
| #endif |
| JSC::UString result; |
| #ifndef QT_NO_QOBJECT |
| result = QCoreApplication::translate(context.UTF8String().c_str(), |
| text.UTF8String().c_str(), |
| comment.UTF8String().c_str(), |
| 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(), |
| 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), |
| uncaughtExceptionLineNumber(-1) |
| { |
| 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; |
| free(p); |
| } |
| } |
| |
| QVariant QScriptEnginePrivate::jscValueToVariant(JSC::ExecState *exec, JSC::JSValue value, int targetType) |
| { |
| if (targetType == QMetaType::QVariant || uint(targetType) == QVariant::LastType) |
| return toVariant(exec, value); |
| QVariant v(targetType, (void *)0); |
| if (convertValue(exec, value, targetType, v.data())) |
| return v; |
| if (isVariant(value)) { |
| v = variantValue(value); |
| if (v.canConvert(targetType)) { |
| v.convert(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); |
| } |
| |
| |
| // This function is called by JSC after all objects reachable by JSC itself |
| // have been processed (see JSC::Heap::markRoots()). |
| // Here we should mark additional objects managed by Qt Script. |
| 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 |
| markQObjectData(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 && !executable->isCompiled()) { |
| 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; |
| } |
| |
| // See ExceptionHelpers.cpp createStackOverflowError() |
| bool QScriptEnginePrivate::isLikelyStackOverflowError(JSC::ExecState *exec, JSC::JSValue value) |
| { |
| if (!isError(value)) |
| return false; |
| |
| JSC::JSValue name = property(exec, value, exec->propertyNames().name); |
| if (!name || !name.isString() || name.toString(exec) != "RangeError") |
| return false; |
| |
| JSC::JSValue message = property(exec, value, exec->propertyNames().message); |
| if (!message || !message.isString() || message.toString(exec) != "Maximum call stack size exceeded.") |
| return false; |
| |
| return true; |
| } |
| |
| /*! |
| \internal |
| Called by the VM when an uncaught exception is being processed. |
| If the VM call stack contains a native call inbetween two JS calls at the |
| time the exception is thrown, this function will get called multiple times |
| for a single exception (once per "interval" of JS call frames). In other |
| words, at the time of this call, the VM stack can be in a partially unwound |
| state. |
| */ |
| void QScriptEnginePrivate::uncaughtException(JSC::ExecState *exec, unsigned bytecodeOffset, |
| JSC::JSValue value) |
| { |
| // Don't capture exception information if we already have. |
| if (uncaughtExceptionLineNumber != -1) |
| return; |
| |
| QScript::SaveFrameHelper saveFrame(this, exec); |
| |
| uncaughtExceptionLineNumber = exec->codeBlock()->lineNumberForBytecodeOffset(exec, bytecodeOffset); |
| |
| if (isLikelyStackOverflowError(exec, value)) { |
| // Don't save the backtrace, it's likely to take forever to create. |
| uncaughtExceptionBacktrace.clear(); |
| } else { |
| uncaughtExceptionBacktrace = contextForFrame(exec)->backtrace(); |
| } |
| } |
| |
| #ifndef QT_NO_QOBJECT |
| |
| void QScriptEnginePrivate::markQObjectData(JSC::MarkStack& markStack) |
| { |
| QHash<QObject*, QScript::QObjectData*>::const_iterator it; |
| // 1. Clear connection mark bits for all objects |
| for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) { |
| QScript::QObjectData *qdata = it.value(); |
| qdata->clearConnectionMarkBits(); |
| } |
| |
| // 2. Iterate until no more connections are marked |
| int markedCount; |
| do { |
| // Drain the stack to ensure mark bits are set; this is used to determine |
| // whether a connection's sender object is weakly referenced |
| markStack.drain(); |
| |
| markedCount = 0; |
| for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) { |
| QScript::QObjectData *qdata = it.value(); |
| markedCount += qdata->markConnections(markStack); |
| } |
| } while (markedCount > 0); |
| markStack.drain(); // One last time before marking wrappers |
| |
| // 3. Mark all wrappers |
| for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) { |
| QScript::QObjectData *qdata = it.value(); |
| qdata->markWrappers(markStack); |
| } |
| } |
| |
| 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 ®exp) |
| { |
| 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 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 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 Qt Script object of class RegExp with the given |
| \a regexp. |
| |
| \sa QScriptValue::toRegExp() |
| */ |
| QScriptValue QScriptEngine::newRegExp(const QRegExp ®exp) |
| { |
| Q_D(QScriptEngine); |
| QScript::APIShim shim(d); |
| return d->scriptValueFromJSCValue(d->newRegExp(d->currentFrame, regexp)); |
| } |
| |
| #endif // QT_NO_REGEXP |
| |
| /*! |
| Creates a Qt Script 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 Qt Script 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{Qt Script} 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 Qt Script's control, any |
| attempt to access the deleted QObject's members through the Qt Script |
| 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 Qt Script 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 Qt Script 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 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 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 Qt Script 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 Qt Script 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 Qt Script 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 Qt Script 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 Qt Script 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 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 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 Qt Script. 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 |
| Qt Script 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 code/src_script_qscriptengine.cpp 14 |
| canEvaluate() will return true, since the program appears to be complete. |
| |
| Given the input |
| \snippet 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 code/src_script_qscriptengine.cpp 16 |
| canEvaluate() will return true, but evaluate() will throw a |
| SyntaxError given the same input. |
| |
| Given the input |
| \snippet code/src_script_qscriptengine.cpp 17 |
| canEvaluate() will return true, even though the code is clearly not |
| syntactically valid Qt Script code. evaluate() will throw a |
| SyntaxError when this code is evaluated. |
| |
| Given the input |
| \snippet 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 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) |
| { |
| 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->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; |
| |
| 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 ®isterFile = 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 |
| { |
| Q_D(const QScriptEngine); |
| if (!hasUncaughtException()) |
| return -1; |
| if (d->uncaughtExceptionLineNumber != -1) |
| return d->uncaughtExceptionLineNumber; |
| |
| return uncaughtException().property(QLatin1String("lineNumber")).toInt32(); |
| } |
| |
| /*! |
| Returns a human-readable backtrace of the last uncaught exception. |
| |
| It is in the form \c{<function-name>() at <file-name>:<line-number>}. |
| |
| \sa uncaughtException() |
| */ |
| QStringList QScriptEngine::uncaughtExceptionBacktrace() const |
| { |
| Q_D(const QScriptEngine); |
| return d->uncaughtExceptionBacktrace; |
| } |
| |
| /*! |
| \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 |
| |
| 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 |
| |
| 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::UnknownType: |
| 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::Long: |
| return JSC::jsNumber(exec, *reinterpret_cast<const long*>(ptr)); |
| case QMetaType::ULong: |
| return JSC::jsNumber(exec, *reinterpret_cast<const ulong*>(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: |
| result = eng->newQObject(*reinterpret_cast<QObject* const *>(ptr)); |
| break; |
| #endif |
| case QMetaType::QVariant: |
| result = eng->newVariant(*reinterpret_cast<const QVariant*>(ptr)); |
| break; |
| default: |
| if (QMetaType::typeFlags(type) & QMetaType::PointerToQObject) { |
| result = eng->newQObject(*reinterpret_cast<QObject* const *>(ptr)); |
| break; |
| } |
| |
| 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::Long: |
| *reinterpret_cast<long*>(ptr) = long(toInteger(exec, value)); |
| return true; |
| case QMetaType::ULong: |
| *reinterpret_cast<ulong*>(ptr) = ulong(toInteger(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; |
| #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::Long: |
| *reinterpret_cast<long*>(ptr) = long(QScript::ToInteger(value)); |
| return true; |
| case QMetaType::ULong: |
| *reinterpret_cast<ulong*>(ptr) = ulong(QScript::ToInteger(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::Long: |
| *reinterpret_cast<long*>(ptr) = long(QScript::ToInteger(value)); |
| return true; |
| case QMetaType::ULong: |
| *reinterpret_cast<ulong*>(ptr) = ulong(QScript::ToInteger(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) { |
| const QString &baseName = QFileInfo(url).baseName(); |
| if (baseName.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) |
| cachedTranslationContext = baseName.mid(4); |
| else |
| cachedTranslationContext = 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 \li Script Function \li Corresponding C++ Function |
| \row \li qsTr() \li QObject::tr() |
| \row \li QT_TR_NOOP() \li QT_TR_NOOP() |
| \row \li qsTranslate() \li QCoreApplication::translate() |
| \row \li QT_TRANSLATE_NOOP() \li QT_TRANSLATE_NOOP() |
| \row \li qsTrId() (since 4.7) \li qtTrId() |
| \row \li QT_TRID_NOOP() (since 4.7) \li 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 Qt Script 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(); |
| std::sort(lst.begin(), lst.end()); |
| 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(); |
| std::sort(lst.begin(), lst.end()); |
| return lst; |
| } |
| |
| /*! \fn template <typename T> 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 Qt Script and C++ Types} for a |
| description of the built-in type conversion provided by |
| Qt Script. By default, the types that are not specially handled by |
| Qt Script 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 template <typename T> 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 Qt Script and C++ Types} for a |
| description of the built-in type conversion provided by |
| Qt Script. |
| |
| \sa toScriptValue(), qScriptRegisterMetaType() |
| */ |
| |
| /*! |
| \fn template <typename T> 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 template <typename T> 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 template <class Container> 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 Qt Script and C++ Types} for more information |
| about the restrictions on types that can be used with QScriptValue. |
| |
| \sa QScriptEngine::fromScriptValue() |
| */ |
| |
| /*! |
| \fn template <class Container> 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 Qt Script and C++ Types} for more information |
| about the restrictions on types that can be used with |
| QScriptValue. |
| |
| \sa qscriptvalue_cast() |
| */ |
| |
| /*! |
| \fn template <typename T> 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 template<typename T> int qScriptRegisterMetaType( |
| QScriptEngine *eng, |
| QScriptValue (*toScriptValue)(QScriptEngine *, const T &t), |
| void (*fromScriptValue)(const QScriptValue &, T &t), |
| const QScriptValue &prototype, T *) |
| |
| \relates QScriptEngine |
| |
| Registers the type \c{T} in the given \a eng. \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 code/src_script_qscriptengine.cpp 20 |
| |
| We must declare it so that the type will be known to QMetaType: |
| |
| \snippet 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 code/src_script_qscriptengine.cpp 22 |
| |
| Now we can register \c{MyStruct} with the engine: |
| \snippet code/src_script_qscriptengine.cpp 23 |
| |
| Working with \c{MyStruct} values is now easy: |
| \snippet 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 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 template<typename T> int qScriptRegisterSequenceMetaType( |
| QScriptEngine *engine, |
| const QScriptValue &prototype, T *) |
| |
| \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 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 \li Input Type \li Result |
| \row \li Undefined \li An invalid QScriptValue. |
| \row \li Null \li An invalid QScriptValue. |
| \row \li Boolean \li A new Boolean object whose internal value is set to the value of the boolean. |
| \row \li Number \li A new Number object whose internal value is set to the value of the number. |
| \row \li String \li A new String object whose internal value is set to the value of the string. |
| \row \li Object \li 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 |
| \inmodule QtScript |
| |
| \brief The QScriptSyntaxCheckResult class provides the result of a script syntax check. |
| |
| \ingroup script |
| |
| 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 |