1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2015 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtScript module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "config.h" |
41 | #include "qscriptvalue.h" |
42 | |
43 | #include "qscriptvalue_p.h" |
44 | #include "qscriptengine.h" |
45 | #include "qscriptengine_p.h" |
46 | #include "qscriptstring_p.h" |
47 | |
48 | #include "JSGlobalObject.h" |
49 | #include "JSImmediate.h" |
50 | #include "JSObject.h" |
51 | #include "JSValue.h" |
52 | #include "JSFunction.h" |
53 | #include "Identifier.h" |
54 | #include "Operations.h" |
55 | #include "Arguments.h" |
56 | |
57 | #include <QtCore/qvariant.h> |
58 | #include <QtCore/qvarlengtharray.h> |
59 | #include <QtCore/qnumeric.h> |
60 | |
61 | /*! |
62 | \since 4.3 |
63 | \class QScriptValue |
64 | \inmodule QtScript |
65 | \brief The QScriptValue class acts as a container for the Qt Script data types. |
66 | |
67 | \ingroup script |
68 | |
69 | QScriptValue supports the types defined in the \l{ECMA-262} |
70 | standard: The primitive types, which are Undefined, Null, Boolean, |
71 | Number, and String; and the Object type. Additionally, Qt Script |
72 | has built-in support for QVariant, QObject and QMetaObject. |
73 | |
74 | For the object-based types (including Date and RegExp), use the |
75 | newT() functions in QScriptEngine (e.g. QScriptEngine::newObject()) |
76 | to create a QScriptValue of the desired type. For the primitive types, |
77 | use one of the QScriptValue constructor overloads. |
78 | |
79 | The methods named isT() (e.g. isBool(), isUndefined()) can be |
80 | used to test if a value is of a certain type. The methods named |
81 | toT() (e.g. toBool(), toString()) can be used to convert a |
82 | QScriptValue to another type. You can also use the generic |
83 | qscriptvalue_cast() function. |
84 | |
85 | Object values have zero or more properties which are themselves |
86 | QScriptValues. Use setProperty() to set a property of an object, and |
87 | call property() to retrieve the value of a property. |
88 | |
89 | \snippet code/src_script_qscriptvalue.cpp 0 |
90 | |
91 | Each property can have a set of attributes; these are specified as |
92 | the third (optional) argument to setProperty(). The attributes of a |
93 | property can be queried by calling the propertyFlags() function. The |
94 | following code snippet creates a property that cannot be modified by |
95 | script code: |
96 | |
97 | \snippet code/src_script_qscriptvalue.cpp 1 |
98 | |
99 | If you want to iterate over the properties of a script object, use |
100 | the QScriptValueIterator class. |
101 | |
102 | Object values have an internal \c{prototype} property, which can be |
103 | accessed with prototype() and setPrototype(). Properties added to a |
104 | prototype are shared by all objects having that prototype; this is |
105 | referred to as prototype-based inheritance. In practice, it means |
106 | that (by default) the property() function will automatically attempt |
107 | to look up look the property in the prototype() (and in the |
108 | prototype of the prototype(), and so on), if the object itself does |
109 | not have the requested property. Note that this prototype-based |
110 | lookup is not performed by setProperty(); setProperty() will always |
111 | create the property in the script object itself. For more |
112 | information, see the \l{Qt Script} documentation. |
113 | |
114 | Function objects (objects for which isFunction() returns true) can |
115 | be invoked by calling call(). Constructor functions can be used to |
116 | construct new objects by calling construct(). |
117 | |
118 | Use equals(), strictlyEquals() and lessThan() to compare a QScriptValue |
119 | to another. |
120 | |
121 | Object values can have custom data associated with them; see the |
122 | setData() and data() functions. By default, this data is not |
123 | accessible to scripts; it can be used to store any data you want to |
124 | associate with the script object. Typically this is used by custom |
125 | class objects (see QScriptClass) to store a C++ type that contains |
126 | the "native" object data. |
127 | |
128 | Note that a QScriptValue for which isObject() is true only carries a |
129 | reference to an actual object; copying the QScriptValue will only |
130 | copy the object reference, not the object itself. If you want to |
131 | clone an object (i.e. copy an object's properties to another |
132 | object), you can do so with the help of a \c{for-in} statement in |
133 | script code, or QScriptValueIterator in C++. |
134 | |
135 | \sa QScriptEngine, QScriptValueIterator |
136 | */ |
137 | |
138 | /*! |
139 | \enum QScriptValue::SpecialValue |
140 | |
141 | This enum is used to specify a single-valued type. |
142 | |
143 | \value UndefinedValue An undefined value. |
144 | |
145 | \value NullValue A null value. |
146 | */ |
147 | |
148 | /*! |
149 | \enum QScriptValue::PropertyFlag |
150 | |
151 | This enum describes the attributes of a property. |
152 | |
153 | \value ReadOnly The property is read-only. Attempts by Qt Script code to write to the property will be ignored. |
154 | |
155 | \value Undeletable Attempts by Qt Script code to \c{delete} the property will be ignored. |
156 | |
157 | \value SkipInEnumeration The property is not to be enumerated by a \c{for-in} enumeration. |
158 | |
159 | \value PropertyGetter The property is defined by a function which will be called to get the property value. |
160 | |
161 | \value PropertySetter The property is defined by a function which will be called to set the property value. |
162 | |
163 | \omitvalue QObjectMember This flag is used to indicate that an existing property is a QObject member (a property or method). |
164 | |
165 | \value KeepExistingFlags This value is used to indicate to setProperty() that the property's flags should be left unchanged. If the property doesn't exist, the default flags (0) will be used. |
166 | |
167 | \omitvalue UserRange Flags in this range are not used by Qt Script, and can be used for custom purposes. |
168 | */ |
169 | |
170 | /*! |
171 | \enum QScriptValue::ResolveFlag |
172 | |
173 | This enum specifies how to look up a property of an object. |
174 | |
175 | \value ResolveLocal Only check the object's own properties. |
176 | |
177 | \value ResolvePrototype Check the object's own properties first, then search the prototype chain. This is the default. |
178 | |
179 | \omitvalue ResolveScope Check the object's own properties first, then search the scope chain. |
180 | |
181 | \omitvalue ResolveFull Check the object's own properties first, then search the prototype chain, and finally search the scope chain. |
182 | */ |
183 | |
184 | QT_BEGIN_NAMESPACE |
185 | |
186 | void QScriptValuePrivate::detachFromEngine() |
187 | { |
188 | if (isJSC()) |
189 | jscValue = JSC::JSValue(); |
190 | engine = 0; |
191 | } |
192 | |
193 | /*! |
194 | \internal |
195 | */ |
196 | QScriptValue::QScriptValue(QScriptValuePrivate *d) |
197 | : d_ptr(d) |
198 | { |
199 | } |
200 | |
201 | /*! |
202 | Constructs an invalid QScriptValue. |
203 | */ |
204 | QScriptValue::QScriptValue() |
205 | : d_ptr(0) |
206 | { |
207 | } |
208 | |
209 | /*! |
210 | Destroys this QScriptValue. |
211 | */ |
212 | QScriptValue::~QScriptValue() |
213 | { |
214 | } |
215 | |
216 | /*! |
217 | Constructs a new QScriptValue that is a copy of \a other. |
218 | |
219 | Note that if \a other is an object (i.e., isObject() would return |
220 | true), then only a reference to the underlying object is copied into |
221 | the new script value (i.e., the object itself is not copied). |
222 | */ |
223 | QScriptValue::QScriptValue(const QScriptValue &other) |
224 | : d_ptr(other.d_ptr) |
225 | { |
226 | } |
227 | |
228 | /*! |
229 | \obsolete |
230 | |
231 | Constructs a new QScriptValue with the special \a value and |
232 | registers it with the script \a engine. |
233 | */ |
234 | QScriptValue::QScriptValue(QScriptEngine *engine, QScriptValue::SpecialValue value) |
235 | : d_ptr(new (QScriptEnginePrivate::get(q: engine))QScriptValuePrivate(QScriptEnginePrivate::get(q: engine))) |
236 | { |
237 | switch (value) { |
238 | case NullValue: |
239 | d_ptr->initFrom(JSC::jsNull()); |
240 | break; |
241 | case UndefinedValue: |
242 | d_ptr->initFrom(JSC::jsUndefined()); |
243 | break; |
244 | } |
245 | } |
246 | |
247 | /*! |
248 | \obsolete |
249 | |
250 | \fn QScriptValue::QScriptValue(QScriptEngine *engine, bool value) |
251 | |
252 | Constructs a new QScriptValue with the boolean \a value and |
253 | registers it with the script \a engine. |
254 | */ |
255 | QScriptValue::QScriptValue(QScriptEngine *engine, bool val) |
256 | : d_ptr(new (QScriptEnginePrivate::get(q: engine))QScriptValuePrivate(QScriptEnginePrivate::get(q: engine))) |
257 | { |
258 | d_ptr->initFrom(JSC::jsBoolean(b: val)); |
259 | } |
260 | |
261 | /*! |
262 | \fn QScriptValue::QScriptValue(QScriptEngine *engine, int value) |
263 | \obsolete |
264 | |
265 | Constructs a new QScriptValue with the integer \a value and |
266 | registers it with the script \a engine. |
267 | */ |
268 | QScriptValue::QScriptValue(QScriptEngine *engine, int val) |
269 | : d_ptr(new (QScriptEnginePrivate::get(q: engine))QScriptValuePrivate(QScriptEnginePrivate::get(q: engine))) |
270 | { |
271 | if (engine) { |
272 | QScript::APIShim shim(d_ptr->engine); |
273 | JSC::ExecState *exec = d_ptr->engine->currentFrame; |
274 | d_ptr->initFrom(JSC::jsNumber(exec, i: val)); |
275 | } else |
276 | d_ptr->initFrom(value: val); |
277 | } |
278 | |
279 | /*! |
280 | \fn QScriptValue::QScriptValue(QScriptEngine *engine, uint value) |
281 | \obsolete |
282 | |
283 | Constructs a new QScriptValue with the unsigned integer \a value and |
284 | registers it with the script \a engine. |
285 | */ |
286 | QScriptValue::QScriptValue(QScriptEngine *engine, uint val) |
287 | : d_ptr(new (QScriptEnginePrivate::get(q: engine))QScriptValuePrivate(QScriptEnginePrivate::get(q: engine))) |
288 | { |
289 | if (engine) { |
290 | QScript::APIShim shim(d_ptr->engine); |
291 | JSC::ExecState *exec = d_ptr->engine->currentFrame; |
292 | d_ptr->initFrom(JSC::jsNumber(exec, i: val)); |
293 | } else |
294 | d_ptr->initFrom(value: val); |
295 | } |
296 | |
297 | /*! |
298 | \fn QScriptValue::QScriptValue(QScriptEngine *engine, qsreal value) |
299 | \obsolete |
300 | |
301 | Constructs a new QScriptValue with the qsreal \a value and |
302 | registers it with the script \a engine. |
303 | */ |
304 | QScriptValue::QScriptValue(QScriptEngine *engine, qsreal val) |
305 | : d_ptr(new (QScriptEnginePrivate::get(q: engine))QScriptValuePrivate(QScriptEnginePrivate::get(q: engine))) |
306 | { |
307 | if (engine) { |
308 | QScript::APIShim shim(d_ptr->engine); |
309 | JSC::ExecState *exec = d_ptr->engine->currentFrame; |
310 | d_ptr->initFrom(JSC::jsNumber(exec, d: val)); |
311 | } else |
312 | d_ptr->initFrom(value: val); |
313 | } |
314 | |
315 | /*! |
316 | \fn QScriptValue::QScriptValue(QScriptEngine *engine, const QString &value) |
317 | \obsolete |
318 | |
319 | Constructs a new QScriptValue with the string \a value and |
320 | registers it with the script \a engine. |
321 | */ |
322 | QScriptValue::QScriptValue(QScriptEngine *engine, const QString &val) |
323 | : d_ptr(new (QScriptEnginePrivate::get(q: engine))QScriptValuePrivate(QScriptEnginePrivate::get(q: engine))) |
324 | { |
325 | if (engine) { |
326 | QScript::APIShim shim(d_ptr->engine); |
327 | JSC::ExecState *exec = d_ptr->engine->currentFrame; |
328 | d_ptr->initFrom(JSC::jsString(exec, s: val)); |
329 | } else { |
330 | d_ptr->initFrom(value: val); |
331 | } |
332 | } |
333 | |
334 | /*! |
335 | \fn QScriptValue::QScriptValue(QScriptEngine *engine, const char *value) |
336 | \obsolete |
337 | |
338 | Constructs a new QScriptValue with the string \a value and |
339 | registers it with the script \a engine. |
340 | */ |
341 | |
342 | #ifndef QT_NO_CAST_FROM_ASCII |
343 | QScriptValue::QScriptValue(QScriptEngine *engine, const char *val) |
344 | : d_ptr(new (QScriptEnginePrivate::get(q: engine))QScriptValuePrivate(QScriptEnginePrivate::get(q: engine))) |
345 | { |
346 | if (engine) { |
347 | QScript::APIShim shim(d_ptr->engine); |
348 | JSC::ExecState *exec = d_ptr->engine->currentFrame; |
349 | d_ptr->initFrom(JSC::jsString(exec, s: val)); |
350 | } else { |
351 | d_ptr->initFrom(value: QString::fromLatin1(str: val)); |
352 | } |
353 | } |
354 | #endif |
355 | |
356 | /*! |
357 | \since 4.5 |
358 | |
359 | Constructs a new QScriptValue with a special \a value. |
360 | */ |
361 | QScriptValue::QScriptValue(SpecialValue value) |
362 | : d_ptr(new (/*engine=*/0)QScriptValuePrivate(/*engine=*/0)) |
363 | { |
364 | switch (value) { |
365 | case NullValue: |
366 | d_ptr->initFrom(JSC::jsNull()); |
367 | break; |
368 | case UndefinedValue: |
369 | d_ptr->initFrom(JSC::jsUndefined()); |
370 | break; |
371 | } |
372 | } |
373 | |
374 | /*! |
375 | \since 4.5 |
376 | |
377 | Constructs a new QScriptValue with a boolean \a value. |
378 | */ |
379 | QScriptValue::QScriptValue(bool value) |
380 | : d_ptr(new (/*engine=*/0)QScriptValuePrivate(/*engine=*/0)) |
381 | { |
382 | d_ptr->initFrom(JSC::jsBoolean(b: value)); |
383 | } |
384 | |
385 | /*! |
386 | \since 4.5 |
387 | |
388 | Constructs a new QScriptValue with a number \a value. |
389 | */ |
390 | QScriptValue::QScriptValue(int value) |
391 | : d_ptr(new (/*engine=*/0)QScriptValuePrivate(/*engine=*/0)) |
392 | { |
393 | d_ptr->initFrom(value); |
394 | } |
395 | |
396 | /*! |
397 | \since 4.5 |
398 | |
399 | Constructs a new QScriptValue with a number \a value. |
400 | */ |
401 | QScriptValue::QScriptValue(uint value) |
402 | : d_ptr(new (/*engine=*/0)QScriptValuePrivate(/*engine=*/0)) |
403 | { |
404 | d_ptr->initFrom(value); |
405 | } |
406 | |
407 | /*! |
408 | \since 4.5 |
409 | |
410 | Constructs a new QScriptValue with a number \a value. |
411 | */ |
412 | QScriptValue::QScriptValue(qsreal value) |
413 | : d_ptr(new (/*engine=*/0)QScriptValuePrivate(/*engine=*/0)) |
414 | { |
415 | d_ptr->initFrom(value); |
416 | } |
417 | |
418 | /*! |
419 | \since 4.5 |
420 | |
421 | Constructs a new QScriptValue with a string \a value. |
422 | */ |
423 | QScriptValue::QScriptValue(const QString &value) |
424 | : d_ptr(new (/*engine=*/0)QScriptValuePrivate(/*engine=*/0)) |
425 | { |
426 | d_ptr->initFrom(value); |
427 | } |
428 | |
429 | /*! |
430 | \since 4.5 |
431 | |
432 | Constructs a new QScriptValue with a string \a value. |
433 | */ |
434 | QScriptValue::QScriptValue(const QLatin1String &value) |
435 | : d_ptr(new (/*engine=*/0)QScriptValuePrivate(/*engine=*/0)) |
436 | { |
437 | d_ptr->initFrom(value); |
438 | } |
439 | |
440 | /*! |
441 | \since 4.5 |
442 | |
443 | Constructs a new QScriptValue with a string \a value. |
444 | */ |
445 | |
446 | #ifndef QT_NO_CAST_FROM_ASCII |
447 | QScriptValue::QScriptValue(const char *value) |
448 | : d_ptr(new (/*engine=*/0)QScriptValuePrivate(/*engine=*/0)) |
449 | { |
450 | d_ptr->initFrom(value: QString::fromLatin1(str: value)); |
451 | } |
452 | #endif |
453 | |
454 | /*! |
455 | Assigns the \a other value to this QScriptValue. |
456 | |
457 | Note that if \a other is an object (isObject() returns true), |
458 | only a reference to the underlying object will be assigned; |
459 | the object itself will not be copied. |
460 | */ |
461 | QScriptValue &QScriptValue::operator=(const QScriptValue &other) |
462 | { |
463 | d_ptr = other.d_ptr; |
464 | return *this; |
465 | } |
466 | |
467 | /*! |
468 | Returns true if this QScriptValue is an object of the Error class; |
469 | otherwise returns false. |
470 | |
471 | \sa QScriptContext::throwError() |
472 | */ |
473 | bool QScriptValue::isError() const |
474 | { |
475 | Q_D(const QScriptValue); |
476 | if (!d || !d->isJSC()) |
477 | return false; |
478 | return QScriptEnginePrivate::isError(value: d->jscValue); |
479 | } |
480 | |
481 | /*! |
482 | Returns true if this QScriptValue is an object of the Array class; |
483 | otherwise returns false. |
484 | |
485 | \sa QScriptEngine::newArray() |
486 | */ |
487 | bool QScriptValue::isArray() const |
488 | { |
489 | Q_D(const QScriptValue); |
490 | if (!d || !d->isJSC()) |
491 | return false; |
492 | return QScriptEnginePrivate::isArray(value: d->jscValue); |
493 | } |
494 | |
495 | /*! |
496 | Returns true if this QScriptValue is an object of the Date class; |
497 | otherwise returns false. |
498 | |
499 | \sa QScriptEngine::newDate() |
500 | */ |
501 | bool QScriptValue::isDate() const |
502 | { |
503 | Q_D(const QScriptValue); |
504 | if (!d || !d->isJSC()) |
505 | return false; |
506 | return QScriptEnginePrivate::isDate(value: d->jscValue); |
507 | } |
508 | |
509 | /*! |
510 | Returns true if this QScriptValue is an object of the RegExp class; |
511 | otherwise returns false. |
512 | |
513 | \sa QScriptEngine::newRegExp() |
514 | */ |
515 | bool QScriptValue::isRegExp() const |
516 | { |
517 | Q_D(const QScriptValue); |
518 | if (!d || !d->isJSC()) |
519 | return false; |
520 | return QScriptEnginePrivate::isRegExp(value: d->jscValue); |
521 | } |
522 | |
523 | /*! |
524 | If this QScriptValue is an object, returns the internal prototype |
525 | (\c{__proto__} property) of this object; otherwise returns an |
526 | invalid QScriptValue. |
527 | |
528 | \sa setPrototype(), isObject() |
529 | */ |
530 | QScriptValue QScriptValue::prototype() const |
531 | { |
532 | Q_D(const QScriptValue); |
533 | if (!d || !d->isObject()) |
534 | return QScriptValue(); |
535 | return d->engine->scriptValueFromJSCValue(JSC::asObject(value: d->jscValue)->prototype()); |
536 | } |
537 | |
538 | /*! |
539 | If this QScriptValue is an object, sets the internal prototype |
540 | (\c{__proto__} property) of this object to be \a prototype; |
541 | otherwise does nothing. |
542 | |
543 | The internal prototype should not be confused with the public |
544 | property with name "prototype"; the public prototype is usually |
545 | only set on functions that act as constructors. |
546 | |
547 | \sa prototype(), isObject() |
548 | */ |
549 | void QScriptValue::setPrototype(const QScriptValue &prototype) |
550 | { |
551 | Q_D(QScriptValue); |
552 | if (!d || !d->isObject()) |
553 | return; |
554 | |
555 | JSC::JSValue other = d->engine->scriptValueToJSCValue(value: prototype); |
556 | if (!other || !(other.isObject() || other.isNull())) |
557 | return; |
558 | |
559 | if (QScriptValuePrivate::getEngine(q: prototype) |
560 | && (QScriptValuePrivate::getEngine(q: prototype) != d->engine)) { |
561 | qWarning(msg: "QScriptValue::setPrototype() failed: " |
562 | "cannot set a prototype created in " |
563 | "a different engine" ); |
564 | return; |
565 | } |
566 | JSC::JSObject *thisObject = JSC::asObject(value: d->jscValue); |
567 | |
568 | // check for cycle |
569 | JSC::JSValue nextPrototypeValue = other; |
570 | while (nextPrototypeValue && nextPrototypeValue.isObject()) { |
571 | JSC::JSObject *nextPrototype = JSC::asObject(value: nextPrototypeValue); |
572 | if (nextPrototype == thisObject) { |
573 | qWarning(msg: "QScriptValue::setPrototype() failed: cyclic prototype value" ); |
574 | return; |
575 | } |
576 | nextPrototypeValue = nextPrototype->prototype(); |
577 | } |
578 | |
579 | thisObject->setPrototype(other); |
580 | |
581 | // Sync the internal Global Object prototype if appropriate. |
582 | if (((thisObject == d->engine->originalGlobalObjectProxy) |
583 | && !d->engine->customGlobalObject()) |
584 | || (thisObject == d->engine->customGlobalObject())) { |
585 | d->engine->originalGlobalObject()->setPrototype(other); |
586 | } |
587 | } |
588 | |
589 | /*! |
590 | \internal |
591 | */ |
592 | QScriptValue QScriptValue::scope() const |
593 | { |
594 | Q_D(const QScriptValue); |
595 | if (!d || !d->isObject()) |
596 | return QScriptValue(); |
597 | QScript::APIShim shim(d->engine); |
598 | // ### make hidden property |
599 | JSC::JSValue result = d->property(name: "__qt_scope__" , resolveMode: QScriptValue::ResolveLocal); |
600 | return d->engine->scriptValueFromJSCValue(value: result); |
601 | } |
602 | |
603 | /*! |
604 | \internal |
605 | */ |
606 | void QScriptValue::setScope(const QScriptValue &scope) |
607 | { |
608 | Q_D(QScriptValue); |
609 | if (!d || !d->isObject()) |
610 | return; |
611 | if (scope.isValid() && QScriptValuePrivate::getEngine(q: scope) |
612 | && (QScriptValuePrivate::getEngine(q: scope) != d->engine)) { |
613 | qWarning(msg: "QScriptValue::setScope() failed: " |
614 | "cannot set a scope object created in " |
615 | "a different engine" ); |
616 | return; |
617 | } |
618 | JSC::JSValue other = d->engine->scriptValueToJSCValue(value: scope); |
619 | JSC::ExecState *exec = d->engine->currentFrame; |
620 | JSC::Identifier id = JSC::Identifier(exec, "__qt_scope__" ); |
621 | if (!scope.isValid()) { |
622 | JSC::asObject(value: d->jscValue)->removeDirect(propertyName: id); |
623 | } else { |
624 | // ### make hidden property |
625 | JSC::asObject(value: d->jscValue)->putDirect(propertyName: id, value: other); |
626 | } |
627 | } |
628 | |
629 | /*! |
630 | Returns true if this QScriptValue is an instance of |
631 | \a other; otherwise returns false. |
632 | |
633 | This QScriptValue is considered to be an instance of \a other if |
634 | \a other is a function and the value of the \c{prototype} |
635 | property of \a other is in the prototype chain of this |
636 | QScriptValue. |
637 | */ |
638 | bool QScriptValue::instanceOf(const QScriptValue &other) const |
639 | { |
640 | Q_D(const QScriptValue); |
641 | if (!d || !d->isObject() || !other.isObject()) |
642 | return false; |
643 | if (QScriptValuePrivate::getEngine(q: other) != d->engine) { |
644 | qWarning(msg: "QScriptValue::instanceof: " |
645 | "cannot perform operation on a value created in " |
646 | "a different engine" ); |
647 | return false; |
648 | } |
649 | JSC::JSValue jscProto = d->engine->scriptValueToJSCValue(value: other.property(name: QLatin1String("prototype" ))); |
650 | if (!jscProto) |
651 | jscProto = JSC::jsUndefined(); |
652 | JSC::ExecState *exec = d->engine->currentFrame; |
653 | JSC::JSValue jscOther = d->engine->scriptValueToJSCValue(value: other); |
654 | return JSC::asObject(value: jscOther)->hasInstance(exec, d->jscValue, prototypeProperty: jscProto); |
655 | } |
656 | |
657 | // ### move |
658 | |
659 | namespace QScript |
660 | { |
661 | |
662 | enum Type { |
663 | Undefined, |
664 | Null, |
665 | Boolean, |
666 | String, |
667 | Number, |
668 | Object |
669 | }; |
670 | |
671 | static Type type(const QScriptValue &v) |
672 | { |
673 | if (v.isUndefined()) |
674 | return Undefined; |
675 | else if (v.isNull()) |
676 | return Null; |
677 | else if (v.isBoolean()) |
678 | return Boolean; |
679 | else if (v.isString()) |
680 | return String; |
681 | else if (v.isNumber()) |
682 | return Number; |
683 | Q_ASSERT(v.isObject()); |
684 | return Object; |
685 | } |
686 | |
687 | static QScriptValue ToPrimitive(const QScriptValue &object, JSC::PreferredPrimitiveType hint = JSC::NoPreference) |
688 | { |
689 | Q_ASSERT(object.isObject()); |
690 | QScriptValuePrivate *pp = QScriptValuePrivate::get(q: object); |
691 | Q_ASSERT(pp->engine != 0); |
692 | QScript::APIShim shim(pp->engine); |
693 | JSC::ExecState *exec = pp->engine->currentFrame; |
694 | JSC::JSValue savedException; |
695 | QScriptEnginePrivate::saveException(exec, val: &savedException); |
696 | JSC::JSValue result = JSC::asObject(value: pp->jscValue)->toPrimitive(exec, preferredType: hint); |
697 | QScriptEnginePrivate::restoreException(exec, val: savedException); |
698 | return pp->engine->scriptValueFromJSCValue(value: result); |
699 | } |
700 | |
701 | static bool IsNumerical(const QScriptValue &value) |
702 | { |
703 | return value.isNumber() || value.isBool(); |
704 | } |
705 | |
706 | static bool LessThan(QScriptValue lhs, QScriptValue rhs) |
707 | { |
708 | if (type(v: lhs) == type(v: rhs)) { |
709 | switch (type(v: lhs)) { |
710 | case Undefined: |
711 | case Null: |
712 | return false; |
713 | |
714 | case Number: |
715 | return lhs.toNumber() < rhs.toNumber(); |
716 | |
717 | case Boolean: |
718 | return lhs.toBool() < rhs.toBool(); |
719 | |
720 | case String: |
721 | return lhs.toString() < rhs.toString(); |
722 | |
723 | case Object: |
724 | break; |
725 | } // switch |
726 | } |
727 | |
728 | if (lhs.isObject()) |
729 | lhs = ToPrimitive(object: lhs, JSC::PreferNumber); |
730 | |
731 | if (rhs.isObject()) |
732 | rhs = ToPrimitive(object: rhs, JSC::PreferNumber); |
733 | |
734 | if (lhs.isString() && rhs.isString()) |
735 | return lhs.toString() < rhs.toString(); |
736 | |
737 | return lhs.toNumber() < rhs.toNumber(); |
738 | } |
739 | |
740 | static bool Equals(QScriptValue lhs, QScriptValue rhs) |
741 | { |
742 | if (type(v: lhs) == type(v: rhs)) { |
743 | switch (type(v: lhs)) { |
744 | case QScript::Undefined: |
745 | case QScript::Null: |
746 | return true; |
747 | |
748 | case QScript::Number: |
749 | return lhs.toNumber() == rhs.toNumber(); |
750 | |
751 | case QScript::Boolean: |
752 | return lhs.toBool() == rhs.toBool(); |
753 | |
754 | case QScript::String: |
755 | return lhs.toString() == rhs.toString(); |
756 | |
757 | case QScript::Object: |
758 | if (lhs.isVariant()) |
759 | return lhs.strictlyEquals(other: rhs) || (lhs.toVariant() == rhs.toVariant()); |
760 | #ifndef QT_NO_QOBJECT |
761 | else if (lhs.isQObject()) |
762 | return (lhs.strictlyEquals(other: rhs)) || (lhs.toQObject() == rhs.toQObject()); |
763 | #endif |
764 | else |
765 | return lhs.strictlyEquals(other: rhs); |
766 | } |
767 | } |
768 | |
769 | if (lhs.isNull() && rhs.isUndefined()) |
770 | return true; |
771 | |
772 | else if (lhs.isUndefined() && rhs.isNull()) |
773 | return true; |
774 | |
775 | else if (IsNumerical(value: lhs) && rhs.isString()) |
776 | return lhs.toNumber() == rhs.toNumber(); |
777 | |
778 | else if (lhs.isString() && IsNumerical(value: rhs)) |
779 | return lhs.toNumber() == rhs.toNumber(); |
780 | |
781 | else if (lhs.isBool()) |
782 | return Equals(lhs: lhs.toNumber(), rhs); |
783 | |
784 | else if (rhs.isBool()) |
785 | return Equals(lhs, rhs: rhs.toNumber()); |
786 | |
787 | else if (lhs.isObject() && !rhs.isNull()) { |
788 | lhs = ToPrimitive(object: lhs); |
789 | |
790 | if (lhs.isValid() && !lhs.isObject()) |
791 | return Equals(lhs, rhs); |
792 | } |
793 | |
794 | else if (rhs.isObject() && ! lhs.isNull()) { |
795 | rhs = ToPrimitive(object: rhs); |
796 | if (rhs.isValid() && !rhs.isObject()) |
797 | return Equals(lhs, rhs); |
798 | } |
799 | |
800 | return false; |
801 | } |
802 | |
803 | } // namespace QScript |
804 | |
805 | /*! |
806 | Returns true if this QScriptValue is less than \a other, otherwise |
807 | returns false. The comparison follows the behavior described in |
808 | \l{ECMA-262} section 11.8.5, "The Abstract Relational Comparison |
809 | Algorithm". |
810 | |
811 | Note that if this QScriptValue or the \a other value are objects, |
812 | calling this function has side effects on the script engine, since |
813 | the engine will call the object's valueOf() function (and possibly |
814 | toString()) in an attempt to convert the object to a primitive value |
815 | (possibly resulting in an uncaught script exception). |
816 | |
817 | \sa equals() |
818 | */ |
819 | bool QScriptValue::lessThan(const QScriptValue &other) const |
820 | { |
821 | Q_D(const QScriptValue); |
822 | // no equivalent function in JSC? There's a jsLess() in VM/Machine.cpp |
823 | if (!isValid() || !other.isValid()) |
824 | return false; |
825 | if (QScriptValuePrivate::getEngine(q: other) && d->engine |
826 | && (QScriptValuePrivate::getEngine(q: other) != d->engine)) { |
827 | qWarning(msg: "QScriptValue::lessThan: " |
828 | "cannot compare to a value created in " |
829 | "a different engine" ); |
830 | return false; |
831 | } |
832 | return QScript::LessThan(lhs: *this, rhs: other); |
833 | } |
834 | |
835 | /*! |
836 | Returns true if this QScriptValue is equal to \a other, otherwise |
837 | returns false. The comparison follows the behavior described in |
838 | \l{ECMA-262} section 11.9.3, "The Abstract Equality Comparison |
839 | Algorithm". |
840 | |
841 | This function can return true even if the type of this QScriptValue |
842 | is different from the type of the \a other value; i.e. the |
843 | comparison is not strict. For example, comparing the number 9 to |
844 | the string "9" returns true; comparing an undefined value to a null |
845 | value returns true; comparing a \c{Number} object whose primitive |
846 | value is 6 to a \c{String} object whose primitive value is "6" |
847 | returns true; and comparing the number 1 to the boolean value |
848 | \c{true} returns true. If you want to perform a comparison |
849 | without such implicit value conversion, use strictlyEquals(). |
850 | |
851 | Note that if this QScriptValue or the \a other value are objects, |
852 | calling this function has side effects on the script engine, since |
853 | the engine will call the object's valueOf() function (and possibly |
854 | toString()) in an attempt to convert the object to a primitive value |
855 | (possibly resulting in an uncaught script exception). |
856 | |
857 | \sa strictlyEquals(), lessThan() |
858 | */ |
859 | bool QScriptValue::equals(const QScriptValue &other) const |
860 | { |
861 | Q_D(const QScriptValue); |
862 | if (!d || !other.d_ptr) |
863 | return (d_ptr == other.d_ptr); |
864 | if (QScriptValuePrivate::getEngine(q: other) && d->engine |
865 | && (QScriptValuePrivate::getEngine(q: other) != d->engine)) { |
866 | qWarning(msg: "QScriptValue::equals: " |
867 | "cannot compare to a value created in " |
868 | "a different engine" ); |
869 | return false; |
870 | } |
871 | if (d->isJSC() && other.d_ptr->isJSC()) { |
872 | QScriptEnginePrivate *eng_p = d->engine; |
873 | if (!eng_p) |
874 | eng_p = other.d_ptr->engine; |
875 | if (eng_p) { |
876 | QScript::APIShim shim(eng_p); |
877 | JSC::ExecState *exec = eng_p->currentFrame; |
878 | JSC::JSValue savedException; |
879 | QScriptEnginePrivate::saveException(exec, val: &savedException); |
880 | bool result = JSC::JSValue::equal(exec, v1: d->jscValue, v2: other.d_ptr->jscValue); |
881 | QScriptEnginePrivate::restoreException(exec, val: savedException); |
882 | return result; |
883 | } |
884 | } |
885 | return QScript::Equals(lhs: *this, rhs: other); |
886 | } |
887 | |
888 | /*! |
889 | Returns true if this QScriptValue is equal to \a other using strict |
890 | comparison (no conversion), otherwise returns false. The comparison |
891 | follows the behavior described in \l{ECMA-262} section 11.9.6, "The |
892 | Strict Equality Comparison Algorithm". |
893 | |
894 | If the type of this QScriptValue is different from the type of the |
895 | \a other value, this function returns false. If the types are equal, |
896 | the result depends on the type, as shown in the following table: |
897 | |
898 | \table |
899 | \header \li Type \li Result |
900 | \row \li Undefined \li true |
901 | \row \li Null \li true |
902 | \row \li Boolean \li true if both values are true, false otherwise |
903 | \row \li Number \li false if either value is NaN (Not-a-Number); true if values are equal, false otherwise |
904 | \row \li String \li true if both values are exactly the same sequence of characters, false otherwise |
905 | \row \li Object \li true if both values refer to the same object, false otherwise |
906 | \endtable |
907 | |
908 | \sa equals() |
909 | */ |
910 | bool QScriptValue::strictlyEquals(const QScriptValue &other) const |
911 | { |
912 | Q_D(const QScriptValue); |
913 | if (!d || !other.d_ptr) |
914 | return (d_ptr == other.d_ptr); |
915 | if (QScriptValuePrivate::getEngine(q: other) && d->engine |
916 | && (QScriptValuePrivate::getEngine(q: other) != d->engine)) { |
917 | qWarning(msg: "QScriptValue::strictlyEquals: " |
918 | "cannot compare to a value created in " |
919 | "a different engine" ); |
920 | return false; |
921 | } |
922 | |
923 | if (d->type != other.d_ptr->type) { |
924 | if (d->type == QScriptValuePrivate::JavaScriptCore) { |
925 | QScriptEnginePrivate *eng_p = d->engine ? d->engine : other.d_ptr->engine; |
926 | if (eng_p) |
927 | return JSC::JSValue::strictEqual(exec: eng_p->currentFrame, v1: d->jscValue, v2: eng_p->scriptValueToJSCValue(value: other)); |
928 | } else if (other.d_ptr->type == QScriptValuePrivate::JavaScriptCore) { |
929 | QScriptEnginePrivate *eng_p = other.d_ptr->engine ? other.d_ptr->engine : d->engine; |
930 | if (eng_p) |
931 | return JSC::JSValue::strictEqual(exec: eng_p->currentFrame, v1: eng_p->scriptValueToJSCValue(value: *this), v2: other.d_ptr->jscValue); |
932 | } |
933 | |
934 | return false; |
935 | } |
936 | switch (d->type) { |
937 | case QScriptValuePrivate::JavaScriptCore: { |
938 | QScriptEnginePrivate *eng_p = d->engine ? d->engine : other.d_ptr->engine; |
939 | JSC::ExecState *exec = eng_p ? eng_p->currentFrame : 0; |
940 | return JSC::JSValue::strictEqual(exec, v1: d->jscValue, v2: other.d_ptr->jscValue); |
941 | } |
942 | case QScriptValuePrivate::Number: |
943 | return (d->numberValue == other.d_ptr->numberValue); |
944 | case QScriptValuePrivate::String: |
945 | return (d->stringValue == other.d_ptr->stringValue); |
946 | } |
947 | return false; |
948 | } |
949 | |
950 | /*! |
951 | Returns the string value of this QScriptValue, as defined in |
952 | \l{ECMA-262} section 9.8, "ToString". |
953 | |
954 | Note that if this QScriptValue is an object, calling this function |
955 | has side effects on the script engine, since the engine will call |
956 | the object's toString() function (and possibly valueOf()) in an |
957 | attempt to convert the object to a primitive value (possibly |
958 | resulting in an uncaught script exception). |
959 | |
960 | \sa isString() |
961 | */ |
962 | QString QScriptValue::toString() const |
963 | { |
964 | Q_D(const QScriptValue); |
965 | if (!d) |
966 | return QString(); |
967 | switch (d->type) { |
968 | case QScriptValuePrivate::JavaScriptCore: { |
969 | if (d->engine) { |
970 | QScript::APIShim shim(d->engine); |
971 | return QScriptEnginePrivate::toString(exec: d->engine->currentFrame, value: d->jscValue); |
972 | } else { |
973 | return QScriptEnginePrivate::toString(exec: 0, value: d->jscValue); |
974 | } } |
975 | case QScriptValuePrivate::Number: |
976 | return QScript::ToString(value: d->numberValue); |
977 | case QScriptValuePrivate::String: |
978 | return d->stringValue; |
979 | } |
980 | return QString(); |
981 | } |
982 | |
983 | /*! |
984 | Returns the number value of this QScriptValue, as defined in |
985 | \l{ECMA-262} section 9.3, "ToNumber". |
986 | |
987 | Note that if this QScriptValue is an object, calling this function |
988 | has side effects on the script engine, since the engine will call |
989 | the object's valueOf() function (and possibly toString()) in an |
990 | attempt to convert the object to a primitive value (possibly |
991 | resulting in an uncaught script exception). |
992 | |
993 | \sa isNumber(), toInteger(), toInt32(), toUInt32(), toUInt16() |
994 | */ |
995 | qsreal QScriptValue::toNumber() const |
996 | { |
997 | Q_D(const QScriptValue); |
998 | if (!d) |
999 | return 0; |
1000 | switch (d->type) { |
1001 | case QScriptValuePrivate::JavaScriptCore: { |
1002 | if (d->engine) { |
1003 | QScript::APIShim shim(d->engine); |
1004 | return QScriptEnginePrivate::toNumber(exec: d->engine->currentFrame, value: d->jscValue); |
1005 | } else { |
1006 | return QScriptEnginePrivate::toNumber(exec: 0, value: d->jscValue); |
1007 | } |
1008 | } |
1009 | case QScriptValuePrivate::Number: |
1010 | return d->numberValue; |
1011 | case QScriptValuePrivate::String: |
1012 | return QScript::ToNumber(value: d->stringValue); |
1013 | } |
1014 | return 0; |
1015 | } |
1016 | |
1017 | /*! |
1018 | \obsolete |
1019 | |
1020 | Use toBool() instead. |
1021 | */ |
1022 | bool QScriptValue::toBoolean() const |
1023 | { |
1024 | Q_D(const QScriptValue); |
1025 | if (!d) |
1026 | return false; |
1027 | switch (d->type) { |
1028 | case QScriptValuePrivate::JavaScriptCore: { |
1029 | if (d->engine) { |
1030 | QScript::APIShim shim(d->engine); |
1031 | return QScriptEnginePrivate::toBool(exec: d->engine->currentFrame, value: d->jscValue); |
1032 | } else { |
1033 | return QScriptEnginePrivate::toBool(exec: 0, value: d->jscValue); |
1034 | } |
1035 | } |
1036 | case QScriptValuePrivate::Number: |
1037 | return QScript::ToBool(value: d->numberValue); |
1038 | case QScriptValuePrivate::String: |
1039 | return QScript::ToBool(value: d->stringValue); |
1040 | } |
1041 | return false; |
1042 | } |
1043 | |
1044 | /*! |
1045 | \since 4.5 |
1046 | |
1047 | Returns the boolean value of this QScriptValue, using the conversion |
1048 | rules described in \l{ECMA-262} section 9.2, "ToBoolean". |
1049 | |
1050 | Note that if this QScriptValue is an object, calling this function |
1051 | has side effects on the script engine, since the engine will call |
1052 | the object's valueOf() function (and possibly toString()) in an |
1053 | attempt to convert the object to a primitive value (possibly |
1054 | resulting in an uncaught script exception). |
1055 | |
1056 | \sa isBool() |
1057 | */ |
1058 | bool QScriptValue::toBool() const |
1059 | { |
1060 | Q_D(const QScriptValue); |
1061 | if (!d) |
1062 | return false; |
1063 | switch (d->type) { |
1064 | case QScriptValuePrivate::JavaScriptCore: { |
1065 | if (d->engine) { |
1066 | QScript::APIShim shim(d->engine); |
1067 | return QScriptEnginePrivate::toBool(exec: d->engine->currentFrame, value: d->jscValue); |
1068 | } else { |
1069 | return QScriptEnginePrivate::toBool(exec: 0, value: d->jscValue); |
1070 | } |
1071 | } |
1072 | case QScriptValuePrivate::Number: |
1073 | return QScript::ToBool(value: d->numberValue); |
1074 | case QScriptValuePrivate::String: |
1075 | return QScript::ToBool(value: d->stringValue); |
1076 | } |
1077 | return false; |
1078 | } |
1079 | |
1080 | /*! |
1081 | Returns the signed 32-bit integer value of this QScriptValue, using |
1082 | the conversion rules described in \l{ECMA-262} section 9.5, "ToInt32". |
1083 | |
1084 | Note that if this QScriptValue is an object, calling this function |
1085 | has side effects on the script engine, since the engine will call |
1086 | the object's valueOf() function (and possibly toString()) in an |
1087 | attempt to convert the object to a primitive value (possibly |
1088 | resulting in an uncaught script exception). |
1089 | |
1090 | \sa toNumber(), toUInt32() |
1091 | */ |
1092 | qint32 QScriptValue::toInt32() const |
1093 | { |
1094 | Q_D(const QScriptValue); |
1095 | if (!d) |
1096 | return 0; |
1097 | switch (d->type) { |
1098 | case QScriptValuePrivate::JavaScriptCore: { |
1099 | if (d->engine) { |
1100 | QScript::APIShim shim(d->engine); |
1101 | return QScriptEnginePrivate::toInt32(exec: d->engine->currentFrame, value: d->jscValue); |
1102 | } else { |
1103 | return QScriptEnginePrivate::toInt32(exec: 0, value: d->jscValue); |
1104 | } |
1105 | } |
1106 | case QScriptValuePrivate::Number: |
1107 | return QScript::ToInt32(d->numberValue); |
1108 | case QScriptValuePrivate::String: |
1109 | return QScript::ToInt32(value: d->stringValue); |
1110 | } |
1111 | return 0; |
1112 | } |
1113 | |
1114 | /*! |
1115 | Returns the unsigned 32-bit integer value of this QScriptValue, using |
1116 | the conversion rules described in \l{ECMA-262} section 9.6, "ToUint32". |
1117 | |
1118 | Note that if this QScriptValue is an object, calling this function |
1119 | has side effects on the script engine, since the engine will call |
1120 | the object's valueOf() function (and possibly toString()) in an |
1121 | attempt to convert the object to a primitive value (possibly |
1122 | resulting in an uncaught script exception). |
1123 | |
1124 | \sa toNumber(), toInt32() |
1125 | */ |
1126 | quint32 QScriptValue::toUInt32() const |
1127 | { |
1128 | Q_D(const QScriptValue); |
1129 | if (!d) |
1130 | return 0; |
1131 | switch (d->type) { |
1132 | case QScriptValuePrivate::JavaScriptCore: { |
1133 | if (d->engine) { |
1134 | QScript::APIShim shim(d->engine); |
1135 | return QScriptEnginePrivate::toUInt32(exec: d->engine->currentFrame, value: d->jscValue); |
1136 | } else { |
1137 | return QScriptEnginePrivate::toUInt32(exec: 0, value: d->jscValue); |
1138 | } |
1139 | } |
1140 | case QScriptValuePrivate::Number: |
1141 | return QScript::ToUInt32(d->numberValue); |
1142 | case QScriptValuePrivate::String: |
1143 | return QScript::ToUInt32(value: d->stringValue); |
1144 | } |
1145 | return 0; |
1146 | } |
1147 | |
1148 | /*! |
1149 | Returns the unsigned 16-bit integer value of this QScriptValue, using |
1150 | the conversion rules described in \l{ECMA-262} section 9.7, "ToUint16". |
1151 | |
1152 | Note that if this QScriptValue is an object, calling this function |
1153 | has side effects on the script engine, since the engine will call |
1154 | the object's valueOf() function (and possibly toString()) in an |
1155 | attempt to convert the object to a primitive value (possibly |
1156 | resulting in an uncaught script exception). |
1157 | |
1158 | \sa toNumber() |
1159 | */ |
1160 | quint16 QScriptValue::toUInt16() const |
1161 | { |
1162 | Q_D(const QScriptValue); |
1163 | if (!d) |
1164 | return 0; |
1165 | switch (d->type) { |
1166 | case QScriptValuePrivate::JavaScriptCore: { |
1167 | if (d->engine) { |
1168 | QScript::APIShim shim(d->engine); |
1169 | return QScriptEnginePrivate::toUInt16(exec: d->engine->currentFrame, value: d->jscValue); |
1170 | } else { |
1171 | return QScriptEnginePrivate::toUInt16(exec: 0, value: d->jscValue); |
1172 | } |
1173 | } |
1174 | case QScriptValuePrivate::Number: |
1175 | return QScript::ToUInt16(d->numberValue); |
1176 | case QScriptValuePrivate::String: |
1177 | return QScript::ToUInt16(value: d->stringValue); |
1178 | } |
1179 | return 0; |
1180 | } |
1181 | |
1182 | /*! |
1183 | Returns the integer value of this QScriptValue, using the conversion |
1184 | rules described in \l{ECMA-262} section 9.4, "ToInteger". |
1185 | |
1186 | Note that if this QScriptValue is an object, calling this function |
1187 | has side effects on the script engine, since the engine will call |
1188 | the object's valueOf() function (and possibly toString()) in an |
1189 | attempt to convert the object to a primitive value (possibly |
1190 | resulting in an uncaught script exception). |
1191 | |
1192 | \sa toNumber() |
1193 | */ |
1194 | qsreal QScriptValue::toInteger() const |
1195 | { |
1196 | Q_D(const QScriptValue); |
1197 | if (!d) |
1198 | return 0; |
1199 | switch (d->type) { |
1200 | case QScriptValuePrivate::JavaScriptCore: { |
1201 | if (d->engine) { |
1202 | QScript::APIShim shim(d->engine); |
1203 | return QScriptEnginePrivate::toInteger(exec: d->engine->currentFrame, value: d->jscValue); |
1204 | } else { |
1205 | return QScriptEnginePrivate::toInteger(exec: 0, value: d->jscValue); |
1206 | } |
1207 | } |
1208 | case QScriptValuePrivate::Number: |
1209 | return QScript::ToInteger(d->numberValue); |
1210 | case QScriptValuePrivate::String: |
1211 | return QScript::ToInteger(value: d->stringValue); |
1212 | } |
1213 | return 0; |
1214 | } |
1215 | |
1216 | /*! |
1217 | Returns the QVariant value of this QScriptValue, if it can be |
1218 | converted to a QVariant; otherwise returns an invalid QVariant. |
1219 | The conversion is performed according to the following table: |
1220 | |
1221 | \table |
1222 | \header \li Input Type \li Result |
1223 | \row \li Undefined \li An invalid QVariant. |
1224 | \row \li Null \li An invalid QVariant. |
1225 | \row \li Boolean \li A QVariant containing the value of the boolean. |
1226 | \row \li Number \li A QVariant containing the value of the number. |
1227 | \row \li String \li A QVariant containing the value of the string. |
1228 | \row \li QVariant Object \li The result is the QVariant value of the object (no conversion). |
1229 | \row \li QObject Object \li A QVariant containing a pointer to the QObject. |
1230 | \row \li Date Object \li A QVariant containing the date value (toDateTime()). |
1231 | \row \li RegExp Object \li A QVariant containing the regular expression value (toRegExp()). |
1232 | \row \li Array Object \li The array is converted to a QVariantList. Each element is converted to a QVariant, recursively; cyclic references are not followed. |
1233 | \row \li Object \li The object is converted to a QVariantMap. Each property is converted to a QVariant, recursively; cyclic references are not followed. |
1234 | \endtable |
1235 | |
1236 | \sa isVariant() |
1237 | */ |
1238 | QVariant QScriptValue::toVariant() const |
1239 | { |
1240 | Q_D(const QScriptValue); |
1241 | if (!d) |
1242 | return QVariant(); |
1243 | switch (d->type) { |
1244 | case QScriptValuePrivate::JavaScriptCore: { |
1245 | if (d->engine) { |
1246 | QScript::APIShim shim(d->engine); |
1247 | return QScriptEnginePrivate::toVariant(d->engine->currentFrame, d->jscValue); |
1248 | } else { |
1249 | return QScriptEnginePrivate::toVariant(0, d->jscValue); |
1250 | } |
1251 | } |
1252 | case QScriptValuePrivate::Number: |
1253 | return QVariant(d->numberValue); |
1254 | case QScriptValuePrivate::String: |
1255 | return QVariant(d->stringValue); |
1256 | } |
1257 | return QVariant(); |
1258 | } |
1259 | |
1260 | /*! |
1261 | \obsolete |
1262 | |
1263 | This function is obsolete; use QScriptEngine::toObject() instead. |
1264 | */ |
1265 | QScriptValue QScriptValue::toObject() const |
1266 | { |
1267 | Q_D(const QScriptValue); |
1268 | if (!d || !d->engine) |
1269 | return QScriptValue(); |
1270 | return engine()->toObject(value: *this); |
1271 | } |
1272 | |
1273 | /*! |
1274 | Returns a QDateTime representation of this value, in local time. |
1275 | If this QScriptValue is not a date, or the value of the date is NaN |
1276 | (Not-a-Number), an invalid QDateTime is returned. |
1277 | |
1278 | \sa isDate() |
1279 | */ |
1280 | QDateTime QScriptValue::toDateTime() const |
1281 | { |
1282 | Q_D(const QScriptValue); |
1283 | if (!d || !d->engine) |
1284 | return QDateTime(); |
1285 | QScript::APIShim shim(d->engine); |
1286 | return QScriptEnginePrivate::toDateTime(exec: d->engine->currentFrame, value: d->jscValue); |
1287 | } |
1288 | |
1289 | #ifndef QT_NO_REGEXP |
1290 | /*! |
1291 | Returns the QRegExp representation of this value. |
1292 | If this QScriptValue is not a regular expression, an empty |
1293 | QRegExp is returned. |
1294 | |
1295 | \sa isRegExp() |
1296 | */ |
1297 | QRegExp QScriptValue::toRegExp() const |
1298 | { |
1299 | Q_D(const QScriptValue); |
1300 | if (!d || !d->engine) |
1301 | return QRegExp(); |
1302 | QScript::APIShim shim(d->engine); |
1303 | return QScriptEnginePrivate::toRegExp(d->engine->currentFrame, d->jscValue); |
1304 | } |
1305 | #endif // QT_NO_REGEXP |
1306 | |
1307 | /*! |
1308 | If this QScriptValue is a QObject, returns the QObject pointer |
1309 | that the QScriptValue represents; otherwise, returns 0. |
1310 | |
1311 | If the QObject that this QScriptValue wraps has been deleted, |
1312 | this function returns 0 (i.e. it is possible for toQObject() |
1313 | to return 0 even when isQObject() returns true). |
1314 | |
1315 | \sa isQObject() |
1316 | */ |
1317 | QObject *QScriptValue::toQObject() const |
1318 | { |
1319 | Q_D(const QScriptValue); |
1320 | if (!d || !d->engine) |
1321 | return 0; |
1322 | QScript::APIShim shim(d->engine); |
1323 | return QScriptEnginePrivate::toQObject(exec: d->engine->currentFrame, value: d->jscValue); |
1324 | } |
1325 | |
1326 | /*! |
1327 | If this QScriptValue is a QMetaObject, returns the QMetaObject pointer |
1328 | that the QScriptValue represents; otherwise, returns 0. |
1329 | |
1330 | \sa isQMetaObject() |
1331 | */ |
1332 | const QMetaObject *QScriptValue::toQMetaObject() const |
1333 | { |
1334 | Q_D(const QScriptValue); |
1335 | if (!d || !d->engine) |
1336 | return 0; |
1337 | QScript::APIShim shim(d->engine); |
1338 | return QScriptEnginePrivate::toQMetaObject(d->engine->currentFrame, value: d->jscValue); |
1339 | } |
1340 | |
1341 | /*! |
1342 | Sets the value of this QScriptValue's property with the given \a name to |
1343 | the given \a value. |
1344 | |
1345 | If this QScriptValue is not an object, this function does nothing. |
1346 | |
1347 | If this QScriptValue does not already have a property with name \a name, |
1348 | a new property is created; the given \a flags then specify how this |
1349 | property may be accessed by script code. |
1350 | |
1351 | If \a value is invalid, the property is removed. |
1352 | |
1353 | If the property is implemented using a setter function (i.e. has the |
1354 | PropertySetter flag set), calling setProperty() has side-effects on |
1355 | the script engine, since the setter function will be called with the |
1356 | given \a value as argument (possibly resulting in an uncaught script |
1357 | exception). |
1358 | |
1359 | Note that you cannot specify custom getter or setter functions for |
1360 | built-in properties, such as the \c{length} property of Array objects |
1361 | or meta properties of QObject objects. |
1362 | |
1363 | \sa property() |
1364 | */ |
1365 | |
1366 | void QScriptValue::setProperty(const QString &name, const QScriptValue &value, |
1367 | const PropertyFlags &flags) |
1368 | { |
1369 | Q_D(QScriptValue); |
1370 | if (!d || !d->isObject()) |
1371 | return; |
1372 | QScript::APIShim shim(d->engine); |
1373 | QScriptEnginePrivate *valueEngine = QScriptValuePrivate::getEngine(q: value); |
1374 | if (valueEngine && (valueEngine != d->engine)) { |
1375 | qWarning(msg: "QScriptValue::setProperty(%s) failed: " |
1376 | "cannot set value created in a different engine" , |
1377 | qPrintable(name)); |
1378 | return; |
1379 | } |
1380 | JSC::JSValue jsValue = d->engine->scriptValueToJSCValue(value); |
1381 | d->setProperty(name, value: jsValue, flags); |
1382 | } |
1383 | |
1384 | /*! |
1385 | Returns the value of this QScriptValue's property with the given \a name, |
1386 | using the given \a mode to resolve the property. |
1387 | |
1388 | If no such property exists, an invalid QScriptValue is returned. |
1389 | |
1390 | If the property is implemented using a getter function (i.e. has the |
1391 | PropertyGetter flag set), calling property() has side-effects on the |
1392 | script engine, since the getter function will be called (possibly |
1393 | resulting in an uncaught script exception). If an exception |
1394 | occurred, property() returns the value that was thrown (typically |
1395 | an \c{Error} object). |
1396 | |
1397 | \sa setProperty(), propertyFlags(), QScriptValueIterator |
1398 | */ |
1399 | QScriptValue QScriptValue::property(const QString &name, |
1400 | const ResolveFlags &mode) const |
1401 | { |
1402 | Q_D(const QScriptValue); |
1403 | if (!d || !d->isObject()) |
1404 | return QScriptValue(); |
1405 | QScript::APIShim shim(d->engine); |
1406 | return d->engine->scriptValueFromJSCValue(value: d->property(name, resolveMode: mode)); |
1407 | } |
1408 | |
1409 | /*! |
1410 | \overload |
1411 | |
1412 | Returns the property at the given \a arrayIndex, using the given \a |
1413 | mode to resolve the property. |
1414 | |
1415 | This function is provided for convenience and performance when |
1416 | working with array objects. |
1417 | |
1418 | If this QScriptValue is not an Array object, this function behaves |
1419 | as if property() was called with the string representation of \a |
1420 | arrayIndex. |
1421 | */ |
1422 | QScriptValue QScriptValue::property(quint32 arrayIndex, |
1423 | const ResolveFlags &mode) const |
1424 | { |
1425 | Q_D(const QScriptValue); |
1426 | if (!d || !d->isObject()) |
1427 | return QScriptValue(); |
1428 | QScript::APIShim shim(d->engine); |
1429 | return d->engine->scriptValueFromJSCValue(value: d->property(index: arrayIndex, resolveMode: mode)); |
1430 | } |
1431 | |
1432 | /*! |
1433 | \overload |
1434 | |
1435 | Sets the property at the given \a arrayIndex to the given \a value. |
1436 | |
1437 | This function is provided for convenience and performance when |
1438 | working with array objects. |
1439 | |
1440 | If this QScriptValue is not an Array object, this function behaves |
1441 | as if setProperty() was called with the string representation of \a |
1442 | arrayIndex. |
1443 | */ |
1444 | void QScriptValue::setProperty(quint32 arrayIndex, const QScriptValue &value, |
1445 | const PropertyFlags &flags) |
1446 | { |
1447 | Q_D(QScriptValue); |
1448 | if (!d || !d->isObject()) |
1449 | return; |
1450 | if (QScriptValuePrivate::getEngine(q: value) |
1451 | && (QScriptValuePrivate::getEngine(q: value) != d->engine)) { |
1452 | qWarning(msg: "QScriptValue::setProperty() failed: " |
1453 | "cannot set value created in a different engine" ); |
1454 | return; |
1455 | } |
1456 | QScript::APIShim shim(d->engine); |
1457 | JSC::JSValue jsValue = d->engine->scriptValueToJSCValue(value); |
1458 | d->setProperty(index: arrayIndex, value: jsValue, flags); |
1459 | } |
1460 | |
1461 | /*! |
1462 | \since 4.4 |
1463 | |
1464 | Returns the value of this QScriptValue's property with the given \a name, |
1465 | using the given \a mode to resolve the property. |
1466 | |
1467 | This overload of property() is useful when you need to look up the |
1468 | same property repeatedly, since the lookup can be performed faster |
1469 | when the name is represented as an interned string. |
1470 | |
1471 | \sa QScriptEngine::toStringHandle(), setProperty() |
1472 | */ |
1473 | QScriptValue QScriptValue::property(const QScriptString &name, |
1474 | const ResolveFlags &mode) const |
1475 | { |
1476 | Q_D(const QScriptValue); |
1477 | if (!d || !d->isObject() || !QScriptStringPrivate::isValid(q: name)) |
1478 | return QScriptValue(); |
1479 | QScript::APIShim shim(d->engine); |
1480 | return d->engine->scriptValueFromJSCValue(value: d->property(id: name.d_ptr->identifier, resolveMode: mode)); |
1481 | } |
1482 | |
1483 | /*! |
1484 | \since 4.4 |
1485 | |
1486 | Sets the value of this QScriptValue's property with the given \a |
1487 | name to the given \a value. The given \a flags specify how this |
1488 | property may be accessed by script code. |
1489 | |
1490 | This overload of setProperty() is useful when you need to set the |
1491 | same property repeatedly, since the operation can be performed |
1492 | faster when the name is represented as an interned string. |
1493 | |
1494 | \sa QScriptEngine::toStringHandle() |
1495 | */ |
1496 | void QScriptValue::setProperty(const QScriptString &name, |
1497 | const QScriptValue &value, |
1498 | const PropertyFlags &flags) |
1499 | { |
1500 | Q_D(QScriptValue); |
1501 | if (!d || !d->isObject() || !QScriptStringPrivate::isValid(q: name)) |
1502 | return; |
1503 | QScriptEnginePrivate *valueEngine = QScriptValuePrivate::getEngine(q: value); |
1504 | if (valueEngine && (valueEngine != d->engine)) { |
1505 | qWarning(msg: "QScriptValue::setProperty(%s) failed: " |
1506 | "cannot set value created in a different engine" , |
1507 | qPrintable(name.toString())); |
1508 | return; |
1509 | } |
1510 | QScript::APIShim shim(d->engine); |
1511 | JSC::JSValue jsValue = d->engine->scriptValueToJSCValue(value); |
1512 | d->setProperty(id: name.d_ptr->identifier, value: jsValue, flags); |
1513 | } |
1514 | |
1515 | /*! |
1516 | Returns the flags of the property with the given \a name, using the |
1517 | given \a mode to resolve the property. |
1518 | |
1519 | \sa property() |
1520 | */ |
1521 | QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QString &name, |
1522 | const ResolveFlags &mode) const |
1523 | { |
1524 | Q_D(const QScriptValue); |
1525 | if (!d || !d->isObject()) |
1526 | return {}; |
1527 | QScript::APIShim shim(d->engine); |
1528 | JSC::ExecState *exec = d->engine->currentFrame; |
1529 | return d->propertyFlags(JSC::Identifier(exec, name), mode); |
1530 | |
1531 | } |
1532 | |
1533 | /*! |
1534 | \since 4.4 |
1535 | |
1536 | Returns the flags of the property with the given \a name, using the |
1537 | given \a mode to resolve the property. |
1538 | |
1539 | \sa property() |
1540 | */ |
1541 | QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QScriptString &name, |
1542 | const ResolveFlags &mode) const |
1543 | { |
1544 | Q_D(const QScriptValue); |
1545 | if (!d || !d->isObject() || !QScriptStringPrivate::isValid(q: name)) |
1546 | return {}; |
1547 | return d->propertyFlags(id: name.d_ptr->identifier, mode); |
1548 | } |
1549 | |
1550 | /*! |
1551 | Calls this QScriptValue as a function, using \a thisObject as |
1552 | the `this' object in the function call, and passing \a args |
1553 | as arguments to the function. Returns the value returned from |
1554 | the function. |
1555 | |
1556 | If this QScriptValue is not a function, call() does nothing |
1557 | and returns an invalid QScriptValue. |
1558 | |
1559 | Note that if \a thisObject is not an object, the global object |
1560 | (see \l{QScriptEngine::globalObject()}) will be used as the |
1561 | `this' object. |
1562 | |
1563 | Calling call() can cause an exception to occur in the script engine; |
1564 | in that case, call() returns the value that was thrown (typically an |
1565 | \c{Error} object). You can call |
1566 | QScriptEngine::hasUncaughtException() to determine if an exception |
1567 | occurred. |
1568 | |
1569 | \snippet code/src_script_qscriptvalue.cpp 2 |
1570 | |
1571 | \sa construct() |
1572 | */ |
1573 | QScriptValue QScriptValue::call(const QScriptValue &thisObject, |
1574 | const QScriptValueList &args) |
1575 | { |
1576 | Q_D(const QScriptValue); |
1577 | if (!d || !d->isObject()) |
1578 | return QScriptValue(); |
1579 | QScript::APIShim shim(d->engine); |
1580 | JSC::JSValue callee = d->jscValue; |
1581 | JSC::CallData callData; |
1582 | JSC::CallType callType = callee.getCallData(callData); |
1583 | if (callType == JSC::CallTypeNone) |
1584 | return QScriptValue(); |
1585 | |
1586 | if (QScriptValuePrivate::getEngine(q: thisObject) |
1587 | && (QScriptValuePrivate::getEngine(q: thisObject) != d->engine)) { |
1588 | qWarning(msg: "QScriptValue::call() failed: " |
1589 | "cannot call function with thisObject created in " |
1590 | "a different engine" ); |
1591 | return QScriptValue(); |
1592 | } |
1593 | |
1594 | JSC::ExecState *exec = d->engine->currentFrame; |
1595 | |
1596 | JSC::JSValue jscThisObject = d->engine->scriptValueToJSCValue(value: thisObject); |
1597 | if (!jscThisObject || !jscThisObject.isObject()) |
1598 | jscThisObject = d->engine->globalObject(); |
1599 | |
1600 | QVarLengthArray<JSC::JSValue, 8> argsVector(args.size()); |
1601 | for (int i = 0; i < args.size(); ++i) { |
1602 | const QScriptValue &arg = args.at(i); |
1603 | if (!arg.isValid()) { |
1604 | argsVector[i] = JSC::jsUndefined(); |
1605 | } else if (QScriptValuePrivate::getEngine(q: arg) |
1606 | && (QScriptValuePrivate::getEngine(q: arg) != d->engine)) { |
1607 | qWarning(msg: "QScriptValue::call() failed: " |
1608 | "cannot call function with argument created in " |
1609 | "a different engine" ); |
1610 | return QScriptValue(); |
1611 | } else { |
1612 | argsVector[i] = d->engine->scriptValueToJSCValue(value: arg); |
1613 | } |
1614 | } |
1615 | JSC::ArgList jscArgs(argsVector.data(), argsVector.size()); |
1616 | |
1617 | JSC::JSValue savedException; |
1618 | QScriptEnginePrivate::saveException(exec, val: &savedException); |
1619 | JSC::JSValue result = JSC::call(exec, functionObject: callee, callType, callData, thisValue: jscThisObject, jscArgs); |
1620 | if (exec->hadException()) { |
1621 | result = exec->exception(); |
1622 | } else { |
1623 | QScriptEnginePrivate::restoreException(exec, val: savedException); |
1624 | } |
1625 | return d->engine->scriptValueFromJSCValue(value: result); |
1626 | } |
1627 | |
1628 | /*! |
1629 | Calls this QScriptValue as a function, using \a thisObject as |
1630 | the `this' object in the function call, and passing \a arguments |
1631 | as arguments to the function. Returns the value returned from |
1632 | the function. |
1633 | |
1634 | If this QScriptValue is not a function, call() does nothing |
1635 | and returns an invalid QScriptValue. |
1636 | |
1637 | \a arguments can be an arguments object, an array, null or |
1638 | undefined; any other type will cause a TypeError to be thrown. |
1639 | |
1640 | Note that if \a thisObject is not an object, the global object |
1641 | (see \l{QScriptEngine::globalObject()}) will be used as the |
1642 | `this' object. |
1643 | |
1644 | One common usage of this function is to forward native function |
1645 | calls to another function: |
1646 | |
1647 | \snippet code/src_script_qscriptvalue.cpp 3 |
1648 | |
1649 | \sa construct(), QScriptContext::argumentsObject() |
1650 | */ |
1651 | QScriptValue QScriptValue::call(const QScriptValue &thisObject, |
1652 | const QScriptValue &arguments) |
1653 | { |
1654 | Q_D(QScriptValue); |
1655 | if (!d || !d->isObject()) |
1656 | return QScriptValue(); |
1657 | QScript::APIShim shim(d->engine); |
1658 | JSC::JSValue callee = d->jscValue; |
1659 | JSC::CallData callData; |
1660 | JSC::CallType callType = callee.getCallData(callData); |
1661 | if (callType == JSC::CallTypeNone) |
1662 | return QScriptValue(); |
1663 | |
1664 | if (QScriptValuePrivate::getEngine(q: thisObject) |
1665 | && (QScriptValuePrivate::getEngine(q: thisObject) != d->engine)) { |
1666 | qWarning(msg: "QScriptValue::call() failed: " |
1667 | "cannot call function with thisObject created in " |
1668 | "a different engine" ); |
1669 | return QScriptValue(); |
1670 | } |
1671 | |
1672 | JSC::ExecState *exec = d->engine->currentFrame; |
1673 | |
1674 | JSC::JSValue jscThisObject = d->engine->scriptValueToJSCValue(value: thisObject); |
1675 | if (!jscThisObject || !jscThisObject.isObject()) |
1676 | jscThisObject = d->engine->globalObject(); |
1677 | |
1678 | JSC::JSValue array = d->engine->scriptValueToJSCValue(value: arguments); |
1679 | // copied from runtime/FunctionPrototype.cpp, functionProtoFuncApply() |
1680 | JSC::MarkedArgumentBuffer applyArgs; |
1681 | if (!array.isUndefinedOrNull()) { |
1682 | if (!array.isObject()) { |
1683 | return d->engine->scriptValueFromJSCValue(JSC::throwError(exec, JSC::TypeError, message: "Arguments must be an array" )); |
1684 | } |
1685 | if (JSC::asObject(value: array)->classInfo() == &JSC::Arguments::info) |
1686 | JSC::asArguments(value: array)->fillArgList(exec, applyArgs); |
1687 | else if (JSC::isJSArray(globalData: &exec->globalData(), v: array)) |
1688 | JSC::asArray(value: array)->fillArgList(exec, applyArgs); |
1689 | else if (JSC::asObject(value: array)->inherits(info: &JSC::JSArray::info)) { |
1690 | unsigned length = JSC::asArray(value: array)->get(exec, propertyName: exec->propertyNames().length).toUInt32(exec); |
1691 | for (unsigned i = 0; i < length; ++i) |
1692 | applyArgs.append(JSC::asArray(value: array)->get(exec, propertyName: i)); |
1693 | } else { |
1694 | return d->engine->scriptValueFromJSCValue(JSC::throwError(exec, JSC::TypeError, message: "Arguments must be an array" )); |
1695 | } |
1696 | } |
1697 | |
1698 | JSC::JSValue savedException; |
1699 | QScriptEnginePrivate::saveException(exec, val: &savedException); |
1700 | JSC::JSValue result = JSC::call(exec, functionObject: callee, callType, callData, thisValue: jscThisObject, applyArgs); |
1701 | if (exec->hadException()) { |
1702 | result = exec->exception(); |
1703 | } else { |
1704 | QScriptEnginePrivate::restoreException(exec, val: savedException); |
1705 | } |
1706 | return d->engine->scriptValueFromJSCValue(value: result); |
1707 | } |
1708 | |
1709 | /*! |
1710 | Creates a new \c{Object} and calls this QScriptValue as a |
1711 | constructor, using the created object as the `this' object and |
1712 | passing \a args as arguments. If the return value from the |
1713 | constructor call is an object, then that object is returned; |
1714 | otherwise the default constructed object is returned. |
1715 | |
1716 | If this QScriptValue is not a function, construct() does nothing |
1717 | and returns an invalid QScriptValue. |
1718 | |
1719 | Calling construct() can cause an exception to occur in the script |
1720 | engine; in that case, construct() returns the value that was thrown |
1721 | (typically an \c{Error} object). You can call |
1722 | QScriptEngine::hasUncaughtException() to determine if an exception |
1723 | occurred. |
1724 | |
1725 | \sa call(), QScriptEngine::newObject() |
1726 | */ |
1727 | QScriptValue QScriptValue::construct(const QScriptValueList &args) |
1728 | { |
1729 | Q_D(const QScriptValue); |
1730 | if (!d || !d->isObject()) |
1731 | return QScriptValue(); |
1732 | QScript::APIShim shim(d->engine); |
1733 | JSC::JSValue callee = d->jscValue; |
1734 | JSC::ConstructData constructData; |
1735 | JSC::ConstructType constructType = callee.getConstructData(constructData); |
1736 | if (constructType == JSC::ConstructTypeNone) |
1737 | return QScriptValue(); |
1738 | |
1739 | JSC::ExecState *exec = d->engine->currentFrame; |
1740 | |
1741 | QVarLengthArray<JSC::JSValue, 8> argsVector(args.size()); |
1742 | for (int i = 0; i < args.size(); ++i) { |
1743 | QScriptValue arg = args.at(i); |
1744 | if (QScriptValuePrivate::getEngine(q: arg) != d->engine && QScriptValuePrivate::getEngine(q: arg)) { |
1745 | qWarning(msg: "QScriptValue::construct() failed: " |
1746 | "cannot construct function with argument created in " |
1747 | "a different engine" ); |
1748 | return QScriptValue(); |
1749 | } |
1750 | if (!arg.isValid()) |
1751 | argsVector[i] = JSC::jsUndefined(); |
1752 | else |
1753 | argsVector[i] = d->engine->scriptValueToJSCValue(value: args.at(i)); |
1754 | } |
1755 | |
1756 | JSC::ArgList jscArgs(argsVector.data(), argsVector.size()); |
1757 | |
1758 | JSC::JSValue savedException; |
1759 | QScriptEnginePrivate::saveException(exec, val: &savedException); |
1760 | JSC::JSValue result; |
1761 | JSC::JSObject *newObject = JSC::construct(exec, constructor: callee, constructType, constructData, jscArgs); |
1762 | if (exec->hadException()) { |
1763 | result = exec->exception(); |
1764 | } else { |
1765 | result = newObject; |
1766 | QScriptEnginePrivate::restoreException(exec, val: savedException); |
1767 | } |
1768 | return d->engine->scriptValueFromJSCValue(value: result); |
1769 | } |
1770 | |
1771 | /*! |
1772 | Creates a new \c{Object} and calls this QScriptValue as a |
1773 | constructor, using the created object as the `this' object and |
1774 | passing \a arguments as arguments. If the return value from the |
1775 | constructor call is an object, then that object is returned; |
1776 | otherwise the default constructed object is returned. |
1777 | |
1778 | If this QScriptValue is not a function, construct() does nothing |
1779 | and returns an invalid QScriptValue. |
1780 | |
1781 | \a arguments can be an arguments object, an array, null or |
1782 | undefined. Any other type will cause a TypeError to be thrown. |
1783 | |
1784 | \sa call(), QScriptEngine::newObject(), QScriptContext::argumentsObject() |
1785 | */ |
1786 | QScriptValue QScriptValue::construct(const QScriptValue &arguments) |
1787 | { |
1788 | Q_D(QScriptValue); |
1789 | if (!d || !d->isObject()) |
1790 | return QScriptValue(); |
1791 | QScript::APIShim shim(d->engine); |
1792 | JSC::JSValue callee = d->jscValue; |
1793 | JSC::ConstructData constructData; |
1794 | JSC::ConstructType constructType = callee.getConstructData(constructData); |
1795 | if (constructType == JSC::ConstructTypeNone) |
1796 | return QScriptValue(); |
1797 | |
1798 | JSC::ExecState *exec = d->engine->currentFrame; |
1799 | |
1800 | if (QScriptValuePrivate::getEngine(q: arguments) != d->engine && QScriptValuePrivate::getEngine(q: arguments)) { |
1801 | qWarning(msg: "QScriptValue::construct() failed: " |
1802 | "cannot construct function with argument created in " |
1803 | "a different engine" ); |
1804 | return QScriptValue(); |
1805 | } |
1806 | JSC::JSValue array = d->engine->scriptValueToJSCValue(value: arguments); |
1807 | // copied from runtime/FunctionPrototype.cpp, functionProtoFuncApply() |
1808 | JSC::MarkedArgumentBuffer applyArgs; |
1809 | if (!array.isUndefinedOrNull()) { |
1810 | if (!array.isObject()) { |
1811 | return d->engine->scriptValueFromJSCValue(JSC::throwError(exec, JSC::TypeError, message: "Arguments must be an array" )); |
1812 | } |
1813 | if (JSC::asObject(value: array)->classInfo() == &JSC::Arguments::info) |
1814 | JSC::asArguments(value: array)->fillArgList(exec, applyArgs); |
1815 | else if (JSC::isJSArray(globalData: &exec->globalData(), v: array)) |
1816 | JSC::asArray(value: array)->fillArgList(exec, applyArgs); |
1817 | else if (JSC::asObject(value: array)->inherits(info: &JSC::JSArray::info)) { |
1818 | unsigned length = JSC::asArray(value: array)->get(exec, propertyName: exec->propertyNames().length).toUInt32(exec); |
1819 | for (unsigned i = 0; i < length; ++i) |
1820 | applyArgs.append(JSC::asArray(value: array)->get(exec, propertyName: i)); |
1821 | } else { |
1822 | return d->engine->scriptValueFromJSCValue(JSC::throwError(exec, JSC::TypeError, message: "Arguments must be an array" )); |
1823 | } |
1824 | } |
1825 | |
1826 | JSC::JSValue savedException; |
1827 | QScriptEnginePrivate::saveException(exec, val: &savedException); |
1828 | JSC::JSValue result; |
1829 | JSC::JSObject *newObject = JSC::construct(exec, constructor: callee, constructType, constructData, applyArgs); |
1830 | if (exec->hadException()) { |
1831 | result = exec->exception(); |
1832 | } else { |
1833 | result = newObject; |
1834 | QScriptEnginePrivate::restoreException(exec, val: savedException); |
1835 | } |
1836 | return d->engine->scriptValueFromJSCValue(value: result); |
1837 | } |
1838 | |
1839 | /*! |
1840 | Returns the QScriptEngine that created this QScriptValue, |
1841 | or 0 if this QScriptValue is invalid or the value is not |
1842 | associated with a particular engine. |
1843 | */ |
1844 | QScriptEngine *QScriptValue::engine() const |
1845 | { |
1846 | Q_D(const QScriptValue); |
1847 | if (!d) |
1848 | return 0; |
1849 | return QScriptEnginePrivate::get(d: d->engine); |
1850 | } |
1851 | |
1852 | /*! |
1853 | \obsolete |
1854 | |
1855 | Use isBool() instead. |
1856 | */ |
1857 | bool QScriptValue::isBoolean() const |
1858 | { |
1859 | Q_D(const QScriptValue); |
1860 | return d && d->isJSC() && d->jscValue.isBoolean(); |
1861 | } |
1862 | |
1863 | /*! |
1864 | \since 4.5 |
1865 | |
1866 | Returns true if this QScriptValue is of the primitive type Boolean; |
1867 | otherwise returns false. |
1868 | |
1869 | \sa toBool() |
1870 | */ |
1871 | bool QScriptValue::isBool() const |
1872 | { |
1873 | Q_D(const QScriptValue); |
1874 | return d && d->isJSC() && d->jscValue.isBoolean(); |
1875 | } |
1876 | |
1877 | /*! |
1878 | Returns true if this QScriptValue is of the primitive type Number; |
1879 | otherwise returns false. |
1880 | |
1881 | \sa toNumber() |
1882 | */ |
1883 | bool QScriptValue::isNumber() const |
1884 | { |
1885 | Q_D(const QScriptValue); |
1886 | if (!d) |
1887 | return false; |
1888 | switch (d->type) { |
1889 | case QScriptValuePrivate::JavaScriptCore: |
1890 | return d->jscValue.isNumber(); |
1891 | case QScriptValuePrivate::Number: |
1892 | return true; |
1893 | case QScriptValuePrivate::String: |
1894 | return false; |
1895 | } |
1896 | return false; |
1897 | } |
1898 | |
1899 | /*! |
1900 | Returns true if this QScriptValue is of the primitive type String; |
1901 | otherwise returns false. |
1902 | |
1903 | \sa toString() |
1904 | */ |
1905 | bool QScriptValue::isString() const |
1906 | { |
1907 | Q_D(const QScriptValue); |
1908 | if (!d) |
1909 | return false; |
1910 | switch (d->type) { |
1911 | case QScriptValuePrivate::JavaScriptCore: |
1912 | return d->jscValue.isString(); |
1913 | case QScriptValuePrivate::Number: |
1914 | return false; |
1915 | case QScriptValuePrivate::String: |
1916 | return true; |
1917 | } |
1918 | return false; |
1919 | } |
1920 | |
1921 | /*! |
1922 | Returns true if this QScriptValue is a function; otherwise returns |
1923 | false. |
1924 | |
1925 | \sa call() |
1926 | */ |
1927 | bool QScriptValue::isFunction() const |
1928 | { |
1929 | Q_D(const QScriptValue); |
1930 | if (!d || !d->isJSC()) |
1931 | return false; |
1932 | return QScript::isFunction(value: d->jscValue); |
1933 | } |
1934 | |
1935 | /*! |
1936 | Returns true if this QScriptValue is of the primitive type Null; |
1937 | otherwise returns false. |
1938 | |
1939 | \sa QScriptEngine::nullValue() |
1940 | */ |
1941 | bool QScriptValue::isNull() const |
1942 | { |
1943 | Q_D(const QScriptValue); |
1944 | return d && d->isJSC() && d->jscValue.isNull(); |
1945 | } |
1946 | |
1947 | /*! |
1948 | Returns true if this QScriptValue is of the primitive type Undefined; |
1949 | otherwise returns false. |
1950 | |
1951 | \sa QScriptEngine::undefinedValue() |
1952 | */ |
1953 | bool QScriptValue::isUndefined() const |
1954 | { |
1955 | Q_D(const QScriptValue); |
1956 | return d && d->isJSC() && d->jscValue.isUndefined(); |
1957 | } |
1958 | |
1959 | /*! |
1960 | Returns true if this QScriptValue is of the Object type; otherwise |
1961 | returns false. |
1962 | |
1963 | Note that function values, variant values, and QObject values are |
1964 | objects, so this function returns true for such values. |
1965 | |
1966 | \sa toObject(), QScriptEngine::newObject() |
1967 | */ |
1968 | bool QScriptValue::isObject() const |
1969 | { |
1970 | Q_D(const QScriptValue); |
1971 | return d && d->isObject(); |
1972 | } |
1973 | |
1974 | /*! |
1975 | Returns true if this QScriptValue is a variant value; |
1976 | otherwise returns false. |
1977 | |
1978 | \sa toVariant(), QScriptEngine::newVariant() |
1979 | */ |
1980 | bool QScriptValue::isVariant() const |
1981 | { |
1982 | Q_D(const QScriptValue); |
1983 | if (!d || !d->isJSC()) |
1984 | return false; |
1985 | return QScriptEnginePrivate::isVariant(value: d->jscValue); |
1986 | } |
1987 | |
1988 | /*! |
1989 | Returns true if this QScriptValue is a QObject; otherwise returns |
1990 | false. |
1991 | |
1992 | Note: This function returns true even if the QObject that this |
1993 | QScriptValue wraps has been deleted. |
1994 | |
1995 | \sa toQObject(), QScriptEngine::newQObject() |
1996 | */ |
1997 | bool QScriptValue::isQObject() const |
1998 | { |
1999 | Q_D(const QScriptValue); |
2000 | if (!d || !d->isJSC()) |
2001 | return false; |
2002 | return QScriptEnginePrivate::isQObject(value: d->jscValue); |
2003 | } |
2004 | |
2005 | /*! |
2006 | Returns true if this QScriptValue is a QMetaObject; otherwise returns |
2007 | false. |
2008 | |
2009 | \sa toQMetaObject(), QScriptEngine::newQMetaObject() |
2010 | */ |
2011 | bool QScriptValue::isQMetaObject() const |
2012 | { |
2013 | Q_D(const QScriptValue); |
2014 | if (!d || !d->isJSC()) |
2015 | return false; |
2016 | return QScriptEnginePrivate::isQMetaObject(value: d->jscValue); |
2017 | } |
2018 | |
2019 | /*! |
2020 | Returns true if this QScriptValue is valid; otherwise returns |
2021 | false. |
2022 | */ |
2023 | bool QScriptValue::isValid() const |
2024 | { |
2025 | Q_D(const QScriptValue); |
2026 | return d && (!d->isJSC() || !!d->jscValue); |
2027 | } |
2028 | |
2029 | /*! |
2030 | \since 4.4 |
2031 | |
2032 | Returns the internal data of this QScriptValue object. Qt Script uses |
2033 | this property to store the primitive value of Date, String, Number |
2034 | and Boolean objects. For other types of object, custom data may be |
2035 | stored using setData(). |
2036 | */ |
2037 | QScriptValue QScriptValue::data() const |
2038 | { |
2039 | Q_D(const QScriptValue); |
2040 | if (!d || !d->isObject()) |
2041 | return QScriptValue(); |
2042 | if (d->jscValue.inherits(classInfo: &QScriptObject::info)) { |
2043 | QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(value: d->jscValue)); |
2044 | return d->engine->scriptValueFromJSCValue(value: scriptObject->data()); |
2045 | } else { |
2046 | // ### make hidden property |
2047 | return property(name: QLatin1String("__qt_data__" ), mode: QScriptValue::ResolveLocal); |
2048 | } |
2049 | } |
2050 | |
2051 | /*! |
2052 | \since 4.4 |
2053 | |
2054 | Sets the internal \a data of this QScriptValue object. You can use |
2055 | this function to set object-specific data that won't be directly |
2056 | accessible to scripts, but may be retrieved in C++ using the data() |
2057 | function. |
2058 | |
2059 | \sa QScriptEngine::reportAdditionalMemoryCost() |
2060 | */ |
2061 | void QScriptValue::setData(const QScriptValue &data) |
2062 | { |
2063 | Q_D(QScriptValue); |
2064 | if (!d || !d->isObject()) |
2065 | return; |
2066 | QScript::APIShim shim(d->engine); |
2067 | JSC::JSValue other = d->engine->scriptValueToJSCValue(value: data); |
2068 | if (d->jscValue.inherits(classInfo: &QScriptObject::info)) { |
2069 | QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(value: d->jscValue)); |
2070 | scriptObject->setData(other); |
2071 | } else { |
2072 | JSC::ExecState *exec = d->engine->currentFrame; |
2073 | JSC::Identifier id = JSC::Identifier(exec, "__qt_data__" ); |
2074 | if (!data.isValid()) { |
2075 | JSC::asObject(value: d->jscValue)->removeDirect(propertyName: id); |
2076 | } else { |
2077 | // ### make hidden property |
2078 | JSC::asObject(value: d->jscValue)->putDirect(propertyName: id, value: other); |
2079 | } |
2080 | } |
2081 | } |
2082 | |
2083 | /*! |
2084 | \since 4.4 |
2085 | |
2086 | Returns the custom script class that this script object is an |
2087 | instance of, or 0 if the object is not of a custom class. |
2088 | |
2089 | \sa setScriptClass() |
2090 | */ |
2091 | QScriptClass *QScriptValue::scriptClass() const |
2092 | { |
2093 | Q_D(const QScriptValue); |
2094 | if (!d || !d->isJSC() || !d->jscValue.inherits(classInfo: &QScriptObject::info)) |
2095 | return 0; |
2096 | QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(value: d->jscValue)); |
2097 | QScriptObjectDelegate *delegate = scriptObject->delegate(); |
2098 | if (!delegate || (delegate->type() != QScriptObjectDelegate::ClassObject)) |
2099 | return 0; |
2100 | return static_cast<QScript::ClassObjectDelegate*>(delegate)->scriptClass(); |
2101 | } |
2102 | |
2103 | /*! |
2104 | \since 4.4 |
2105 | |
2106 | Sets the custom script class of this script object to \a scriptClass. |
2107 | This can be used to "promote" a plain script object (e.g. created |
2108 | by the "new" operator in a script, or by QScriptEngine::newObject() in C++) |
2109 | to an object of a custom type. |
2110 | |
2111 | If \a scriptClass is 0, the object will be demoted to a plain |
2112 | script object. |
2113 | |
2114 | \sa scriptClass(), setData() |
2115 | */ |
2116 | void QScriptValue::setScriptClass(QScriptClass *scriptClass) |
2117 | { |
2118 | Q_D(QScriptValue); |
2119 | if (!d || !d->isObject()) |
2120 | return; |
2121 | if (!d->jscValue.inherits(classInfo: &QScriptObject::info)) { |
2122 | qWarning(msg: "QScriptValue::setScriptClass() failed: " |
2123 | "cannot change class of non-QScriptObject" ); |
2124 | return; |
2125 | } |
2126 | QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(value: d->jscValue)); |
2127 | if (!scriptClass) { |
2128 | scriptObject->setDelegate(0); |
2129 | } else { |
2130 | QScriptObjectDelegate *delegate = scriptObject->delegate(); |
2131 | if (!delegate || (delegate->type() != QScriptObjectDelegate::ClassObject)) { |
2132 | delegate = new QScript::ClassObjectDelegate(scriptClass); |
2133 | scriptObject->setDelegate(delegate); |
2134 | } |
2135 | static_cast<QScript::ClassObjectDelegate*>(delegate)->setScriptClass(scriptClass); |
2136 | } |
2137 | } |
2138 | |
2139 | /*! |
2140 | \internal |
2141 | |
2142 | Returns the ID of this object, or -1 if this QScriptValue is not an |
2143 | object. |
2144 | |
2145 | \sa QScriptEngine::objectById() |
2146 | */ |
2147 | qint64 QScriptValue::objectId() const |
2148 | { |
2149 | return d_ptr?d_ptr->objectId():-1; |
2150 | } |
2151 | QT_END_NAMESPACE |
2152 | |