source: trunk/src/script/api/qscriptengine.cpp@ 1036

Last change on this file since 1036 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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