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

source code of qtscript/src/script/api/qscriptengine.cpp