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