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