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

Last change on this file since 618 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 133.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 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#include "qnumeric.h"
28
29#include "qscriptengine_p.h"
30#include "qscriptengineagent_p.h"
31#include "qscriptcontext_p.h"
32#include "qscriptstring_p.h"
33#include "qscriptvalue_p.h"
34#include "qscriptvalueiterator.h"
35#include "qscriptclass.h"
36#include "qscriptcontextinfo.h"
37#include "qscriptprogram.h"
38#include "qscriptprogram_p.h"
39#include "qdebug.h"
40
41#include <QtCore/qstringlist.h>
42#include <QtCore/qmetaobject.h>
43
44#include "Error.h"
45#include "JSArray.h"
46#include "JSLock.h"
47#include "Interpreter.h"
48#include "DateConstructor.h"
49#include "RegExpConstructor.h"
50
51#include "PrototypeFunction.h"
52#include "InitializeThreading.h"
53#include "ObjectPrototype.h"
54#include "SourceCode.h"
55#include "FunctionPrototype.h"
56#include "TimeoutChecker.h"
57#include "JSFunction.h"
58#include "Parser.h"
59#include "Operations.h"
60
61#include "utils/qscriptdate_p.h"
62#include "bridge/qscriptfunction_p.h"
63#include "bridge/qscriptobject_p.h"
64#include "bridge/qscriptclassobject_p.h"
65#include "bridge/qscriptvariant_p.h"
66#include "bridge/qscriptqobject_p.h"
67#include "bridge/qscriptglobalobject_p.h"
68#include "bridge/qscriptactivationobject_p.h"
69
70#ifndef QT_NO_QOBJECT
71#include <QtCore/qcoreapplication.h>
72#include <QtCore/qdir.h>
73#include <QtCore/qfile.h>
74#include <QtCore/qfileinfo.h>
75#include <QtCore/qpluginloader.h>
76#include <QtCore/qset.h>
77#include <QtCore/qtextstream.h>
78#include "qscriptextensioninterface.h"
79#endif
80
81Q_DECLARE_METATYPE(QScriptValue)
82#ifndef QT_NO_QOBJECT
83Q_DECLARE_METATYPE(QObjectList)
84#endif
85Q_DECLARE_METATYPE(QList<int>)
86
87QT_BEGIN_NAMESPACE
88
89/*!
90 \since 4.3
91 \class QScriptEngine
92 \reentrant
93
94 \brief The QScriptEngine class provides an environment for evaluating Qt Script code.
95
96 \ingroup script
97 \mainclass
98
99 See the \l{QtScript} documentation for information about the Qt Script language,
100 and how to get started with scripting your C++ application.
101
102 \section1 Evaluating Scripts
103
104 Use evaluate() to evaluate script code; this is the C++ equivalent
105 of the built-in script function \c{eval()}.
106
107 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 0
108
109 evaluate() returns a QScriptValue that holds the result of the
110 evaluation. The QScriptValue class provides functions for converting
111 the result to various C++ types (e.g. QScriptValue::toString()
112 and QScriptValue::toNumber()).
113
114 The following code snippet shows how a script function can be
115 defined and then invoked from C++ using QScriptValue::call():
116
117 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 1
118
119 As can be seen from the above snippets, a script is provided to the
120 engine in the form of a string. One common way of loading scripts is
121 by reading the contents of a file and passing it to evaluate():
122
123 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 2
124
125 Here we pass the name of the file as the second argument to
126 evaluate(). This does not affect evaluation in any way; the second
127 argument is a general-purpose string that is used to identify the
128 script for debugging purposes (for example, our filename will now
129 show up in any uncaughtExceptionBacktrace() involving the script).
130
131 \section1 Engine Configuration
132
133 The globalObject() function returns the \bold {Global Object}
134 associated with the script engine. Properties of the Global Object
135 are accessible from any script code (i.e. they are global
136 variables). Typically, before evaluating "user" scripts, you will
137 want to configure a script engine by adding one or more properties
138 to the Global Object:
139
140 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 3
141
142 Adding custom properties to the scripting environment is one of the
143 standard means of providing a scripting API that is specific to your
144 application. Usually these custom properties are objects created by
145 the newQObject() or newObject() functions, or constructor functions
146 created by newFunction().
147
148 \section1 Script Exceptions
149
150 evaluate() can throw a script exception (e.g. due to a syntax
151 error); in that case, the return value is the value that was thrown
152 (typically an \c{Error} object). You can check whether the
153 evaluation caused an exception by calling hasUncaughtException(). In
154 that case, you can call toString() on the error object to obtain an
155 error message. The current uncaught exception is also available
156 through uncaughtException(). You can obtain a human-readable
157 backtrace of the exception with uncaughtExceptionBacktrace().
158 Calling clearExceptions() will cause any uncaught exceptions to be
159 cleared.
160
161 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 4
162
163 The checkSyntax() function can be used to determine whether code can be
164 usefully passed to evaluate().
165
166 \section1 Script Object Creation
167
168 Use newObject() to create a standard Qt Script object; this is the
169 C++ equivalent of the script statement \c{new Object()}. You can use
170 the object-specific functionality in QScriptValue to manipulate the
171 script object (e.g. QScriptValue::setProperty()). Similarly, use
172 newArray() to create a Qt Script array object. Use newDate() to
173 create a \c{Date} object, and newRegExp() to create a \c{RegExp}
174 object.
175
176 \section1 QObject Integration
177
178 Use newQObject() to wrap a QObject (or subclass)
179 pointer. newQObject() returns a proxy script object; properties,
180 children, and signals and slots of the QObject are available as
181 properties of the proxy object. No binding code is needed because it
182 is done dynamically using the Qt meta object system.
183
184 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 5
185
186 Use qScriptConnect() to connect a C++ signal to a script function;
187 this is the Qt Script equivalent of QObject::connect(). When a
188 script function is invoked in response to a C++ signal, it can cause
189 a script exception; you can connect to the signalHandlerException()
190 signal to catch such an exception.
191
192 Use newQMetaObject() to wrap a QMetaObject; this gives you a "script
193 representation" of a QObject-based class. newQMetaObject() returns a
194 proxy script object; enum values of the class are available as
195 properties of the proxy object. You can also specify a function that
196 will be used to construct objects of the class (e.g. when the
197 constructor is invoked from a script). For classes that have a
198 "standard" Qt constructor, Qt Script can provide a default script
199 constructor for you; see scriptValueFromQMetaObject().
200
201 See the \l{QtScript} documentation for more information on
202 the QObject integration.
203
204 \section1 Support for Custom C++ Types
205
206 Use newVariant() to wrap a QVariant. This can be used to store
207 values of custom (non-QObject) C++ types that have been registered
208 with the Qt meta-type system. To make such types scriptable, you
209 typically associate a prototype (delegate) object with the C++ type
210 by calling setDefaultPrototype(); the prototype object defines the
211 scripting API for the C++ type. Unlike the QObject integration,
212 there is no automatic binding possible here; i.e. you have to create
213 the scripting API yourself, for example by using the QScriptable
214 class.
215
216 Use fromScriptValue() to cast from a QScriptValue to another type,
217 and toScriptValue() to create a QScriptValue from another value.
218 You can specify how the conversion of C++ types is to be performed
219 with qScriptRegisterMetaType() and qScriptRegisterSequenceMetaType().
220 By default, Qt Script will use QVariant to store values of custom
221 types.
222
223 \section1 Importing Extensions
224
225 Use importExtension() to import plugin-based extensions into the
226 engine. Call availableExtensions() to obtain a list naming all the
227 available extensions, and importedExtensions() to obtain a list
228 naming only those extensions that have been imported.
229
230 Call pushContext() to open up a new variable scope, and popContext()
231 to close the current scope. This is useful if you are implementing
232 an extension that evaluates script code containing temporary
233 variable definitions (e.g. \c{var foo = 123;}) that are safe to
234 discard when evaluation has completed.
235
236 \section1 Native Functions
237
238 Use newFunction() to wrap native (C++) functions, including
239 constructors for your own custom types, so that these can be invoked
240 from script code. Such functions must have the signature
241 QScriptEngine::FunctionSignature. You may then pass the function as
242 argument to newFunction(). Here is an example of a function that
243 returns the sum of its first two arguments:
244
245 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 6
246
247 To expose this function to script code, you can set it as a property
248 of the Global Object:
249
250 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 7
251
252 Once this is done, script code can call your function in the exact
253 same manner as a "normal" script function:
254
255 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 8
256
257 \section1 Long-running Scripts
258
259 If you need to evaluate possibly long-running scripts from the main
260 (GUI) thread, you should first call setProcessEventsInterval() to
261 make sure that the GUI stays responsive. You can abort a currently
262 running script by calling abortEvaluation(). You can determine
263 whether an engine is currently running a script by calling
264 isEvaluating().
265
266 \section1 Core Debugging/Tracing Facilities
267
268 Since Qt 4.4, you can be notified of events pertaining to script
269 execution (e.g. script function calls and statement execution)
270 through the QScriptEngineAgent interface; see the setAgent()
271 function. This can be used to implement debugging and profiling of a
272 QScriptEngine.
273
274 \sa QScriptValue, QScriptContext, QScriptEngineAgent
275
276*/
277
278/*!
279 \enum QScriptEngine::ValueOwnership
280
281 This enum specifies the ownership when wrapping a C++ value, e.g. by using newQObject().
282
283 \value QtOwnership The standard Qt ownership rules apply, i.e. the associated object will never be explicitly deleted by the script engine. This is the default. (QObject ownership is explained in \l{Object Trees and Object Ownership}.)
284 \value ScriptOwnership The value is owned by the script environment. The associated data will be deleted when appropriate (i.e. after the garbage collector has discovered that there are no more live references to the value).
285 \value AutoOwnership If the associated object has a parent, the Qt ownership rules apply (QtOwnership); otherwise, the object is owned by the script environment (ScriptOwnership).
286*/
287
288/*!
289 \enum QScriptEngine::QObjectWrapOption
290
291 These flags specify options when wrapping a QObject pointer with newQObject().
292
293 \value ExcludeChildObjects The script object will not expose child objects as properties.
294 \value ExcludeSuperClassMethods The script object will not expose signals and slots inherited from the superclass.
295 \value ExcludeSuperClassProperties The script object will not expose properties inherited from the superclass.
296 \value ExcludeSuperClassContents Shorthand form for ExcludeSuperClassMethods | ExcludeSuperClassProperties
297 \value ExcludeDeleteLater The script object will not expose the QObject::deleteLater() slot.
298 \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.
299 \value PreferExistingWrapperObject If a wrapper object with the requested configuration already exists, return that object.
300 \value SkipMethodsInEnumeration Don't include methods (signals and slots) when enumerating the object's properties.
301*/
302
303class QScriptSyntaxCheckResultPrivate
304{
305public:
306 QScriptSyntaxCheckResultPrivate() { ref = 0; }
307 ~QScriptSyntaxCheckResultPrivate() {}
308
309 QScriptSyntaxCheckResult::State state;
310 int errorColumnNumber;
311 int errorLineNumber;
312 QString errorMessage;
313 QBasicAtomicInt ref;
314};
315
316class QScriptTypeInfo
317{
318public:
319 QScriptTypeInfo() : signature(0, '\0'), marshal(0), demarshal(0)
320 { }
321
322 QByteArray signature;
323 QScriptEngine::MarshalFunction marshal;
324 QScriptEngine::DemarshalFunction demarshal;
325 JSC::JSValue prototype;
326};
327
328namespace QScript
329{
330
331void GlobalClientData::mark(JSC::MarkStack& markStack)
332{
333 engine->mark(markStack);
334}
335
336class TimeoutCheckerProxy : public JSC::TimeoutChecker
337{
338public:
339 TimeoutCheckerProxy(const JSC::TimeoutChecker& originalChecker)
340 : JSC::TimeoutChecker(originalChecker)
341 , m_shouldProcessEvents(false)
342 , m_shouldAbortEvaluation(false)
343 {}
344
345 void setShouldProcessEvents(bool shouldProcess) { m_shouldProcessEvents = shouldProcess; }
346 void setShouldAbort(bool shouldAbort) { m_shouldAbortEvaluation = shouldAbort; }
347 bool shouldAbort() { return m_shouldAbortEvaluation; }
348
349 virtual bool didTimeOut(JSC::ExecState* exec)
350 {
351 if (JSC::TimeoutChecker::didTimeOut(exec))
352 return true;
353
354 if (m_shouldProcessEvents)
355 QCoreApplication::processEvents();
356
357 return m_shouldAbortEvaluation;
358 }
359
360private:
361 bool m_shouldProcessEvents;
362 bool m_shouldAbortEvaluation;
363};
364
365static int toDigit(char c)
366{
367 if ((c >= '0') && (c <= '9'))
368 return c - '0';
369 else if ((c >= 'a') && (c <= 'z'))
370 return 10 + c - 'a';
371 else if ((c >= 'A') && (c <= 'Z'))
372 return 10 + c - 'A';
373 return -1;
374}
375
376qsreal integerFromString(const char *buf, int size, int radix)
377{
378 if (size == 0)
379 return qSNaN();
380
381 qsreal sign = 1.0;
382 int i = 0;
383 if (buf[0] == '+') {
384 ++i;
385 } else if (buf[0] == '-') {
386 sign = -1.0;
387 ++i;
388 }
389
390 if (((size-i) >= 2) && (buf[i] == '0')) {
391 if (((buf[i+1] == 'x') || (buf[i+1] == 'X'))
392 && (radix < 34)) {
393 if ((radix != 0) && (radix != 16))
394 return 0;
395 radix = 16;
396 i += 2;
397 } else {
398 if (radix == 0) {
399 radix = 8;
400 ++i;
401 }
402 }
403 } else if (radix == 0) {
404 radix = 10;
405 }
406
407 int j = i;
408 for ( ; i < size; ++i) {
409 int d = toDigit(buf[i]);
410 if ((d == -1) || (d >= radix))
411 break;
412 }
413 qsreal result;
414 if (j == i) {
415 if (!qstrcmp(buf, "Infinity"))
416 result = qInf();
417 else
418 result = qSNaN();
419 } else {
420 result = 0;
421 qsreal multiplier = 1;
422 for (--i ; i >= j; --i, multiplier *= radix)
423 result += toDigit(buf[i]) * multiplier;
424 }
425 result *= sign;
426 return result;
427}
428
429qsreal integerFromString(const QString &str, int radix)
430{
431 QByteArray ba = str.trimmed().toUtf8();
432 return integerFromString(ba.constData(), ba.size(), radix);
433}
434
435bool isFunction(JSC::JSValue value)
436{
437 if (!value || !value.isObject())
438 return false;
439 JSC::CallData callData;
440 return (JSC::asObject(value)->getCallData(callData) != JSC::CallTypeNone);
441}
442
443static JSC::JSValue JSC_HOST_CALL functionConnect(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
444static JSC::JSValue JSC_HOST_CALL functionDisconnect(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
445
446JSC::JSValue JSC_HOST_CALL functionDisconnect(JSC::ExecState *exec, JSC::JSObject * /*callee*/, JSC::JSValue thisObject, const JSC::ArgList &args)
447{
448#ifndef QT_NO_QOBJECT
449 if (args.size() == 0) {
450 return JSC::throwError(exec, JSC::GeneralError, "Function.prototype.disconnect: no arguments given");
451 }
452
453 if (!JSC::asObject(thisObject)->inherits(&QScript::QtFunction::info)) {
454 return JSC::throwError(exec, JSC::TypeError, "Function.prototype.disconnect: this object is not a signal");
455 }
456
457 QScript::QtFunction *qtSignal = static_cast<QScript::QtFunction*>(JSC::asObject(thisObject));
458
459 const QMetaObject *meta = qtSignal->metaObject();
460 if (!meta) {
461 return JSC::throwError(exec, JSC::TypeError, "Function.prototype.discconnect: cannot disconnect from deleted QObject");
462 }
463
464 QMetaMethod sig = meta->method(qtSignal->initialIndex());
465 if (sig.methodType() != QMetaMethod::Signal) {
466 QString message = QString::fromLatin1("Function.prototype.disconnect: %0::%1 is not a signal")
467 .arg(QLatin1String(qtSignal->metaObject()->className()))
468 .arg(QLatin1String(sig.signature()));
469 return JSC::throwError(exec, JSC::TypeError, message);
470 }
471
472 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
473
474 JSC::JSValue receiver;
475 JSC::JSValue slot;
476 JSC::JSValue arg0 = args.at(0);
477 if (args.size() < 2) {
478 slot = arg0;
479 } else {
480 receiver = arg0;
481 JSC::JSValue arg1 = args.at(1);
482 if (isFunction(arg1))
483 slot = arg1;
484 else {
485 // ### don't go via QScriptValue
486 QScript::SaveFrameHelper saveFrame(engine, exec);
487 QScriptValue tmp = engine->scriptValueFromJSCValue(arg0);
488 QString propertyName(arg1.toString(exec));
489 slot = engine->scriptValueToJSCValue(tmp.property(propertyName, QScriptValue::ResolvePrototype));
490 }
491 }
492
493 if (!isFunction(slot)) {
494 return JSC::throwError(exec, JSC::TypeError, "Function.prototype.disconnect: target is not a function");
495 }
496
497 bool ok = engine->scriptDisconnect(thisObject, receiver, slot);
498 if (!ok) {
499 QString message = QString::fromLatin1("Function.prototype.disconnect: failed to disconnect from %0::%1")
500 .arg(QLatin1String(qtSignal->metaObject()->className()))
501 .arg(QLatin1String(sig.signature()));
502 return JSC::throwError(exec, JSC::GeneralError, message);
503 }
504 return JSC::jsUndefined();
505#else
506 Q_UNUSED(eng);
507 return context->throwError(QScriptContext::TypeError,
508 QLatin1String("Function.prototype.disconnect"));
509#endif // QT_NO_QOBJECT
510}
511
512JSC::JSValue JSC_HOST_CALL functionConnect(JSC::ExecState *exec, JSC::JSObject * /*callee*/, JSC::JSValue thisObject, const JSC::ArgList &args)
513{
514#ifndef QT_NO_QOBJECT
515 if (args.size() == 0) {
516 return JSC::throwError(exec, JSC::GeneralError,"Function.prototype.connect: no arguments given");
517 }
518
519 if (!JSC::asObject(thisObject)->inherits(&QScript::QtFunction::info)) {
520 return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: this object is not a signal");
521 }
522
523 QScript::QtFunction *qtSignal = static_cast<QScript::QtFunction*>(JSC::asObject(thisObject));
524
525 const QMetaObject *meta = qtSignal->metaObject();
526 if (!meta) {
527 return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: cannot connect to deleted QObject");
528 }
529
530 QMetaMethod sig = meta->method(qtSignal->initialIndex());
531 if (sig.methodType() != QMetaMethod::Signal) {
532 QString message = QString::fromLatin1("Function.prototype.connect: %0::%1 is not a signal")
533 .arg(QLatin1String(qtSignal->metaObject()->className()))
534 .arg(QLatin1String(sig.signature()));
535 return JSC::throwError(exec, JSC::TypeError, message);
536 }
537
538 {
539 QList<int> overloads = qtSignal->overloadedIndexes();
540 if (!overloads.isEmpty()) {
541 overloads.append(qtSignal->initialIndex());
542 QByteArray signature = sig.signature();
543 QString message = QString::fromLatin1("Function.prototype.connect: ambiguous connect to %0::%1(); candidates are\n")
544 .arg(QLatin1String(qtSignal->metaObject()->className()))
545 .arg(QLatin1String(signature.left(signature.indexOf('('))));
546 for (int i = 0; i < overloads.size(); ++i) {
547 QMetaMethod mtd = meta->method(overloads.at(i));
548 message.append(QString::fromLatin1(" %0\n").arg(QString::fromLatin1(mtd.signature())));
549 }
550 message.append(QString::fromLatin1("Use e.g. object['%0'].connect() to connect to a particular overload")
551 .arg(QLatin1String(signature)));
552 return JSC::throwError(exec, JSC::GeneralError, message);
553 }
554 }
555
556 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
557
558 JSC::JSValue receiver;
559 JSC::JSValue slot;
560 JSC::JSValue arg0 = args.at(0);
561 if (args.size() < 2) {
562 slot = arg0;
563 } else {
564 receiver = arg0;
565 JSC::JSValue arg1 = args.at(1);
566 if (isFunction(arg1))
567 slot = arg1;
568 else {
569 // ### don't go via QScriptValue
570 QScript::SaveFrameHelper saveFrame(engine, exec);
571 QScriptValue tmp = engine->scriptValueFromJSCValue(arg0);
572 QString propertyName = arg1.toString(exec);
573 slot = engine->scriptValueToJSCValue(tmp.property(propertyName, QScriptValue::ResolvePrototype));
574 }
575 }
576
577 if (!isFunction(slot)) {
578 return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: target is not a function");
579 }
580
581 bool ok = engine->scriptConnect(thisObject, receiver, slot, Qt::AutoConnection);
582 if (!ok) {
583 QString message = QString::fromLatin1("Function.prototype.connect: failed to connect to %0::%1")
584 .arg(QLatin1String(qtSignal->metaObject()->className()))
585 .arg(QLatin1String(sig.signature()));
586 return JSC::throwError(exec, JSC::GeneralError, message);
587 }
588 return JSC::jsUndefined();
589#else
590 Q_UNUSED(eng);
591 Q_UNUSED(classInfo);
592 return context->throwError(QScriptContext::TypeError,
593 QLatin1String("Function.prototype.connect"));
594#endif // QT_NO_QOBJECT
595}
596
597static JSC::JSValue JSC_HOST_CALL functionPrint(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
598static JSC::JSValue JSC_HOST_CALL functionGC(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
599static JSC::JSValue JSC_HOST_CALL functionVersion(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
600
601JSC::JSValue JSC_HOST_CALL functionPrint(JSC::ExecState* exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList& args)
602{
603 QString result;
604 for (unsigned i = 0; i < args.size(); ++i) {
605 if (i != 0)
606 result.append(QLatin1Char(' '));
607 QString s(args.at(i).toString(exec));
608 if (exec->hadException())
609 break;
610 result.append(s);
611 }
612 if (exec->hadException())
613 return exec->exception();
614 qDebug("%s", qPrintable(result));
615 return JSC::jsUndefined();
616}
617
618JSC::JSValue JSC_HOST_CALL functionGC(JSC::ExecState* exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&)
619{
620 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
621 engine->collectGarbage();
622 return JSC::jsUndefined();
623}
624
625JSC::JSValue JSC_HOST_CALL functionVersion(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&)
626{
627 return JSC::JSValue(exec, 1);
628}
629
630static JSC::JSValue JSC_HOST_CALL functionQsTranslate(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
631static JSC::JSValue JSC_HOST_CALL functionQsTranslateNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
632static JSC::JSValue JSC_HOST_CALL functionQsTr(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
633static JSC::JSValue JSC_HOST_CALL functionQsTrNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
634
635JSC::JSValue JSC_HOST_CALL functionQsTranslate(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
636{
637 if (args.size() < 2)
638 return JSC::throwError(exec, JSC::GeneralError, "qsTranslate() requires at least two arguments");
639 if (!args.at(0).isString())
640 return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): first argument (context) must be a string");
641 if (!args.at(1).isString())
642 return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): second argument (text) must be a string");
643 if ((args.size() > 2) && !args.at(2).isString())
644 return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): third argument (comment) must be a string");
645 if ((args.size() > 3) && !args.at(3).isString())
646 return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): fourth argument (encoding) must be a string");
647 if ((args.size() > 4) && !args.at(4).isNumber())
648 return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): fifth argument (n) must be a number");
649#ifndef QT_NO_QOBJECT
650 QString context(args.at(0).toString(exec));
651#endif
652 QString text(args.at(1).toString(exec));
653#ifndef QT_NO_QOBJECT
654 QString comment;
655 if (args.size() > 2)
656 comment = args.at(2).toString(exec);
657 QCoreApplication::Encoding encoding = QCoreApplication::CodecForTr;
658 if (args.size() > 3) {
659 QString encStr(args.at(3).toString(exec));
660 if (encStr == QLatin1String("CodecForTr"))
661 encoding = QCoreApplication::CodecForTr;
662 else if (encStr == QLatin1String("UnicodeUTF8"))
663 encoding = QCoreApplication::UnicodeUTF8;
664 else
665 return JSC::throwError(exec, JSC::GeneralError, QString::fromLatin1("qsTranslate(): invalid encoding '%s'").arg(encStr));
666 }
667 int n = -1;
668 if (args.size() > 4)
669 n = args.at(4).toInt32(exec);
670#endif
671 QString result;
672#ifndef QT_NO_QOBJECT
673 result = QCoreApplication::translate(context.toLatin1().constData(),
674 text.toLatin1().constData(),
675 comment.toLatin1().constData(),
676 encoding, n);
677#else
678 result = text;
679#endif
680 return JSC::jsString(exec, result);
681}
682
683JSC::JSValue JSC_HOST_CALL functionQsTranslateNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
684{
685 if (args.size() < 2)
686 return JSC::jsUndefined();
687 return args.at(1);
688}
689
690JSC::JSValue JSC_HOST_CALL functionQsTr(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
691{
692 if (args.size() < 1)
693 return JSC::throwError(exec, JSC::GeneralError, "qsTr() requires at least one argument");
694 if (!args.at(0).isString())
695 return JSC::throwError(exec, JSC::GeneralError, "qsTr(): first argument (text) must be a string");
696 if ((args.size() > 1) && !args.at(1).isString())
697 return JSC::throwError(exec, JSC::GeneralError, "qsTr(): second argument (comment) must be a string");
698 if ((args.size() > 2) && !args.at(2).isNumber())
699 return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): third argument (n) must be a number");
700#ifndef QT_NO_QOBJECT
701 QString context;
702 QScriptContext *ctx = QScriptEnginePrivate::contextForFrame(exec);
703 if (ctx && ctx->parentContext())
704 context = QFileInfo(QScriptContextInfo(ctx->parentContext()).fileName()).baseName();
705#endif
706 QString text(args.at(0).toString(exec));
707#ifndef QT_NO_QOBJECT
708 QString comment;
709 if (args.size() > 1)
710 comment = args.at(1).toString(exec);
711 int n = -1;
712 if (args.size() > 2)
713 n = args.at(2).toInt32(exec);
714#endif
715 QString result;
716#ifndef QT_NO_QOBJECT
717 result = QCoreApplication::translate(context.toLatin1().constData(),
718 text.toLatin1().constData(),
719 comment.toLatin1().constData(),
720 QCoreApplication::CodecForTr, n);
721#else
722 result = text;
723#endif
724 return JSC::jsString(exec, result);
725}
726
727JSC::JSValue JSC_HOST_CALL functionQsTrNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
728{
729 if (args.size() < 1)
730 return JSC::jsUndefined();
731 return args.at(0);
732}
733
734static JSC::JSValue JSC_HOST_CALL stringProtoFuncArg(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
735
736JSC::JSValue JSC_HOST_CALL stringProtoFuncArg(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisObject, const JSC::ArgList &args)
737{
738 QString value(thisObject.toString(exec));
739 JSC::JSValue arg = (args.size() != 0) ? args.at(0) : JSC::jsUndefined();
740 QString result;
741 if (arg.isString())
742 result = value.arg(arg.toString(exec));
743 else if (arg.isNumber())
744 result = value.arg(arg.toNumber(exec));
745 return JSC::jsString(exec, result);
746}
747
748
749#if !defined(QT_NO_QOBJECT) && !defined(QT_NO_LIBRARY)
750static QScriptValue __setupPackage__(QScriptContext *ctx, QScriptEngine *eng)
751{
752 QString path = ctx->argument(0).toString();
753 QStringList components = path.split(QLatin1Char('.'));
754 QScriptValue o = eng->globalObject();
755 for (int i = 0; i < components.count(); ++i) {
756 QString name = components.at(i);
757 QScriptValue oo = o.property(name);
758 if (!oo.isValid()) {
759 oo = eng->newObject();
760 o.setProperty(name, oo);
761 }
762 o = oo;
763 }
764 return o;
765}
766#endif
767
768} // namespace QScript
769
770QScriptEnginePrivate::QScriptEnginePrivate()
771 : registeredScriptValues(0), freeScriptValues(0),
772 registeredScriptStrings(0), inEval(false)
773{
774 qMetaTypeId<QScriptValue>();
775 qMetaTypeId<QList<int> >();
776#ifndef QT_NO_QOBJECT
777 qMetaTypeId<QObjectList>();
778#endif
779
780 if (!QCoreApplication::instance()) {
781 qFatal("QScriptEngine: Must construct a Q(Core)Application before a QScriptEngine");
782 return;
783 }
784 JSC::initializeThreading();
785
786 globalData = JSC::JSGlobalData::create().releaseRef();
787 globalData->clientData = new QScript::GlobalClientData(this);
788 JSC::JSGlobalObject *globalObject = new (globalData)QScript::GlobalObject();
789
790 JSC::ExecState* exec = globalObject->globalExec();
791
792 scriptObjectStructure = QScriptObject::createStructure(globalObject->objectPrototype());
793
794 qobjectPrototype = new (exec) QScript::QObjectPrototype(exec, QScript::QObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
795 qobjectWrapperObjectStructure = QScriptObject::createStructure(qobjectPrototype);
796
797 qmetaobjectPrototype = new (exec) QScript::QMetaObjectPrototype(exec, QScript::QMetaObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
798 qmetaobjectWrapperObjectStructure = QScript::QMetaObjectWrapperObject::createStructure(qmetaobjectPrototype);
799
800 variantPrototype = new (exec) QScript::QVariantPrototype(exec, QScript::QVariantPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
801 variantWrapperObjectStructure = QScriptObject::createStructure(variantPrototype);
802
803 globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "print"), QScript::functionPrint));
804 globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 0, JSC::Identifier(exec, "gc"), QScript::functionGC));
805 globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 0, JSC::Identifier(exec, "version"), QScript::functionVersion));
806
807 // ### rather than extending Function.prototype, consider creating a QtSignal.prototype
808 globalObject->functionPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "disconnect"), QScript::functionDisconnect));
809 globalObject->functionPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "connect"), QScript::functionConnect));
810
811 JSC::TimeoutChecker* originalChecker = globalData->timeoutChecker;
812 globalData->timeoutChecker = new QScript::TimeoutCheckerProxy(*originalChecker);
813 delete originalChecker;
814
815 currentFrame = exec;
816
817 originalGlobalObjectProxy = 0;
818 activeAgent = 0;
819 agentLineNumber = -1;
820 processEventsInterval = -1;
821}
822
823QScriptEnginePrivate::~QScriptEnginePrivate()
824{
825 //disconnect all loadedScripts and generate all jsc::debugger::scriptUnload events
826 QHash<intptr_t,QScript::UStringSourceProviderWithFeedback*>::const_iterator it;
827 for (it = loadedScripts.constBegin(); it != loadedScripts.constEnd(); ++it)
828 it.value()->disconnectFromEngine();
829
830 while (!ownedAgents.isEmpty())
831 delete ownedAgents.takeFirst();
832
833 detachAllRegisteredScriptValues();
834 detachAllRegisteredScriptStrings();
835 qDeleteAll(m_qobjectData);
836 qDeleteAll(m_typeInfos);
837 JSC::JSLock lock(false);
838 globalData->heap.destroy();
839 globalData->deref();
840 while (freeScriptValues) {
841 QScriptValuePrivate *p = freeScriptValues;
842 freeScriptValues = p->next;
843 qFree(p);
844 }
845}
846
847QScriptValue QScriptEnginePrivate::scriptValueFromVariant(const QVariant &v)
848{
849 Q_Q(QScriptEngine);
850 QScriptValue result = q->create(v.userType(), v.data());
851 Q_ASSERT(result.isValid());
852 return result;
853}
854
855QVariant QScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value, int targetType)
856{
857 QVariant v(targetType, (void *)0);
858 if (QScriptEnginePrivate::convert(value, targetType, v.data(), this))
859 return v;
860 if (uint(targetType) == QVariant::LastType)
861 return value.toVariant();
862 if (value.isVariant()) {
863 v = value.toVariant();
864 if (v.canConvert(QVariant::Type(targetType))) {
865 v.convert(QVariant::Type(targetType));
866 return v;
867 }
868 QByteArray typeName = v.typeName();
869 if (typeName.endsWith('*')
870 && (QMetaType::type(typeName.left(typeName.size()-1)) == targetType)) {
871 return QVariant(targetType, *reinterpret_cast<void* *>(v.data()));
872 }
873 }
874
875 return QVariant();
876}
877
878JSC::JSValue QScriptEnginePrivate::jscValueFromVariant(const QVariant &v)
879{
880 // ### it's inefficient to convert to QScriptValue and then to JSValue
881 QScriptValue vv = scriptValueFromVariant(v);
882 QScriptValuePrivate *p = QScriptValuePrivate::get(vv);
883 switch (p->type) {
884 case QScriptValuePrivate::JavaScriptCore:
885 return p->jscValue;
886 case QScriptValuePrivate::Number:
887 return JSC::jsNumber(currentFrame, p->numberValue);
888 case QScriptValuePrivate::String: {
889 JSC::UString str = p->stringValue;
890 return JSC::jsString(currentFrame, str);
891 }
892 }
893 return JSC::JSValue();
894}
895
896QVariant QScriptEnginePrivate::jscValueToVariant(JSC::JSValue value, int targetType)
897{
898 // ### it's inefficient to convert to QScriptValue and then to QVariant
899 return scriptValueToVariant(scriptValueFromJSCValue(value), targetType);
900}
901
902QScriptValue QScriptEnginePrivate::arrayFromStringList(const QStringList &lst)
903{
904 Q_Q(QScriptEngine);
905 QScriptValue arr = q->newArray(lst.size());
906 for (int i = 0; i < lst.size(); ++i)
907 arr.setProperty(i, QScriptValue(q, lst.at(i)));
908 return arr;
909}
910
911QStringList QScriptEnginePrivate::stringListFromArray(const QScriptValue &arr)
912{
913 QStringList lst;
914 uint len = arr.property(QLatin1String("length")).toUInt32();
915 for (uint i = 0; i < len; ++i)
916 lst.append(arr.property(i).toString());
917 return lst;
918}
919
920QScriptValue QScriptEnginePrivate::arrayFromVariantList(const QVariantList &lst)
921{
922 Q_Q(QScriptEngine);
923 QScriptValue arr = q->newArray(lst.size());
924 for (int i = 0; i < lst.size(); ++i)
925 arr.setProperty(i, scriptValueFromVariant(lst.at(i)));
926 return arr;
927}
928
929QVariantList QScriptEnginePrivate::variantListFromArray(const QScriptValue &arr)
930{
931 QVariantList lst;
932 uint len = arr.property(QLatin1String("length")).toUInt32();
933 for (uint i = 0; i < len; ++i)
934 lst.append(arr.property(i).toVariant());
935 return lst;
936}
937
938QScriptValue QScriptEnginePrivate::objectFromVariantMap(const QVariantMap &vmap)
939{
940 Q_Q(QScriptEngine);
941 QScriptValue obj = q->newObject();
942 QVariantMap::const_iterator it;
943 for (it = vmap.constBegin(); it != vmap.constEnd(); ++it)
944 obj.setProperty(it.key(), scriptValueFromVariant(it.value()));
945 return obj;
946}
947
948QVariantMap QScriptEnginePrivate::variantMapFromObject(const QScriptValue &obj)
949{
950 QVariantMap vmap;
951 QScriptValueIterator it(obj);
952 while (it.hasNext()) {
953 it.next();
954 vmap.insert(it.name(), it.value().toVariant());
955 }
956 return vmap;
957}
958
959JSC::JSValue QScriptEnginePrivate::defaultPrototype(int metaTypeId) const
960{
961 QScriptTypeInfo *info = m_typeInfos.value(metaTypeId);
962 if (!info)
963 return JSC::JSValue();
964 return info->prototype;
965}
966
967void QScriptEnginePrivate::setDefaultPrototype(int metaTypeId, JSC::JSValue prototype)
968{
969 QScriptTypeInfo *info = m_typeInfos.value(metaTypeId);
970 if (!info) {
971 info = new QScriptTypeInfo();
972 m_typeInfos.insert(metaTypeId, info);
973 }
974 info->prototype = prototype;
975}
976
977JSC::JSGlobalObject *QScriptEnginePrivate::originalGlobalObject() const
978{
979 return globalData->head;
980}
981
982JSC::JSObject *QScriptEnginePrivate::customGlobalObject() const
983{
984 QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
985 return glob->customGlobalObject;
986}
987
988JSC::JSObject *QScriptEnginePrivate::getOriginalGlobalObjectProxy()
989{
990 if (!originalGlobalObjectProxy) {
991 JSC::ExecState* exec = currentFrame;
992 originalGlobalObjectProxy = new (exec)QScript::OriginalGlobalObjectProxy(scriptObjectStructure, originalGlobalObject());
993 }
994 return originalGlobalObjectProxy;
995}
996
997JSC::JSObject *QScriptEnginePrivate::globalObject() const
998{
999 QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
1000 if (glob->customGlobalObject)
1001 return glob->customGlobalObject;
1002 return glob;
1003}
1004
1005void QScriptEnginePrivate::setGlobalObject(JSC::JSObject *object)
1006{
1007 if (object == globalObject())
1008 return;
1009 QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
1010 if (object == originalGlobalObjectProxy)
1011 glob->customGlobalObject = 0;
1012 else {
1013 Q_ASSERT(object != originalGlobalObject());
1014 glob->customGlobalObject = object;
1015 }
1016}
1017
1018/*!
1019 \internal
1020
1021 If the given \a value is the original global object, returns the custom
1022 global object or a proxy to the original global object; otherwise returns \a
1023 value.
1024*/
1025JSC::JSValue QScriptEnginePrivate::toUsableValue(JSC::JSValue value)
1026{
1027 if (!value || !value.isObject() || !JSC::asObject(value)->isGlobalObject())
1028 return value;
1029 Q_ASSERT(JSC::asObject(value) == originalGlobalObject());
1030 if (customGlobalObject())
1031 return customGlobalObject();
1032 if (!originalGlobalObjectProxy)
1033 originalGlobalObjectProxy = new (currentFrame)QScript::OriginalGlobalObjectProxy(scriptObjectStructure, originalGlobalObject());
1034 return originalGlobalObjectProxy;
1035}
1036/*!
1037 \internal
1038 Return the 'this' value for a given context
1039*/
1040JSC::JSValue QScriptEnginePrivate::thisForContext(JSC::ExecState *frame)
1041{
1042 if (frame->codeBlock() != 0) {
1043 return frame->thisValue();
1044 } else if(frame == frame->lexicalGlobalObject()->globalExec()) {
1045 return frame->globalThisValue();
1046 } else {
1047 JSC::Register *thisRegister = thisRegisterForFrame(frame);
1048 return thisRegister->jsValue();
1049 }
1050}
1051
1052JSC::Register* QScriptEnginePrivate::thisRegisterForFrame(JSC::ExecState *frame)
1053{
1054 Q_ASSERT(frame->codeBlock() == 0); // only for native calls
1055 return frame->registers() - JSC::RegisterFile::CallFrameHeaderSize - frame->argumentCount();
1056}
1057
1058/*! \internal
1059 For native context, we use the ReturnValueRegister entry in the stackframe header to store flags.
1060 We can do that because this header is not used as the native function return their value thought C++
1061
1062 when setting flags, NativeContext should always be set
1063
1064 contextFlags returns 0 for non native context
1065 */
1066uint QScriptEnginePrivate::contextFlags(JSC::ExecState *exec)
1067{
1068 if (exec->codeBlock())
1069 return 0; //js function doesn't have flags
1070
1071 return exec->returnValueRegister();
1072}
1073
1074void QScriptEnginePrivate::setContextFlags(JSC::ExecState *exec, uint flags)
1075{
1076 Q_ASSERT(!exec->codeBlock());
1077 exec->registers()[JSC::RegisterFile::ReturnValueRegister] = JSC::Register::withInt(flags);
1078}
1079
1080
1081void QScriptEnginePrivate::mark(JSC::MarkStack& markStack)
1082{
1083 Q_Q(QScriptEngine);
1084
1085 markStack.append(originalGlobalObject());
1086 markStack.append(globalObject());
1087 if (originalGlobalObjectProxy)
1088 markStack.append(originalGlobalObjectProxy);
1089
1090 if (qobjectPrototype)
1091 markStack.append(qobjectPrototype);
1092 if (qmetaobjectPrototype)
1093 markStack.append(qmetaobjectPrototype);
1094 if (variantPrototype)
1095 markStack.append(variantPrototype);
1096
1097 {
1098 QScriptValuePrivate *it;
1099 for (it = registeredScriptValues; it != 0; it = it->next) {
1100 if (it->isJSC())
1101 markStack.append(it->jscValue);
1102 }
1103 }
1104
1105 {
1106 QHash<int, QScriptTypeInfo*>::const_iterator it;
1107 for (it = m_typeInfos.constBegin(); it != m_typeInfos.constEnd(); ++it) {
1108 if ((*it)->prototype)
1109 markStack.append((*it)->prototype);
1110 }
1111 }
1112
1113 {
1114 QScriptContext *context = q->currentContext();
1115
1116 while (context) {
1117 JSC::ScopeChainNode *node = frameForContext(context)->scopeChain();
1118 JSC::ScopeChainIterator it(node);
1119 for (it = node->begin(); it != node->end(); ++it) {
1120 JSC::JSObject *object = *it;
1121 if (object)
1122 markStack.append(object);
1123 }
1124
1125 context = context->parentContext();
1126 }
1127 }
1128
1129#ifndef QT_NO_QOBJECT
1130 markStack.drain(); // make sure everything is marked before marking qobject data
1131 {
1132 QHash<QObject*, QScript::QObjectData*>::const_iterator it;
1133 for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) {
1134 QScript::QObjectData *qdata = it.value();
1135 qdata->mark(markStack);
1136 }
1137 }
1138#endif
1139}
1140
1141bool QScriptEnginePrivate::isCollecting() const
1142{
1143 return globalData->heap.isBusy();
1144}
1145
1146void QScriptEnginePrivate::collectGarbage()
1147{
1148 JSC::JSLock lock(false);
1149 globalData->heap.collect();
1150}
1151
1152QScript::TimeoutCheckerProxy *QScriptEnginePrivate::timeoutChecker() const
1153{
1154 return static_cast<QScript::TimeoutCheckerProxy*>(globalData->timeoutChecker);
1155}
1156
1157void QScriptEnginePrivate::agentDeleted(QScriptEngineAgent *agent)
1158{
1159 ownedAgents.removeOne(agent);
1160 if (activeAgent == agent) {
1161 QScriptEngineAgentPrivate::get(agent)->detach();
1162 activeAgent = 0;
1163 }
1164}
1165
1166JSC::JSValue QScriptEnginePrivate::evaluateHelper(JSC::ExecState *exec, intptr_t sourceId,
1167 JSC::EvalExecutable *executable,
1168 bool &compile)
1169{
1170 Q_Q(QScriptEngine);
1171 JSC::JSLock lock(false); // ### hmmm
1172 QBoolBlocker inEvalBlocker(inEval, true);
1173 q->currentContext()->activationObject(); //force the creation of a context for native function;
1174
1175 JSC::Debugger* debugger = originalGlobalObject()->debugger();
1176 if (debugger)
1177 debugger->evaluateStart(sourceId);
1178
1179 q->clearExceptions();
1180 JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject());
1181
1182 if (compile) {
1183 JSC::JSObject* error = executable->compile(exec, exec->scopeChain());
1184 if (error) {
1185 compile = false;
1186 exec->setException(error);
1187
1188 if (debugger) {
1189 debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, error), sourceId, false);
1190 debugger->evaluateStop(error, sourceId);
1191 }
1192
1193 return error;
1194 }
1195 }
1196
1197 JSC::JSValue thisValue = thisForContext(exec);
1198 JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull())
1199 ? exec->dynamicGlobalObject() : thisValue.toObject(exec);
1200 JSC::JSValue exceptionValue;
1201 timeoutChecker()->setShouldAbort(false);
1202 if (processEventsInterval > 0)
1203 timeoutChecker()->reset();
1204
1205 JSC::JSValue result = exec->interpreter()->execute(executable, exec, thisObject, exec->scopeChain(), &exceptionValue);
1206
1207 if (timeoutChecker()->shouldAbort()) {
1208 if (abortResult.isError())
1209 exec->setException(scriptValueToJSCValue(abortResult));
1210
1211 if (debugger)
1212 debugger->evaluateStop(scriptValueToJSCValue(abortResult), sourceId);
1213
1214 return scriptValueToJSCValue(abortResult);
1215 }
1216
1217 if (exceptionValue) {
1218 exec->setException(exceptionValue);
1219
1220 if (debugger)
1221 debugger->evaluateStop(exceptionValue, sourceId);
1222
1223 return exceptionValue;
1224 }
1225
1226 if (debugger)
1227 debugger->evaluateStop(result, sourceId);
1228
1229 Q_ASSERT(!exec->hadException());
1230 return result;
1231}
1232
1233#ifndef QT_NO_QOBJECT
1234
1235JSC::JSValue QScriptEnginePrivate::newQObject(
1236 QObject *object, QScriptEngine::ValueOwnership ownership,
1237 const QScriptEngine::QObjectWrapOptions &options)
1238{
1239 if (!object)
1240 return JSC::jsNull();
1241 JSC::ExecState* exec = currentFrame;
1242 QScript::QObjectData *data = qobjectData(object);
1243 bool preferExisting = (options & QScriptEngine::PreferExistingWrapperObject) != 0;
1244 QScriptEngine::QObjectWrapOptions opt = options & ~QScriptEngine::PreferExistingWrapperObject;
1245 QScriptObject *result = 0;
1246 if (preferExisting) {
1247 result = data->findWrapper(ownership, opt);
1248 if (result)
1249 return result;
1250 }
1251 result = new (exec) QScriptObject(qobjectWrapperObjectStructure);
1252 if (preferExisting)
1253 data->registerWrapper(result, ownership, opt);
1254 result->setDelegate(new QScript::QObjectDelegate(object, ownership, options));
1255 /*if (setDefaultPrototype)*/ {
1256 const QMetaObject *meta = object->metaObject();
1257 while (meta) {
1258 QByteArray typeString = meta->className();
1259 typeString.append('*');
1260 int typeId = QMetaType::type(typeString);
1261 if (typeId != 0) {
1262 JSC::JSValue proto = defaultPrototype(typeId);
1263 if (proto) {
1264 result->setPrototype(proto);
1265 break;
1266 }
1267 }
1268 meta = meta->superClass();
1269 }
1270 }
1271 return result;
1272}
1273
1274JSC::JSValue QScriptEnginePrivate::newQMetaObject(
1275 const QMetaObject *metaObject, JSC::JSValue ctor)
1276{
1277 if (!metaObject)
1278 return JSC::jsNull();
1279 JSC::ExecState* exec = currentFrame;
1280 QScript::QMetaObjectWrapperObject *result = new (exec) QScript::QMetaObjectWrapperObject(exec, metaObject, ctor, qmetaobjectWrapperObjectStructure);
1281 return result;
1282}
1283
1284bool QScriptEnginePrivate::convertToNativeQObject(const QScriptValue &value,
1285 const QByteArray &targetType,
1286 void **result)
1287{
1288 if (!targetType.endsWith('*'))
1289 return false;
1290 if (QObject *qobject = value.toQObject()) {
1291 int start = targetType.startsWith("const ") ? 6 : 0;
1292 QByteArray className = targetType.mid(start, targetType.size()-start-1);
1293 if (void *instance = qobject->qt_metacast(className)) {
1294 *result = instance;
1295 return true;
1296 }
1297 }
1298 return false;
1299}
1300
1301QScript::QObjectData *QScriptEnginePrivate::qobjectData(QObject *object)
1302{
1303 QHash<QObject*, QScript::QObjectData*>::const_iterator it;
1304 it = m_qobjectData.constFind(object);
1305 if (it != m_qobjectData.constEnd())
1306 return it.value();
1307
1308 QScript::QObjectData *data = new QScript::QObjectData(this);
1309 m_qobjectData.insert(object, data);
1310 QObject::connect(object, SIGNAL(destroyed(QObject*)),
1311 q_func(), SLOT(_q_objectDestroyed(QObject*)));
1312 return data;
1313}
1314
1315void QScriptEnginePrivate::_q_objectDestroyed(QObject *object)
1316{
1317 QHash<QObject*, QScript::QObjectData*>::iterator it;
1318 it = m_qobjectData.find(object);
1319 Q_ASSERT(it != m_qobjectData.end());
1320 QScript::QObjectData *data = it.value();
1321 m_qobjectData.erase(it);
1322 delete data;
1323}
1324
1325void QScriptEnginePrivate::disposeQObject(QObject *object)
1326{
1327 // TODO
1328/* if (isCollecting()) {
1329 // wait until we're done with GC before deleting it
1330 int index = m_qobjectsToBeDeleted.indexOf(object);
1331 if (index == -1)
1332 m_qobjectsToBeDeleted.append(object);
1333 } else*/ {
1334 delete object;
1335 }
1336}
1337
1338void QScriptEnginePrivate::emitSignalHandlerException()
1339{
1340 Q_Q(QScriptEngine);
1341 emit q->signalHandlerException(q->uncaughtException());
1342}
1343
1344bool QScriptEnginePrivate::scriptConnect(QObject *sender, const char *signal,
1345 JSC::JSValue receiver, JSC::JSValue function,
1346 Qt::ConnectionType type)
1347{
1348 Q_ASSERT(sender);
1349 Q_ASSERT(signal);
1350 const QMetaObject *meta = sender->metaObject();
1351 int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
1352 if (index == -1)
1353 return false;
1354 return scriptConnect(sender, index, receiver, function, /*wrapper=*/JSC::JSValue(), type);
1355}
1356
1357bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, const char *signal,
1358 JSC::JSValue receiver, JSC::JSValue function)
1359{
1360 Q_ASSERT(sender);
1361 Q_ASSERT(signal);
1362 const QMetaObject *meta = sender->metaObject();
1363 int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
1364 if (index == -1)
1365 return false;
1366 return scriptDisconnect(sender, index, receiver, function);
1367}
1368
1369bool QScriptEnginePrivate::scriptConnect(QObject *sender, int signalIndex,
1370 JSC::JSValue receiver, JSC::JSValue function,
1371 JSC::JSValue senderWrapper,
1372 Qt::ConnectionType type)
1373{
1374 QScript::QObjectData *data = qobjectData(sender);
1375 return data->addSignalHandler(sender, signalIndex, receiver, function, senderWrapper, type);
1376}
1377
1378bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, int signalIndex,
1379 JSC::JSValue receiver, JSC::JSValue function)
1380{
1381 QScript::QObjectData *data = qobjectData(sender);
1382 if (!data)
1383 return false;
1384 return data->removeSignalHandler(sender, signalIndex, receiver, function);
1385}
1386
1387bool QScriptEnginePrivate::scriptConnect(JSC::JSValue signal, JSC::JSValue receiver,
1388 JSC::JSValue function, Qt::ConnectionType type)
1389{
1390 QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(JSC::asObject(signal));
1391 int index = fun->mostGeneralMethod();
1392 return scriptConnect(fun->qobject(), index, receiver, function, fun->wrapperObject(), type);
1393}
1394
1395bool QScriptEnginePrivate::scriptDisconnect(JSC::JSValue signal, JSC::JSValue receiver,
1396 JSC::JSValue function)
1397{
1398 QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(JSC::asObject(signal));
1399 int index = fun->mostGeneralMethod();
1400 return scriptDisconnect(fun->qobject(), index, receiver, function);
1401}
1402
1403#endif
1404
1405void QScriptEnginePrivate::detachAllRegisteredScriptValues()
1406{
1407 QScriptValuePrivate *it;
1408 QScriptValuePrivate *next;
1409 for (it = registeredScriptValues; it != 0; it = next) {
1410 it->detachFromEngine();
1411 next = it->next;
1412 it->prev = 0;
1413 it->next = 0;
1414 }
1415 registeredScriptValues = 0;
1416}
1417
1418void QScriptEnginePrivate::detachAllRegisteredScriptStrings()
1419{
1420 QScriptStringPrivate *it;
1421 QScriptStringPrivate *next;
1422 for (it = registeredScriptStrings; it != 0; it = next) {
1423 it->detachFromEngine();
1424 next = it->next;
1425 it->prev = 0;
1426 it->next = 0;
1427 }
1428 registeredScriptStrings = 0;
1429}
1430
1431#ifdef QT_NO_QOBJECT
1432
1433QScriptEngine::QScriptEngine()
1434 : d_ptr(new QScriptEnginePrivate)
1435{
1436 d_ptr->q_ptr = this;
1437}
1438
1439/*! \internal
1440*/
1441QScriptEngine::QScriptEngine(QScriptEnginePrivate &dd)
1442 : d_ptr(&dd)
1443{
1444 d_ptr->q_ptr = this;
1445}
1446#else
1447
1448/*!
1449 Constructs a QScriptEngine object.
1450
1451 The globalObject() is initialized to have properties as described in
1452 \l{ECMA-262}, Section 15.1.
1453*/
1454QScriptEngine::QScriptEngine()
1455 : QObject(*new QScriptEnginePrivate, 0)
1456{
1457}
1458
1459/*!
1460 Constructs a QScriptEngine object with the given \a parent.
1461
1462 The globalObject() is initialized to have properties as described in
1463 \l{ECMA-262}, Section 15.1.
1464*/
1465
1466QScriptEngine::QScriptEngine(QObject *parent)
1467 : QObject(*new QScriptEnginePrivate, parent)
1468{
1469}
1470
1471/*! \internal
1472*/
1473QScriptEngine::QScriptEngine(QScriptEnginePrivate &dd, QObject *parent)
1474 : QObject(dd, parent)
1475{
1476}
1477#endif
1478
1479/*!
1480 Destroys this QScriptEngine.
1481*/
1482QScriptEngine::~QScriptEngine()
1483{
1484#ifdef QT_NO_QOBJECT
1485 delete d_ptr;
1486 d_ptr = 0;
1487#endif
1488}
1489
1490/*!
1491 Returns this engine's Global Object.
1492
1493 By default, the Global Object contains the built-in objects that are
1494 part of \l{ECMA-262}, such as Math, Date and String. Additionally,
1495 you can set properties of the Global Object to make your own
1496 extensions available to all script code. Non-local variables in
1497 script code will be created as properties of the Global Object, as
1498 well as local variables in global code.
1499*/
1500QScriptValue QScriptEngine::globalObject() const
1501{
1502 Q_D(const QScriptEngine);
1503 JSC::JSObject *result = d->globalObject();
1504 return const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(result);
1505}
1506
1507/*!
1508 \since 4.5
1509
1510 Sets this engine's Global Object to be the given \a object.
1511 If \a object is not a valid script object, this function does
1512 nothing.
1513
1514 When setting a custom global object, you may want to use
1515 QScriptValueIterator to copy the properties of the standard Global
1516 Object; alternatively, you can set the internal prototype of your
1517 custom object to be the original Global Object.
1518*/
1519void QScriptEngine::setGlobalObject(const QScriptValue &object)
1520{
1521 Q_D(QScriptEngine);
1522 if (!object.isObject())
1523 return;
1524 JSC::JSObject *jscObject = JSC::asObject(d->scriptValueToJSCValue(object));
1525 d->setGlobalObject(jscObject);
1526}
1527
1528/*!
1529 Returns a QScriptValue of the primitive type Null.
1530
1531 \sa undefinedValue()
1532*/
1533QScriptValue QScriptEngine::nullValue()
1534{
1535 Q_D(QScriptEngine);
1536 return d->scriptValueFromJSCValue(JSC::jsNull());
1537}
1538
1539/*!
1540 Returns a QScriptValue of the primitive type Undefined.
1541
1542 \sa nullValue()
1543*/
1544QScriptValue QScriptEngine::undefinedValue()
1545{
1546 Q_D(QScriptEngine);
1547 return d->scriptValueFromJSCValue(JSC::jsUndefined());
1548}
1549
1550/*!
1551 Creates a constructor function from \a fun, with the given \a length.
1552 The \c{prototype} property of the resulting function is set to be the
1553 given \a prototype. The \c{constructor} property of \a prototype is
1554 set to be the resulting function.
1555
1556 When a function is called as a constructor (e.g. \c{new Foo()}), the
1557 `this' object associated with the function call is the new object
1558 that the function is expected to initialize; the prototype of this
1559 default constructed object will be the function's public
1560 \c{prototype} property. If you always want the function to behave as
1561 a constructor (e.g. \c{Foo()} should also create a new object), or
1562 if you need to create your own object rather than using the default
1563 `this' object, you should make sure that the prototype of your
1564 object is set correctly; either by setting it manually, or, when
1565 wrapping a custom type, by having registered the defaultPrototype()
1566 of that type. Example:
1567
1568 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 9
1569
1570 To wrap a custom type and provide a constructor for it, you'd typically
1571 do something like this:
1572
1573 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 10
1574*/
1575QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun,
1576 const QScriptValue &prototype,
1577 int length)
1578{
1579 Q_D(QScriptEngine);
1580 JSC::ExecState* exec = d->currentFrame;
1581 JSC::JSValue function = new (exec)QScript::FunctionWrapper(exec, length, JSC::Identifier(exec, ""), fun);
1582 QScriptValue result = d->scriptValueFromJSCValue(function);
1583 result.setProperty(QLatin1String("prototype"), prototype, QScriptValue::Undeletable);
1584 const_cast<QScriptValue&>(prototype)
1585 .setProperty(QLatin1String("constructor"), result,
1586 QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1587 return result;
1588}
1589
1590#ifndef QT_NO_REGEXP
1591
1592extern QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
1593
1594/*!
1595 Creates a QtScript object of class RegExp with the given
1596 \a regexp.
1597
1598 \sa QScriptValue::toRegExp()
1599*/
1600QScriptValue QScriptEngine::newRegExp(const QRegExp &regexp)
1601{
1602 Q_D(QScriptEngine);
1603 JSC::ExecState* exec = d->currentFrame;
1604 JSC::JSValue buf[2];
1605 JSC::ArgList args(buf, sizeof(buf));
1606
1607 //convert the pattern to a ECMAScript pattern
1608 QString pattern = qt_regexp_toCanonical(regexp.pattern(), regexp.patternSyntax());
1609 if (regexp.isMinimal()) {
1610 QString ecmaPattern;
1611 int len = pattern.length();
1612 ecmaPattern.reserve(len);
1613 int i = 0;
1614 const QChar *wc = pattern.unicode();
1615 bool inBracket = false;
1616 while (i < len) {
1617 QChar c = wc[i++];
1618 ecmaPattern += c;
1619 switch (c.unicode()) {
1620 case '?':
1621 case '+':
1622 case '*':
1623 case '}':
1624 if (!inBracket)
1625 ecmaPattern += QLatin1Char('?');
1626 break;
1627 case '\\':
1628 if (i < len)
1629 ecmaPattern += wc[i++];
1630 break;
1631 case '[':
1632 inBracket = true;
1633 break;
1634 case ']':
1635 inBracket = false;
1636 break;
1637 default:
1638 break;
1639 }
1640 }
1641 pattern = ecmaPattern;
1642 }
1643
1644 JSC::UString jscPattern = pattern;
1645 QString flags;
1646 if (regexp.caseSensitivity() == Qt::CaseInsensitive)
1647 flags.append(QLatin1Char('i'));
1648 JSC::UString jscFlags = flags;
1649 buf[0] = JSC::jsString(exec, jscPattern);
1650 buf[1] = JSC::jsString(exec, jscFlags);
1651 JSC::JSObject* result = JSC::constructRegExp(exec, args);
1652 return d->scriptValueFromJSCValue(result);
1653}
1654
1655#endif // QT_NO_REGEXP
1656
1657/*!
1658 Creates a QtScript object holding the given variant \a value.
1659
1660 If a default prototype has been registered with the meta type id of
1661 \a value, then the prototype of the created object will be that
1662 prototype; otherwise, the prototype will be the Object prototype
1663 object.
1664
1665 \sa setDefaultPrototype(), QScriptValue::toVariant()
1666*/
1667QScriptValue QScriptEngine::newVariant(const QVariant &value)
1668{
1669 Q_D(QScriptEngine);
1670 JSC::ExecState* exec = d->currentFrame;
1671 QScriptObject *obj = new (exec) QScriptObject(d->variantWrapperObjectStructure);
1672 obj->setDelegate(new QScript::QVariantDelegate(value));
1673 QScriptValue result = d->scriptValueFromJSCValue(obj);
1674 QScriptValue proto = defaultPrototype(value.userType());
1675 if (proto.isValid())
1676 result.setPrototype(proto);
1677 return result;
1678}
1679
1680/*!
1681 \since 4.4
1682 \overload
1683
1684 Initializes the given Qt Script \a object to hold the given variant
1685 \a value, and returns the \a object.
1686
1687 This function enables you to "promote" a plain Qt Script object
1688 (created by the newObject() function) to a variant, or to replace
1689 the variant contained inside an object previously created by the
1690 newVariant() function.
1691
1692 The prototype() of the \a object will remain unchanged.
1693
1694 If \a object is not an object, this function behaves like the normal
1695 newVariant(), i.e. it creates a new script object and returns it.
1696
1697 This function is useful when you want to provide a script
1698 constructor for a C++ type. If your constructor is invoked in a
1699 \c{new} expression (QScriptContext::isCalledAsConstructor() returns
1700 true), you can pass QScriptContext::thisObject() (the default
1701 constructed script object) to this function to initialize the new
1702 object.
1703*/
1704QScriptValue QScriptEngine::newVariant(const QScriptValue &object,
1705 const QVariant &value)
1706{
1707 if (!object.isObject())
1708 return newVariant(value);
1709 JSC::JSObject *jscObject = JSC::asObject(QScriptValuePrivate::get(object)->jscValue);
1710 if (!jscObject->inherits(&QScriptObject::info)) {
1711 qWarning("QScriptEngine::newVariant(): changing class of non-QScriptObject not supported");
1712 return QScriptValue();
1713 }
1714 QScriptObject *jscScriptObject = static_cast<QScriptObject*>(jscObject);
1715 if (!object.isVariant()) {
1716 jscScriptObject->setDelegate(new QScript::QVariantDelegate(value));
1717 } else {
1718 QScriptValuePrivate::get(object)->setVariantValue(value);
1719 }
1720 return object;
1721}
1722
1723#ifndef QT_NO_QOBJECT
1724/*!
1725 Creates a QtScript object that wraps the given QObject \a
1726 object, using the given \a ownership. The given \a options control
1727 various aspects of the interaction with the resulting script object.
1728
1729 Signals and slots, properties and children of \a object are
1730 available as properties of the created QScriptValue. For more
1731 information, see the \l{QtScript} documentation.
1732
1733 If \a object is a null pointer, this function returns nullValue().
1734
1735 If a default prototype has been registered for the \a object's class
1736 (or its superclass, recursively), the prototype of the new script
1737 object will be set to be that default prototype.
1738
1739 If the given \a object is deleted outside of QtScript's control, any
1740 attempt to access the deleted QObject's members through the QtScript
1741 wrapper object (either by script code or C++) will result in a
1742 script exception.
1743
1744 \sa QScriptValue::toQObject()
1745*/
1746QScriptValue QScriptEngine::newQObject(QObject *object, ValueOwnership ownership,
1747 const QObjectWrapOptions &options)
1748{
1749 Q_D(QScriptEngine);
1750 JSC::JSValue jscQObject = d->newQObject(object, ownership, options);
1751 return d->scriptValueFromJSCValue(jscQObject);
1752}
1753
1754/*!
1755 \since 4.4
1756 \overload
1757
1758 Initializes the given \a scriptObject to hold the given \a qtObject,
1759 and returns the \a scriptObject.
1760
1761 This function enables you to "promote" a plain Qt Script object
1762 (created by the newObject() function) to a QObject proxy, or to
1763 replace the QObject contained inside an object previously created by
1764 the newQObject() function.
1765
1766 The prototype() of the \a scriptObject will remain unchanged.
1767
1768 If \a scriptObject is not an object, this function behaves like the
1769 normal newQObject(), i.e. it creates a new script object and returns
1770 it.
1771
1772 This function is useful when you want to provide a script
1773 constructor for a QObject-based class. If your constructor is
1774 invoked in a \c{new} expression
1775 (QScriptContext::isCalledAsConstructor() returns true), you can pass
1776 QScriptContext::thisObject() (the default constructed script object)
1777 to this function to initialize the new object.
1778*/
1779QScriptValue QScriptEngine::newQObject(const QScriptValue &scriptObject,
1780 QObject *qtObject,
1781 ValueOwnership ownership,
1782 const QObjectWrapOptions &options)
1783{
1784 if (!scriptObject.isObject())
1785 return newQObject(qtObject, ownership, options);
1786 JSC::JSObject *jscObject = JSC::asObject(QScriptValuePrivate::get(scriptObject)->jscValue);
1787 if (!jscObject->inherits(&QScriptObject::info)) {
1788 qWarning("QScriptEngine::newQObject(): changing class of non-QScriptObject not supported");
1789 return QScriptValue();
1790 }
1791 QScriptObject *jscScriptObject = static_cast<QScriptObject*>(jscObject);
1792 if (!scriptObject.isQObject()) {
1793 jscScriptObject->setDelegate(new QScript::QObjectDelegate(qtObject, ownership, options));
1794 } else {
1795 QScript::QObjectDelegate *delegate = static_cast<QScript::QObjectDelegate*>(jscScriptObject->delegate());
1796 delegate->setValue(qtObject);
1797 delegate->setOwnership(ownership);
1798 delegate->setOptions(options);
1799 }
1800 return scriptObject;
1801}
1802
1803#endif // QT_NO_QOBJECT
1804
1805/*!
1806 Creates a QtScript object of class Object.
1807
1808 The prototype of the created object will be the Object
1809 prototype object.
1810
1811 \sa newArray(), QScriptValue::setProperty()
1812*/
1813QScriptValue QScriptEngine::newObject()
1814{
1815 Q_D(QScriptEngine);
1816 JSC::ExecState* exec = d->currentFrame;
1817 JSC::JSObject *result = new (exec)QScriptObject(d->scriptObjectStructure);
1818 return d->scriptValueFromJSCValue(result);
1819}
1820
1821/*!
1822 \since 4.4
1823 \overload
1824
1825 Creates a QtScript Object of the given class, \a scriptClass.
1826
1827 The prototype of the created object will be the Object
1828 prototype object.
1829
1830 \a data, if specified, is set as the internal data of the
1831 new object (using QScriptValue::setData()).
1832
1833 \sa QScriptValue::scriptClass()
1834*/
1835QScriptValue QScriptEngine::newObject(QScriptClass *scriptClass,
1836 const QScriptValue &data)
1837{
1838 Q_D(QScriptEngine);
1839 JSC::ExecState* exec = d->currentFrame;
1840 QScriptObject *result = new (exec) QScriptObject(d->scriptObjectStructure);
1841 result->setDelegate(new QScript::ClassObjectDelegate(scriptClass));
1842 QScriptValue scriptObject = d->scriptValueFromJSCValue(result);
1843 scriptObject.setData(data);
1844 QScriptValue proto = scriptClass->prototype();
1845 if (proto.isValid())
1846 scriptObject.setPrototype(proto);
1847 return scriptObject;
1848}
1849
1850/*!
1851 \internal
1852*/
1853QScriptValue QScriptEngine::newActivationObject()
1854{
1855 qWarning("QScriptEngine::newActivationObject() not implemented");
1856 // ### JSActivation or JSVariableObject?
1857 return QScriptValue();
1858}
1859
1860/*!
1861 Creates a QScriptValue that wraps a native (C++) function. \a fun
1862 must be a C++ function with signature QScriptEngine::FunctionSignature. \a
1863 length is the number of arguments that \a fun expects; this becomes
1864 the \c{length} property of the created QScriptValue.
1865
1866 Note that \a length only gives an indication of the number of
1867 arguments that the function expects; an actual invocation of a
1868 function can include any number of arguments. You can check the
1869 \l{QScriptContext::argumentCount()}{argumentCount()} of the
1870 QScriptContext associated with the invocation to determine the
1871 actual number of arguments passed.
1872
1873 A \c{prototype} property is automatically created for the resulting
1874 function object, to provide for the possibility that the function
1875 will be used as a constructor.
1876
1877 By combining newFunction() and the property flags
1878 QScriptValue::PropertyGetter and QScriptValue::PropertySetter, you
1879 can create script object properties that behave like normal
1880 properties in script code, but are in fact accessed through
1881 functions (analogous to how properties work in \l{Qt's Property
1882 System}). Example:
1883
1884 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 11
1885
1886 When the property \c{foo} of the script object is subsequently
1887 accessed in script code, \c{getSetFoo()} will be invoked to handle
1888 the access. In this particular case, we chose to store the "real"
1889 value of \c{foo} as a property of the accessor function itself; you
1890 are of course free to do whatever you like in this function.
1891
1892 In the above example, a single native function was used to handle
1893 both reads and writes to the property; the argument count is used to
1894 determine if we are handling a read or write. You can also use two
1895 separate functions; just specify the relevant flag
1896 (QScriptValue::PropertyGetter or QScriptValue::PropertySetter) when
1897 setting the property, e.g.:
1898
1899 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 12
1900
1901 \sa QScriptValue::call()
1902*/
1903QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun, int length)
1904{
1905 Q_D(QScriptEngine);
1906 JSC::ExecState* exec = d->currentFrame;
1907 JSC::JSValue function = new (exec)QScript::FunctionWrapper(exec, length, JSC::Identifier(exec, ""), fun);
1908 QScriptValue result = d->scriptValueFromJSCValue(function);
1909 QScriptValue proto = newObject();
1910 result.setProperty(QLatin1String("prototype"), proto, QScriptValue::Undeletable);
1911 proto.setProperty(QLatin1String("constructor"), result,
1912 QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1913 return result;
1914}
1915
1916/*!
1917 \internal
1918 \since 4.4
1919*/
1920QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionWithArgSignature fun, void *arg)
1921{
1922 Q_D(QScriptEngine);
1923 JSC::ExecState* exec = d->currentFrame;
1924 JSC::JSValue function = new (exec)QScript::FunctionWithArgWrapper(exec, /*length=*/0, JSC::Identifier(exec, ""), fun, arg);
1925 QScriptValue result = d->scriptValueFromJSCValue(function);
1926 QScriptValue proto = newObject();
1927 result.setProperty(QLatin1String("prototype"), proto, QScriptValue::Undeletable);
1928 proto.setProperty(QLatin1String("constructor"), result,
1929 QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
1930 return result;
1931}
1932
1933/*!
1934 Creates a QtScript object of class Array with the given \a length.
1935
1936 \sa newObject()
1937*/
1938QScriptValue QScriptEngine::newArray(uint length)
1939{
1940 Q_D(QScriptEngine);
1941 JSC::ExecState* exec = d->currentFrame;
1942 JSC::JSArray* result = JSC::constructEmptyArray(exec, length);
1943 return d->scriptValueFromJSCValue(result);
1944}
1945
1946/*!
1947 Creates a QtScript object of class RegExp with the given
1948 \a pattern and \a flags.
1949
1950 The legal flags are 'g' (global), 'i' (ignore case), and 'm'
1951 (multiline).
1952*/
1953QScriptValue QScriptEngine::newRegExp(const QString &pattern, const QString &flags)
1954{
1955 Q_D(QScriptEngine);
1956 JSC::ExecState* exec = d->currentFrame;
1957 JSC::JSValue buf[2];
1958 JSC::ArgList args(buf, sizeof(buf));
1959 JSC::UString jscPattern = pattern;
1960 QString strippedFlags;
1961 if (flags.contains(QLatin1Char('i')))
1962 strippedFlags += QLatin1Char('i');
1963 if (flags.contains(QLatin1Char('m')))
1964 strippedFlags += QLatin1Char('m');
1965 if (flags.contains(QLatin1Char('g')))
1966 strippedFlags += QLatin1Char('g');
1967 JSC::UString jscFlags = strippedFlags;
1968 buf[0] = JSC::jsString(exec, jscPattern);
1969 buf[1] = JSC::jsString(exec, jscFlags);
1970 JSC::JSObject* result = JSC::constructRegExp(exec, args);
1971 return d->scriptValueFromJSCValue(result);
1972}
1973
1974/*!
1975 Creates a QtScript object of class Date with the given
1976 \a value (the number of milliseconds since 01 January 1970,
1977 UTC).
1978*/
1979QScriptValue QScriptEngine::newDate(qsreal value)
1980{
1981 Q_D(QScriptEngine);
1982 JSC::ExecState* exec = d->currentFrame;
1983 JSC::JSValue val = JSC::jsNumber(exec, value);
1984 JSC::ArgList args(&val, 1);
1985 JSC::JSObject *result = JSC::constructDate(exec, args);
1986 return d->scriptValueFromJSCValue(result);
1987}
1988
1989/*!
1990 Creates a QtScript object of class Date from the given \a value.
1991
1992 \sa QScriptValue::toDateTime()
1993*/
1994QScriptValue QScriptEngine::newDate(const QDateTime &value)
1995{
1996 return newDate(QScript::FromDateTime(value));
1997}
1998
1999#ifndef QT_NO_QOBJECT
2000/*!
2001 Creates a QtScript object that represents a QObject class, using the
2002 the given \a metaObject and constructor \a ctor.
2003
2004 Enums of \a metaObject (declared with Q_ENUMS) are available as
2005 properties of the created QScriptValue. When the class is called as
2006 a function, \a ctor will be called to create a new instance of the
2007 class.
2008
2009 Example:
2010
2011 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 27
2012
2013 \sa newQObject(), scriptValueFromQMetaObject()
2014*/
2015QScriptValue QScriptEngine::newQMetaObject(
2016 const QMetaObject *metaObject, const QScriptValue &ctor)
2017{
2018 Q_D(QScriptEngine);
2019 JSC::JSValue jscCtor = d->scriptValueToJSCValue(ctor);
2020 JSC::JSValue jscQMetaObject = d->newQMetaObject(metaObject, jscCtor);
2021 return d->scriptValueFromJSCValue(jscQMetaObject);
2022}
2023
2024/*!
2025 \fn QScriptValue QScriptEngine::scriptValueFromQMetaObject()
2026
2027 Creates a QScriptValue that represents the Qt class \c{T}.
2028
2029 This function is used in combination with one of the
2030 Q_SCRIPT_DECLARE_QMETAOBJECT() macro. Example:
2031
2032 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 13
2033
2034 \warning This function is not available with MSVC 6. Use
2035 qScriptValueFromQMetaObject() instead if you need to support that version
2036 of the compiler.
2037
2038 \sa QScriptEngine::newQMetaObject()
2039*/
2040
2041/*!
2042 \fn QScriptValue qScriptValueFromQMetaObject(QScriptEngine *engine)
2043 \since 4.3
2044 \relates QScriptEngine
2045
2046 Uses \a engine to create a QScriptValue that represents the Qt class
2047 \c{T}.
2048
2049 This function is equivalent to
2050 QScriptEngine::scriptValueFromQMetaObject(). It is provided as a
2051 work-around for MSVC 6, which doesn't support member template
2052 functions.
2053
2054 \sa QScriptEngine::newQMetaObject()
2055*/
2056#endif // QT_NO_QOBJECT
2057
2058/*!
2059 \obsolete
2060
2061 Returns true if \a program can be evaluated; i.e. the code is
2062 sufficient to determine whether it appears to be a syntactically
2063 correct program, or contains a syntax error.
2064
2065 This function returns false if \a program is incomplete; i.e. the
2066 input is syntactically correct up to the point where the input is
2067 terminated.
2068
2069 Note that this function only does a static check of \a program;
2070 e.g. it does not check whether references to variables are
2071 valid, and so on.
2072
2073 A typical usage of canEvaluate() is to implement an interactive
2074 interpreter for QtScript. The user is repeatedly queried for
2075 individual lines of code; the lines are concatened internally, and
2076 only when canEvaluate() returns true for the resulting program is it
2077 passed to evaluate().
2078
2079 The following are some examples to illustrate the behavior of
2080 canEvaluate(). (Note that all example inputs are assumed to have an
2081 explicit newline as their last character, since otherwise the
2082 QtScript parser would automatically insert a semi-colon character at
2083 the end of the input, and this could cause canEvaluate() to produce
2084 different results.)
2085
2086 Given the input
2087 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 14
2088 canEvaluate() will return true, since the program appears to be complete.
2089
2090 Given the input
2091 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 15
2092 canEvaluate() will return false, since the if-statement is not complete,
2093 but is syntactically correct so far.
2094
2095 Given the input
2096 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 16
2097 canEvaluate() will return true, but evaluate() will throw a
2098 SyntaxError given the same input.
2099
2100 Given the input
2101 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 17
2102 canEvaluate() will return true, even though the code is clearly not
2103 syntactically valid QtScript code. evaluate() will throw a
2104 SyntaxError when this code is evaluated.
2105
2106 Given the input
2107 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 18
2108 canEvaluate() will return true, but evaluate() will throw a
2109 ReferenceError if \c{foo} is not defined in the script
2110 environment.
2111
2112 \sa evaluate(), checkSyntax()
2113*/
2114bool QScriptEngine::canEvaluate(const QString &program) const
2115{
2116 return QScriptEnginePrivate::canEvaluate(program);
2117}
2118
2119
2120bool QScriptEnginePrivate::canEvaluate(const QString &program)
2121{
2122 QScript::SyntaxChecker checker;
2123 QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
2124 return (result.state != QScript::SyntaxChecker::Intermediate);
2125}
2126
2127/*!
2128 \since 4.5
2129
2130 Checks the syntax of the given \a program. Returns a
2131 QScriptSyntaxCheckResult object that contains the result of the check.
2132*/
2133QScriptSyntaxCheckResult QScriptEngine::checkSyntax(const QString &program)
2134{
2135 return QScriptEnginePrivate::checkSyntax(program);
2136}
2137
2138QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &program)
2139{
2140 QScript::SyntaxChecker checker;
2141 QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
2142 QScriptSyntaxCheckResultPrivate *p = new QScriptSyntaxCheckResultPrivate();
2143 switch (result.state) {
2144 case QScript::SyntaxChecker::Error:
2145 p->state = QScriptSyntaxCheckResult::Error;
2146 break;
2147 case QScript::SyntaxChecker::Intermediate:
2148 p->state = QScriptSyntaxCheckResult::Intermediate;
2149 break;
2150 case QScript::SyntaxChecker::Valid:
2151 p->state = QScriptSyntaxCheckResult::Valid;
2152 break;
2153 }
2154 p->errorLineNumber = result.errorLineNumber;
2155 p->errorColumnNumber = result.errorColumnNumber;
2156 p->errorMessage = result.errorMessage;
2157 return QScriptSyntaxCheckResult(p);
2158}
2159
2160
2161
2162/*!
2163 Evaluates \a program, using \a lineNumber as the base line number,
2164 and returns the result of the evaluation.
2165
2166 The script code will be evaluated in the current context.
2167
2168 The evaluation of \a program can cause an exception in the
2169 engine; in this case the return value will be the exception
2170 that was thrown (typically an \c{Error} object). You can call
2171 hasUncaughtException() to determine if an exception occurred in
2172 the last call to evaluate().
2173
2174 \a lineNumber is used to specify a starting line number for \a
2175 program; line number information reported by the engine that pertain
2176 to this evaluation (e.g. uncaughtExceptionLineNumber()) will be
2177 based on this argument. For example, if \a program consists of two
2178 lines of code, and the statement on the second line causes a script
2179 exception, uncaughtExceptionLineNumber() would return the given \a
2180 lineNumber plus one. When no starting line number is specified, line
2181 numbers will be 1-based.
2182
2183 \a fileName is used for error reporting. For example in error objects
2184 the file name is accessible through the "fileName" property if it's
2185 provided with this function.
2186
2187 \sa canEvaluate(), hasUncaughtException(), isEvaluating(), abortEvaluation()
2188*/
2189
2190QScriptValue QScriptEngine::evaluate(const QString &program, const QString &fileName, int lineNumber)
2191{
2192 Q_D(QScriptEngine);
2193 WTF::PassRefPtr<QScript::UStringSourceProviderWithFeedback> provider
2194 = QScript::UStringSourceProviderWithFeedback::create(program, fileName, lineNumber, d);
2195 intptr_t sourceId = provider->asID();
2196 JSC::SourceCode source(provider, lineNumber); //after construction of SourceCode provider variable will be null.
2197
2198 JSC::ExecState* exec = d->currentFrame;
2199 JSC::EvalExecutable executable(exec, source);
2200 bool compile = true;
2201 return d->scriptValueFromJSCValue(d->evaluateHelper(exec, sourceId, &executable, compile));
2202}
2203
2204/*!
2205 \internal
2206 \since 4.6
2207
2208 Evaluates the given \a program and returns the result of the
2209 evaluation.
2210*/
2211QScriptValue QScriptEngine::evaluate(const QScriptProgram &program)
2212{
2213 Q_D(QScriptEngine);
2214 QScriptProgramPrivate *program_d = QScriptProgramPrivate::get(program);
2215 if (!program_d)
2216 return QScriptValue();
2217
2218 JSC::ExecState* exec = d->currentFrame;
2219 JSC::EvalExecutable *executable = program_d->executable(exec, d);
2220 bool compile = !program_d->isCompiled;
2221 JSC::JSValue result = d->evaluateHelper(exec, program_d->sourceId,
2222 executable, compile);
2223 if (compile)
2224 program_d->isCompiled = true;
2225 return d->scriptValueFromJSCValue(result);
2226}
2227
2228/*!
2229 Returns the current context.
2230
2231 The current context is typically accessed to retrieve the arguments
2232 and `this' object in native functions; for convenience, it is
2233 available as the first argument in QScriptEngine::FunctionSignature.
2234*/
2235QScriptContext *QScriptEngine::currentContext() const
2236{
2237 Q_D(const QScriptEngine);
2238 return const_cast<QScriptEnginePrivate*>(d)->contextForFrame(d->currentFrame);
2239}
2240
2241/*!
2242 Enters a new execution context and returns the associated
2243 QScriptContext object.
2244
2245 Once you are done with the context, you should call popContext() to
2246 restore the old context.
2247
2248 By default, the `this' object of the new context is the Global Object.
2249 The context's \l{QScriptContext::callee()}{callee}() will be invalid.
2250
2251 This function is useful when you want to evaluate script code
2252 as if it were the body of a function. You can use the context's
2253 \l{QScriptContext::activationObject()}{activationObject}() to initialize
2254 local variables that will be available to scripts. Example:
2255
2256 \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 19
2257
2258 In the above example, the new variable "tmp" defined in the script
2259 will be local to the context; in other words, the script doesn't
2260 have any effect on the global environment.
2261
2262 Returns 0 in case of stack overflow
2263
2264 \sa popContext()
2265*/
2266QScriptContext *QScriptEngine::pushContext()
2267{
2268 Q_D(QScriptEngine);
2269
2270 JSC::CallFrame* newFrame = d->pushContext(d->currentFrame, d->currentFrame->globalData().dynamicGlobalObject,
2271 JSC::ArgList(), /*callee = */0);
2272
2273 if (agent())
2274 agent()->contextPush();
2275
2276 return d->contextForFrame(newFrame);
2277}
2278
2279/*! \internal
2280 push a context for a native function.
2281 JSC native function doesn't have different stackframe or context. so we need to create one.
2282
2283 use popContext right after to go back to the previous context the context if no stack overflow has hapenned
2284
2285 exec is the current top frame.
2286
2287 return the new top frame. (might be the same as exec if a new stackframe was not needed) or 0 if stack overflow
2288*/
2289JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, JSC::JSValue _thisObject,
2290 const JSC::ArgList& args, JSC::JSObject *callee, bool calledAsConstructor,
2291 bool clearScopeChain)
2292{
2293 JSC::JSValue thisObject = _thisObject;
2294 if (calledAsConstructor) {
2295 //JSC doesn't create default created object for native functions. so we do it
2296 JSC::JSValue prototype = callee->get(exec, exec->propertyNames().prototype);
2297 JSC::Structure *structure = prototype.isObject() ? JSC::asObject(prototype)->inheritorID()
2298 : originalGlobalObject()->emptyObjectStructure();
2299 thisObject = new (exec) QScriptObject(structure);
2300 }
2301
2302 int flags = NativeContext;
2303 if (calledAsConstructor)
2304 flags |= CalledAsConstructorContext;
2305
2306 //build a frame
2307 JSC::CallFrame *newCallFrame = exec;
2308 if (callee == 0 //called from public QScriptEngine::pushContext
2309 || exec->returnPC() == 0 || (contextFlags(exec) & NativeContext) //called from native-native call
2310 || (exec->codeBlock() && exec->callee() != callee)) { //the interpreter did not build a frame for us.
2311 //We need to check if the Interpreter might have already created a frame for function called from JS.
2312 JSC::Interpreter *interp = exec->interpreter();
2313 JSC::Register *oldEnd = interp->registerFile().end();
2314 int argc = args.size() + 1; //add "this"
2315 JSC::Register *newEnd = oldEnd + argc + JSC::RegisterFile::CallFrameHeaderSize;
2316 if (!interp->registerFile().grow(newEnd))
2317 return 0; //### Stack overflow
2318 newCallFrame = JSC::CallFrame::create(oldEnd);
2319 newCallFrame[0] = thisObject;
2320 int dst = 0;
2321 JSC::ArgList::const_iterator it;
2322 for (it = args.begin(); it != args.end(); ++it)
2323 newCallFrame[++dst] = *it;
2324 newCallFrame += argc + JSC::RegisterFile::CallFrameHeaderSize;
2325
2326 if (!clearScopeChain) {
2327 newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee);
2328 } else {
2329 JSC::JSObject *jscObject = originalGlobalObject();
2330 JSC::ScopeChainNode *scn = new JSC::ScopeChainNode(0, jscObject, &exec->globalData(), jscObject);
2331 newCallFrame->init(0, /*vPC=*/0, scn, exec, flags | ShouldRestoreCallFrame, argc, callee);
2332 }
2333 } else {
2334 setContextFlags(newCallFrame, flags);
2335#if ENABLE(JIT)
2336 exec->registers()[JSC::RegisterFile::Callee] = JSC::JSValue(callee); //JIT let the callee set the 'callee'
2337#endif
2338 if (calledAsConstructor) {
2339 //update the new created this
2340 JSC::Register* thisRegister = thisRegisterForFrame(newCallFrame);
2341 *thisRegister = thisObject;
2342 }
2343 }
2344 currentFrame = newCallFrame;
2345 return newCallFrame;
2346}
2347
2348
2349/*!
2350 Pops the current execution context and restores the previous one.
2351 This function must be used in conjunction with pushContext().
2352
2353 \sa pushContext()
2354*/
2355void QScriptEngine::popContext()
2356{
2357 if (agent())
2358 agent()->contextPop();
2359 Q_D(QScriptEngine);
2360 if (d->currentFrame->returnPC() != 0 || d->currentFrame->codeBlock() != 0
2361 || !currentContext()->parentContext()) {
2362 qWarning("QScriptEngine::popContext() doesn't match with pushContext()");
2363 return;
2364 }
2365
2366 d->popContext();
2367}
2368
2369/*! \internal
2370 counter part of QScriptEnginePrivate::pushContext
2371 */
2372void QScriptEnginePrivate::popContext()
2373{
2374 uint flags = contextFlags(currentFrame);
2375 bool hasScope = flags & HasScopeContext;
2376 if (flags & ShouldRestoreCallFrame) { //normal case
2377 JSC::RegisterFile &registerFile = currentFrame->interpreter()->registerFile();
2378 JSC::Register *const newEnd = currentFrame->registers() - JSC::RegisterFile::CallFrameHeaderSize - currentFrame->argumentCount();
2379 if (hasScope)
2380 currentFrame->scopeChain()->pop()->deref();
2381 registerFile.shrink(newEnd);
2382 } else if(hasScope) { //the stack frame was created by the Interpreter, we don't need to rewind it.
2383 currentFrame->setScopeChain(currentFrame->scopeChain()->pop());
2384 currentFrame->scopeChain()->deref();
2385 }
2386 currentFrame = currentFrame->callerFrame();
2387}
2388
2389/*!
2390 Returns true if the last script evaluation resulted in an uncaught
2391 exception; otherwise returns false.
2392
2393 The exception state is cleared when evaluate() is called.
2394
2395 \sa uncaughtException(), uncaughtExceptionLineNumber(),
2396 uncaughtExceptionBacktrace()
2397*/
2398bool QScriptEngine::hasUncaughtException() const
2399{
2400 Q_D(const QScriptEngine);
2401 JSC::ExecState* exec = d->globalExec();
2402 return exec->hadException() || d->currentException().isValid();
2403}
2404
2405/*!
2406 Returns the current uncaught exception, or an invalid QScriptValue
2407 if there is no uncaught exception.
2408
2409 The exception value is typically an \c{Error} object; in that case,
2410 you can call toString() on the return value to obtain an error
2411 message.
2412
2413 \sa hasUncaughtException(), uncaughtExceptionLineNumber(),
2414 uncaughtExceptionBacktrace()
2415*/
2416QScriptValue QScriptEngine::uncaughtException() const
2417{
2418 Q_D(const QScriptEngine);
2419 QScriptValue result;
2420 JSC::ExecState* exec = d->globalExec();
2421 if (exec->hadException())
2422 result = const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(exec->exception());
2423 else
2424 result = d->currentException();
2425 return result;
2426}
2427
2428/*!
2429 Returns the line number where the last uncaught exception occurred.
2430
2431 Line numbers are 1-based, unless a different base was specified as
2432 the second argument to evaluate().
2433
2434 \sa hasUncaughtException(), uncaughtExceptionBacktrace()
2435*/
2436int QScriptEngine::uncaughtExceptionLineNumber() const
2437{
2438 if (!hasUncaughtException())
2439 return -1;
2440 return uncaughtException().property(QLatin1String("lineNumber")).toInt32();
2441}
2442
2443/*!