1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtScript module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL-ONLY$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser
11 ** General Public License version 2.1 as published by the Free Software
12 ** Foundation and appearing in the file LICENSE.LGPL included in the
13 ** packaging of this file.  Please review the following information to
14 ** ensure the GNU Lesser General Public License version 2.1 requirements
15 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** If you have questions regarding the use of this file, please contact
18 ** us via http://www.qt.io/contact-us/.
19 **
20 ** $QT_END_LICENSE$
21 **
22 ****************************************************************************/
23 
24 #include "config.h"
25 #include "qscriptengine.h"
26 #include "qscriptsyntaxchecker_p.h"
27 
28 #include "qscriptengine_p.h"
29 #include "qscriptengineagent_p.h"
30 #include "qscriptcontext_p.h"
31 #include "qscriptstring_p.h"
32 #include "qscriptvalue_p.h"
33 #include "qscriptvalueiterator.h"
34 #include "qscriptclass.h"
35 #include "qscriptcontextinfo.h"
36 #include "qscriptprogram.h"
37 #include "qscriptprogram_p.h"
38 #include "qdebug.h"
39 
40 #include <QtCore/qstringlist.h>
41 #include <QtCore/qmetaobject.h>
42 
43 #include <math.h>
44 
45 #include "CodeBlock.h"
46 #include "Error.h"
47 #include "Interpreter.h"
48 
49 #include "ExceptionHelpers.h"
50 #include "PrototypeFunction.h"
51 #include "InitializeThreading.h"
52 #include "ObjectPrototype.h"
53 #include "SourceCode.h"
54 #include "FunctionPrototype.h"
55 #include "TimeoutChecker.h"
56 #include "JSFunction.h"
57 #include "Parser.h"
58 #include "PropertyNameArray.h"
59 #include "Operations.h"
60 
61 #include "bridge/qscriptfunction_p.h"
62 #include "bridge/qscriptclassobject_p.h"
63 #include "bridge/qscriptvariant_p.h"
64 #include "bridge/qscriptqobject_p.h"
65 #include "bridge/qscriptglobalobject_p.h"
66 #include "bridge/qscriptactivationobject_p.h"
67 #include "bridge/qscriptstaticscopeobject_p.h"
68 
69 #ifndef QT_NO_QOBJECT
70 #include <QtCore/qcoreapplication.h>
71 #include <QtCore/qdir.h>
72 #include <QtCore/qfile.h>
73 #include <QtCore/qfileinfo.h>
74 #include <QtCore/qpluginloader.h>
75 #include <QtCore/qset.h>
76 #include <QtCore/qtextstream.h>
77 #include "qscriptextensioninterface.h"
78 #endif
79 
80 Q_DECLARE_METATYPE(QScriptValue)
81 #ifndef QT_NO_QOBJECT
82 Q_DECLARE_METATYPE(QObjectList)
83 #endif
84 Q_DECLARE_METATYPE(QList<int>)
85 
86 QT_BEGIN_NAMESPACE
87 
88 /*!
89   \since 4.3
90   \class QScriptEngine
91   \reentrant
92 
93   \brief The QScriptEngine class provides an environment for evaluating Qt Script code.
94 
95   \ingroup script
96   \mainclass
97 
98   See the \l{QtScript} documentation for information about the Qt Script language,
99   and how to get started with scripting your C++ application.
100 
101   \section1 Evaluating Scripts
102 
103   Use evaluate() to evaluate script code; this is the C++ equivalent
104   of the built-in script function \c{eval()}.
105 
106   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 0
107 
108   evaluate() returns a QScriptValue that holds the result of the
109   evaluation. The QScriptValue class provides functions for converting
110   the result to various C++ types (e.g. QScriptValue::toString()
111   and QScriptValue::toNumber()).
112 
113   The following code snippet shows how a script function can be
114   defined and then invoked from C++ using QScriptValue::call():
115 
116   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 1
117 
118   As can be seen from the above snippets, a script is provided to the
119   engine in the form of a string. One common way of loading scripts is
120   by reading the contents of a file and passing it to evaluate():
121 
122   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 2
123 
124   Here we pass the name of the file as the second argument to
125   evaluate().  This does not affect evaluation in any way; the second
126   argument is a general-purpose string that is used to identify the
127   script for debugging purposes (for example, our filename will now
128   show up in any uncaughtExceptionBacktrace() involving the script).
129 
130   \section1 Engine Configuration
131 
132   The globalObject() function returns the \bold {Global Object}
133   associated with the script engine. Properties of the Global Object
134   are accessible from any script code (i.e. they are global
135   variables). Typically, before evaluating "user" scripts, you will
136   want to configure a script engine by adding one or more properties
137   to the Global Object:
138 
139   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 3
140 
141   Adding custom properties to the scripting environment is one of the
142   standard means of providing a scripting API that is specific to your
143   application. Usually these custom properties are objects created by
144   the newQObject() or newObject() functions, or constructor functions
145   created by newFunction().
146 
147   \section1 Script Exceptions
148 
149   evaluate() can throw a script exception (e.g. due to a syntax
150   error); in that case, the return value is the value that was thrown
151   (typically an \c{Error} object). You can check whether the
152   evaluation caused an exception by calling hasUncaughtException(). In
153   that case, you can call toString() on the error object to obtain an
154   error message. The current uncaught exception is also available
155   through uncaughtException().
156   Calling clearExceptions() will cause any uncaught exceptions to be
157   cleared.
158 
159   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 4
160 
161   The checkSyntax() function can be used to determine whether code can be
162   usefully passed to evaluate().
163 
164   \section1 Script Object Creation
165 
166   Use newObject() to create a standard Qt Script object; this is the
167   C++ equivalent of the script statement \c{new Object()}. You can use
168   the object-specific functionality in QScriptValue to manipulate the
169   script object (e.g. QScriptValue::setProperty()). Similarly, use
170   newArray() to create a Qt Script array object. Use newDate() to
171   create a \c{Date} object, and newRegExp() to create a \c{RegExp}
172   object.
173 
174   \section1 QObject Integration
175 
176   Use newQObject() to wrap a QObject (or subclass)
177   pointer. newQObject() returns a proxy script object; properties,
178   children, and signals and slots of the QObject are available as
179   properties of the proxy object. No binding code is needed because it
180   is done dynamically using the Qt meta object system.
181 
182   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 5
183 
184   Use qScriptConnect() to connect a C++ signal to a script function;
185   this is the Qt Script equivalent of QObject::connect().  When a
186   script function is invoked in response to a C++ signal, it can cause
187   a script exception; you can connect to the signalHandlerException()
188   signal to catch such an exception.
189 
190   Use newQMetaObject() to wrap a QMetaObject; this gives you a "script
191   representation" of a QObject-based class. newQMetaObject() returns a
192   proxy script object; enum values of the class are available as
193   properties of the proxy object. You can also specify a function that
194   will be used to construct objects of the class (e.g.  when the
195   constructor is invoked from a script). For classes that have a
196   "standard" Qt constructor, Qt Script can provide a default script
197   constructor for you; see scriptValueFromQMetaObject().
198 
199   For more information about QObject integration, see
200   \l{Making Applications Scriptable}
201 
202   \section1 Support for Custom C++ Types
203 
204   Use newVariant() to wrap a QVariant. This can be used to store
205   values of custom (non-QObject) C++ types that have been registered
206   with the Qt meta-type system. To make such types scriptable, you
207   typically associate a prototype (delegate) object with the C++ type
208   by calling setDefaultPrototype(); the prototype object defines the
209   scripting API for the C++ type. Unlike the QObject integration,
210   there is no automatic binding possible here; i.e. you have to create
211   the scripting API yourself, for example by using the QScriptable
212   class.
213 
214   Use fromScriptValue() to cast from a QScriptValue to another type,
215   and toScriptValue() to create a QScriptValue from another value.
216   You can specify how the conversion of C++ types is to be performed
217   with qScriptRegisterMetaType() and qScriptRegisterSequenceMetaType().
218   By default, Qt Script will use QVariant to store values of custom
219   types.
220 
221   \section1 Importing Extensions
222 
223   Use importExtension() to import plugin-based extensions into the
224   engine. Call availableExtensions() to obtain a list naming all the
225   available extensions, and importedExtensions() to obtain a list
226   naming only those extensions that have been imported.
227 
228   Call pushContext() to open up a new variable scope, and popContext()
229   to close the current scope. This is useful if you are implementing
230   an extension that evaluates script code containing temporary
231   variable definitions (e.g. \c{var foo = 123;}) that are safe to
232   discard when evaluation has completed.
233 
234   \section1 Native Functions
235 
236   Use newFunction() to wrap native (C++) functions, including
237   constructors for your own custom types, so that these can be invoked
238   from script code. Such functions must have the signature
239   QScriptEngine::FunctionSignature. You may then pass the function as
240   argument to newFunction(). Here is an example of a function that
241   returns the sum of its first two arguments:
242 
243   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 6
244 
245   To expose this function to script code, you can set it as a property
246   of the Global Object:
247 
248   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 7
249 
250   Once this is done, script code can call your function in the exact
251   same manner as a "normal" script function:
252 
253   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 8
254 
255   \section1 Long-running Scripts
256 
257   If you need to evaluate possibly long-running scripts from the main
258   (GUI) thread, you should first call setProcessEventsInterval() to
259   make sure that the GUI stays responsive. You can abort a currently
260   running script by calling abortEvaluation(). You can determine
261   whether an engine is currently running a script by calling
262   isEvaluating().
263 
264   \section1 Garbage Collection
265 
266   Qt Script objects may be garbage collected when they are no longer
267   referenced. There is no guarantee as to when automatic garbage
268   collection will take place.
269 
270   The collectGarbage() function can be called to explicitly request
271   garbage collection.
272 
273   The reportAdditionalMemoryCost() function can be called to indicate
274   that a Qt Script object occupies memory that isn't managed by the
275   scripting environment. Reporting the additional cost makes it more
276   likely that the garbage collector will be triggered. This can be
277   useful, for example, when many custom, native Qt Script objects are
278   allocated.
279 
280   \section1 Core Debugging/Tracing Facilities
281 
282   Since Qt 4.4, you can be notified of events pertaining to script
283   execution (e.g. script function calls and statement execution)
284   through the QScriptEngineAgent interface; see the setAgent()
285   function. This can be used to implement debugging and profiling of a
286   QScriptEngine.
287 
288   \sa QScriptValue, QScriptContext, QScriptEngineAgent
289 
290 */
291 
292 /*!
293     \enum QScriptEngine::ValueOwnership
294 
295     This enum specifies the ownership when wrapping a C++ value, e.g. by using newQObject().
296 
297     \value QtOwnership The standard Qt ownership rules apply, i.e. the
298     associated object will never be explicitly deleted by the script
299     engine. This is the default. (QObject ownership is explained in
300     \l{Object Trees & Ownership}.)
301 
302     \value ScriptOwnership The value is owned by the script
303     environment. The associated data will be deleted when appropriate
304     (i.e. after the garbage collector has discovered that there are no
305     more live references to the value).
306 
307     \value AutoOwnership If the associated object has a parent, the Qt
308     ownership rules apply (QtOwnership); otherwise, the object is
309     owned by the script environment (ScriptOwnership).
310 
311 */
312 
313 /*!
314     \enum  QScriptEngine::QObjectWrapOption
315 
316     These flags specify options when wrapping a QObject pointer with newQObject().
317 
318     \value ExcludeChildObjects The script object will not expose child objects as properties.
319     \value ExcludeSuperClassMethods The script object will not expose signals and slots inherited from the superclass.
320     \value ExcludeSuperClassProperties The script object will not expose properties inherited from the superclass.
321     \value ExcludeSuperClassContents Shorthand form for ExcludeSuperClassMethods | ExcludeSuperClassProperties
322     \value ExcludeDeleteLater The script object will not expose the QObject::deleteLater() slot.
323     \value ExcludeSlots The script object will not expose the QObject's slots.
324     \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.
325     \value PreferExistingWrapperObject If a wrapper object with the requested configuration already exists, return that object.
326     \value SkipMethodsInEnumeration Don't include methods (signals and slots) when enumerating the object's properties.
327 */
328 
329 class QScriptSyntaxCheckResultPrivate
330 {
331 public:
QScriptSyntaxCheckResultPrivate()332     QScriptSyntaxCheckResultPrivate() { ref = 0; }
~QScriptSyntaxCheckResultPrivate()333     ~QScriptSyntaxCheckResultPrivate() {}
334 
335     QScriptSyntaxCheckResult::State state;
336     int errorColumnNumber;
337     int errorLineNumber;
338     QString errorMessage;
339     QBasicAtomicInt ref;
340 };
341 
342 class QScriptTypeInfo
343 {
344 public:
QScriptTypeInfo()345     QScriptTypeInfo() : signature(0, '\0'), marshal(0), demarshal(0)
346     { }
347 
348     QByteArray signature;
349     QScriptEngine::MarshalFunction marshal;
350     QScriptEngine::DemarshalFunction demarshal;
351     JSC::JSValue prototype;
352 };
353 
354 namespace QScript
355 {
356 
357 static const qsreal D32 = 4294967296.0;
358 
ToInt32(qsreal n)359 qint32 ToInt32(qsreal n)
360 {
361     if (qIsNaN(n) || qIsInf(n) || (n == 0))
362         return 0;
363 
364     qsreal sign = (n < 0) ? -1.0 : 1.0;
365     qsreal abs_n = fabs(n);
366 
367     n = ::fmod(sign * ::floor(abs_n), D32);
368     const double D31 = D32 / 2.0;
369 
370     if (sign == -1 && n < -D31)
371         n += D32;
372 
373     else if (sign != -1 && n >= D31)
374         n -= D32;
375 
376     return qint32 (n);
377 }
378 
ToUInt32(qsreal n)379 quint32 ToUInt32(qsreal n)
380 {
381     if (qIsNaN(n) || qIsInf(n) || (n == 0))
382         return 0;
383 
384     qsreal sign = (n < 0) ? -1.0 : 1.0;
385     qsreal abs_n = fabs(n);
386 
387     n = ::fmod(sign * ::floor(abs_n), D32);
388 
389     if (n < 0)
390         n += D32;
391 
392     return quint32 (n);
393 }
394 
ToUInt16(qsreal n)395 quint16 ToUInt16(qsreal n)
396 {
397     static const qsreal D16 = 65536.0;
398 
399     if (qIsNaN(n) || qIsInf(n) || (n == 0))
400         return 0;
401 
402     qsreal sign = (n < 0) ? -1.0 : 1.0;
403     qsreal abs_n = fabs(n);
404 
405     n = ::fmod(sign * ::floor(abs_n), D16);
406 
407     if (n < 0)
408         n += D16;
409 
410     return quint16 (n);
411 }
412 
ToInteger(qsreal n)413 qsreal ToInteger(qsreal n)
414 {
415     if (qIsNaN(n))
416         return 0;
417 
418     if (n == 0 || qIsInf(n))
419         return n;
420 
421     int sign = n < 0 ? -1 : 1;
422     return sign * ::floor(::fabs(n));
423 }
424 
425 #ifdef Q_CC_MSVC
426 // MSVC2008 crashes if these are inlined.
427 
ToString(qsreal value)428 QString ToString(qsreal value)
429 {
430     return JSC::UString::from(value);
431 }
432 
ToNumber(const QString & value)433 qsreal ToNumber(const QString &value)
434 {
435     return ((JSC::UString)value).toDouble();
436 }
437 
438 #endif
439 
440 static const qsreal MsPerSecond = 1000.0;
441 
MsFromTime(qsreal t)442 static inline int MsFromTime(qsreal t)
443 {
444     int r = int(::fmod(t, MsPerSecond));
445     return (r >= 0) ? r : r + int(MsPerSecond);
446 }
447 
448 /*!
449   \internal
450   Converts a JS date value (milliseconds) to a QDateTime (local time).
451 */
MsToDateTime(JSC::ExecState * exec,qsreal t)452 QDateTime MsToDateTime(JSC::ExecState *exec, qsreal t)
453 {
454     if (qIsNaN(t))
455         return QDateTime();
456     JSC::GregorianDateTime tm;
457     JSC::msToGregorianDateTime(exec, t, /*output UTC=*/true, tm);
458     int ms = MsFromTime(t);
459     QDateTime convertedUTC = QDateTime(QDate(tm.year + 1900, tm.month + 1, tm.monthDay),
460                                        QTime(tm.hour, tm.minute, tm.second, ms), Qt::UTC);
461     return convertedUTC.toLocalTime();
462 }
463 
464 /*!
465   \internal
466   Converts a QDateTime to a JS date value (milliseconds).
467 */
DateTimeToMs(JSC::ExecState * exec,const QDateTime & dt)468 qsreal DateTimeToMs(JSC::ExecState *exec, const QDateTime &dt)
469 {
470     if (!dt.isValid())
471         return qSNaN();
472     QDateTime utc = dt.toUTC();
473     QDate date = utc.date();
474     QTime time = utc.time();
475     JSC::GregorianDateTime tm;
476     tm.year = date.year() - 1900;
477     tm.month = date.month() - 1;
478     tm.monthDay = date.day();
479     tm.weekDay = date.dayOfWeek();
480     tm.yearDay = date.dayOfYear();
481     tm.hour = time.hour();
482     tm.minute = time.minute();
483     tm.second = time.second();
484     return JSC::gregorianDateTimeToMS(exec, tm, time.msec(), /*inputIsUTC=*/true);
485 }
486 
mark(JSC::MarkStack & markStack)487 void GlobalClientData::mark(JSC::MarkStack& markStack)
488 {
489     engine->mark(markStack);
490 }
491 
492 class TimeoutCheckerProxy : public JSC::TimeoutChecker
493 {
494 public:
TimeoutCheckerProxy(const JSC::TimeoutChecker & originalChecker)495     TimeoutCheckerProxy(const JSC::TimeoutChecker& originalChecker)
496         : JSC::TimeoutChecker(originalChecker)
497         , m_shouldProcessEvents(false)
498         , m_shouldAbortEvaluation(false)
499     {}
500 
setShouldProcessEvents(bool shouldProcess)501     void setShouldProcessEvents(bool shouldProcess) { m_shouldProcessEvents = shouldProcess; }
setShouldAbort(bool shouldAbort)502     void setShouldAbort(bool shouldAbort) { m_shouldAbortEvaluation = shouldAbort; }
shouldAbort()503     bool shouldAbort() { return m_shouldAbortEvaluation; }
504 
didTimeOut(JSC::ExecState * exec)505     virtual bool didTimeOut(JSC::ExecState* exec)
506     {
507         if (JSC::TimeoutChecker::didTimeOut(exec))
508             return true;
509 
510         if (m_shouldProcessEvents)
511             QCoreApplication::processEvents();
512 
513         return m_shouldAbortEvaluation;
514     }
515 
516 private:
517     bool m_shouldProcessEvents;
518     bool m_shouldAbortEvaluation;
519 };
520 
toDigit(char c)521 static int toDigit(char c)
522 {
523     if ((c >= '0') && (c <= '9'))
524         return c - '0';
525     else if ((c >= 'a') && (c <= 'z'))
526         return 10 + c - 'a';
527     else if ((c >= 'A') && (c <= 'Z'))
528         return 10 + c - 'A';
529     return -1;
530 }
531 
integerFromString(const char * buf,int size,int radix)532 qsreal integerFromString(const char *buf, int size, int radix)
533 {
534     if (size == 0)
535         return qSNaN();
536 
537     qsreal sign = 1.0;
538     int i = 0;
539     if (buf[0] == '+') {
540         ++i;
541     } else if (buf[0] == '-') {
542         sign = -1.0;
543         ++i;
544     }
545 
546     if (((size-i) >= 2) && (buf[i] == '0')) {
547         if (((buf[i+1] == 'x') || (buf[i+1] == 'X'))
548             && (radix < 34)) {
549             if ((radix != 0) && (radix != 16))
550                 return 0;
551             radix = 16;
552             i += 2;
553         } else {
554             if (radix == 0) {
555                 radix = 8;
556                 ++i;
557             }
558         }
559     } else if (radix == 0) {
560         radix = 10;
561     }
562 
563     int j = i;
564     for ( ; i < size; ++i) {
565         int d = toDigit(buf[i]);
566         if ((d == -1) || (d >= radix))
567             break;
568     }
569     qsreal result;
570     if (j == i) {
571         if (!qstrcmp(buf, "Infinity"))
572             result = qInf();
573         else
574             result = qSNaN();
575     } else {
576         result = 0;
577         qsreal multiplier = 1;
578         for (--i ; i >= j; --i, multiplier *= radix)
579             result += toDigit(buf[i]) * multiplier;
580     }
581     result *= sign;
582     return result;
583 }
584 
integerFromString(const QString & str,int radix)585 qsreal integerFromString(const QString &str, int radix)
586 {
587     QByteArray ba = str.trimmed().toUtf8();
588     return integerFromString(ba.constData(), ba.size(), radix);
589 }
590 
isFunction(JSC::JSValue value)591 bool isFunction(JSC::JSValue value)
592 {
593     if (!value || !value.isObject())
594         return false;
595     JSC::CallData callData;
596     return (JSC::asObject(value)->getCallData(callData) != JSC::CallTypeNone);
597 }
598 
599 static JSC::JSValue JSC_HOST_CALL functionConnect(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
600 static JSC::JSValue JSC_HOST_CALL functionDisconnect(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
601 
functionDisconnect(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue thisObject,const JSC::ArgList & args)602 JSC::JSValue JSC_HOST_CALL functionDisconnect(JSC::ExecState *exec, JSC::JSObject * /*callee*/, JSC::JSValue thisObject, const JSC::ArgList &args)
603 {
604 #ifndef QT_NO_QOBJECT
605     if (args.size() == 0) {
606         return JSC::throwError(exec, JSC::GeneralError, "Function.prototype.disconnect: no arguments given");
607     }
608 
609     if (!JSC::asObject(thisObject)->inherits(&QScript::QtFunction::info)) {
610         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.disconnect: this object is not a signal");
611     }
612 
613     QScript::QtFunction *qtSignal = static_cast<QScript::QtFunction*>(JSC::asObject(thisObject));
614 
615     const QMetaObject *meta = qtSignal->metaObject();
616     if (!meta) {
617         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.discconnect: cannot disconnect from deleted QObject");
618     }
619 
620     QMetaMethod sig = meta->method(qtSignal->initialIndex());
621     if (sig.methodType() != QMetaMethod::Signal) {
622         QString message = QString::fromLatin1("Function.prototype.disconnect: %0::%1 is not a signal")
623                           .arg(QLatin1String(qtSignal->metaObject()->className()))
624                           .arg(QLatin1String(sig.signature()));
625         return JSC::throwError(exec, JSC::TypeError, message);
626     }
627 
628     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
629 
630     JSC::JSValue receiver;
631     JSC::JSValue slot;
632     JSC::JSValue arg0 = args.at(0);
633     if (args.size() < 2) {
634         slot = arg0;
635     } else {
636         receiver = arg0;
637         JSC::JSValue arg1 = args.at(1);
638         if (isFunction(arg1))
639             slot = arg1;
640         else {
641             QScript::SaveFrameHelper saveFrame(engine, exec);
642             JSC::UString propertyName = QScriptEnginePrivate::toString(exec, arg1);
643             slot = QScriptEnginePrivate::property(exec, arg0, propertyName, QScriptValue::ResolvePrototype);
644         }
645     }
646 
647     if (!isFunction(slot)) {
648         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.disconnect: target is not a function");
649     }
650 
651     bool ok = engine->scriptDisconnect(thisObject, receiver, slot);
652     if (!ok) {
653         QString message = QString::fromLatin1("Function.prototype.disconnect: failed to disconnect from %0::%1")
654                           .arg(QLatin1String(qtSignal->metaObject()->className()))
655                           .arg(QLatin1String(sig.signature()));
656         return JSC::throwError(exec, JSC::GeneralError, message);
657     }
658     return JSC::jsUndefined();
659 #else
660     Q_UNUSED(eng);
661     return context->throwError(QScriptContext::TypeError,
662                                QLatin1String("Function.prototype.disconnect"));
663 #endif // QT_NO_QOBJECT
664 }
665 
functionConnect(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue thisObject,const JSC::ArgList & args)666 JSC::JSValue JSC_HOST_CALL functionConnect(JSC::ExecState *exec, JSC::JSObject * /*callee*/, JSC::JSValue thisObject, const JSC::ArgList &args)
667 {
668 #ifndef QT_NO_QOBJECT
669     if (args.size() == 0) {
670         return JSC::throwError(exec, JSC::GeneralError,"Function.prototype.connect: no arguments given");
671     }
672 
673     if (!JSC::asObject(thisObject)->inherits(&QScript::QtFunction::info)) {
674         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: this object is not a signal");
675     }
676 
677     QScript::QtFunction *qtSignal = static_cast<QScript::QtFunction*>(JSC::asObject(thisObject));
678 
679     const QMetaObject *meta = qtSignal->metaObject();
680     if (!meta) {
681         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: cannot connect to deleted QObject");
682     }
683 
684     QMetaMethod sig = meta->method(qtSignal->initialIndex());
685     if (sig.methodType() != QMetaMethod::Signal) {
686         QString message = QString::fromLatin1("Function.prototype.connect: %0::%1 is not a signal")
687                           .arg(QLatin1String(qtSignal->metaObject()->className()))
688                           .arg(QLatin1String(sig.signature()));
689         return JSC::throwError(exec, JSC::TypeError, message);
690     }
691 
692     {
693         QList<int> overloads = qtSignal->overloadedIndexes();
694         if (!overloads.isEmpty()) {
695             overloads.append(qtSignal->initialIndex());
696             QByteArray signature = sig.signature();
697             QString message = QString::fromLatin1("Function.prototype.connect: ambiguous connect to %0::%1(); candidates are\n")
698                               .arg(QLatin1String(qtSignal->metaObject()->className()))
699                               .arg(QLatin1String(signature.left(signature.indexOf('('))));
700             for (int i = 0; i < overloads.size(); ++i) {
701                 QMetaMethod mtd = meta->method(overloads.at(i));
702                 message.append(QString::fromLatin1("    %0\n").arg(QString::fromLatin1(mtd.signature())));
703             }
704             message.append(QString::fromLatin1("Use e.g. object['%0'].connect() to connect to a particular overload")
705                            .arg(QLatin1String(signature)));
706             return JSC::throwError(exec, JSC::GeneralError, message);
707         }
708     }
709 
710     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
711 
712     JSC::JSValue receiver;
713     JSC::JSValue slot;
714     JSC::JSValue arg0 = args.at(0);
715     if (args.size() < 2) {
716         slot = arg0;
717     } else {
718         receiver = arg0;
719         JSC::JSValue arg1 = args.at(1);
720         if (isFunction(arg1))
721             slot = arg1;
722         else {
723             QScript::SaveFrameHelper saveFrame(engine, exec);
724             JSC::UString propertyName = QScriptEnginePrivate::toString(exec, arg1);
725             slot = QScriptEnginePrivate::property(exec, arg0, propertyName, QScriptValue::ResolvePrototype);
726         }
727     }
728 
729     if (!isFunction(slot)) {
730         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: target is not a function");
731     }
732 
733     bool ok = engine->scriptConnect(thisObject, receiver, slot, Qt::AutoConnection);
734     if (!ok) {
735         QString message = QString::fromLatin1("Function.prototype.connect: failed to connect to %0::%1")
736                           .arg(QLatin1String(qtSignal->metaObject()->className()))
737                           .arg(QLatin1String(sig.signature()));
738         return JSC::throwError(exec, JSC::GeneralError, message);
739     }
740     return JSC::jsUndefined();
741 #else
742     Q_UNUSED(eng);
743     Q_UNUSED(classInfo);
744     return context->throwError(QScriptContext::TypeError,
745                                QLatin1String("Function.prototype.connect"));
746 #endif // QT_NO_QOBJECT
747 }
748 
749 static JSC::JSValue JSC_HOST_CALL functionPrint(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
750 static JSC::JSValue JSC_HOST_CALL functionGC(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
751 static JSC::JSValue JSC_HOST_CALL functionVersion(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
752 
functionPrint(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)753 JSC::JSValue JSC_HOST_CALL functionPrint(JSC::ExecState* exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList& args)
754 {
755     QString result;
756     for (unsigned i = 0; i < args.size(); ++i) {
757         if (i != 0)
758             result.append(QLatin1Char(' '));
759         QString s(args.at(i).toString(exec));
760         if (exec->hadException())
761             break;
762         result.append(s);
763     }
764     if (exec->hadException())
765         return exec->exception();
766     qDebug("%s", qPrintable(result));
767     return JSC::jsUndefined();
768 }
769 
functionGC(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue,const JSC::ArgList &)770 JSC::JSValue JSC_HOST_CALL functionGC(JSC::ExecState* exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&)
771 {
772     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
773     engine->collectGarbage();
774     return JSC::jsUndefined();
775 }
776 
functionVersion(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue,const JSC::ArgList &)777 JSC::JSValue JSC_HOST_CALL functionVersion(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&)
778 {
779     return JSC::JSValue(exec, 1);
780 }
781 
782 #ifndef QT_NO_TRANSLATION
783 
784 static JSC::JSValue JSC_HOST_CALL functionQsTranslate(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
785 static JSC::JSValue JSC_HOST_CALL functionQsTranslateNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
786 static JSC::JSValue JSC_HOST_CALL functionQsTr(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
787 static JSC::JSValue JSC_HOST_CALL functionQsTrNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
788 static JSC::JSValue JSC_HOST_CALL functionQsTrId(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
789 static JSC::JSValue JSC_HOST_CALL functionQsTrIdNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
790 
functionQsTranslate(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)791 JSC::JSValue JSC_HOST_CALL functionQsTranslate(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
792 {
793     if (args.size() < 2)
794         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate() requires at least two arguments");
795     if (!args.at(0).isString())
796         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): first argument (context) must be a string");
797     if (!args.at(1).isString())
798         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): second argument (text) must be a string");
799     if ((args.size() > 2) && !args.at(2).isString())
800         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): third argument (comment) must be a string");
801     if ((args.size() > 3) && !args.at(3).isString())
802         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): fourth argument (encoding) must be a string");
803     if ((args.size() > 4) && !args.at(4).isNumber())
804         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): fifth argument (n) must be a number");
805 #ifndef QT_NO_QOBJECT
806     JSC::UString context = args.at(0).toString(exec);
807 #endif
808     JSC::UString text = args.at(1).toString(exec);
809 #ifndef QT_NO_QOBJECT
810     JSC::UString comment;
811     if (args.size() > 2)
812         comment = args.at(2).toString(exec);
813     QCoreApplication::Encoding encoding = QCoreApplication::UnicodeUTF8;
814     if (args.size() > 3) {
815         JSC::UString encStr = args.at(3).toString(exec);
816         if (encStr == "CodecForTr")
817             encoding = QCoreApplication::CodecForTr;
818         else if (encStr == "UnicodeUTF8")
819             encoding = QCoreApplication::UnicodeUTF8;
820         else
821             return JSC::throwError(exec, JSC::GeneralError, QString::fromLatin1("qsTranslate(): invalid encoding '%0'").arg(encStr));
822     }
823     int n = -1;
824     if (args.size() > 4)
825         n = args.at(4).toInt32(exec);
826 #endif
827     JSC::UString result;
828 #ifndef QT_NO_QOBJECT
829     result = QCoreApplication::translate(context.UTF8String().c_str(),
830                                          text.UTF8String().c_str(),
831                                          comment.UTF8String().c_str(),
832                                          encoding, n);
833 #else
834     result = text;
835 #endif
836     return JSC::jsString(exec, result);
837 }
838 
functionQsTranslateNoOp(JSC::ExecState *,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)839 JSC::JSValue JSC_HOST_CALL functionQsTranslateNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
840 {
841     if (args.size() < 2)
842         return JSC::jsUndefined();
843     return args.at(1);
844 }
845 
functionQsTr(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)846 JSC::JSValue JSC_HOST_CALL functionQsTr(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
847 {
848     if (args.size() < 1)
849         return JSC::throwError(exec, JSC::GeneralError, "qsTr() requires at least one argument");
850     if (!args.at(0).isString())
851         return JSC::throwError(exec, JSC::GeneralError, "qsTr(): first argument (text) must be a string");
852     if ((args.size() > 1) && !args.at(1).isString())
853         return JSC::throwError(exec, JSC::GeneralError, "qsTr(): second argument (comment) must be a string");
854     if ((args.size() > 2) && !args.at(2).isNumber())
855         return JSC::throwError(exec, JSC::GeneralError, "qsTr(): third argument (n) must be a number");
856 #ifndef QT_NO_QOBJECT
857     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
858     JSC::UString context;
859     // The first non-empty source URL in the call stack determines the translation context.
860     {
861         JSC::ExecState *frame = exec->callerFrame()->removeHostCallFrameFlag();
862         while (frame) {
863             if (frame->codeBlock() && QScriptEnginePrivate::hasValidCodeBlockRegister(frame)
864                 && frame->codeBlock()->source()
865                 && !frame->codeBlock()->source()->url().isEmpty()) {
866                 context = engine->translationContextFromUrl(frame->codeBlock()->source()->url());
867                 break;
868             }
869             frame = frame->callerFrame()->removeHostCallFrameFlag();
870         }
871     }
872 #endif
873     JSC::UString text = args.at(0).toString(exec);
874 #ifndef QT_NO_QOBJECT
875     JSC::UString comment;
876     if (args.size() > 1)
877         comment = args.at(1).toString(exec);
878     int n = -1;
879     if (args.size() > 2)
880         n = args.at(2).toInt32(exec);
881 #endif
882     JSC::UString result;
883 #ifndef QT_NO_QOBJECT
884     result = QCoreApplication::translate(context.UTF8String().c_str(),
885                                          text.UTF8String().c_str(),
886                                          comment.UTF8String().c_str(),
887                                          QCoreApplication::UnicodeUTF8, n);
888 #else
889     result = text;
890 #endif
891     return JSC::jsString(exec, result);
892 }
893 
functionQsTrNoOp(JSC::ExecState *,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)894 JSC::JSValue JSC_HOST_CALL functionQsTrNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
895 {
896     if (args.size() < 1)
897         return JSC::jsUndefined();
898     return args.at(0);
899 }
900 
functionQsTrId(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)901 JSC::JSValue JSC_HOST_CALL functionQsTrId(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
902 {
903     if (args.size() < 1)
904         return JSC::throwError(exec, JSC::GeneralError, "qsTrId() requires at least one argument");
905     if (!args.at(0).isString())
906         return JSC::throwError(exec, JSC::TypeError, "qsTrId(): first argument (id) must be a string");
907     if ((args.size() > 1) && !args.at(1).isNumber())
908         return JSC::throwError(exec, JSC::TypeError, "qsTrId(): second argument (n) must be a number");
909     JSC::UString id = args.at(0).toString(exec);
910     int n = -1;
911     if (args.size() > 1)
912         n = args.at(1).toInt32(exec);
913     return JSC::jsString(exec, qtTrId(id.UTF8String().c_str(), n));
914 }
915 
functionQsTrIdNoOp(JSC::ExecState *,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)916 JSC::JSValue JSC_HOST_CALL functionQsTrIdNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
917 {
918     if (args.size() < 1)
919         return JSC::jsUndefined();
920     return args.at(0);
921 }
922 #endif // QT_NO_TRANSLATION
923 
924 static JSC::JSValue JSC_HOST_CALL stringProtoFuncArg(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
925 
stringProtoFuncArg(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue thisObject,const JSC::ArgList & args)926 JSC::JSValue JSC_HOST_CALL stringProtoFuncArg(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisObject, const JSC::ArgList &args)
927 {
928     QString value(thisObject.toString(exec));
929     JSC::JSValue arg = (args.size() != 0) ? args.at(0) : JSC::jsUndefined();
930     QString result;
931     if (arg.isString())
932         result = value.arg(arg.toString(exec));
933     else if (arg.isNumber())
934         result = value.arg(arg.toNumber(exec));
935     return JSC::jsString(exec, result);
936 }
937 
938 
939 #if !defined(QT_NO_QOBJECT) && !defined(QT_NO_LIBRARY)
__setupPackage__(QScriptContext * ctx,QScriptEngine * eng)940 static QScriptValue __setupPackage__(QScriptContext *ctx, QScriptEngine *eng)
941 {
942     QString path = ctx->argument(0).toString();
943     QStringList components = path.split(QLatin1Char('.'));
944     QScriptValue o = eng->globalObject();
945     for (int i = 0; i < components.count(); ++i) {
946         QString name = components.at(i);
947         QScriptValue oo = o.property(name);
948         if (!oo.isValid()) {
949             oo = eng->newObject();
950             o.setProperty(name, oo);
951         }
952         o = oo;
953     }
954     return o;
955 }
956 #endif
957 
958 } // namespace QScript
959 
QScriptEnginePrivate()960 QScriptEnginePrivate::QScriptEnginePrivate()
961     : originalGlobalObjectProxy(0), currentFrame(0),
962       qobjectPrototype(0), qmetaobjectPrototype(0), variantPrototype(0),
963       activeAgent(0), agentLineNumber(-1),
964       registeredScriptValues(0), freeScriptValues(0), freeScriptValuesCount(0),
965       registeredScriptStrings(0), processEventsInterval(-1), inEval(false)
966 {
967     qMetaTypeId<QScriptValue>();
968     qMetaTypeId<QList<int> >();
969 #ifndef QT_NO_QOBJECT
970     qMetaTypeId<QObjectList>();
971 #endif
972 
973     if (!QCoreApplication::instance()) {
974         qFatal("QScriptEngine: Must construct a Q(Core)Application before a QScriptEngine");
975         return;
976     }
977     JSC::initializeThreading();
978     JSC::IdentifierTable *oldTable = JSC::currentIdentifierTable();
979     globalData = JSC::JSGlobalData::create().releaseRef();
980     globalData->clientData = new QScript::GlobalClientData(this);
981     JSC::JSGlobalObject *globalObject = new (globalData)QScript::GlobalObject();
982 
983     JSC::ExecState* exec = globalObject->globalExec();
984 
985     scriptObjectStructure = QScriptObject::createStructure(globalObject->objectPrototype());
986     staticScopeObjectStructure = QScriptStaticScopeObject::createStructure(JSC::jsNull());
987 
988     qobjectPrototype = new (exec) QScript::QObjectPrototype(exec, QScript::QObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
989     qobjectWrapperObjectStructure = QScriptObject::createStructure(qobjectPrototype);
990 
991     qmetaobjectPrototype = new (exec) QScript::QMetaObjectPrototype(exec, QScript::QMetaObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
992     qmetaobjectWrapperObjectStructure = QScript::QMetaObjectWrapperObject::createStructure(qmetaobjectPrototype);
993 
994     variantPrototype = new (exec) QScript::QVariantPrototype(exec, QScript::QVariantPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
995     variantWrapperObjectStructure = QScriptObject::createStructure(variantPrototype);
996 
997     globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "print"), QScript::functionPrint));
998     globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 0, JSC::Identifier(exec, "gc"), QScript::functionGC));
999     globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 0, JSC::Identifier(exec, "version"), QScript::functionVersion));
1000 
1001     // ### rather than extending Function.prototype, consider creating a QtSignal.prototype
1002     globalObject->functionPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "disconnect"), QScript::functionDisconnect));
1003     globalObject->functionPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "connect"), QScript::functionConnect));
1004 
1005     JSC::TimeoutChecker* originalChecker = globalData->timeoutChecker;
1006     globalData->timeoutChecker = new QScript::TimeoutCheckerProxy(*originalChecker);
1007     delete originalChecker;
1008 
1009     currentFrame = exec;
1010 
1011     cachedTranslationUrl = JSC::UString();
1012     cachedTranslationContext = JSC::UString();
1013     JSC::setCurrentIdentifierTable(oldTable);
1014 }
1015 
~QScriptEnginePrivate()1016 QScriptEnginePrivate::~QScriptEnginePrivate()
1017 {
1018     QScript::APIShim shim(this);
1019 
1020     //disconnect all loadedScripts and generate all jsc::debugger::scriptUnload events
1021     QHash<intptr_t,QScript::UStringSourceProviderWithFeedback*>::const_iterator it;
1022     for (it = loadedScripts.constBegin(); it != loadedScripts.constEnd(); ++it)
1023         it.value()->disconnectFromEngine();
1024 
1025     while (!ownedAgents.isEmpty())
1026         delete ownedAgents.takeFirst();
1027 
1028     detachAllRegisteredScriptPrograms();
1029     detachAllRegisteredScriptValues();
1030     detachAllRegisteredScriptStrings();
1031     qDeleteAll(m_qobjectData);
1032     qDeleteAll(m_typeInfos);
1033     globalData->heap.destroy();
1034     globalData->deref();
1035     while (freeScriptValues) {
1036         QScriptValuePrivate *p = freeScriptValues;
1037         freeScriptValues = p->next;
1038         qFree(p);
1039     }
1040 }
1041 
jscValueToVariant(JSC::ExecState * exec,JSC::JSValue value,int targetType)1042 QVariant QScriptEnginePrivate::jscValueToVariant(JSC::ExecState *exec, JSC::JSValue value, int targetType)
1043 {
1044     QVariant v(targetType, (void *)0);
1045     if (convertValue(exec, value, targetType, v.data()))
1046         return v;
1047     if (uint(targetType) == QVariant::LastType)
1048         return toVariant(exec, value);
1049     if (isVariant(value)) {
1050         v = variantValue(value);
1051         if (v.canConvert(QVariant::Type(targetType))) {
1052             v.convert(QVariant::Type(targetType));
1053             return v;
1054         }
1055         QByteArray typeName = v.typeName();
1056         if (typeName.endsWith('*')
1057             && (QMetaType::type(typeName.left(typeName.size()-1)) == targetType)) {
1058             return QVariant(targetType, *reinterpret_cast<void* *>(v.data()));
1059         }
1060     }
1061     return QVariant();
1062 }
1063 
arrayFromStringList(JSC::ExecState * exec,const QStringList & lst)1064 JSC::JSValue QScriptEnginePrivate::arrayFromStringList(JSC::ExecState *exec, const QStringList &lst)
1065 {
1066     JSC::JSValue arr =  newArray(exec, lst.size());
1067     for (int i = 0; i < lst.size(); ++i)
1068         setProperty(exec, arr, i, JSC::jsString(exec, lst.at(i)));
1069     return arr;
1070 }
1071 
stringListFromArray(JSC::ExecState * exec,JSC::JSValue arr)1072 QStringList QScriptEnginePrivate::stringListFromArray(JSC::ExecState *exec, JSC::JSValue arr)
1073 {
1074     QStringList lst;
1075     uint len = toUInt32(exec, property(exec, arr, exec->propertyNames().length));
1076     for (uint i = 0; i < len; ++i)
1077         lst.append(toString(exec, property(exec, arr, i)));
1078     return lst;
1079 }
1080 
arrayFromVariantList(JSC::ExecState * exec,const QVariantList & lst)1081 JSC::JSValue QScriptEnginePrivate::arrayFromVariantList(JSC::ExecState *exec, const QVariantList &lst)
1082 {
1083     JSC::JSValue arr = newArray(exec, lst.size());
1084     for (int i = 0; i < lst.size(); ++i)
1085         setProperty(exec, arr, i, jscValueFromVariant(exec, lst.at(i)));
1086     return arr;
1087 }
1088 
variantListFromArray(JSC::ExecState * exec,JSC::JSArray * arr)1089 QVariantList QScriptEnginePrivate::variantListFromArray(JSC::ExecState *exec, JSC::JSArray *arr)
1090 {
1091     QScriptEnginePrivate *eng = QScript::scriptEngineFromExec(exec);
1092     if (eng->visitedConversionObjects.contains(arr))
1093         return QVariantList(); // Avoid recursion.
1094     eng->visitedConversionObjects.insert(arr);
1095     QVariantList lst;
1096     uint len = toUInt32(exec, property(exec, arr, exec->propertyNames().length));
1097     for (uint i = 0; i < len; ++i)
1098         lst.append(toVariant(exec, property(exec, arr, i)));
1099     eng->visitedConversionObjects.remove(arr);
1100     return lst;
1101 }
1102 
objectFromVariantMap(JSC::ExecState * exec,const QVariantMap & vmap)1103 JSC::JSValue QScriptEnginePrivate::objectFromVariantMap(JSC::ExecState *exec, const QVariantMap &vmap)
1104 {
1105     JSC::JSValue obj = JSC::constructEmptyObject(exec);
1106     QVariantMap::const_iterator it;
1107     for (it = vmap.constBegin(); it != vmap.constEnd(); ++it)
1108         setProperty(exec, obj, it.key(), jscValueFromVariant(exec, it.value()));
1109     return obj;
1110 }
1111 
variantMapFromObject(JSC::ExecState * exec,JSC::JSObject * obj)1112 QVariantMap QScriptEnginePrivate::variantMapFromObject(JSC::ExecState *exec, JSC::JSObject *obj)
1113 {
1114     QScriptEnginePrivate *eng = QScript::scriptEngineFromExec(exec);
1115     if (eng->visitedConversionObjects.contains(obj))
1116         return QVariantMap(); // Avoid recursion.
1117     eng->visitedConversionObjects.insert(obj);
1118     JSC::PropertyNameArray propertyNames(exec);
1119     obj->getOwnPropertyNames(exec, propertyNames, JSC::IncludeDontEnumProperties);
1120     QVariantMap vmap;
1121     JSC::PropertyNameArray::const_iterator it = propertyNames.begin();
1122     for( ; it != propertyNames.end(); ++it)
1123         vmap.insert(it->ustring(), toVariant(exec, property(exec, obj, *it)));
1124     eng->visitedConversionObjects.remove(obj);
1125     return vmap;
1126 }
1127 
defaultPrototype(int metaTypeId) const1128 JSC::JSValue QScriptEnginePrivate::defaultPrototype(int metaTypeId) const
1129 {
1130     QScriptTypeInfo *info = m_typeInfos.value(metaTypeId);
1131     if (!info)
1132         return JSC::JSValue();
1133     return info->prototype;
1134 }
1135 
setDefaultPrototype(int metaTypeId,JSC::JSValue prototype)1136 void QScriptEnginePrivate::setDefaultPrototype(int metaTypeId, JSC::JSValue prototype)
1137 {
1138     QScriptTypeInfo *info = m_typeInfos.value(metaTypeId);
1139     if (!info) {
1140         info = new QScriptTypeInfo();
1141         m_typeInfos.insert(metaTypeId, info);
1142     }
1143     info->prototype = prototype;
1144 }
1145 
originalGlobalObject() const1146 JSC::JSGlobalObject *QScriptEnginePrivate::originalGlobalObject() const
1147 {
1148     return globalData->head;
1149 }
1150 
customGlobalObject() const1151 JSC::JSObject *QScriptEnginePrivate::customGlobalObject() const
1152 {
1153     QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
1154     return glob->customGlobalObject;
1155 }
1156 
getOriginalGlobalObjectProxy()1157 JSC::JSObject *QScriptEnginePrivate::getOriginalGlobalObjectProxy()
1158 {
1159     if (!originalGlobalObjectProxy) {
1160         JSC::ExecState* exec = currentFrame;
1161         originalGlobalObjectProxy = new (exec)QScript::OriginalGlobalObjectProxy(scriptObjectStructure, originalGlobalObject());
1162     }
1163     return originalGlobalObjectProxy;
1164 }
1165 
globalObject() const1166 JSC::JSObject *QScriptEnginePrivate::globalObject() const
1167 {
1168     QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
1169     if (glob->customGlobalObject)
1170         return glob->customGlobalObject;
1171     return glob;
1172 }
1173 
setGlobalObject(JSC::JSObject * object)1174 void QScriptEnginePrivate::setGlobalObject(JSC::JSObject *object)
1175 {
1176     if (object == globalObject())
1177         return;
1178     QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
1179     if (object == originalGlobalObjectProxy) {
1180         glob->customGlobalObject = 0;
1181         // Sync the internal prototype, since JSObject::prototype() is not virtual.
1182         glob->setPrototype(originalGlobalObjectProxy->prototype());
1183     } else {
1184         Q_ASSERT(object != originalGlobalObject());
1185         glob->customGlobalObject = object;
1186         // Sync the internal prototype, since JSObject::prototype() is not virtual.
1187         glob->setPrototype(object->prototype());
1188     }
1189 }
1190 
1191 /*!
1192   \internal
1193 
1194   If the given \a value is the original global object, returns the custom
1195   global object or a proxy to the original global object; otherwise returns \a
1196   value.
1197 */
toUsableValue(JSC::JSValue value)1198 JSC::JSValue QScriptEnginePrivate::toUsableValue(JSC::JSValue value)
1199 {
1200     if (!value || !value.isObject() || !JSC::asObject(value)->isGlobalObject())
1201         return value;
1202     Q_ASSERT(JSC::asObject(value) == originalGlobalObject());
1203     if (customGlobalObject())
1204         return customGlobalObject();
1205     if (!originalGlobalObjectProxy)
1206         originalGlobalObjectProxy = new (currentFrame)QScript::OriginalGlobalObjectProxy(scriptObjectStructure, originalGlobalObject());
1207     return originalGlobalObjectProxy;
1208 }
1209 /*!
1210     \internal
1211     Return the 'this' value for a given context
1212 */
thisForContext(JSC::ExecState * frame)1213 JSC::JSValue QScriptEnginePrivate::thisForContext(JSC::ExecState *frame)
1214 {
1215     if (frame->codeBlock() != 0) {
1216         return frame->thisValue();
1217     } else if(frame == frame->lexicalGlobalObject()->globalExec()) {
1218         return frame->globalThisValue();
1219     } else {
1220         JSC::Register *thisRegister = thisRegisterForFrame(frame);
1221         return thisRegister->jsValue();
1222     }
1223 }
1224 
thisRegisterForFrame(JSC::ExecState * frame)1225 JSC::Register* QScriptEnginePrivate::thisRegisterForFrame(JSC::ExecState *frame)
1226 {
1227     Q_ASSERT(frame->codeBlock() == 0); // only for native calls
1228     return frame->registers() - JSC::RegisterFile::CallFrameHeaderSize - frame->argumentCount();
1229 }
1230 
1231 /*! \internal
1232      For native context, we use the ReturnValueRegister entry in the stackframe header to store flags.
1233      We can do that because this header is not used as the native function return their value thought C++
1234 
1235      when setting flags, NativeContext should always be set
1236 
1237      contextFlags returns 0 for non native context
1238  */
contextFlags(JSC::ExecState * exec)1239 uint QScriptEnginePrivate::contextFlags(JSC::ExecState *exec)
1240 {
1241     if (exec->codeBlock())
1242         return 0; //js function doesn't have flags
1243 
1244     return exec->returnValueRegister();
1245 }
1246 
setContextFlags(JSC::ExecState * exec,uint flags)1247 void QScriptEnginePrivate::setContextFlags(JSC::ExecState *exec, uint flags)
1248 {
1249     Q_ASSERT(!exec->codeBlock());
1250     exec->registers()[JSC::RegisterFile::ReturnValueRegister] = JSC::Register::withInt(flags);
1251 }
1252 
1253 
mark(JSC::MarkStack & markStack)1254 void QScriptEnginePrivate::mark(JSC::MarkStack& markStack)
1255 {
1256     Q_Q(QScriptEngine);
1257 
1258     if (originalGlobalObject()) {
1259         markStack.append(originalGlobalObject());
1260         markStack.append(globalObject());
1261         if (originalGlobalObjectProxy)
1262             markStack.append(originalGlobalObjectProxy);
1263     }
1264 
1265     if (qobjectPrototype)
1266         markStack.append(qobjectPrototype);
1267     if (qmetaobjectPrototype)
1268         markStack.append(qmetaobjectPrototype);
1269     if (variantPrototype)
1270         markStack.append(variantPrototype);
1271 
1272     {
1273         QScriptValuePrivate *it;
1274         for (it = registeredScriptValues; it != 0; it = it->next) {
1275             if (it->isJSC())
1276                 markStack.append(it->jscValue);
1277         }
1278     }
1279 
1280     {
1281         QHash<int, QScriptTypeInfo*>::const_iterator it;
1282         for (it = m_typeInfos.constBegin(); it != m_typeInfos.constEnd(); ++it) {
1283             if ((*it)->prototype)
1284                 markStack.append((*it)->prototype);
1285         }
1286     }
1287 
1288     if (q) {
1289         QScriptContext *context = q->currentContext();
1290 
1291         while (context) {
1292             JSC::ScopeChainNode *node = frameForContext(context)->scopeChain();
1293             JSC::ScopeChainIterator it(node);
1294             for (it = node->begin(); it != node->end(); ++it) {
1295                 JSC::JSObject *object = *it;
1296                 if (object)
1297                     markStack.append(object);
1298             }
1299 
1300             context = context->parentContext();
1301         }
1302     }
1303 
1304 #ifndef QT_NO_QOBJECT
1305     markStack.drain(); // make sure everything is marked before marking qobject data
1306     {
1307         QHash<QObject*, QScript::QObjectData*>::const_iterator it;
1308         for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) {
1309             QScript::QObjectData *qdata = it.value();
1310             qdata->mark(markStack);
1311         }
1312     }
1313 #endif
1314 }
1315 
isCollecting() const1316 bool QScriptEnginePrivate::isCollecting() const
1317 {
1318     return globalData->heap.isBusy();
1319 }
1320 
collectGarbage()1321 void QScriptEnginePrivate::collectGarbage()
1322 {
1323     QScript::APIShim shim(this);
1324     globalData->heap.collectAllGarbage();
1325 }
1326 
reportAdditionalMemoryCost(int size)1327 void QScriptEnginePrivate::reportAdditionalMemoryCost(int size)
1328 {
1329     if (size > 0)
1330         globalData->heap.reportExtraMemoryCost(size);
1331 }
1332 
timeoutChecker() const1333 QScript::TimeoutCheckerProxy *QScriptEnginePrivate::timeoutChecker() const
1334 {
1335     return static_cast<QScript::TimeoutCheckerProxy*>(globalData->timeoutChecker);
1336 }
1337 
agentDeleted(QScriptEngineAgent * agent)1338 void QScriptEnginePrivate::agentDeleted(QScriptEngineAgent *agent)
1339 {
1340     ownedAgents.removeOne(agent);
1341     if (activeAgent == agent) {
1342         QScriptEngineAgentPrivate::get(agent)->detach();
1343         activeAgent = 0;
1344     }
1345 }
1346 
evaluateHelper(JSC::ExecState * exec,intptr_t sourceId,JSC::EvalExecutable * executable,bool & compile)1347 JSC::JSValue QScriptEnginePrivate::evaluateHelper(JSC::ExecState *exec, intptr_t sourceId,
1348                                                   JSC::EvalExecutable *executable,
1349                                                   bool &compile)
1350 {
1351     Q_Q(QScriptEngine);
1352     QBoolBlocker inEvalBlocker(inEval, true);
1353     q->currentContext()->activationObject(); //force the creation of a context for native function;
1354 
1355     JSC::Debugger* debugger = originalGlobalObject()->debugger();
1356     if (debugger)
1357         debugger->evaluateStart(sourceId);
1358 
1359     q->clearExceptions();
1360     JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject);
1361 
1362     if (compile && !executable->isCompiled()) {
1363         JSC::JSObject* error = executable->compile(exec, exec->scopeChain());
1364         if (error) {
1365             compile = false;
1366             exec->setException(error);
1367 
1368             if (debugger) {
1369                 debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, error), sourceId, false);
1370                 debugger->evaluateStop(error, sourceId);
1371             }
1372 
1373             return error;
1374         }
1375     }
1376 
1377     JSC::JSValue thisValue = thisForContext(exec);
1378     JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull())
1379                                 ? exec->dynamicGlobalObject() : thisValue.toObject(exec);
1380     JSC::JSValue exceptionValue;
1381     timeoutChecker()->setShouldAbort(false);
1382     if (processEventsInterval > 0)
1383         timeoutChecker()->reset();
1384 
1385     JSC::JSValue result = exec->interpreter()->execute(executable, exec, thisObject, exec->scopeChain(), &exceptionValue);
1386 
1387     if (timeoutChecker()->shouldAbort()) {
1388         if (abortResult.isError())
1389             exec->setException(scriptValueToJSCValue(abortResult));
1390 
1391         if (debugger)
1392             debugger->evaluateStop(scriptValueToJSCValue(abortResult), sourceId);
1393 
1394         return scriptValueToJSCValue(abortResult);
1395     }
1396 
1397     if (exceptionValue) {
1398         exec->setException(exceptionValue);
1399 
1400         if (debugger)
1401             debugger->evaluateStop(exceptionValue, sourceId);
1402 
1403         return exceptionValue;
1404     }
1405 
1406     if (debugger)
1407         debugger->evaluateStop(result, sourceId);
1408 
1409     Q_ASSERT(!exec->hadException());
1410     return result;
1411 }
1412 
1413 #ifndef QT_NO_QOBJECT
1414 
newQObject(QObject * object,QScriptEngine::ValueOwnership ownership,const QScriptEngine::QObjectWrapOptions & options)1415 JSC::JSValue QScriptEnginePrivate::newQObject(
1416     QObject *object, QScriptEngine::ValueOwnership ownership,
1417     const QScriptEngine::QObjectWrapOptions &options)
1418 {
1419     if (!object)
1420         return JSC::jsNull();
1421     JSC::ExecState* exec = currentFrame;
1422     QScript::QObjectData *data = qobjectData(object);
1423     bool preferExisting = (options & QScriptEngine::PreferExistingWrapperObject) != 0;
1424     QScriptEngine::QObjectWrapOptions opt = options & ~QScriptEngine::PreferExistingWrapperObject;
1425     QScriptObject *result = 0;
1426     if (preferExisting) {
1427         result = data->findWrapper(ownership, opt);
1428         if (result)
1429             return result;
1430     }
1431     result = new (exec) QScriptObject(qobjectWrapperObjectStructure);
1432     if (preferExisting)
1433         data->registerWrapper(result, ownership, opt);
1434     result->setDelegate(new QScript::QObjectDelegate(object, ownership, options));
1435     /*if (setDefaultPrototype)*/ {
1436         const QMetaObject *meta = object->metaObject();
1437         while (meta) {
1438             QByteArray typeString = meta->className();
1439             typeString.append('*');
1440             int typeId = QMetaType::type(typeString);
1441             if (typeId != 0) {
1442                 JSC::JSValue proto = defaultPrototype(typeId);
1443                 if (proto) {
1444                     result->setPrototype(proto);
1445                     break;
1446                 }
1447             }
1448             meta = meta->superClass();
1449         }
1450     }
1451     return result;
1452 }
1453 
newQMetaObject(const QMetaObject * metaObject,JSC::JSValue ctor)1454 JSC::JSValue QScriptEnginePrivate::newQMetaObject(
1455     const QMetaObject *metaObject, JSC::JSValue ctor)
1456 {
1457     if (!metaObject)
1458         return JSC::jsNull();
1459     JSC::ExecState* exec = currentFrame;
1460     QScript::QMetaObjectWrapperObject *result = new (exec) QScript::QMetaObjectWrapperObject(exec, metaObject, ctor, qmetaobjectWrapperObjectStructure);
1461     return result;
1462 }
1463 
convertToNativeQObject(JSC::ExecState * exec,JSC::JSValue value,const QByteArray & targetType,void ** result)1464 bool QScriptEnginePrivate::convertToNativeQObject(JSC::ExecState *exec, JSC::JSValue value,
1465                                                   const QByteArray &targetType,
1466                                                   void **result)
1467 {
1468     if (!targetType.endsWith('*'))
1469         return false;
1470     if (QObject *qobject = toQObject(exec, value)) {
1471         int start = targetType.startsWith("const ") ? 6 : 0;
1472         QByteArray className = targetType.mid(start, targetType.size()-start-1);
1473         if (void *instance = qobject->qt_metacast(className)) {
1474             *result = instance;
1475             return true;
1476         }
1477     }
1478     return false;
1479 }
1480 
qobjectData(QObject * object)1481 QScript::QObjectData *QScriptEnginePrivate::qobjectData(QObject *object)
1482 {
1483     QHash<QObject*, QScript::QObjectData*>::const_iterator it;
1484     it = m_qobjectData.constFind(object);
1485     if (it != m_qobjectData.constEnd())
1486         return it.value();
1487 
1488     QScript::QObjectData *data = new QScript::QObjectData(this);
1489     m_qobjectData.insert(object, data);
1490     QObject::connect(object, SIGNAL(destroyed(QObject*)),
1491                      q_func(), SLOT(_q_objectDestroyed(QObject*)));
1492     return data;
1493 }
1494 
_q_objectDestroyed(QObject * object)1495 void QScriptEnginePrivate::_q_objectDestroyed(QObject *object)
1496 {
1497     QHash<QObject*, QScript::QObjectData*>::iterator it;
1498     it = m_qobjectData.find(object);
1499     Q_ASSERT(it != m_qobjectData.end());
1500     QScript::QObjectData *data = it.value();
1501     m_qobjectData.erase(it);
1502     delete data;
1503 }
1504 
disposeQObject(QObject * object)1505 void QScriptEnginePrivate::disposeQObject(QObject *object)
1506 {
1507     // TODO
1508 /*    if (isCollecting()) {
1509         // wait until we're done with GC before deleting it
1510         int index = m_qobjectsToBeDeleted.indexOf(object);
1511         if (index == -1)
1512             m_qobjectsToBeDeleted.append(object);
1513             } else*/ {
1514         delete object;
1515     }
1516 }
1517 
emitSignalHandlerException()1518 void QScriptEnginePrivate::emitSignalHandlerException()
1519 {
1520     Q_Q(QScriptEngine);
1521     emit q->signalHandlerException(q->uncaughtException());
1522 }
1523 
scriptConnect(QObject * sender,const char * signal,JSC::JSValue receiver,JSC::JSValue function,Qt::ConnectionType type)1524 bool QScriptEnginePrivate::scriptConnect(QObject *sender, const char *signal,
1525                                          JSC::JSValue receiver, JSC::JSValue function,
1526                                          Qt::ConnectionType type)
1527 {
1528     Q_ASSERT(sender);
1529     Q_ASSERT(signal);
1530     const QMetaObject *meta = sender->metaObject();
1531     int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
1532     if (index == -1)
1533         return false;
1534     return scriptConnect(sender, index, receiver, function, /*wrapper=*/JSC::JSValue(), type);
1535 }
1536 
scriptDisconnect(QObject * sender,const char * signal,JSC::JSValue receiver,JSC::JSValue function)1537 bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, const char *signal,
1538                                             JSC::JSValue receiver, JSC::JSValue function)
1539 {
1540     Q_ASSERT(sender);
1541     Q_ASSERT(signal);
1542     const QMetaObject *meta = sender->metaObject();
1543     int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
1544     if (index == -1)
1545         return false;
1546     return scriptDisconnect(sender, index, receiver, function);
1547 }
1548 
scriptConnect(QObject * sender,int signalIndex,JSC::JSValue receiver,JSC::JSValue function,JSC::JSValue senderWrapper,Qt::ConnectionType type)1549 bool QScriptEnginePrivate::scriptConnect(QObject *sender, int signalIndex,
1550                                          JSC::JSValue receiver, JSC::JSValue function,
1551                                          JSC::JSValue senderWrapper,
1552                                          Qt::ConnectionType type)
1553 {
1554     QScript::QObjectData *data = qobjectData(sender);
1555     return data->addSignalHandler(sender, signalIndex, receiver, function, senderWrapper, type);
1556 }
1557 
scriptDisconnect(QObject * sender,int signalIndex,JSC::JSValue receiver,JSC::JSValue function)1558 bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, int signalIndex,
1559                                             JSC::JSValue receiver, JSC::JSValue function)
1560 {
1561     QScript::QObjectData *data = qobjectData(sender);
1562     if (!data)
1563         return false;
1564     return data->removeSignalHandler(sender, signalIndex, receiver, function);
1565 }
1566 
scriptConnect(JSC::JSValue signal,JSC::JSValue receiver,JSC::JSValue function,Qt::ConnectionType type)1567 bool QScriptEnginePrivate::scriptConnect(JSC::JSValue signal, JSC::JSValue receiver,
1568                                          JSC::JSValue function, Qt::ConnectionType type)
1569 {
1570     QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(JSC::asObject(signal));
1571     int index = fun->mostGeneralMethod();
1572     return scriptConnect(fun->qobject(), index, receiver, function, fun->wrapperObject(), type);
1573 }
1574 
scriptDisconnect(JSC::JSValue signal,JSC::JSValue receiver,JSC::JSValue function)1575 bool QScriptEnginePrivate::scriptDisconnect(JSC::JSValue signal, JSC::JSValue receiver,
1576                                             JSC::JSValue function)
1577 {
1578     QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(JSC::asObject(signal));
1579     int index = fun->mostGeneralMethod();
1580     return scriptDisconnect(fun->qobject(), index, receiver, function);
1581 }
1582 
1583 #endif
1584 
detachAllRegisteredScriptPrograms()1585 void QScriptEnginePrivate::detachAllRegisteredScriptPrograms()
1586 {
1587     QSet<QScriptProgramPrivate*>::const_iterator it;
1588     for (it = registeredScriptPrograms.constBegin(); it != registeredScriptPrograms.constEnd(); ++it)
1589         (*it)->detachFromEngine();
1590     registeredScriptPrograms.clear();
1591 }
1592 
detachAllRegisteredScriptValues()1593 void QScriptEnginePrivate::detachAllRegisteredScriptValues()
1594 {
1595     QScriptValuePrivate *it;
1596     QScriptValuePrivate *next;
1597     for (it = registeredScriptValues; it != 0; it = next) {
1598         it->detachFromEngine();
1599         next = it->next;
1600         it->prev = 0;
1601         it->next = 0;
1602     }
1603     registeredScriptValues = 0;
1604 }
1605 
detachAllRegisteredScriptStrings()1606 void QScriptEnginePrivate::detachAllRegisteredScriptStrings()
1607 {
1608     QScriptStringPrivate *it;
1609     QScriptStringPrivate *next;
1610     for (it = registeredScriptStrings; it != 0; it = next) {
1611         it->detachFromEngine();
1612         next = it->next;
1613         it->prev = 0;
1614         it->next = 0;
1615     }
1616     registeredScriptStrings = 0;
1617 }
1618 
1619 #ifndef QT_NO_REGEXP
1620 
1621 Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
1622 
newRegExp(JSC::ExecState * exec,const QRegExp & regexp)1623 JSC::JSValue QScriptEnginePrivate::newRegExp(JSC::ExecState *exec, const QRegExp &regexp)
1624 {
1625     JSC::JSValue buf[2];
1626     JSC::ArgList args(buf, sizeof(buf));
1627 
1628     //convert the pattern to a ECMAScript pattern
1629     QString pattern = qt_regexp_toCanonical(regexp.pattern(), regexp.patternSyntax());
1630     if (regexp.isMinimal()) {
1631         QString ecmaPattern;
1632         int len = pattern.length();
1633         ecmaPattern.reserve(len);
1634         int i = 0;
1635         const QChar *wc = pattern.unicode();
1636         bool inBracket = false;
1637         while (i < len) {
1638             QChar c = wc[i++];
1639             ecmaPattern += c;
1640             switch (c.unicode()) {
1641             case '?':
1642             case '+':
1643             case '*':
1644             case '}':
1645                 if (!inBracket)
1646                     ecmaPattern += QLatin1Char('?');
1647                 break;
1648             case '\\':
1649                 if (i < len)
1650                     ecmaPattern += wc[i++];
1651                 break;
1652             case '[':
1653                 inBracket = true;
1654                 break;
1655             case ']':
1656                 inBracket = false;
1657                break;
1658             default:
1659                 break;
1660             }
1661         }
1662         pattern = ecmaPattern;
1663     }
1664 
1665     JSC::UString jscPattern = pattern;
1666     QString flags;
1667     if (regexp.caseSensitivity() == Qt::CaseInsensitive)
1668         flags.append(QLatin1Char('i'));
1669     JSC::UString jscFlags = flags;
1670     buf[0] = JSC::jsString(exec, jscPattern);
1671     buf[1] = JSC::jsString(exec, jscFlags);
1672     return JSC::constructRegExp(exec, args);
1673 }
1674 
1675 #endif
1676 
newRegExp(JSC::ExecState * exec,const QString & pattern,const QString & flags)1677 JSC::JSValue QScriptEnginePrivate::newRegExp(JSC::ExecState *exec, const QString &pattern, const QString &flags)
1678 {
1679     JSC::JSValue buf[2];
1680     JSC::ArgList args(buf, sizeof(buf));
1681     JSC::UString jscPattern = pattern;
1682     QString strippedFlags;
1683     if (flags.contains(QLatin1Char('i')))
1684         strippedFlags += QLatin1Char('i');
1685     if (flags.contains(QLatin1Char('m')))
1686         strippedFlags += QLatin1Char('m');
1687     if (flags.contains(QLatin1Char('g')))
1688         strippedFlags += QLatin1Char('g');
1689     JSC::UString jscFlags = strippedFlags;
1690     buf[0] = JSC::jsString(exec, jscPattern);
1691     buf[1] = JSC::jsString(exec, jscFlags);
1692     return JSC::constructRegExp(exec, args);
1693 }
1694 
newVariant(const QVariant & value)1695 JSC::JSValue QScriptEnginePrivate::newVariant(const QVariant &value)
1696 {
1697     QScriptObject *obj = new (currentFrame) QScriptObject(variantWrapperObjectStructure);
1698     obj->setDelegate(new QScript::QVariantDelegate(value));
1699     JSC::JSValue proto = defaultPrototype(value.userType());
1700     if (proto)
1701         obj->setPrototype(proto);
1702     return obj;
1703 }
1704 
newVariant(JSC::JSValue objectValue,const QVariant & value)1705 JSC::JSValue QScriptEnginePrivate::newVariant(JSC::JSValue objectValue,
1706                                               const QVariant &value)
1707 {
1708     if (!isObject(objectValue))
1709         return newVariant(value);
1710     JSC::JSObject *jscObject = JSC::asObject(objectValue);
1711     if (!jscObject->inherits(&QScriptObject::info)) {
1712         qWarning("QScriptEngine::newVariant(): changing class of non-QScriptObject not supported");
1713         return JSC::JSValue();
1714     }
1715     QScriptObject *jscScriptObject = static_cast<QScriptObject*>(jscObject);
1716     if (!isVariant(objectValue)) {
1717         jscScriptObject->setDelegate(new QScript::QVariantDelegate(value));
1718     } else {
1719         setVariantValue(objectValue, value);
1720     }
1721     return objectValue;
1722 }
1723 
1724 #ifndef QT_NO_REGEXP
1725 
toRegExp(JSC::ExecState * exec,JSC::JSValue value)1726 QRegExp QScriptEnginePrivate::toRegExp(JSC::ExecState *exec, JSC::JSValue value)
1727 {
1728     if (!isRegExp(value))
1729         return QRegExp();
1730     QString pattern = toString(exec, property(exec, value, "source", QScriptValue::ResolvePrototype));
1731     Qt::CaseSensitivity kase = Qt::CaseSensitive;
1732     if (toBool(exec, property(exec, value, "ignoreCase", QScriptValue::ResolvePrototype)))
1733         kase = Qt::CaseInsensitive;
1734     return QRegExp(pattern, kase, QRegExp::RegExp2);
1735 }
1736 
1737 #endif
1738 
toVariant(JSC::ExecState * exec,JSC::JSValue value)1739 QVariant QScriptEnginePrivate::toVariant(JSC::ExecState *exec, JSC::JSValue value)
1740 {
1741     if (!value) {
1742         return QVariant();
1743     } else if (isObject(value)) {
1744         if (isVariant(value))
1745             return variantValue(value);
1746 #ifndef QT_NO_QOBJECT
1747         else if (isQObject(value))
1748             return QVariant::fromValue(toQObject(exec, value));
1749 #endif
1750         else if (isDate(value))
1751             return QVariant(toDateTime(exec, value));
1752 #ifndef QT_NO_REGEXP
1753         else if (isRegExp(value))
1754             return QVariant(toRegExp(exec, value));
1755 #endif
1756         else if (isArray(value))
1757             return variantListFromArray(exec, JSC::asArray(value));
1758         else if (QScriptDeclarativeClass *dc = declarativeClass(value))
1759             return dc->toVariant(declarativeObject(value));
1760         return variantMapFromObject(exec, JSC::asObject(value));
1761     } else if (value.isInt32()) {
1762         return QVariant(toInt32(exec, value));
1763     } else if (value.isDouble()) {
1764         return QVariant(toNumber(exec, value));
1765     } else if (value.isString()) {
1766         return QVariant(toString(exec, value));
1767     } else if (value.isBoolean()) {
1768         return QVariant(toBool(exec, value));
1769     }
1770     return QVariant();
1771 }
1772 
propertyHelper(JSC::ExecState * exec,JSC::JSValue value,const JSC::Identifier & id,int resolveMode)1773 JSC::JSValue QScriptEnginePrivate::propertyHelper(JSC::ExecState *exec, JSC::JSValue value, const JSC::Identifier &id, int resolveMode)
1774 {
1775     JSC::JSValue result;
1776     if (!(resolveMode & QScriptValue::ResolvePrototype)) {
1777         // Look in the object's own properties
1778         JSC::JSObject *object = JSC::asObject(value);
1779         JSC::PropertySlot slot(object);
1780         if (object->getOwnPropertySlot(exec, id, slot))
1781             result = slot.getValue(exec, id);
1782     }
1783     if (!result && (resolveMode & QScriptValue::ResolveScope)) {
1784         // ### check if it's a function object and look in the scope chain
1785         JSC::JSValue scope = property(exec, value, "__qt_scope__", QScriptValue::ResolveLocal);
1786         if (isObject(scope))
1787             result = property(exec, scope, id, resolveMode);
1788     }
1789     return result;
1790 }
1791 
propertyHelper(JSC::ExecState * exec,JSC::JSValue value,quint32 index,int resolveMode)1792 JSC::JSValue QScriptEnginePrivate::propertyHelper(JSC::ExecState *exec, JSC::JSValue value, quint32 index, int resolveMode)
1793 {
1794     JSC::JSValue result;
1795     if (!(resolveMode & QScriptValue::ResolvePrototype)) {
1796         // Look in the object's own properties
1797         JSC::JSObject *object = JSC::asObject(value);
1798         JSC::PropertySlot slot(object);
1799         if (object->getOwnPropertySlot(exec, index, slot))
1800             result = slot.getValue(exec, index);
1801     }
1802     return result;
1803 }
1804 
setProperty(JSC::ExecState * exec,JSC::JSValue objectValue,const JSC::Identifier & id,JSC::JSValue value,const QScriptValue::PropertyFlags & flags)1805 void QScriptEnginePrivate::setProperty(JSC::ExecState *exec, JSC::JSValue objectValue, const JSC::Identifier &id,
1806                                        JSC::JSValue value, const QScriptValue::PropertyFlags &flags)
1807 {
1808     JSC::JSObject *thisObject = JSC::asObject(objectValue);
1809     JSC::JSValue setter = thisObject->lookupSetter(exec, id);
1810     JSC::JSValue getter = thisObject->lookupGetter(exec, id);
1811     if ((flags & QScriptValue::PropertyGetter) || (flags & QScriptValue::PropertySetter)) {
1812         if (!value) {
1813             // deleting getter/setter
1814             if ((flags & QScriptValue::PropertyGetter) && (flags & QScriptValue::PropertySetter)) {
1815                 // deleting both: just delete the property
1816                 thisObject->deleteProperty(exec, id);
1817             } else if (flags & QScriptValue::PropertyGetter) {
1818                 // preserve setter, if there is one
1819                 thisObject->deleteProperty(exec, id);
1820                 if (setter && setter.isObject())
1821                     thisObject->defineSetter(exec, id, JSC::asObject(setter));
1822             } else { // flags & QScriptValue::PropertySetter
1823                 // preserve getter, if there is one
1824                 thisObject->deleteProperty(exec, id);
1825                 if (getter && getter.isObject())
1826                     thisObject->defineGetter(exec, id, JSC::asObject(getter));
1827             }
1828         } else {
1829             if (value.isObject()) { // ### should check if it has callData()
1830                 // defining getter/setter
1831                 if (id == exec->propertyNames().underscoreProto) {
1832                     qWarning("QScriptValue::setProperty() failed: "
1833                              "cannot set getter or setter of native property `__proto__'");
1834                 } else {
1835                     if (flags & QScriptValue::PropertyGetter)
1836                         thisObject->defineGetter(exec, id, JSC::asObject(value));
1837                     if (flags & QScriptValue::PropertySetter)
1838                         thisObject->defineSetter(exec, id, JSC::asObject(value));
1839                 }
1840             } else {
1841                 qWarning("QScriptValue::setProperty(): getter/setter must be a function");
1842             }
1843         }
1844     } else {
1845         // setting the value
1846         if (getter && getter.isObject() && !(setter && setter.isObject())) {
1847             qWarning("QScriptValue::setProperty() failed: "
1848                      "property '%s' has a getter but no setter",
1849                      qPrintable(QString(id.ustring())));
1850             return;
1851         }
1852         if (!value) {
1853             // ### check if it's a getter/setter property
1854             thisObject->deleteProperty(exec, id);
1855         } else if (flags != QScriptValue::KeepExistingFlags) {
1856             if (thisObject->hasOwnProperty(exec, id))
1857                 thisObject->deleteProperty(exec, id); // ### hmmm - can't we just update the attributes?
1858             thisObject->putWithAttributes(exec, id, value, propertyFlagsToJSCAttributes(flags));
1859         } else {
1860             JSC::PutPropertySlot slot;
1861             thisObject->put(exec, id, value, slot);
1862         }
1863     }
1864 }
1865 
setProperty(JSC::ExecState * exec,JSC::JSValue objectValue,quint32 index,JSC::JSValue value,const QScriptValue::PropertyFlags & flags)1866 void QScriptEnginePrivate::setProperty(JSC::ExecState *exec, JSC::JSValue objectValue, quint32 index,
1867                                        JSC::JSValue value, const QScriptValue::PropertyFlags &flags)
1868 {
1869     if (!value) {
1870         JSC::asObject(objectValue)->deleteProperty(exec, index);
1871     } else {
1872         if ((flags & QScriptValue::PropertyGetter) || (flags & QScriptValue::PropertySetter)) {
1873             // fall back to string-based setProperty(), since there is no
1874             // JSC::JSObject::defineGetter(unsigned)
1875             setProperty(exec, objectValue, JSC::Identifier::from(exec, index), value, flags);
1876         } else {
1877             if (flags != QScriptValue::KeepExistingFlags) {
1878                 //                if (JSC::asObject(d->jscValue)->hasOwnProperty(exec, arrayIndex))
1879                 //                    JSC::asObject(d->jscValue)->deleteProperty(exec, arrayIndex);
1880                 unsigned attribs = 0;
1881                 if (flags & QScriptValue::ReadOnly)
1882                     attribs |= JSC::ReadOnly;
1883                 if (flags & QScriptValue::SkipInEnumeration)
1884                     attribs |= JSC::DontEnum;
1885                 if (flags & QScriptValue::Undeletable)
1886                     attribs |= JSC::DontDelete;
1887                 attribs |= flags & QScriptValue::UserRange;
1888                 JSC::asObject(objectValue)->putWithAttributes(exec, index, value, attribs);
1889             } else {
1890                 JSC::asObject(objectValue)->put(exec, index, value);
1891             }
1892         }
1893     }
1894 }
1895 
propertyFlags(JSC::ExecState * exec,JSC::JSValue value,const JSC::Identifier & id,const QScriptValue::ResolveFlags & mode)1896 QScriptValue::PropertyFlags QScriptEnginePrivate::propertyFlags(JSC::ExecState *exec, JSC::JSValue value, const JSC::Identifier &id,
1897                                                                 const QScriptValue::ResolveFlags &mode)
1898 {
1899     JSC::JSObject *object = JSC::asObject(value);
1900     unsigned attribs = 0;
1901     JSC::PropertyDescriptor descriptor;
1902     if (object->getOwnPropertyDescriptor(exec, id, descriptor))
1903         attribs = descriptor.attributes();
1904     else {
1905         if ((mode & QScriptValue::ResolvePrototype) && object->prototype() && object->prototype().isObject()) {
1906             JSC::JSValue proto = object->prototype();
1907             return propertyFlags(exec, proto, id, mode);
1908         }
1909         return 0;
1910     }
1911     QScriptValue::PropertyFlags result = 0;
1912     if (attribs & JSC::ReadOnly)
1913         result |= QScriptValue::ReadOnly;
1914     if (attribs & JSC::DontEnum)
1915         result |= QScriptValue::SkipInEnumeration;
1916     if (attribs & JSC::DontDelete)
1917         result |= QScriptValue::Undeletable;
1918     //We cannot rely on attribs JSC::Setter/Getter because they are not necesserly set by JSC (bug?)
1919     if (attribs & JSC::Getter || !object->lookupGetter(exec, id).isUndefinedOrNull())
1920         result |= QScriptValue::PropertyGetter;
1921     if (attribs & JSC::Setter || !object->lookupSetter(exec, id).isUndefinedOrNull())
1922         result |= QScriptValue::PropertySetter;
1923 #ifndef QT_NO_QOBJECT
1924     if (attribs & QScript::QObjectMemberAttribute)
1925         result |= QScriptValue::QObjectMember;
1926 #endif
1927     result |= QScriptValue::PropertyFlag(attribs & QScriptValue::UserRange);
1928     return result;
1929 }
1930 
toStringHandle(const JSC::Identifier & name)1931 QScriptString QScriptEnginePrivate::toStringHandle(const JSC::Identifier &name)
1932 {
1933     QScriptString result;
1934     QScriptStringPrivate *p = new QScriptStringPrivate(this, name, QScriptStringPrivate::HeapAllocated);
1935     QScriptStringPrivate::init(result, p);
1936     registerScriptString(p);
1937     return result;
1938 }
1939 
1940 #ifdef QT_NO_QOBJECT
1941 
QScriptEngine()1942 QScriptEngine::QScriptEngine()
1943     : d_ptr(new QScriptEnginePrivate)
1944 {
1945     d_ptr->q_ptr = this;
1946 }
1947 
1948 /*! \internal
1949 */
QScriptEngine(QScriptEnginePrivate & dd)1950 QScriptEngine::QScriptEngine(QScriptEnginePrivate &dd)
1951     : d_ptr(&dd)
1952 {
1953     d_ptr->q_ptr = this;
1954 }
1955 #else
1956 
1957 /*!
1958     Constructs a QScriptEngine object.
1959 
1960     The globalObject() is initialized to have properties as described in
1961     \l{ECMA-262}, Section 15.1.
1962 */
QScriptEngine()1963 QScriptEngine::QScriptEngine()
1964     : QObject(*new QScriptEnginePrivate, 0)
1965 {
1966 }
1967 
1968 /*!
1969     Constructs a QScriptEngine object with the given \a parent.
1970 
1971     The globalObject() is initialized to have properties as described in
1972     \l{ECMA-262}, Section 15.1.
1973 */
1974 
QScriptEngine(QObject * parent)1975 QScriptEngine::QScriptEngine(QObject *parent)
1976     : QObject(*new QScriptEnginePrivate, parent)
1977 {
1978 }
1979 
1980 /*! \internal
1981 */
QScriptEngine(QScriptEnginePrivate & dd,QObject * parent)1982 QScriptEngine::QScriptEngine(QScriptEnginePrivate &dd, QObject *parent)
1983     : QObject(dd, parent)
1984 {
1985 }
1986 #endif
1987 
1988 /*!
1989   Destroys this QScriptEngine.
1990 */
~QScriptEngine()1991 QScriptEngine::~QScriptEngine()
1992 {
1993 #ifdef QT_NO_QOBJECT
1994     delete d_ptr;
1995     d_ptr = 0;
1996 #endif
1997 }
1998 
1999 /*!
2000   Returns this engine's Global Object.
2001 
2002   By default, the Global Object contains the built-in objects that are
2003   part of \l{ECMA-262}, such as Math, Date and String. Additionally,
2004   you can set properties of the Global Object to make your own
2005   extensions available to all script code. Non-local variables in
2006   script code will be created as properties of the Global Object, as
2007   well as local variables in global code.
2008 */
globalObject() const2009 QScriptValue QScriptEngine::globalObject() const
2010 {
2011     Q_D(const QScriptEngine);
2012     QScript::APIShim shim(const_cast<QScriptEnginePrivate*>(d));
2013     JSC::JSObject *result = d->globalObject();
2014     return const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(result);
2015 }
2016 
2017 /*!
2018   \since 4.5
2019 
2020   Sets this engine's Global Object to be the given \a object.
2021   If \a object is not a valid script object, this function does
2022   nothing.
2023 
2024   When setting a custom global object, you may want to use
2025   QScriptValueIterator to copy the properties of the standard Global
2026   Object; alternatively, you can set the internal prototype of your
2027   custom object to be the original Global Object.
2028 */
setGlobalObject(const QScriptValue & object)2029 void QScriptEngine::setGlobalObject(const QScriptValue &object)
2030 {
2031     Q_D(QScriptEngine);
2032     if (!object.isObject())
2033         return;
2034     QScript::APIShim shim(d);
2035     JSC::JSObject *jscObject = JSC::asObject(d->scriptValueToJSCValue(object));
2036     d->setGlobalObject(jscObject);
2037 }
2038 
2039 /*!
2040   Returns a QScriptValue of the primitive type Null.
2041 
2042   \sa undefinedValue()
2043 */
nullValue()2044 QScriptValue QScriptEngine::nullValue()
2045 {
2046     Q_D(QScriptEngine);
2047     return d->scriptValueFromJSCValue(JSC::jsNull());
2048 }
2049 
2050 /*!
2051   Returns a QScriptValue of the primitive type Undefined.
2052 
2053   \sa nullValue()
2054 */
undefinedValue()2055 QScriptValue QScriptEngine::undefinedValue()
2056 {
2057     Q_D(QScriptEngine);
2058     return d->scriptValueFromJSCValue(JSC::jsUndefined());
2059 }
2060 
2061 /*!
2062   Creates a constructor function from \a fun, with the given \a length.
2063   The \c{prototype} property of the resulting function is set to be the
2064   given \a prototype. The \c{constructor} property of \a prototype is
2065   set to be the resulting function.
2066 
2067   When a function is called as a constructor (e.g. \c{new Foo()}), the
2068   `this' object associated with the function call is the new object
2069   that the function is expected to initialize; the prototype of this
2070   default constructed object will be the function's public
2071   \c{prototype} property. If you always want the function to behave as
2072   a constructor (e.g. \c{Foo()} should also create a new object), or
2073   if you need to create your own object rather than using the default
2074   `this' object, you should make sure that the prototype of your
2075   object is set correctly; either by setting it manually, or, when
2076   wrapping a custom type, by having registered the defaultPrototype()
2077   of that type. Example:
2078 
2079   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 9
2080 
2081   To wrap a custom type and provide a constructor for it, you'd typically
2082   do something like this:
2083 
2084   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 10
2085 */
newFunction(QScriptEngine::FunctionSignature fun,const QScriptValue & prototype,int length)2086 QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun,
2087                                         const QScriptValue &prototype,
2088                                         int length)
2089 {
2090     Q_D(QScriptEngine);
2091     QScript::APIShim shim(d);
2092     JSC::ExecState* exec = d->currentFrame;
2093     JSC::JSValue function = new (exec)QScript::FunctionWrapper(exec, length, JSC::Identifier(exec, ""), fun);
2094     QScriptValue result = d->scriptValueFromJSCValue(function);
2095     result.setProperty(QLatin1String("prototype"), prototype,
2096                        QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
2097     const_cast<QScriptValue&>(prototype)
2098         .setProperty(QLatin1String("constructor"), result, QScriptValue::SkipInEnumeration);
2099     return result;
2100 }
2101 
2102 #ifndef QT_NO_REGEXP
2103 
2104 /*!
2105   Creates a QtScript object of class RegExp with the given
2106   \a regexp.
2107 
2108   \sa QScriptValue::toRegExp()
2109 */
newRegExp(const QRegExp & regexp)2110 QScriptValue QScriptEngine::newRegExp(const QRegExp &regexp)
2111 {
2112     Q_D(QScriptEngine);
2113     QScript::APIShim shim(d);
2114     return d->scriptValueFromJSCValue(d->newRegExp(d->currentFrame, regexp));
2115 }
2116 
2117 #endif // QT_NO_REGEXP
2118 
2119 /*!
2120   Creates a QtScript object holding the given variant \a value.
2121 
2122   If a default prototype has been registered with the meta type id of
2123   \a value, then the prototype of the created object will be that
2124   prototype; otherwise, the prototype will be the Object prototype
2125   object.
2126 
2127   \sa setDefaultPrototype(), QScriptValue::toVariant(), reportAdditionalMemoryCost()
2128 */
newVariant(const QVariant & value)2129 QScriptValue QScriptEngine::newVariant(const QVariant &value)
2130 {
2131     Q_D(QScriptEngine);
2132     QScript::APIShim shim(d);
2133     return d->scriptValueFromJSCValue(d->newVariant(value));
2134 }
2135 
2136 /*!
2137   \since 4.4
2138   \overload
2139 
2140   Initializes the given Qt Script \a object to hold the given variant
2141   \a value, and returns the \a object.
2142 
2143   This function enables you to "promote" a plain Qt Script object
2144   (created by the newObject() function) to a variant, or to replace
2145   the variant contained inside an object previously created by the
2146   newVariant() function.
2147 
2148   The prototype() of the \a object will remain unchanged.
2149 
2150   If \a object is not an object, this function behaves like the normal
2151   newVariant(), i.e. it creates a new script object and returns it.
2152 
2153   This function is useful when you want to provide a script
2154   constructor for a C++ type. If your constructor is invoked in a
2155   \c{new} expression (QScriptContext::isCalledAsConstructor() returns
2156   true), you can pass QScriptContext::thisObject() (the default
2157   constructed script object) to this function to initialize the new
2158   object.
2159 
2160   \sa reportAdditionalMemoryCost()
2161 */
newVariant(const QScriptValue & object,const QVariant & value)2162 QScriptValue QScriptEngine::newVariant(const QScriptValue &object,
2163                                        const QVariant &value)
2164 {
2165     Q_D(QScriptEngine);
2166     QScript::APIShim shim(d);
2167     JSC::JSValue jsObject = d->scriptValueToJSCValue(object);
2168     return d->scriptValueFromJSCValue(d->newVariant(jsObject, value));
2169 }
2170 
2171 #ifndef QT_NO_QOBJECT
2172 /*!
2173   Creates a QtScript object that wraps the given QObject \a
2174   object, using the given \a ownership. The given \a options control
2175   various aspects of the interaction with the resulting script object.
2176 
2177   Signals and slots, properties and children of \a object are
2178   available as properties of the created QScriptValue. For more
2179   information, see the \l{QtScript} documentation.
2180 
2181   If \a object is a null pointer, this function returns nullValue().
2182 
2183   If a default prototype has been registered for the \a object's class
2184   (or its superclass, recursively), the prototype of the new script
2185   object will be set to be that default prototype.
2186 
2187   If the given \a object is deleted outside of QtScript's control, any
2188   attempt to access the deleted QObject's members through the QtScript
2189   wrapper object (either by script code or C++) will result in a
2190   script exception.
2191 
2192   \sa QScriptValue::toQObject(), reportAdditionalMemoryCost()
2193 */
newQObject(QObject * object,ValueOwnership ownership,const QObjectWrapOptions & options)2194 QScriptValue QScriptEngine::newQObject(QObject *object, ValueOwnership ownership,
2195                                        const QObjectWrapOptions &options)
2196 {
2197     Q_D(QScriptEngine);
2198     QScript::APIShim shim(d);
2199     JSC::JSValue jscQObject = d->newQObject(object, ownership, options);
2200     return d->scriptValueFromJSCValue(jscQObject);
2201 }
2202 
2203 /*!
2204   \since 4.4
2205   \overload
2206 
2207   Initializes the given \a scriptObject to hold the given \a qtObject,
2208   and returns the \a scriptObject.
2209 
2210   This function enables you to "promote" a plain Qt Script object
2211   (created by the newObject() function) to a QObject proxy, or to
2212   replace the QObject contained inside an object previously created by
2213   the newQObject() function.
2214 
2215   The prototype() of the \a scriptObject will remain unchanged.
2216 
2217   If \a scriptObject is not an object, this function behaves like the
2218   normal newQObject(), i.e. it creates a new script object and returns
2219   it.
2220 
2221   This function is useful when you want to provide a script
2222   constructor for a QObject-based class. If your constructor is
2223   invoked in a \c{new} expression
2224   (QScriptContext::isCalledAsConstructor() returns true), you can pass
2225   QScriptContext::thisObject() (the default constructed script object)
2226   to this function to initialize the new object.
2227 
2228   \sa reportAdditionalMemoryCost()
2229 */
newQObject(const QScriptValue & scriptObject,QObject * qtObject,ValueOwnership ownership,const QObjectWrapOptions & options)2230 QScriptValue QScriptEngine::newQObject(const QScriptValue &scriptObject,
2231                                        QObject *qtObject,
2232                                        ValueOwnership ownership,
2233                                        const QObjectWrapOptions &options)
2234 {
2235     Q_D(QScriptEngine);
2236     if (!scriptObject.isObject())
2237         return newQObject(qtObject, ownership, options);
2238     QScript::APIShim shim(d);
2239     JSC::JSObject *jscObject = JSC::asObject(QScriptValuePrivate::get(scriptObject)->jscValue);
2240     if (!jscObject->inherits(&QScriptObject::info)) {
2241         qWarning("QScriptEngine::newQObject(): changing class of non-QScriptObject not supported");
2242         return QScriptValue();
2243     }
2244     QScriptObject *jscScriptObject = static_cast<QScriptObject*>(jscObject);
2245     if (!scriptObject.isQObject()) {
2246         jscScriptObject->setDelegate(new QScript::QObjectDelegate(qtObject, ownership, options));
2247     } else {
2248         QScript::QObjectDelegate *delegate = static_cast<QScript::QObjectDelegate*>(jscScriptObject->delegate());
2249         delegate->setValue(qtObject);
2250         delegate->setOwnership(ownership);
2251         delegate->setOptions(options);
2252     }
2253     return scriptObject;
2254 }
2255 
2256 #endif // QT_NO_QOBJECT
2257 
2258 /*!
2259   Creates a QtScript object of class Object.
2260 
2261   The prototype of the created object will be the Object
2262   prototype object.
2263 
2264   \sa newArray(), QScriptValue::setProperty()
2265 */
newObject()2266 QScriptValue QScriptEngine::newObject()
2267 {
2268     Q_D(QScriptEngine);
2269     QScript::APIShim shim(d);
2270     return d->scriptValueFromJSCValue(d->newObject());
2271 }
2272 
2273 /*!
2274   \since 4.4
2275   \overload
2276 
2277   Creates a QtScript Object of the given class, \a scriptClass.
2278 
2279   The prototype of the created object will be the Object
2280   prototype object.
2281 
2282   \a data, if specified, is set as the internal data of the
2283   new object (using QScriptValue::setData()).
2284 
2285   \sa QScriptValue::scriptClass(), reportAdditionalMemoryCost()
2286 */
newObject(QScriptClass * scriptClass,const QScriptValue & data)2287 QScriptValue QScriptEngine::newObject(QScriptClass *scriptClass,
2288                                       const QScriptValue &data)
2289 {
2290     Q_D(QScriptEngine);
2291     QScript::APIShim shim(d);
2292     JSC::ExecState* exec = d->currentFrame;
2293     QScriptObject *result = new (exec) QScriptObject(d->scriptObjectStructure);
2294     result->setDelegate(new QScript::ClassObjectDelegate(scriptClass));
2295     QScriptValue scriptObject = d->scriptValueFromJSCValue(result);
2296     scriptObject.setData(data);
2297     QScriptValue proto = scriptClass->prototype();
2298     if (proto.isValid())
2299         scriptObject.setPrototype(proto);
2300     return scriptObject;
2301 }
2302 
2303 /*!
2304   \internal
2305 */
newActivationObject()2306 QScriptValue QScriptEngine::newActivationObject()
2307 {
2308     qWarning("QScriptEngine::newActivationObject() not implemented");
2309     // ### JSActivation or JSVariableObject?
2310     return QScriptValue();
2311 }
2312 
2313 /*!
2314   Creates a QScriptValue that wraps a native (C++) function. \a fun
2315   must be a C++ function with signature QScriptEngine::FunctionSignature.  \a
2316   length is the number of arguments that \a fun expects; this becomes
2317   the \c{length} property of the created QScriptValue.
2318 
2319   Note that \a length only gives an indication of the number of
2320   arguments that the function expects; an actual invocation of a
2321   function can include any number of arguments. You can check the
2322   \l{QScriptContext::argumentCount()}{argumentCount()} of the
2323   QScriptContext associated with the invocation to determine the
2324   actual number of arguments passed.
2325 
2326   A \c{prototype} property is automatically created for the resulting
2327   function object, to provide for the possibility that the function
2328   will be used as a constructor.
2329 
2330   By combining newFunction() and the property flags
2331   QScriptValue::PropertyGetter and QScriptValue::PropertySetter, you
2332   can create script object properties that behave like normal
2333   properties in script code, but are in fact accessed through
2334   functions (analogous to how properties work in \l{Qt's Property
2335   System}). Example:
2336 
2337   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 11
2338 
2339   When the property \c{foo} of the script object is subsequently
2340   accessed in script code, \c{getSetFoo()} will be invoked to handle
2341   the access.  In this particular case, we chose to store the "real"
2342   value of \c{foo} as a property of the accessor function itself; you
2343   are of course free to do whatever you like in this function.
2344 
2345   In the above example, a single native function was used to handle
2346   both reads and writes to the property; the argument count is used to
2347   determine if we are handling a read or write. You can also use two
2348   separate functions; just specify the relevant flag
2349   (QScriptValue::PropertyGetter or QScriptValue::PropertySetter) when
2350   setting the property, e.g.:
2351 
2352   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 12
2353 
2354   \sa QScriptValue::call()
2355 */
newFunction(QScriptEngine::FunctionSignature fun,int length)2356 QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun, int length)
2357 {
2358     Q_D(QScriptEngine);
2359     QScript::APIShim shim(d);
2360     JSC::ExecState* exec = d->currentFrame;
2361     JSC::JSValue function = new (exec)QScript::FunctionWrapper(exec, length, JSC::Identifier(exec, ""), fun);
2362     QScriptValue result = d->scriptValueFromJSCValue(function);
2363     QScriptValue proto = newObject();
2364     result.setProperty(QLatin1String("prototype"), proto,
2365                        QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
2366     proto.setProperty(QLatin1String("constructor"), result, QScriptValue::SkipInEnumeration);
2367     return result;
2368 }
2369 
2370 /*!
2371   \internal
2372   \since 4.4
2373 */
newFunction(QScriptEngine::FunctionWithArgSignature fun,void * arg)2374 QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionWithArgSignature fun, void *arg)
2375 {
2376     Q_D(QScriptEngine);
2377     QScript::APIShim shim(d);
2378     JSC::ExecState* exec = d->currentFrame;
2379     JSC::JSValue function = new (exec)QScript::FunctionWithArgWrapper(exec, /*length=*/0, JSC::Identifier(exec, ""), fun, arg);
2380     QScriptValue result = d->scriptValueFromJSCValue(function);
2381     QScriptValue proto = newObject();
2382     result.setProperty(QLatin1String("prototype"), proto,
2383                        QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
2384     proto.setProperty(QLatin1String("constructor"), result, QScriptValue::SkipInEnumeration);
2385     return result;
2386 }
2387 
2388 /*!
2389   Creates a QtScript object of class Array with the given \a length.
2390 
2391   \sa newObject()
2392 */
newArray(uint length)2393 QScriptValue QScriptEngine::newArray(uint length)
2394 {
2395     Q_D(QScriptEngine);
2396     QScript::APIShim shim(d);
2397     return d->scriptValueFromJSCValue(d->newArray(d->currentFrame, length));
2398 }
2399 
2400 /*!
2401   Creates a QtScript object of class RegExp with the given
2402   \a pattern and \a flags.
2403 
2404   The legal flags are 'g' (global), 'i' (ignore case), and 'm'
2405   (multiline).
2406 */
newRegExp(const QString & pattern,const QString & flags)2407 QScriptValue QScriptEngine::newRegExp(const QString &pattern, const QString &flags)
2408 {
2409     Q_D(QScriptEngine);
2410     QScript::APIShim shim(d);
2411     return d->scriptValueFromJSCValue(d->newRegExp(d->currentFrame, pattern, flags));
2412 }
2413 
2414 /*!
2415   Creates a QtScript object of class Date with the given
2416   \a value (the number of milliseconds since 01 January 1970,
2417   UTC).
2418 */
newDate(qsreal value)2419 QScriptValue QScriptEngine::newDate(qsreal value)
2420 {
2421     Q_D(QScriptEngine);
2422     QScript::APIShim shim(d);
2423     return d->scriptValueFromJSCValue(d->newDate(d->currentFrame, value));
2424 }
2425 
2426 /*!
2427   Creates a QtScript object of class Date from the given \a value.
2428 
2429   \sa QScriptValue::toDateTime()
2430 */
newDate(const QDateTime & value)2431 QScriptValue QScriptEngine::newDate(const QDateTime &value)
2432 {
2433     Q_D(QScriptEngine);
2434     QScript::APIShim shim(d);
2435     return d->scriptValueFromJSCValue(d->newDate(d->currentFrame, value));
2436 }
2437 
2438 #ifndef QT_NO_QOBJECT
2439 /*!
2440   Creates a QtScript object that represents a QObject class, using the
2441   the given \a metaObject and constructor \a ctor.
2442 
2443   Enums of \a metaObject (declared with Q_ENUMS) are available as
2444   properties of the created QScriptValue. When the class is called as
2445   a function, \a ctor will be called to create a new instance of the
2446   class.
2447 
2448   Example:
2449 
2450   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 27
2451 
2452   \sa newQObject(), scriptValueFromQMetaObject()
2453 */
newQMetaObject(const QMetaObject * metaObject,const QScriptValue & ctor)2454 QScriptValue QScriptEngine::newQMetaObject(
2455     const QMetaObject *metaObject, const QScriptValue &ctor)
2456 {
2457     Q_D(QScriptEngine);
2458     QScript::APIShim shim(d);
2459     JSC::JSValue jscCtor = d->scriptValueToJSCValue(ctor);
2460     JSC::JSValue jscQMetaObject = d->newQMetaObject(metaObject, jscCtor);
2461     return d->scriptValueFromJSCValue(jscQMetaObject);
2462 }
2463 
2464 /*!
2465   \fn QScriptValue QScriptEngine::scriptValueFromQMetaObject()
2466 
2467   Creates a QScriptValue that represents the Qt class \c{T}.
2468 
2469   This function is used in combination with one of the
2470   Q_SCRIPT_DECLARE_QMETAOBJECT() macro. Example:
2471 
2472   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 13
2473 
2474   \sa QScriptEngine::newQMetaObject()
2475 */
2476 
2477 /*!
2478   \fn QScriptValue qScriptValueFromQMetaObject(QScriptEngine *engine)
2479   \since 4.3
2480   \relates QScriptEngine
2481   \obsolete
2482 
2483   Uses \a engine to create a QScriptValue that represents the Qt class
2484   \c{T}.
2485 
2486   This function is equivalent to
2487   QScriptEngine::scriptValueFromQMetaObject().
2488 
2489   \note This function was provided as a workaround for MSVC 6
2490   which did not support member template functions. It is advised
2491   to use the other form in new code.
2492 
2493   \sa QScriptEngine::newQMetaObject()
2494 */
2495 #endif // QT_NO_QOBJECT
2496 
2497 /*!
2498   \obsolete
2499 
2500   Returns true if \a program can be evaluated; i.e. the code is
2501   sufficient to determine whether it appears to be a syntactically
2502   correct program, or contains a syntax error.
2503 
2504   This function returns false if \a program is incomplete; i.e. the
2505   input is syntactically correct up to the point where the input is
2506   terminated.
2507 
2508   Note that this function only does a static check of \a program;
2509   e.g. it does not check whether references to variables are
2510   valid, and so on.
2511 
2512   A typical usage of canEvaluate() is to implement an interactive
2513   interpreter for QtScript. The user is repeatedly queried for
2514   individual lines of code; the lines are concatened internally, and
2515   only when canEvaluate() returns true for the resulting program is it
2516   passed to evaluate().
2517 
2518   The following are some examples to illustrate the behavior of
2519   canEvaluate(). (Note that all example inputs are assumed to have an
2520   explicit newline as their last character, since otherwise the
2521   QtScript parser would automatically insert a semi-colon character at
2522   the end of the input, and this could cause canEvaluate() to produce
2523   different results.)
2524 
2525   Given the input
2526   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 14
2527   canEvaluate() will return true, since the program appears to be complete.
2528 
2529   Given the input
2530   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 15
2531   canEvaluate() will return false, since the if-statement is not complete,
2532   but is syntactically correct so far.
2533 
2534   Given the input
2535   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 16
2536   canEvaluate() will return true, but evaluate() will throw a
2537   SyntaxError given the same input.
2538 
2539   Given the input
2540   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 17
2541   canEvaluate() will return true, even though the code is clearly not
2542   syntactically valid QtScript code. evaluate() will throw a
2543   SyntaxError when this code is evaluated.
2544 
2545   Given the input
2546   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 18
2547   canEvaluate() will return true, but evaluate() will throw a
2548   ReferenceError if \c{foo} is not defined in the script
2549   environment.
2550 
2551   \sa evaluate(), checkSyntax()
2552 */
canEvaluate(const QString & program) const2553 bool QScriptEngine::canEvaluate(const QString &program) const
2554 {
2555     return QScriptEnginePrivate::canEvaluate(program);
2556 }
2557 
2558 
canEvaluate(const QString & program)2559 bool QScriptEnginePrivate::canEvaluate(const QString &program)
2560 {
2561     QScript::SyntaxChecker checker;
2562     QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
2563     return (result.state != QScript::SyntaxChecker::Intermediate);
2564 }
2565 
2566 /*!
2567   \since 4.5
2568 
2569   Checks the syntax of the given \a program. Returns a
2570   QScriptSyntaxCheckResult object that contains the result of the check.
2571 */
checkSyntax(const QString & program)2572 QScriptSyntaxCheckResult QScriptEngine::checkSyntax(const QString &program)
2573 {
2574     return QScriptEnginePrivate::checkSyntax(program);
2575 }
2576 
checkSyntax(const QString & program)2577 QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &program)
2578 {
2579     QScript::SyntaxChecker checker;
2580     QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
2581     QScriptSyntaxCheckResultPrivate *p = new QScriptSyntaxCheckResultPrivate();
2582     switch (result.state) {
2583     case QScript::SyntaxChecker::Error:
2584         p->state = QScriptSyntaxCheckResult::Error;
2585         break;
2586     case QScript::SyntaxChecker::Intermediate:
2587         p->state = QScriptSyntaxCheckResult::Intermediate;
2588         break;
2589     case QScript::SyntaxChecker::Valid:
2590         p->state = QScriptSyntaxCheckResult::Valid;
2591         break;
2592     }
2593     p->errorLineNumber = result.errorLineNumber;
2594     p->errorColumnNumber = result.errorColumnNumber;
2595     p->errorMessage = result.errorMessage;
2596     return QScriptSyntaxCheckResult(p);
2597 }
2598 
2599 
2600 
2601 /*!
2602   Evaluates \a program, using \a lineNumber as the base line number,
2603   and returns the result of the evaluation.
2604 
2605   The script code will be evaluated in the current context.
2606 
2607   The evaluation of \a program can cause an exception in the
2608   engine; in this case the return value will be the exception
2609   that was thrown (typically an \c{Error} object). You can call
2610   hasUncaughtException() to determine if an exception occurred in
2611   the last call to evaluate().
2612 
2613   \a lineNumber is used to specify a starting line number for \a
2614   program; line number information reported by the engine that pertain
2615   to this evaluation (e.g. uncaughtExceptionLineNumber()) will be
2616   based on this argument. For example, if \a program consists of two
2617   lines of code, and the statement on the second line causes a script
2618   exception, uncaughtExceptionLineNumber() would return the given \a
2619   lineNumber plus one. When no starting line number is specified, line
2620   numbers will be 1-based.
2621 
2622   \a fileName is used for error reporting. For example in error objects
2623   the file name is accessible through the "fileName" property if it's
2624   provided with this function.
2625 
2626   \sa canEvaluate(), hasUncaughtException(), isEvaluating(), abortEvaluation()
2627 */
2628 
evaluate(const QString & program,const QString & fileName,int lineNumber)2629 QScriptValue QScriptEngine::evaluate(const QString &program, const QString &fileName, int lineNumber)
2630 {
2631     Q_D(QScriptEngine);
2632     QScript::APIShim shim(d);
2633     WTF::PassRefPtr<QScript::UStringSourceProviderWithFeedback> provider
2634             = QScript::UStringSourceProviderWithFeedback::create(program, fileName, lineNumber, d);
2635     intptr_t sourceId = provider->asID();
2636     JSC::SourceCode source(provider, lineNumber); //after construction of SourceCode provider variable will be null.
2637 
2638     JSC::ExecState* exec = d->currentFrame;
2639     WTF::RefPtr<JSC::EvalExecutable> executable = JSC::EvalExecutable::create(exec, source);
2640     bool compile = true;
2641     return d->scriptValueFromJSCValue(d->evaluateHelper(exec, sourceId, executable.get(), compile));
2642 }
2643 
2644 /*!
2645   \since 4.7
2646 
2647   Evaluates the given \a program and returns the result of the
2648   evaluation.
2649 */
evaluate(const QScriptProgram & program)2650 QScriptValue QScriptEngine::evaluate(const QScriptProgram &program)
2651 {
2652     Q_D(QScriptEngine);
2653     QScriptProgramPrivate *program_d = QScriptProgramPrivate::get(program);
2654     if (!program_d)
2655         return QScriptValue();
2656 
2657     QScript::APIShim shim(d);
2658     JSC::ExecState* exec = d->currentFrame;
2659     JSC::EvalExecutable *executable = program_d->executable(exec, d);
2660     bool compile = !program_d->isCompiled;
2661     JSC::JSValue result = d->evaluateHelper(exec, program_d->sourceId,
2662                                             executable, compile);
2663     if (compile)
2664         program_d->isCompiled = true;
2665     return d->scriptValueFromJSCValue(result);
2666 }
2667 
2668 /*!
2669   Returns the current context.
2670 
2671   The current context is typically accessed to retrieve the arguments
2672   and `this' object in native functions; for convenience, it is
2673   available as the first argument in QScriptEngine::FunctionSignature.
2674 */
currentContext() const2675 QScriptContext *QScriptEngine::currentContext() const
2676 {
2677     Q_D(const QScriptEngine);
2678     return const_cast<QScriptEnginePrivate*>(d)->contextForFrame(d->currentFrame);
2679 }
2680 
2681 /*!
2682   Enters a new execution context and returns the associated
2683   QScriptContext object.
2684 
2685   Once you are done with the context, you should call popContext() to
2686   restore the old context.
2687 
2688   By default, the `this' object of the new context is the Global Object.
2689   The context's \l{QScriptContext::callee()}{callee}() will be invalid.
2690 
2691   This function is useful when you want to evaluate script code
2692   as if it were the body of a function. You can use the context's
2693   \l{QScriptContext::activationObject()}{activationObject}() to initialize
2694   local variables that will be available to scripts. Example:
2695 
2696   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 19
2697 
2698   In the above example, the new variable "tmp" defined in the script
2699   will be local to the context; in other words, the script doesn't
2700   have any effect on the global environment.
2701 
2702   Returns 0 in case of stack overflow
2703 
2704   \sa popContext()
2705 */
pushContext()2706 QScriptContext *QScriptEngine::pushContext()
2707 {
2708     Q_D(QScriptEngine);
2709     QScript::APIShim shim(d);
2710 
2711     JSC::CallFrame* newFrame = d->pushContext(d->currentFrame, d->currentFrame->globalData().dynamicGlobalObject,
2712                                               JSC::ArgList(), /*callee = */0);
2713 
2714     if (agent())
2715         agent()->contextPush();
2716 
2717     return d->contextForFrame(newFrame);
2718 }
2719 
2720 /*! \internal
2721    push a context for a native function.
2722    JSC native function doesn't have different stackframe or context. so we need to create one.
2723 
2724    use popContext right after to go back to the previous context the context if no stack overflow has hapenned
2725 
2726    exec is the current top frame.
2727 
2728    return the new top frame. (might be the same as exec if a new stackframe was not needed) or 0 if stack overflow
2729 */
pushContext(JSC::CallFrame * exec,JSC::JSValue _thisObject,const JSC::ArgList & args,JSC::JSObject * callee,bool calledAsConstructor,bool clearScopeChain)2730 JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, JSC::JSValue _thisObject,
2731                                                   const JSC::ArgList& args, JSC::JSObject *callee, bool calledAsConstructor,
2732                                                   bool clearScopeChain)
2733 {
2734     JSC::JSValue thisObject = _thisObject;
2735     if (!callee) {
2736         // callee can't be zero, as this can cause JSC to crash during GC
2737         // marking phase if the context's Arguments object has been created.
2738         // Fake it by using the global object. Note that this is also handled
2739         // in QScriptContext::callee(), as that function should still return
2740         // an invalid value.
2741         callee = originalGlobalObject();
2742     }
2743     if (calledAsConstructor) {
2744         //JSC doesn't create default created object for native functions. so we do it
2745         JSC::JSValue prototype = callee->get(exec, exec->propertyNames().prototype);
2746         JSC::Structure *structure = prototype.isObject() ? JSC::asObject(prototype)->inheritorID()
2747                                                          : originalGlobalObject()->emptyObjectStructure();
2748         thisObject = new (exec) QScriptObject(structure);
2749     }
2750 
2751     int flags = NativeContext;
2752     if (calledAsConstructor)
2753         flags |= CalledAsConstructorContext;
2754 
2755     //build a frame
2756     JSC::CallFrame *newCallFrame = exec;
2757     if (callee == 0 //called from  public QScriptEngine::pushContext
2758         || exec->returnPC() == 0 || (contextFlags(exec) & NativeContext) //called from native-native call
2759         || (exec->codeBlock() && exec->callee() != callee)) { //the interpreter did not build a frame for us.
2760         //We need to check if the Interpreter might have already created a frame for function called from JS.
2761         JSC::Interpreter *interp = exec->interpreter();
2762         JSC::Register *oldEnd = interp->registerFile().end();
2763         int argc = args.size() + 1; //add "this"
2764         JSC::Register *newEnd = oldEnd + argc + JSC::RegisterFile::CallFrameHeaderSize;
2765         if (!interp->registerFile().grow(newEnd))
2766             return 0; //### Stack overflow
2767         newCallFrame = JSC::CallFrame::create(oldEnd);
2768         newCallFrame[0] = thisObject;
2769         int dst = 0;
2770         JSC::ArgList::const_iterator it;
2771         for (it = args.begin(); it != args.end(); ++it)
2772             newCallFrame[++dst] = *it;
2773         newCallFrame += argc + JSC::RegisterFile::CallFrameHeaderSize;
2774 
2775         if (!clearScopeChain) {
2776             newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee);
2777         } else {
2778             newCallFrame->init(0, /*vPC=*/0, globalExec()->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee);
2779         }
2780     } else {
2781         setContextFlags(newCallFrame, flags);
2782 #if ENABLE(JIT)
2783         exec->registers()[JSC::RegisterFile::Callee] = JSC::JSValue(callee); //JIT let the callee set the 'callee'
2784 #endif
2785         if (calledAsConstructor) {
2786             //update the new created this
2787             JSC::Register* thisRegister = thisRegisterForFrame(newCallFrame);
2788             *thisRegister = thisObject;
2789         }
2790     }
2791     currentFrame = newCallFrame;
2792     return newCallFrame;
2793 }
2794 
2795 
2796 /*!
2797   Pops the current execution context and restores the previous one.
2798   This function must be used in conjunction with pushContext().
2799 
2800   \sa pushContext()
2801 */
popContext()2802 void QScriptEngine::popContext()
2803 {
2804     if (agent())
2805         agent()->contextPop();
2806     Q_D(QScriptEngine);
2807     QScript::APIShim shim(d);
2808     if (d->currentFrame->returnPC() != 0 || d->currentFrame->codeBlock() != 0
2809         || !currentContext()->parentContext()) {
2810         qWarning("QScriptEngine::popContext() doesn't match with pushContext()");
2811         return;
2812     }
2813 
2814     d->popContext();
2815 }
2816 
2817 /*! \internal
2818     counter part of QScriptEnginePrivate::pushContext
2819  */
popContext()2820 void QScriptEnginePrivate::popContext()
2821 {
2822     uint flags = contextFlags(currentFrame);
2823     bool hasScope = flags & HasScopeContext;
2824     if (flags & ShouldRestoreCallFrame) { //normal case
2825         JSC::RegisterFile &registerFile = currentFrame->interpreter()->registerFile();
2826         JSC::Register *const newEnd = currentFrame->registers() - JSC::RegisterFile::CallFrameHeaderSize - currentFrame->argumentCount();
2827         if (hasScope)
2828             currentFrame->scopeChain()->pop()->deref();
2829         registerFile.shrink(newEnd);
2830     } else if(hasScope) { //the stack frame was created by the Interpreter, we don't need to rewind it.
2831         currentFrame->setScopeChain(currentFrame->scopeChain()->pop());
2832         currentFrame->scopeChain()->deref();
2833     }
2834     currentFrame = currentFrame->callerFrame();
2835 }
2836 
2837 /*!
2838   Returns true if the last script evaluation resulted in an uncaught
2839   exception; otherwise returns false.
2840 
2841   The exception state is cleared when evaluate() is called.
2842 
2843   \sa uncaughtException(), uncaughtExceptionLineNumber()
2844 */
hasUncaughtException() const2845 bool QScriptEngine::hasUncaughtException() const
2846 {
2847     Q_D(const QScriptEngine);
2848     JSC::ExecState* exec = d->globalExec();
2849     return exec->hadException() || d->currentException().isValid();
2850 }
2851 
2852 /*!
2853   Returns the current uncaught exception, or an invalid QScriptValue
2854   if there is no uncaught exception.
2855 
2856   The exception value is typically an \c{Error} object; in that case,
2857   you can call toString() on the return value to obtain an error
2858   message.
2859 
2860   \sa hasUncaughtException(), uncaughtExceptionLineNumber(),
2861 */
uncaughtException() const2862 QScriptValue QScriptEngine::uncaughtException() const
2863 {
2864     Q_D(const QScriptEngine);
2865     QScriptValue result;
2866     JSC::ExecState* exec = d->globalExec();
2867     if (exec->hadException())
2868         result = const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(exec->exception());
2869     else
2870         result = d->currentException();
2871     return result;
2872 }
2873 
2874 /*!
2875   Returns the line number where the last uncaught exception occurred.
2876 
2877   Line numbers are 1-based, unless a different base was specified as
2878   the second argument to evaluate().
2879 
2880   \sa hasUncaughtException()
2881 */
uncaughtExceptionLineNumber() const2882 int QScriptEngine::uncaughtExceptionLineNumber() const
2883 {
2884     if (!hasUncaughtException())
2885         return -1;
2886     return uncaughtException().property(QLatin1String("lineNumber")).toInt32();
2887 }
2888 
2889 /*!
2890   Returns a human-readable backtrace of the last uncaught exception.
2891 
2892   It is in the form \c{<function-name>()@<file-name>:<line-number>}.
2893 
2894   \sa uncaughtException()
2895 */
uncaughtExceptionBacktrace() const2896 QStringList QScriptEngine::uncaughtExceptionBacktrace() const
2897 {
2898     if (!hasUncaughtException())
2899         return QStringList();
2900 // ### currently no way to get a full backtrace from JSC without installing a
2901 // debugger that reimplements exception() and store the backtrace there.
2902     QScriptValue value = uncaughtException();
2903     if (!value.isError())
2904         return QStringList();
2905     QStringList result;
2906     result.append(QString::fromLatin1("<anonymous>()@%0:%1")
2907                   .arg(value.property(QLatin1String("fileName")).toString())
2908                   .arg(value.property(QLatin1String("lineNumber")).toInt32()));
2909     return result;
2910 }
2911 
2912 /*!
2913   \since 4.4
2914 
2915   Clears any uncaught exceptions in this engine.
2916 
2917   \sa hasUncaughtException()
2918 */
clearExceptions()2919 void QScriptEngine::clearExceptions()
2920 {
2921     Q_D(QScriptEngine);
2922     JSC::ExecState* exec = d->currentFrame;
2923     exec->clearException();
2924     d->clearCurrentException();
2925 }
2926 
2927 /*!
2928   Returns the default prototype associated with the given \a metaTypeId,
2929   or an invalid QScriptValue if no default prototype has been set.
2930 
2931   \sa setDefaultPrototype()
2932 */
defaultPrototype(int metaTypeId) const2933 QScriptValue QScriptEngine::defaultPrototype(int metaTypeId) const
2934 {
2935     Q_D(const QScriptEngine);
2936     return const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(d->defaultPrototype(metaTypeId));
2937 }
2938 
2939 /*!
2940   Sets the default prototype of the C++ type identified by the given
2941   \a metaTypeId to \a prototype.
2942 
2943   The default prototype provides a script interface for values of
2944   type \a metaTypeId when a value of that type is accessed from script
2945   code.  Whenever the script engine (implicitly or explicitly) creates
2946   a QScriptValue from a value of type \a metaTypeId, the default
2947   prototype will be set as the QScriptValue's prototype.
2948 
2949   The \a prototype object itself may be constructed using one of two
2950   principal techniques; the simplest is to subclass QScriptable, which
2951   enables you to define the scripting API of the type through QObject
2952   properties and slots.  Another possibility is to create a script
2953   object by calling newObject(), and populate the object with the
2954   desired properties (e.g. native functions wrapped with
2955   newFunction()).
2956 
2957   \sa defaultPrototype(), qScriptRegisterMetaType(), QScriptable, {Default Prototypes Example}
2958 */
setDefaultPrototype(int metaTypeId,const QScriptValue & prototype)2959 void QScriptEngine::setDefaultPrototype(int metaTypeId, const QScriptValue &prototype)
2960 {
2961     Q_D(QScriptEngine);
2962     d->setDefaultPrototype(metaTypeId, d->scriptValueToJSCValue(prototype));
2963 }
2964 
2965 /*!
2966   \typedef QScriptEngine::FunctionSignature
2967   \relates QScriptEngine
2968 
2969   The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *)}.
2970 
2971   A function with such a signature can be passed to
2972   QScriptEngine::newFunction() to wrap the function.
2973 */
2974 
2975 /*!
2976   \typedef QScriptEngine::FunctionWithArgSignature
2977   \relates QScriptEngine
2978 
2979   The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *, void *)}.
2980 
2981   A function with such a signature can be passed to
2982   QScriptEngine::newFunction() to wrap the function.
2983 */
2984 
2985 /*!
2986     \typedef QScriptEngine::MarshalFunction
2987     \internal
2988 */
2989 
2990 /*!
2991     \typedef QScriptEngine::DemarshalFunction
2992     \internal
2993 */
2994 
2995 /*!
2996     \internal
2997 */
create(int type,const void * ptr)2998 QScriptValue QScriptEngine::create(int type, const void *ptr)
2999 {
3000     Q_D(QScriptEngine);
3001     QScript::APIShim shim(d);
3002     return d->scriptValueFromJSCValue(d->create(d->currentFrame, type, ptr));
3003 }
3004 
create(JSC::ExecState * exec,int type,const void * ptr)3005 JSC::JSValue QScriptEnginePrivate::create(JSC::ExecState *exec, int type, const void *ptr)
3006 {
3007     Q_ASSERT(ptr != 0);
3008     JSC::JSValue result;
3009     QScriptEnginePrivate *eng = exec ? QScript::scriptEngineFromExec(exec) : 0;
3010     QScriptTypeInfo *info = eng ? eng->m_typeInfos.value(type) : 0;
3011     if (info && info->marshal) {
3012         result = eng->scriptValueToJSCValue(info->marshal(eng->q_func(), ptr));
3013     } else {
3014         // check if it's one of the types we know
3015         switch (QMetaType::Type(type)) {
3016         case QMetaType::Void:
3017             return JSC::jsUndefined();
3018         case QMetaType::Bool:
3019             return JSC::jsBoolean(*reinterpret_cast<const bool*>(ptr));
3020         case QMetaType::Int:
3021             return JSC::jsNumber(exec, *reinterpret_cast<const int*>(ptr));
3022         case QMetaType::UInt:
3023             return JSC::jsNumber(exec, *reinterpret_cast<const uint*>(ptr));
3024         case QMetaType::LongLong:
3025             return JSC::jsNumber(exec, qsreal(*reinterpret_cast<const qlonglong*>(ptr)));
3026         case QMetaType::ULongLong:
3027             return JSC::jsNumber(exec, qsreal(*reinterpret_cast<const qulonglong*>(ptr)));
3028         case QMetaType::Double:
3029             return JSC::jsNumber(exec, qsreal(*reinterpret_cast<const double*>(ptr)));
3030         case QMetaType::QString:
3031             return JSC::jsString(exec, *reinterpret_cast<const QString*>(ptr));
3032         case QMetaType::Float:
3033             return JSC::jsNumber(exec, *reinterpret_cast<const float*>(ptr));
3034         case QMetaType::Short:
3035             return JSC::jsNumber(exec, *reinterpret_cast<const short*>(ptr));
3036         case QMetaType::UShort:
3037             return JSC::jsNumber(exec, *reinterpret_cast<const unsigned short*>(ptr));
3038         case QMetaType::Char:
3039             return JSC::jsNumber(exec, *reinterpret_cast<const char*>(ptr));
3040         case QMetaType::UChar:
3041             return JSC::jsNumber(exec, *reinterpret_cast<const unsigned char*>(ptr));
3042         case QMetaType::QChar:
3043             return JSC::jsNumber(exec, (*reinterpret_cast<const QChar*>(ptr)).unicode());
3044         case QMetaType::QStringList:
3045             result = arrayFromStringList(exec, *reinterpret_cast<const QStringList *>(ptr));
3046             break;
3047         case QMetaType::QVariantList:
3048             result = arrayFromVariantList(exec, *reinterpret_cast<const QVariantList *>(ptr));
3049             break;
3050         case QMetaType::QVariantMap:
3051             result = objectFromVariantMap(exec, *reinterpret_cast<const QVariantMap *>(ptr));
3052             break;
3053         case QMetaType::QDateTime:
3054             result = newDate(exec, *reinterpret_cast<const QDateTime *>(ptr));
3055             break;
3056         case QMetaType::QDate:
3057             result = newDate(exec, QDateTime(*reinterpret_cast<const QDate *>(ptr)));
3058             break;
3059 #ifndef QT_NO_REGEXP
3060         case QMetaType::QRegExp:
3061             result = newRegExp(exec, *reinterpret_cast<const QRegExp *>(ptr));
3062             break;
3063 #endif
3064 #ifndef QT_NO_QOBJECT
3065         case QMetaType::QObjectStar:
3066         case QMetaType::QWidgetStar:
3067             result = eng->newQObject(*reinterpret_cast<QObject* const *>(ptr));
3068             break;
3069 #endif
3070         case QMetaType::QVariant:
3071             result = eng->newVariant(*reinterpret_cast<const QVariant*>(ptr));
3072             break;
3073         default:
3074             if (type == qMetaTypeId<QScriptValue>()) {
3075                 result = eng->scriptValueToJSCValue(*reinterpret_cast<const QScriptValue*>(ptr));
3076                 if (!result)
3077                     return JSC::jsUndefined();
3078             }
3079 
3080 #ifndef QT_NO_QOBJECT
3081             // lazy registration of some common list types
3082             else if (type == qMetaTypeId<QObjectList>()) {
3083                 qScriptRegisterSequenceMetaType<QObjectList>(eng->q_func());
3084                 return create(exec, type, ptr);
3085             }
3086 #endif
3087             else if (type == qMetaTypeId<QList<int> >()) {
3088                 qScriptRegisterSequenceMetaType<QList<int> >(eng->q_func());
3089                 return create(exec, type, ptr);
3090             }
3091 
3092             else {
3093                 QByteArray typeName = QMetaType::typeName(type);
3094                 if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(ptr))
3095                     return JSC::jsNull();
3096                 else
3097                     result = eng->newVariant(QVariant(type, ptr));
3098             }
3099         }
3100     }
3101     if (result && result.isObject() && info && info->prototype
3102         && JSC::JSValue::strictEqual(exec, JSC::asObject(result)->prototype(), eng->originalGlobalObject()->objectPrototype())) {
3103         JSC::asObject(result)->setPrototype(info->prototype);
3104     }
3105     return result;
3106 }
3107 
convertValue(JSC::ExecState * exec,JSC::JSValue value,int type,void * ptr)3108 bool QScriptEnginePrivate::convertValue(JSC::ExecState *exec, JSC::JSValue value,
3109                                         int type, void *ptr)
3110 {
3111     QScriptEnginePrivate *eng = exec ? QScript::scriptEngineFromExec(exec) : 0;
3112     if (eng) {
3113         QScriptTypeInfo *info = eng->m_typeInfos.value(type);
3114         if (info && info->demarshal) {
3115             info->demarshal(eng->scriptValueFromJSCValue(value), ptr);
3116             return true;
3117         }
3118     }
3119 
3120     // check if it's one of the types we know
3121     switch (QMetaType::Type(type)) {
3122     case QMetaType::Bool:
3123         *reinterpret_cast<bool*>(ptr) = toBool(exec, value);
3124         return true;
3125     case QMetaType::Int:
3126         *reinterpret_cast<int*>(ptr) = toInt32(exec, value);
3127         return true;
3128     case QMetaType::UInt:
3129         *reinterpret_cast<uint*>(ptr) = toUInt32(exec, value);
3130         return true;
3131     case QMetaType::LongLong:
3132         *reinterpret_cast<qlonglong*>(ptr) = qlonglong(toInteger(exec, value));
3133         return true;
3134     case QMetaType::ULongLong:
3135         *reinterpret_cast<qulonglong*>(ptr) = qulonglong(toInteger(exec, value));
3136         return true;
3137     case QMetaType::Double:
3138         *reinterpret_cast<double*>(ptr) = toNumber(exec, value);
3139         return true;
3140     case QMetaType::QString:
3141         if (value.isUndefined() || value.isNull())
3142             *reinterpret_cast<QString*>(ptr) = QString();
3143         else
3144             *reinterpret_cast<QString*>(ptr) = toString(exec, value);
3145         return true;
3146     case QMetaType::Float:
3147         *reinterpret_cast<float*>(ptr) = toNumber(exec, value);
3148         return true;
3149     case QMetaType::Short:
3150         *reinterpret_cast<short*>(ptr) = short(toInt32(exec, value));
3151         return true;
3152     case QMetaType::UShort:
3153         *reinterpret_cast<unsigned short*>(ptr) = QScript::ToUInt16(toNumber(exec, value));
3154         return true;
3155     case QMetaType::Char:
3156         *reinterpret_cast<char*>(ptr) = char(toInt32(exec, value));
3157         return true;
3158     case QMetaType::UChar:
3159         *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(toInt32(exec, value));
3160         return true;
3161     case QMetaType::QChar:
3162         if (value.isString()) {
3163             QString str = toString(exec, value);
3164             *reinterpret_cast<QChar*>(ptr) = str.isEmpty() ? QChar() : str.at(0);
3165         } else {
3166             *reinterpret_cast<QChar*>(ptr) = QChar(QScript::ToUInt16(toNumber(exec, value)));
3167         }
3168         return true;
3169     case QMetaType::QDateTime:
3170         if (isDate(value)) {
3171             *reinterpret_cast<QDateTime *>(ptr) = toDateTime(exec, value);
3172             return true;
3173         } break;
3174     case QMetaType::QDate:
3175         if (isDate(value)) {
3176             *reinterpret_cast<QDate *>(ptr) = toDateTime(exec, value).date();
3177             return true;
3178         } break;
3179 #ifndef QT_NO_REGEXP
3180     case QMetaType::QRegExp:
3181         if (isRegExp(value)) {
3182             *reinterpret_cast<QRegExp *>(ptr) = toRegExp(exec, value);
3183             return true;
3184         } break;
3185 #endif
3186 #ifndef QT_NO_QOBJECT
3187     case QMetaType::QObjectStar:
3188         if (isQObject(value) || value.isNull()) {
3189             *reinterpret_cast<QObject* *>(ptr) = toQObject(exec, value);
3190             return true;
3191         } break;
3192     case QMetaType::QWidgetStar:
3193         if (isQObject(value) || value.isNull()) {
3194             QObject *qo = toQObject(exec, value);
3195             if (!qo || qo->isWidgetType()) {
3196                 *reinterpret_cast<QWidget* *>(ptr) = reinterpret_cast<QWidget*>(qo);
3197                 return true;
3198             }
3199         } break;
3200 #endif
3201     case QMetaType::QStringList:
3202         if (isArray(value)) {
3203             *reinterpret_cast<QStringList *>(ptr) = stringListFromArray(exec, value);
3204             return true;
3205         } break;
3206     case QMetaType::QVariantList:
3207         if (isArray(value)) {
3208             *reinterpret_cast<QVariantList *>(ptr) = variantListFromArray(exec, JSC::asArray(value));
3209             return true;
3210         } break;
3211     case QMetaType::QVariantMap:
3212         if (isObject(value)) {
3213             *reinterpret_cast<QVariantMap *>(ptr) = variantMapFromObject(exec, JSC::asObject(value));
3214             return true;
3215         } break;
3216     case QMetaType::QVariant:
3217         *reinterpret_cast<QVariant*>(ptr) = toVariant(exec, value);
3218         return true;
3219     default:
3220     ;
3221     }
3222 
3223     QByteArray name = QMetaType::typeName(type);
3224 #ifndef QT_NO_QOBJECT
3225     if (convertToNativeQObject(exec, value, name, reinterpret_cast<void* *>(ptr)))
3226         return true;
3227 #endif
3228     if (isVariant(value) && name.endsWith('*')) {
3229         int valueType = QMetaType::type(name.left(name.size()-1));
3230         QVariant &var = variantValue(value);
3231         if (valueType == var.userType()) {
3232             *reinterpret_cast<void* *>(ptr) = var.data();
3233             return true;
3234         } else {
3235             // look in the prototype chain
3236             JSC::JSValue proto = JSC::asObject(value)->prototype();
3237             while (proto.isObject()) {
3238                 bool canCast = false;
3239                 if (isVariant(proto)) {
3240                     canCast = (type == variantValue(proto).userType())
3241                               || (valueType && (valueType == variantValue(proto).userType()));
3242                 }
3243 #ifndef QT_NO_QOBJECT
3244                 else if (isQObject(proto)) {
3245                     QByteArray className = name.left(name.size()-1);
3246                     if (QObject *qobject = toQObject(exec, proto))
3247                         canCast = qobject->qt_metacast(className) != 0;
3248                 }
3249 #endif
3250                 if (canCast) {
3251                     QByteArray varTypeName = QMetaType::typeName(var.userType());
3252                     if (varTypeName.endsWith('*'))
3253                         *reinterpret_cast<void* *>(ptr) = *reinterpret_cast<void* *>(var.data());
3254                     else
3255                         *reinterpret_cast<void* *>(ptr) = var.data();
3256                     return true;
3257                 }
3258                 proto = JSC::asObject(proto)->prototype();
3259             }
3260         }
3261     } else if (value.isNull() && name.endsWith('*')) {
3262         *reinterpret_cast<void* *>(ptr) = 0;
3263         return true;
3264     } else if (type == qMetaTypeId<QScriptValue>()) {
3265         if (!eng)
3266             return false;
3267         *reinterpret_cast<QScriptValue*>(ptr) = eng->scriptValueFromJSCValue(value);
3268         return true;
3269     }
3270 
3271     // lazy registration of some common list types
3272 #ifndef QT_NO_QOBJECT
3273     else if (type == qMetaTypeId<QObjectList>()) {
3274         if (!eng)
3275             return false;
3276         qScriptRegisterSequenceMetaType<QObjectList>(eng->q_func());
3277         return convertValue(exec, value, type, ptr);
3278     }
3279 #endif
3280     else if (type == qMetaTypeId<QList<int> >()) {
3281         if (!eng)
3282             return false;
3283         qScriptRegisterSequenceMetaType<QList<int> >(eng->q_func());
3284         return convertValue(exec, value, type, ptr);
3285     }
3286 
3287 #if 0
3288     if (!name.isEmpty()) {
3289         qWarning("QScriptEngine::convert: unable to convert value to type `%s'",
3290                  name.constData());
3291     }
3292 #endif
3293     return false;
3294 }
3295 
convertNumber(qsreal value,int type,void * ptr)3296 bool QScriptEnginePrivate::convertNumber(qsreal value, int type, void *ptr)
3297 {
3298     switch (QMetaType::Type(type)) {
3299     case QMetaType::Bool:
3300         *reinterpret_cast<bool*>(ptr) = QScript::ToBool(value);
3301         return true;
3302     case QMetaType::Int:
3303         *reinterpret_cast<int*>(ptr) = QScript::ToInt32(value);
3304         return true;
3305     case QMetaType::UInt:
3306         *reinterpret_cast<uint*>(ptr) = QScript::ToUInt32(value);
3307         return true;
3308     case QMetaType::LongLong:
3309         *reinterpret_cast<qlonglong*>(ptr) = qlonglong(QScript::ToInteger(value));
3310         return true;
3311     case QMetaType::ULongLong:
3312         *reinterpret_cast<qulonglong*>(ptr) = qulonglong(QScript::ToInteger(value));
3313         return true;
3314     case QMetaType::Double:
3315         *reinterpret_cast<double*>(ptr) = value;
3316         return true;
3317     case QMetaType::QString:
3318         *reinterpret_cast<QString*>(ptr) = QScript::ToString(value);
3319         return true;
3320     case QMetaType::Float:
3321         *reinterpret_cast<float*>(ptr) = value;
3322         return true;
3323     case QMetaType::Short:
3324         *reinterpret_cast<short*>(ptr) = short(QScript::ToInt32(value));
3325         return true;
3326     case QMetaType::UShort:
3327         *reinterpret_cast<unsigned short*>(ptr) = QScript::ToUInt16(value);
3328         return true;
3329     case QMetaType::Char:
3330         *reinterpret_cast<char*>(ptr) = char(QScript::ToInt32(value));
3331         return true;
3332     case QMetaType::UChar:
3333         *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(QScript::ToInt32(value));
3334         return true;
3335     case QMetaType::QChar:
3336         *reinterpret_cast<QChar*>(ptr) = QChar(QScript::ToUInt16(value));
3337         return true;
3338     default:
3339         break;
3340     }
3341     return false;
3342 }
3343 
convertString(const QString & value,int type,void * ptr)3344 bool QScriptEnginePrivate::convertString(const QString &value, int type, void *ptr)
3345 {
3346     switch (QMetaType::Type(type)) {
3347     case QMetaType::Bool:
3348         *reinterpret_cast<bool*>(ptr) = QScript::ToBool(value);
3349         return true;
3350     case QMetaType::Int:
3351         *reinterpret_cast<int*>(ptr) = QScript::ToInt32(value);
3352         return true;
3353     case QMetaType::UInt:
3354         *reinterpret_cast<uint*>(ptr) = QScript::ToUInt32(value);
3355         return true;
3356     case QMetaType::LongLong:
3357         *reinterpret_cast<qlonglong*>(ptr) = qlonglong(QScript::ToInteger(value));
3358         return true;
3359     case QMetaType::ULongLong:
3360         *reinterpret_cast<qulonglong*>(ptr) = qulonglong(QScript::ToInteger(value));
3361         return true;
3362     case QMetaType::Double:
3363         *reinterpret_cast<double*>(ptr) = QScript::ToNumber(value);
3364         return true;
3365     case QMetaType::QString:
3366         *reinterpret_cast<QString*>(ptr) = value;
3367         return true;
3368     case QMetaType::Float:
3369         *reinterpret_cast<float*>(ptr) = QScript::ToNumber(value);
3370         return true;
3371     case QMetaType::Short:
3372         *reinterpret_cast<short*>(ptr) = short(QScript::ToInt32(value));
3373         return true;
3374     case QMetaType::UShort:
3375         *reinterpret_cast<unsigned short*>(ptr) = QScript::ToUInt16(value);
3376         return true;
3377     case QMetaType::Char:
3378         *reinterpret_cast<char*>(ptr) = char(QScript::ToInt32(value));
3379         return true;
3380     case QMetaType::UChar:
3381         *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(QScript::ToInt32(value));
3382         return true;
3383     case QMetaType::QChar:
3384         *reinterpret_cast<QChar*>(ptr) = QChar(QScript::ToUInt16(value));
3385         return true;
3386     default:
3387         break;
3388     }
3389     return false;
3390 }
3391 
hasDemarshalFunction(int type) const3392 bool QScriptEnginePrivate::hasDemarshalFunction(int type) const
3393 {
3394     QScriptTypeInfo *info = m_typeInfos.value(type);
3395     return info && (info->demarshal != 0);
3396 }
3397 
translationContextFromUrl(const JSC::UString & url)3398 JSC::UString QScriptEnginePrivate::translationContextFromUrl(const JSC::UString &url)
3399 {
3400     if (url != cachedTranslationUrl) {
3401         cachedTranslationContext = QFileInfo(url).baseName();
3402         cachedTranslationUrl = url;
3403     }
3404     return cachedTranslationContext;
3405 }
3406 
3407 /*!
3408     \internal
3409 */
convert(const QScriptValue & value,int type,void * ptr)3410 bool QScriptEngine::convert(const QScriptValue &value, int type, void *ptr)
3411 {
3412     Q_D(QScriptEngine);
3413     QScript::APIShim shim(d);
3414     return QScriptEnginePrivate::convertValue(d->currentFrame, d->scriptValueToJSCValue(value), type, ptr);
3415 }
3416 
3417 /*!
3418     \internal
3419 */
convertV2(const QScriptValue & value,int type,void * ptr)3420 bool QScriptEngine::convertV2(const QScriptValue &value, int type, void *ptr)
3421 {
3422     QScriptValuePrivate *vp = QScriptValuePrivate::get(value);
3423     if (vp) {
3424         switch (vp->type) {
3425         case QScriptValuePrivate::JavaScriptCore: {
3426             if (vp->engine) {
3427                 QScript::APIShim shim(vp->engine);
3428                 return QScriptEnginePrivate::convertValue(vp->engine->currentFrame, vp->jscValue, type, ptr);
3429             } else {
3430                 return QScriptEnginePrivate::convertValue(0, vp->jscValue, type, ptr);
3431             }
3432         }
3433         case QScriptValuePrivate::Number:
3434             return QScriptEnginePrivate::convertNumber(vp->numberValue, type, ptr);
3435         case QScriptValuePrivate::String:
3436             return QScriptEnginePrivate::convertString(vp->stringValue, type, ptr);
3437         }
3438     }
3439     return false;
3440 }
3441 
3442 /*!
3443     \internal
3444 */
registerCustomType(int type,MarshalFunction mf,DemarshalFunction df,const QScriptValue & prototype)3445 void QScriptEngine::registerCustomType(int type, MarshalFunction mf,
3446                                        DemarshalFunction df,
3447                                        const QScriptValue &prototype)
3448 {
3449     Q_D(QScriptEngine);
3450     QScript::APIShim shim(d);
3451     QScriptTypeInfo *info = d->m_typeInfos.value(type);
3452     if (!info) {
3453         info = new QScriptTypeInfo();
3454         d->m_typeInfos.insert(type, info);
3455     }
3456     info->marshal = mf;
3457     info->demarshal = df;
3458     info->prototype = d->scriptValueToJSCValue(prototype);
3459 }
3460 
3461 /*!
3462   \since 4.5
3463 
3464   Installs translator functions on the given \a object, or on the Global
3465   Object if no object is specified.
3466 
3467   The relation between Qt Script translator functions and C++ translator
3468   functions is described in the following table:
3469 
3470     \table
3471     \header \o Script Function \o Corresponding C++ Function
3472     \row    \o qsTr()       \o QObject::tr()
3473     \row    \o QT_TR_NOOP() \o QT_TR_NOOP()
3474     \row    \o qsTranslate() \o QCoreApplication::translate()
3475     \row    \o QT_TRANSLATE_NOOP() \o QT_TRANSLATE_NOOP()
3476     \row    \o qsTrId() (since 4.7) \o qtTrId()
3477     \row    \o QT_TRID_NOOP() (since 4.7) \o QT_TRID_NOOP()
3478     \endtable
3479 
3480   \sa {Internationalization with Qt}
3481 */
installTranslatorFunctions(const QScriptValue & object)3482 void QScriptEngine::installTranslatorFunctions(const QScriptValue &object)
3483 {
3484     Q_D(QScriptEngine);
3485     QScript::APIShim shim(d);
3486     JSC::ExecState* exec = d->currentFrame;
3487     JSC::JSValue jscObject = d->scriptValueToJSCValue(object);
3488     JSC::JSGlobalObject *glob = d->originalGlobalObject();
3489     if (!jscObject || !jscObject.isObject())
3490         jscObject = d->globalObject();
3491 //    unsigned attribs = JSC::DontEnum;
3492 
3493 #ifndef QT_NO_TRANSLATION
3494     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 5, JSC::Identifier(exec, "qsTranslate"), QScript::functionQsTranslate));
3495     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 2, JSC::Identifier(exec, "QT_TRANSLATE_NOOP"), QScript::functionQsTranslateNoOp));
3496     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 3, JSC::Identifier(exec, "qsTr"), QScript::functionQsTr));
3497     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "QT_TR_NOOP"), QScript::functionQsTrNoOp));
3498     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "qsTrId"), QScript::functionQsTrId));
3499     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "QT_TRID_NOOP"), QScript::functionQsTrIdNoOp));
3500 #endif
3501 
3502     glob->stringPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "arg"), QScript::stringProtoFuncArg));
3503 }
3504 
3505 /*!
3506     Imports the given \a extension into this QScriptEngine.  Returns
3507     undefinedValue() if the extension was successfully imported. You
3508     can call hasUncaughtException() to check if an error occurred; in
3509     that case, the return value is the value that was thrown by the
3510     exception (usually an \c{Error} object).
3511 
3512     QScriptEngine ensures that a particular extension is only imported
3513     once; subsequent calls to importExtension() with the same extension
3514     name will do nothing and return undefinedValue().
3515 
3516     \sa availableExtensions(), QScriptExtensionPlugin, {Creating QtScript Extensions}
3517 */
importExtension(const QString & extension)3518 QScriptValue QScriptEngine::importExtension(const QString &extension)
3519 {
3520 #if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
3521     Q_UNUSED(extension);
3522 #else
3523     Q_D(QScriptEngine);
3524     QScript::APIShim shim(d);
3525     if (d->importedExtensions.contains(extension))
3526         return undefinedValue(); // already imported
3527 
3528     QScriptContext *context = currentContext();
3529     QCoreApplication *app = QCoreApplication::instance();
3530     if (!app)
3531         return context->throwError(QLatin1String("No application object"));
3532 
3533     QObjectList staticPlugins = QPluginLoader::staticInstances();
3534     QStringList libraryPaths = app->libraryPaths();
3535     QString dot = QLatin1String(".");
3536     QStringList pathComponents = extension.split(dot);
3537     QString initDotJs = QLatin1String("__init__.js");
3538 
3539     QString ext;
3540     for (int i = 0; i < pathComponents.count(); ++i) {
3541         if (!ext.isEmpty())
3542             ext.append(dot);
3543         ext.append(pathComponents.at(i));
3544         if (d->importedExtensions.contains(ext))
3545             continue; // already imported
3546 
3547         if (d->extensionsBeingImported.contains(ext)) {
3548             return context->throwError(QString::fromLatin1("recursive import of %0")
3549                                        .arg(extension));
3550         }
3551         d->extensionsBeingImported.insert(ext);
3552 
3553         QScriptExtensionInterface *iface = 0;
3554         QString initjsContents;
3555         QString initjsFileName;
3556 
3557         // look for the extension in static plugins
3558         for (int j = 0; j < staticPlugins.size(); ++j) {
3559             iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(j));
3560             if (!iface)
3561                 continue;
3562             if (iface->keys().contains(ext))
3563                 break; // use this one
3564             else
3565                 iface = 0; // keep looking
3566         }
3567 
3568         {
3569             // look for __init__.js resource
3570             QString path = QString::fromLatin1(":/qtscriptextension");
3571             for (int j = 0; j <= i; ++j) {
3572                 path.append(QLatin1Char('/'));
3573                 path.append(pathComponents.at(j));
3574             }
3575             path.append(QLatin1Char('/'));
3576             path.append(initDotJs);
3577             QFile file(path);
3578             if (file.open(QIODevice::ReadOnly)) {
3579                 QTextStream ts(&file);
3580                 initjsContents = ts.readAll();
3581                 initjsFileName = path;
3582                 file.close();
3583             }
3584         }
3585 
3586         if (!iface && initjsContents.isEmpty()) {
3587             // look for the extension in library paths
3588             for (int j = 0; j < libraryPaths.count(); ++j) {
3589                 QString libPath = libraryPaths.at(j) + QDir::separator() + QLatin1String("script");
3590                 QDir dir(libPath);
3591                 if (!dir.exists(dot))
3592                     continue;
3593 
3594                 // look for C++ plugin
3595                 QFileInfoList files = dir.entryInfoList(QDir::Files);
3596                 for (int k = 0; k < files.count(); ++k) {
3597                     QFileInfo entry = files.at(k);
3598                     QString filePath = entry.canonicalFilePath();
3599                     QPluginLoader loader(filePath);
3600                     iface = qobject_cast<QScriptExtensionInterface*>(loader.instance());
3601                     if (iface) {
3602                         if (iface->keys().contains(ext))
3603                             break; // use this one
3604                         else
3605                             iface = 0; // keep looking
3606                     }
3607                 }
3608 
3609                 // look for __init__.js in the corresponding dir
3610                 QDir dirdir(libPath);
3611                 bool dirExists = dirdir.exists();
3612                 for (int k = 0; dirExists && (k <= i); ++k)
3613                     dirExists = dirdir.cd(pathComponents.at(k));
3614                 if (dirExists && dirdir.exists(initDotJs)) {
3615                     QFile file(dirdir.canonicalPath()
3616                                + QDir::separator() + initDotJs);
3617                     if (file.open(QIODevice::ReadOnly)) {
3618                         QTextStream ts(&file);
3619                         initjsContents = ts.readAll();
3620                         initjsFileName = file.fileName();
3621                         file.close();
3622                     }
3623                 }
3624 
3625                 if (iface || !initjsContents.isEmpty())
3626                     break;
3627             }
3628         }
3629 
3630         if (!iface && initjsContents.isEmpty()) {
3631             d->extensionsBeingImported.remove(ext);
3632             return context->throwError(
3633                 QString::fromLatin1("Unable to import %0: no such extension")
3634                 .arg(extension));
3635         }
3636 
3637         // initialize the extension in a new context
3638         QScriptContext *ctx = pushContext();
3639         ctx->setThisObject(globalObject());
3640         ctx->activationObject().setProperty(QLatin1String("__extension__"), ext,
3641                                             QScriptValue::ReadOnly | QScriptValue::Undeletable);
3642         ctx->activationObject().setProperty(QLatin1String("__setupPackage__"),
3643                                             newFunction(QScript::__setupPackage__));
3644         ctx->activationObject().setProperty(QLatin1String("__postInit__"), QScriptValue(QScriptValue::UndefinedValue));
3645 
3646         // the script is evaluated first
3647         if (!initjsContents.isEmpty()) {
3648             QScriptValue ret = evaluate(initjsContents, initjsFileName);
3649             if (hasUncaughtException()) {
3650                 popContext();
3651                 d->extensionsBeingImported.remove(ext);
3652                 return ret;
3653             }
3654         }
3655 
3656         // next, the C++ plugin is called
3657         if (iface) {
3658             iface->initialize(ext, this);
3659             if (hasUncaughtException()) {
3660                 QScriptValue ret = uncaughtException(); // ctx_p->returnValue();
3661                 popContext();
3662                 d->extensionsBeingImported.remove(ext);
3663                 return ret;
3664             }
3665         }
3666 
3667         // if the __postInit__ function has been set, we call it
3668         QScriptValue postInit = ctx->activationObject().property(QLatin1String("__postInit__"));
3669         if (postInit.isFunction()) {
3670             postInit.call(globalObject());
3671             if (hasUncaughtException()) {
3672                 QScriptValue ret = uncaughtException(); // ctx_p->returnValue();
3673                 popContext();
3674                 d->extensionsBeingImported.remove(ext);
3675                 return ret;
3676             }
3677         }
3678 
3679         popContext();
3680 
3681         d->importedExtensions.insert(ext);
3682         d->extensionsBeingImported.remove(ext);
3683     } // for (i)
3684 #endif // QT_NO_QOBJECT
3685     return undefinedValue();
3686 }
3687 
3688 /*!
3689     \since 4.4
3690 
3691     Returns a list naming the available extensions that can be
3692     imported using the importExtension() function. This list includes
3693     extensions that have been imported.
3694 
3695     \sa importExtension(), importedExtensions()
3696 */
availableExtensions() const3697 QStringList QScriptEngine::availableExtensions() const
3698 {
3699 #if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
3700     return QStringList();
3701 #else
3702     QCoreApplication *app = QCoreApplication::instance();
3703     if (!app)
3704         return QStringList();
3705 
3706     QSet<QString> result;
3707 
3708     QObjectList staticPlugins = QPluginLoader::staticInstances();
3709     for (int i = 0; i < staticPlugins.size(); ++i) {
3710         QScriptExtensionInterface *iface;
3711         iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(i));
3712         if (iface) {
3713             QStringList keys = iface->keys();
3714             for (int j = 0; j < keys.count(); ++j)
3715                 result << keys.at(j);
3716         }
3717     }
3718 
3719     QStringList libraryPaths = app->libraryPaths();
3720     for (int i = 0; i < libraryPaths.count(); ++i) {
3721         QString libPath = libraryPaths.at(i) + QDir::separator() + QLatin1String("script");
3722         QDir dir(libPath);
3723         if (!dir.exists())
3724             continue;
3725 
3726         // look for C++ plugins
3727         QFileInfoList files = dir.entryInfoList(QDir::Files);
3728         for (int j = 0; j < files.count(); ++j) {
3729             QFileInfo entry = files.at(j);
3730             QString filePath = entry.canonicalFilePath();
3731             QPluginLoader loader(filePath);
3732             QScriptExtensionInterface *iface;
3733             iface = qobject_cast<QScriptExtensionInterface*>(loader.instance());
3734             if (iface) {
3735                 QStringList keys = iface->keys();
3736                 for (int k = 0; k < keys.count(); ++k)
3737                     result << keys.at(k);
3738             }
3739         }
3740 
3741         // look for scripts
3742         QString initDotJs = QLatin1String("__init__.js");
3743         QList<QFileInfo> stack;
3744         stack << dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
3745         while (!stack.isEmpty()) {
3746             QFileInfo entry = stack.takeLast();
3747             QDir dd(entry.canonicalFilePath());
3748             if (dd.exists(initDotJs)) {
3749                 QString rpath = dir.relativeFilePath(dd.canonicalPath());
3750                 QStringList components = rpath.split(QLatin1Char('/'));
3751                 result << components.join(QLatin1String("."));
3752                 stack << dd.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
3753             }
3754         }
3755     }
3756 
3757     QStringList lst = result.toList();
3758     qSort(lst);
3759     return lst;
3760 #endif
3761 }
3762 
3763 /*!
3764     \since 4.4
3765 
3766     Returns a list naming the extensions that have been imported
3767     using the importExtension() function.
3768 
3769     \sa availableExtensions()
3770 */
importedExtensions() const3771 QStringList QScriptEngine::importedExtensions() const
3772 {
3773     Q_D(const QScriptEngine);
3774     QStringList lst = d->importedExtensions.toList();
3775     qSort(lst);
3776     return lst;
3777 }
3778 
3779 /*! \fn QScriptValue QScriptEngine::toScriptValue(const T &value)
3780 
3781     Creates a QScriptValue with the given \a value.
3782 
3783     Note that the template type \c{T} must be known to QMetaType.
3784 
3785     See \l{Conversion Between QtScript and C++ Types} for a
3786     description of the built-in type conversion provided by
3787     QtScript. By default, the types that are not specially handled by
3788     QtScript are represented as QVariants (e.g. the \a value is passed
3789     to newVariant()); you can change this behavior by installing your
3790     own type conversion functions with qScriptRegisterMetaType().
3791 
3792     \sa fromScriptValue(), qScriptRegisterMetaType()
3793 */
3794 
3795 /*! \fn T QScriptEngine::fromScriptValue(const QScriptValue &value)
3796 
3797     Returns the given \a value converted to the template type \c{T}.
3798 
3799     Note that \c{T} must be known to QMetaType.
3800 
3801     See \l{Conversion Between QtScript and C++ Types} for a
3802     description of the built-in type conversion provided by
3803     QtScript.
3804 
3805     \sa toScriptValue(), qScriptRegisterMetaType()
3806 */
3807 
3808 /*!
3809     \fn QScriptValue qScriptValueFromValue(QScriptEngine *engine, const T &value)
3810     \since 4.3
3811     \relates QScriptEngine
3812     \obsolete
3813 
3814     Creates a QScriptValue using the given \a engine with the given \a
3815     value of template type \c{T}.
3816 
3817     This function is equivalent to QScriptEngine::toScriptValue().
3818 
3819     \note This function was provided as a workaround for MSVC 6
3820     which did not support member template functions. It is advised
3821     to use the other form in new code.
3822 
3823     \sa QScriptEngine::toScriptValue(), qscriptvalue_cast()
3824 */
3825 
3826 /*!
3827     \fn T qScriptValueToValue(const QScriptValue &value)
3828     \since 4.3
3829     \relates QScriptEngine
3830     \obsolete
3831 
3832     Returns the given \a value converted to the template type \c{T}.
3833 
3834     This function is equivalent to QScriptEngine::fromScriptValue().
3835 
3836     \note This function was provided as a workaround for MSVC 6
3837     which did not support member template functions. It is advised
3838     to use the other form in new code.
3839 
3840     \sa QScriptEngine::fromScriptValue()
3841 */
3842 
3843 /*!
3844     \fn QScriptValue qScriptValueFromSequence(QScriptEngine *engine, const Container &container)
3845     \since 4.3
3846     \relates QScriptEngine
3847 
3848     Creates an array in the form of a QScriptValue using the given \a engine
3849     with the given \a container of template type \c{Container}.
3850 
3851     The \c Container type must provide a \c const_iterator class to enable the
3852     contents of the container to be copied into the array.
3853 
3854     Additionally, the type of each element in the sequence should be
3855     suitable for conversion to a QScriptValue.  See
3856     \l{Conversion Between QtScript and C++ Types} for more information
3857     about the restrictions on types that can be used with QScriptValue.
3858 
3859     \sa QScriptEngine::fromScriptValue()
3860 */
3861 
3862 /*!
3863     \fn void qScriptValueToSequence(const QScriptValue &value, Container &container)
3864     \since 4.3
3865     \relates QScriptEngine
3866 
3867     Copies the elements in the sequence specified by \a value to the given
3868     \a container of template type \c{Container}.
3869 
3870     The \a value used is typically an array, but any container can be copied
3871     as long as it provides a \c length property describing how many elements
3872     it contains.
3873 
3874     Additionally, the type of each element in the sequence must be
3875     suitable for conversion to a C++ type from a QScriptValue.  See
3876     \l{Conversion Between QtScript and C++ Types} for more information
3877     about the restrictions on types that can be used with
3878     QScriptValue.
3879 
3880     \sa qscriptvalue_cast()
3881 */
3882 
3883 /*!
3884     \fn T qscriptvalue_cast(const QScriptValue &value)
3885     \since 4.3
3886     \relates QScriptValue
3887 
3888     Returns the given \a value converted to the template type \c{T}.
3889 
3890     \sa qScriptRegisterMetaType(), QScriptEngine::toScriptValue()
3891 */
3892 
3893 /*! \fn int qScriptRegisterMetaType(
3894             QScriptEngine *engine,
3895             QScriptValue (*toScriptValue)(QScriptEngine *, const T &t),
3896             void (*fromScriptValue)(const QScriptValue &, T &t),
3897             const QScriptValue &prototype = QScriptValue())
3898     \relates QScriptEngine
3899 
3900     Registers the type \c{T} in the given \a engine. \a toScriptValue must
3901     be a function that will convert from a value of type \c{T} to a
3902     QScriptValue, and \a fromScriptValue a function that does the
3903     opposite. \a prototype, if valid, is the prototype that's set on
3904     QScriptValues returned by \a toScriptValue.
3905 
3906     Returns the internal ID used by QMetaType.
3907 
3908     You only need to call this function if you want to provide custom
3909     conversion of values of type \c{T}, i.e. if the default
3910     QVariant-based representation and conversion is not
3911     appropriate. (Note that custom QObject-derived types also fall in
3912     this category; e.g. for a QObject-derived class called MyObject,
3913     you probably want to define conversion functions for MyObject*
3914     that utilize QScriptEngine::newQObject() and
3915     QScriptValue::toQObject().)
3916 
3917     If you only want to define a common script interface for values of
3918     type \c{T}, and don't care how those values are represented
3919     (i.e. storing them in QVariants is fine), use
3920     \l{QScriptEngine::setDefaultPrototype()}{setDefaultPrototype}()
3921     instead; this will minimize conversion costs.
3922 
3923     You need to declare the custom type first with
3924     Q_DECLARE_METATYPE().
3925 
3926     After a type has been registered, you can convert from a
3927     QScriptValue to that type using
3928     \l{QScriptEngine::fromScriptValue()}{fromScriptValue}(), and
3929     create a QScriptValue from a value of that type using
3930     \l{QScriptEngine::toScriptValue()}{toScriptValue}(). The engine
3931     will take care of calling the proper conversion function when
3932     calling C++ slots, and when getting or setting a C++ property;
3933     i.e. the custom type may be used seamlessly on both the C++ side
3934     and the script side.
3935 
3936     The following is an example of how to use this function. We will
3937     specify custom conversion of our type \c{MyStruct}. Here's the C++
3938     type:
3939 
3940     \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 20
3941 
3942     We must declare it so that the type will be known to QMetaType:
3943 
3944     \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 21
3945 
3946     Next, the \c{MyStruct} conversion functions. We represent the
3947     \c{MyStruct} value as a script object and just copy the properties:
3948 
3949     \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 22
3950 
3951     Now we can register \c{MyStruct} with the engine:
3952     \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 23
3953 
3954     Working with \c{MyStruct} values is now easy:
3955     \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 24
3956 
3957     If you want to be able to construct values of your custom type
3958     from script code, you have to register a constructor function for
3959     the type. For example:
3960 
3961     \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 25
3962 
3963     \sa qScriptRegisterSequenceMetaType(), qRegisterMetaType()
3964 */
3965 
3966 /*!
3967     \macro Q_SCRIPT_DECLARE_QMETAOBJECT(QMetaObject, ArgType)
3968     \since 4.3
3969     \relates QScriptEngine
3970 
3971     Declares the given \a QMetaObject. Used in combination with
3972     QScriptEngine::scriptValueFromQMetaObject() to make enums and
3973     instantiation of \a QMetaObject available to script code. The
3974     constructor generated by this macro takes a single argument of
3975     type \a ArgType; typically the argument is the parent type of the
3976     new instance, in which case \a ArgType is \c{QWidget*} or
3977     \c{QObject*}. Objects created by the constructor will have
3978     QScriptEngine::AutoOwnership ownership.
3979 */
3980 
3981 /*! \fn int qScriptRegisterSequenceMetaType(
3982             QScriptEngine *engine,
3983             const QScriptValue &prototype = QScriptValue())
3984     \relates QScriptEngine
3985 
3986     Registers the sequence type \c{T} in the given \a engine. This
3987     function provides conversion functions that convert between \c{T}
3988     and Qt Script \c{Array} objects. \c{T} must provide a
3989     const_iterator class and begin(), end() and push_back()
3990     functions. If \a prototype is valid, it will be set as the
3991     prototype of \c{Array} objects due to conversion from \c{T};
3992     otherwise, the standard \c{Array} prototype will be used.
3993 
3994     Returns the internal ID used by QMetaType.
3995 
3996     You need to declare the container type first with
3997     Q_DECLARE_METATYPE(). If the element type isn't a standard Qt/C++
3998     type, it must be declared using Q_DECLARE_METATYPE() as well.
3999     Example:
4000 
4001     \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 26
4002 
4003     \sa qScriptRegisterMetaType()
4004 */
4005 
4006 /*!
4007   Runs the garbage collector.
4008 
4009   The garbage collector will attempt to reclaim memory by locating and
4010   disposing of objects that are no longer reachable in the script
4011   environment.
4012 
4013   Normally you don't need to call this function; the garbage collector
4014   will automatically be invoked when the QScriptEngine decides that
4015   it's wise to do so (i.e. when a certain number of new objects have
4016   been created). However, you can call this function to explicitly
4017   request that garbage collection should be performed as soon as
4018   possible.
4019 
4020   \sa reportAdditionalMemoryCost()
4021 */
collectGarbage()4022 void QScriptEngine::collectGarbage()
4023 {
4024     Q_D(QScriptEngine);
4025     d->collectGarbage();
4026 }
4027 
4028 /*!
4029   \since 4.7
4030 
4031   Reports an additional memory cost of the given \a size, measured in
4032   bytes, to the garbage collector.
4033 
4034   This function can be called to indicate that a Qt Script object has
4035   memory associated with it that isn't managed by Qt Script itself.
4036   Reporting the additional cost makes it more likely that the garbage
4037   collector will be triggered.
4038 
4039   Note that if the additional memory is shared with objects outside
4040   the scripting environment, the cost should not be reported, since
4041   collecting the Qt Script object would not cause the memory to be
4042   freed anyway.
4043 
4044   Negative \a size values are ignored, i.e. this function can't be
4045   used to report that the additional memory has been deallocated.
4046 
4047   \sa collectGarbage()
4048 */
reportAdditionalMemoryCost(int size)4049 void QScriptEngine::reportAdditionalMemoryCost(int size)
4050 {
4051     Q_D(QScriptEngine);
4052     d->reportAdditionalMemoryCost(size);
4053 }
4054 
4055 /*!
4056 
4057   Sets the interval between calls to QCoreApplication::processEvents
4058   to \a interval milliseconds.
4059 
4060   While the interpreter is running, all event processing is by default
4061   blocked. This means for instance that the gui will not be updated
4062   and timers will not be fired. To allow event processing during
4063   interpreter execution one can specify the processing interval to be
4064   a positive value, indicating the number of milliseconds between each
4065   time QCoreApplication::processEvents() is called.
4066 
4067   The default value is -1, which disables event processing during
4068   interpreter execution.
4069 
4070   You can use QCoreApplication::postEvent() to post an event that
4071   performs custom processing at the next interval. For example, you
4072   could keep track of the total running time of the script and call
4073   abortEvaluation() when you detect that the script has been running
4074   for a long time without completing.
4075 
4076   \sa processEventsInterval()
4077 */
setProcessEventsInterval(int interval)4078 void QScriptEngine::setProcessEventsInterval(int interval)
4079 {
4080     Q_D(QScriptEngine);
4081     d->processEventsInterval = interval;
4082 
4083     if (interval > 0)
4084         d->globalData->timeoutChecker->setCheckInterval(interval);
4085 
4086     d->timeoutChecker()->setShouldProcessEvents(interval > 0);
4087 }
4088 
4089 /*!
4090 
4091   Returns the interval in milliseconds between calls to
4092   QCoreApplication::processEvents() while the interpreter is running.
4093 
4094   \sa setProcessEventsInterval()
4095 */
processEventsInterval() const4096 int QScriptEngine::processEventsInterval() const
4097 {
4098     Q_D(const QScriptEngine);
4099     return d->processEventsInterval;
4100 }
4101 
4102 /*!
4103   \since 4.4
4104 
4105   Returns true if this engine is currently evaluating a script,
4106   otherwise returns false.
4107 
4108   \sa evaluate(), abortEvaluation()
4109 */
isEvaluating() const4110 bool QScriptEngine::isEvaluating() const
4111 {
4112     Q_D(const QScriptEngine);
4113     return (d->currentFrame != d->globalExec()) || d->inEval;
4114 }
4115 
4116 /*!
4117   \since 4.4
4118 
4119   Aborts any script evaluation currently taking place in this engine.
4120   The given \a result is passed back as the result of the evaluation
4121   (i.e. it is returned from the call to evaluate() being aborted).
4122 
4123   If the engine isn't evaluating a script (i.e. isEvaluating() returns
4124   false), this function does nothing.
4125 
4126   Call this function if you need to abort a running script for some
4127   reason, e.g.  when you have detected that the script has been
4128   running for several seconds without completing.
4129 
4130   \sa evaluate(), isEvaluating(), setProcessEventsInterval()
4131 */
abortEvaluation(const QScriptValue & result)4132 void QScriptEngine::abortEvaluation(const QScriptValue &result)
4133 {
4134     Q_D(QScriptEngine);
4135     if (!isEvaluating())
4136         return;
4137     d->abortResult = result;
4138     d->timeoutChecker()->setShouldAbort(true);
4139     JSC::throwError(d->currentFrame, JSC::createInterruptedExecutionException(&d->currentFrame->globalData()).toObject(d->currentFrame));
4140 }
4141 
4142 #ifndef QT_NO_QOBJECT
4143 
4144 /*!
4145   \since 4.4
4146   \relates QScriptEngine
4147 
4148   Creates a connection from the \a signal in the \a sender to the
4149   given \a function. If \a receiver is an object, it will act as the
4150   `this' object when the signal handler function is invoked. Returns
4151   true if the connection succeeds; otherwise returns false.
4152 
4153   \sa qScriptDisconnect(), QScriptEngine::signalHandlerException()
4154 */
qScriptConnect(QObject * sender,const char * signal,const QScriptValue & receiver,const QScriptValue & function)4155 bool qScriptConnect(QObject *sender, const char *signal,
4156                     const QScriptValue &receiver, const QScriptValue &function)
4157 {
4158     if (!sender || !signal)
4159         return false;
4160     if (!function.isFunction())
4161         return false;
4162     if (receiver.isObject() && (receiver.engine() != function.engine()))
4163         return false;
4164     QScriptEnginePrivate *engine = QScriptEnginePrivate::get(function.engine());
4165     QScript::APIShim shim(engine);
4166     JSC::JSValue jscReceiver = engine->scriptValueToJSCValue(receiver);
4167     JSC::JSValue jscFunction = engine->scriptValueToJSCValue(function);
4168     return engine->scriptConnect(sender, signal, jscReceiver, jscFunction,
4169                                  Qt::AutoConnection);
4170 }
4171 
4172 /*!
4173   \since 4.4
4174   \relates QScriptEngine
4175 
4176   Disconnects the \a signal in the \a sender from the given (\a
4177   receiver, \a function) pair. Returns true if the connection is
4178   successfully broken; otherwise returns false.
4179 
4180   \sa qScriptConnect()
4181 */
qScriptDisconnect(QObject * sender,const char * signal,const QScriptValue & receiver,const QScriptValue & function)4182 bool qScriptDisconnect(QObject *sender, const char *signal,
4183                        const QScriptValue &receiver, const QScriptValue &function)
4184 {
4185     if (!sender || !signal)
4186         return false;
4187     if (!function.isFunction())
4188         return false;
4189     if (receiver.isObject() && (receiver.engine() != function.engine()))
4190         return false;
4191     QScriptEnginePrivate *engine = QScriptEnginePrivate::get(function.engine());
4192     QScript::APIShim shim(engine);
4193     JSC::JSValue jscReceiver = engine->scriptValueToJSCValue(receiver);
4194     JSC::JSValue jscFunction = engine->scriptValueToJSCValue(function);
4195     return engine->scriptDisconnect(sender, signal, jscReceiver, jscFunction);
4196 }
4197 
4198 /*!
4199     \since 4.4
4200     \fn void QScriptEngine::signalHandlerException(const QScriptValue &exception)
4201 
4202     This signal is emitted when a script function connected to a signal causes
4203     an \a exception.
4204 
4205     \sa qScriptConnect()
4206 */
4207 
4208 QT_BEGIN_INCLUDE_NAMESPACE
4209 #include "moc_qscriptengine.cpp"
4210 QT_END_INCLUDE_NAMESPACE
4211 
4212 #endif // QT_NO_QOBJECT
4213 
4214 /*!
4215   \since 4.4
4216 
4217   Installs the given \a agent on this engine. The agent will be
4218   notified of various events pertaining to script execution. This is
4219   useful when you want to find out exactly what the engine is doing,
4220   e.g. when evaluate() is called. The agent interface is the basis of
4221   tools like debuggers and profilers.
4222 
4223   The engine maintains ownership of the \a agent.
4224 
4225   Calling this function will replace the existing agent, if any.
4226 
4227   \sa agent()
4228 */
setAgent(QScriptEngineAgent * agent)4229 void QScriptEngine::setAgent(QScriptEngineAgent *agent)
4230 {
4231     Q_D(QScriptEngine);
4232     if (agent && (agent->engine() != this)) {
4233         qWarning("QScriptEngine::setAgent(): "
4234                  "cannot set agent belonging to different engine");
4235         return;
4236     }
4237     QScript::APIShim shim(d);
4238     if (d->activeAgent)
4239         QScriptEngineAgentPrivate::get(d->activeAgent)->detach();
4240     d->activeAgent = agent;
4241     if (agent) {
4242         QScriptEngineAgentPrivate::get(agent)->attach();
4243     }
4244 }
4245 
4246 /*!
4247   \since 4.4
4248 
4249   Returns the agent currently installed on this engine, or 0 if no
4250   agent is installed.
4251 
4252   \sa setAgent()
4253 */
agent() const4254 QScriptEngineAgent *QScriptEngine::agent() const
4255 {
4256     Q_D(const QScriptEngine);
4257     return d->activeAgent;
4258 }
4259 
4260 /*!
4261   \since 4.4
4262 
4263   Returns a handle that represents the given string, \a str.
4264 
4265   QScriptString can be used to quickly look up properties, and
4266   compare property names, of script objects.
4267 
4268   \sa QScriptValue::property()
4269 */
toStringHandle(const QString & str)4270 QScriptString QScriptEngine::toStringHandle(const QString &str)
4271 {
4272     Q_D(QScriptEngine);
4273     QScript::APIShim shim(d);
4274     return d->toStringHandle(JSC::Identifier(d->currentFrame, str));
4275 }
4276 
4277 /*!
4278   \since 4.5
4279 
4280   Converts the given \a value to an object, if such a conversion is
4281   possible; otherwise returns an invalid QScriptValue. The conversion
4282   is performed according to the following table:
4283 
4284     \table
4285     \header \o Input Type \o Result
4286     \row    \o Undefined  \o An invalid QScriptValue.
4287     \row    \o Null       \o An invalid QScriptValue.
4288     \row    \o Boolean    \o A new Boolean object whose internal value is set to the value of the boolean.
4289     \row    \o Number     \o A new Number object whose internal value is set to the value of the number.
4290     \row    \o String     \o A new String object whose internal value is set to the value of the string.
4291     \row    \o Object     \o The result is the object itself (no conversion).
4292     \endtable
4293 
4294     \sa newObject()
4295 */
toObject(const QScriptValue & value)4296 QScriptValue QScriptEngine::toObject(const QScriptValue &value)
4297 {
4298     Q_D(QScriptEngine);
4299     QScript::APIShim shim(d);
4300     JSC::JSValue jscValue = d->scriptValueToJSCValue(value);
4301     if (!jscValue || jscValue.isUndefined() || jscValue.isNull())
4302         return QScriptValue();
4303     JSC::ExecState* exec = d->currentFrame;
4304     JSC::JSValue result = jscValue.toObject(exec);
4305     return d->scriptValueFromJSCValue(result);
4306 }
4307 
4308 /*!
4309   \internal
4310 
4311   Returns the object with the given \a id, or an invalid
4312   QScriptValue if there is no object with that id.
4313 
4314   \sa QScriptValue::objectId()
4315 */
objectById(qint64 id) const4316 QScriptValue QScriptEngine::objectById(qint64 id) const
4317 {
4318     Q_D(const QScriptEngine);
4319     // Assumes that the cell was not been garbage collected
4320     return const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue((JSC::JSCell*)id);
4321 }
4322 
4323 /*!
4324   \since 4.5
4325   \class QScriptSyntaxCheckResult
4326 
4327   \brief The QScriptSyntaxCheckResult class provides the result of a script syntax check.
4328 
4329   \ingroup script
4330   \mainclass
4331 
4332   QScriptSyntaxCheckResult is returned by QScriptEngine::checkSyntax() to
4333   provide information about the syntactical (in)correctness of a script.
4334 */
4335 
4336 /*!
4337     \enum QScriptSyntaxCheckResult::State
4338 
4339     This enum specifies the state of a syntax check.
4340 
4341     \value Error The program contains a syntax error.
4342     \value Intermediate The program is incomplete.
4343     \value Valid The program is a syntactically correct Qt Script program.
4344 */
4345 
4346 /*!
4347   Constructs a new QScriptSyntaxCheckResult from the \a other result.
4348 */
QScriptSyntaxCheckResult(const QScriptSyntaxCheckResult & other)4349 QScriptSyntaxCheckResult::QScriptSyntaxCheckResult(const QScriptSyntaxCheckResult &other)
4350     : d_ptr(other.d_ptr)
4351 {
4352 }
4353 
4354 /*!
4355   \internal
4356 */
QScriptSyntaxCheckResult(QScriptSyntaxCheckResultPrivate * d)4357 QScriptSyntaxCheckResult::QScriptSyntaxCheckResult(QScriptSyntaxCheckResultPrivate *d)
4358     : d_ptr(d)
4359 {
4360 }
4361 
4362 /*!
4363   \internal
4364 */
QScriptSyntaxCheckResult()4365 QScriptSyntaxCheckResult::QScriptSyntaxCheckResult()
4366     : d_ptr(0)
4367 {
4368 }
4369 
4370 /*!
4371   Destroys this QScriptSyntaxCheckResult.
4372 */
~QScriptSyntaxCheckResult()4373 QScriptSyntaxCheckResult::~QScriptSyntaxCheckResult()
4374 {
4375 }
4376 
4377 /*!
4378   Returns the state of this QScriptSyntaxCheckResult.
4379 */
state() const4380 QScriptSyntaxCheckResult::State QScriptSyntaxCheckResult::state() const
4381 {
4382     Q_D(const QScriptSyntaxCheckResult);
4383     if (!d)
4384         return Valid;
4385     return d->state;
4386 }
4387 
4388 /*!
4389   Returns the error line number of this QScriptSyntaxCheckResult, or -1 if
4390   there is no error.
4391 
4392   \sa state(), errorMessage()
4393 */
errorLineNumber() const4394 int QScriptSyntaxCheckResult::errorLineNumber() const
4395 {
4396     Q_D(const QScriptSyntaxCheckResult);
4397     if (!d)
4398         return -1;
4399     return d->errorLineNumber;
4400 }
4401 
4402 /*!
4403   Returns the error column number of this QScriptSyntaxCheckResult, or -1 if
4404   there is no error.
4405 
4406   \sa state(), errorLineNumber()
4407 */
errorColumnNumber() const4408 int QScriptSyntaxCheckResult::errorColumnNumber() const
4409 {
4410     Q_D(const QScriptSyntaxCheckResult);
4411     if (!d)
4412         return -1;
4413     return d->errorColumnNumber;
4414 }
4415 
4416 /*!
4417   Returns the error message of this QScriptSyntaxCheckResult, or an empty
4418   string if there is no error.
4419 
4420   \sa state(), errorLineNumber()
4421 */
errorMessage() const4422 QString QScriptSyntaxCheckResult::errorMessage() const
4423 {
4424     Q_D(const QScriptSyntaxCheckResult);
4425     if (!d)
4426         return QString();
4427     return d->errorMessage;
4428 }
4429 
4430 /*!
4431   Assigns the \a other result to this QScriptSyntaxCheckResult, and returns a
4432   reference to this QScriptSyntaxCheckResult.
4433 */
operator =(const QScriptSyntaxCheckResult & other)4434 QScriptSyntaxCheckResult &QScriptSyntaxCheckResult::operator=(const QScriptSyntaxCheckResult &other)
4435 {
4436     d_ptr = other.d_ptr;
4437     return *this;
4438 }
4439 
4440 #ifdef QT_BUILD_INTERNAL
qt_script_isJITEnabled()4441 Q_AUTOTEST_EXPORT bool qt_script_isJITEnabled()
4442 {
4443 #if ENABLE(JIT)
4444     return true;
4445 #else
4446     return false;
4447 #endif
4448 }
4449 #endif
4450 
4451 #ifdef Q_CC_MSVC
4452 // Try to prevent compiler from crashing.
4453 #pragma optimize("", off)
4454 #endif
4455 
4456 QT_END_NAMESPACE
4457