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