1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQml 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 <QtCore/qstring.h> |
41 | #include <QtCore/qvarlengtharray.h> |
42 | #include <QtCore/qdatetime.h> |
43 | #include "qjsengine.h" |
44 | #include "qjsvalue.h" |
45 | #include "qjsvalue_p.h" |
46 | #include "qv4value_p.h" |
47 | #include "qv4object_p.h" |
48 | #include "qv4functionobject_p.h" |
49 | #include "qv4dateobject_p.h" |
50 | #include "qv4runtime_p.h" |
51 | #include "qv4variantobject_p.h" |
52 | #include "qv4regexpobject_p.h" |
53 | #include "qv4errorobject_p.h" |
54 | #include <private/qv4mm_p.h> |
55 | #include <private/qv4jscall_p.h> |
56 | #include <private/qv4qobjectwrapper_p.h> |
57 | |
58 | /*! |
59 | \since 5.0 |
60 | \class QJSValue |
61 | |
62 | \brief The QJSValue class acts as a container for Qt/JavaScript data types. |
63 | |
64 | \ingroup qtjavascript |
65 | \inmodule QtQml |
66 | |
67 | QJSValue supports the types defined in the \l{ECMA-262} |
68 | standard: The primitive types, which are Undefined, Null, Boolean, |
69 | Number, and String; and the Object and Array types. Additionally, built-in |
70 | support is provided for Qt/C++ types such as QVariant and QObject. |
71 | |
72 | For the object-based types (including Date and RegExp), use the |
73 | newT() functions in QJSEngine (e.g. QJSEngine::newObject()) |
74 | to create a QJSValue of the desired type. For the primitive types, |
75 | use one of the QJSValue constructor overloads. For other types, e.g. |
76 | registered gadget types such as QPoint, you can use QJSEngine::toScriptValue. |
77 | |
78 | The methods named isT() (e.g. isBool(), isUndefined()) can be |
79 | used to test if a value is of a certain type. The methods named |
80 | toT() (e.g. toBool(), toString()) can be used to convert a |
81 | QJSValue to another type. You can also use the generic |
82 | qjsvalue_cast() function. |
83 | |
84 | Object values have zero or more properties which are themselves |
85 | QJSValues. Use setProperty() to set a property of an object, and |
86 | call property() to retrieve the value of a property. |
87 | |
88 | \snippet code/src_script_qjsvalue.cpp 0 |
89 | |
90 | If you want to iterate over the properties of a script object, use |
91 | the QJSValueIterator class. |
92 | |
93 | Object values have an internal \c{prototype} property, which can be |
94 | accessed with prototype() and setPrototype(). |
95 | |
96 | Function objects (objects for which isCallable()) returns true) can |
97 | be invoked by calling call(). Constructor functions can be used to |
98 | construct new objects by calling callAsConstructor(). |
99 | |
100 | Use equals() or strictlyEquals() to compare a QJSValue to another. |
101 | |
102 | Note that a QJSValue for which isObject() is true only carries a |
103 | reference to an actual object; copying the QJSValue will only |
104 | copy the object reference, not the object itself. If you want to |
105 | clone an object (i.e. copy an object's properties to another |
106 | object), you can do so with the help of a \c{for-in} statement in |
107 | script code, or QJSValueIterator in C++. |
108 | |
109 | \sa QJSEngine, QJSValueIterator |
110 | |
111 | \section1 Working With Arrays |
112 | |
113 | To create an array using QJSValue, use \l QJSEngine::newArray(): |
114 | |
115 | \code |
116 | // Assumes that this class was declared in QML. |
117 | QJSValue jsArray = engine->newArray(3); |
118 | \endcode |
119 | |
120 | To set individual elements in the array, use |
121 | the \l {QJSValue::}{setProperty(quint32 arrayIndex, const QJSValue &value)} |
122 | overload. For example, to fill the array above with integers: |
123 | |
124 | \code |
125 | for (int i = 0; i < 3; ++i) { |
126 | jsArray.setProperty(i, QRandomGenerator::global().generate()); |
127 | } |
128 | \endcode |
129 | |
130 | To determine the length of the array, access the \c "length" property. |
131 | To access array elements, use the |
132 | \l {QJSValue::}{property(quint32 arrayIndex)} overload. The following code |
133 | reads the array we created above back into a list: |
134 | |
135 | \code |
136 | QVector<int> integers; |
137 | const int length = jsArray.property("length").toInt(); |
138 | for (int i = 0; i < length; ++i) { |
139 | integers.append(jsArray.property(i).toInt()); |
140 | } |
141 | \endcode |
142 | */ |
143 | |
144 | /*! |
145 | \enum QJSValue::SpecialValue |
146 | |
147 | This enum is used to specify a single-valued type. |
148 | |
149 | \value UndefinedValue An undefined value. |
150 | |
151 | \value NullValue A null value. |
152 | */ |
153 | |
154 | /*! |
155 | \typedef QJSValueList |
156 | \relates QJSValue |
157 | |
158 | This is a typedef for a QList<QJSValue>. |
159 | */ |
160 | |
161 | /*! |
162 | \enum QJSValue::ErrorType |
163 | \since 5.12 |
164 | |
165 | Use this enum for JavaScript language-specific types of Error objects. |
166 | |
167 | They may be useful when emulating language features in C++ requires the use |
168 | of specialized exception types. In addition, they may help to more clearly |
169 | communicate certain typical conditions, instead of throwing a generic |
170 | JavaScript exception. For example, code that deals with networking and |
171 | resource locators may find it useful to propagate errors related to |
172 | malformed locators using the URIError type. |
173 | |
174 | \omitvalue NoError |
175 | \value GenericError A generic Error object, but not of a specific sub-type. |
176 | \omitvalue EvalError |
177 | \value RangeError A value did not match the expected set or range. |
178 | \value ReferenceError A non-existing variable referenced. |
179 | \value SyntaxError An invalid token or sequence of tokens was encountered |
180 | that does not conform with the syntax of the language. |
181 | \value TypeError An operand or argument is incompatible with the type |
182 | expected. |
183 | \value URIError A URI handling function was used incorrectly or the URI |
184 | provided is malformed. |
185 | */ |
186 | |
187 | QT_BEGIN_NAMESPACE |
188 | |
189 | using namespace QV4; |
190 | |
191 | /*! |
192 | Constructs a new QJSValue with a boolean \a value. |
193 | */ |
194 | QJSValue::QJSValue(bool value) |
195 | { |
196 | QJSValuePrivate::setVariant(jsval: this, v: QVariant(value)); |
197 | } |
198 | |
199 | /*! |
200 | \internal |
201 | */ |
202 | QJSValue::QJSValue(ExecutionEngine *e, quint64 val) |
203 | { |
204 | QJSValuePrivate::setValue(jsval: this, engine: e, v: val); |
205 | } |
206 | |
207 | /*! |
208 | Constructs a new QJSValue with a number \a value. |
209 | */ |
210 | QJSValue::QJSValue(int value) |
211 | { |
212 | QJSValuePrivate::setVariant(jsval: this, v: QVariant(value)); |
213 | } |
214 | |
215 | /*! |
216 | Constructs a new QJSValue with a number \a value. |
217 | */ |
218 | QJSValue::QJSValue(uint value) |
219 | { |
220 | QJSValuePrivate::setVariant(jsval: this, v: QVariant((double)value)); |
221 | } |
222 | |
223 | /*! |
224 | Constructs a new QJSValue with a number \a value. |
225 | */ |
226 | QJSValue::QJSValue(double value) |
227 | { |
228 | QJSValuePrivate::setVariant(jsval: this, v: QVariant(value)); |
229 | } |
230 | |
231 | /*! |
232 | Constructs a new QJSValue with a string \a value. |
233 | */ |
234 | QJSValue::QJSValue(const QString& value) |
235 | { |
236 | QJSValuePrivate::setVariant(jsval: this, v: QVariant(value)); |
237 | } |
238 | |
239 | /*! |
240 | Constructs a new QJSValue with a special \a value. |
241 | */ |
242 | QJSValue::QJSValue(SpecialValue value) |
243 | : d(0) |
244 | { |
245 | if (value == NullValue) |
246 | QJSValuePrivate::setVariant(jsval: this, v: QVariant::fromValue(value: nullptr)); |
247 | } |
248 | |
249 | /*! |
250 | Constructs a new QJSValue with a string \a value. |
251 | */ |
252 | QJSValue::QJSValue(const QLatin1String &value) |
253 | { |
254 | QJSValuePrivate::setVariant(jsval: this, v: QVariant(value)); |
255 | } |
256 | |
257 | /*! |
258 | Constructs a new QJSValue with a string \a value. |
259 | */ |
260 | #ifndef QT_NO_CAST_FROM_ASCII |
261 | QJSValue::QJSValue(const char *value) |
262 | { |
263 | QJSValuePrivate::setVariant(jsval: this, v: QVariant(QString::fromUtf8(str: value))); |
264 | } |
265 | #endif |
266 | |
267 | /*! |
268 | Constructs a new QJSValue that is a copy of \a other. |
269 | |
270 | Note that if \a other is an object (i.e., isObject() would return |
271 | true), then only a reference to the underlying object is copied into |
272 | the new script value (i.e., the object itself is not copied). |
273 | */ |
274 | QJSValue::QJSValue(const QJSValue& other) |
275 | : d(0) |
276 | { |
277 | QV4::Value *v = QJSValuePrivate::getValue(jsval: &other); |
278 | if (v) { |
279 | QJSValuePrivate::setValue(jsval: this, engine: QJSValuePrivate::engine(jsval: &other), v: *v); |
280 | } else if (QVariant *v = QJSValuePrivate::getVariant(jsval: &other)) { |
281 | QJSValuePrivate::setVariant(jsval: this, v: *v); |
282 | } |
283 | } |
284 | |
285 | /*! |
286 | \fn QJSValue::QJSValue(QJSValue && other) |
287 | |
288 | Move constructor. Moves from \a other into this QJSValue object. |
289 | */ |
290 | |
291 | /*! |
292 | \fn QJSValue &QJSValue::operator=(QJSValue && other) |
293 | |
294 | Move-assigns \a other to this QJSValue object. |
295 | */ |
296 | |
297 | /*! |
298 | Destroys this QJSValue. |
299 | */ |
300 | QJSValue::~QJSValue() |
301 | { |
302 | QJSValuePrivate::free(jsval: this); |
303 | } |
304 | |
305 | /*! |
306 | Returns true if this QJSValue is of the primitive type Boolean; |
307 | otherwise returns false. |
308 | |
309 | \sa toBool() |
310 | */ |
311 | bool QJSValue::isBool() const |
312 | { |
313 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
314 | if (val) |
315 | return val->isBoolean(); |
316 | QVariant *variant = QJSValuePrivate::getVariant(jsval: this); |
317 | return variant && variant->userType() == QMetaType::Bool; |
318 | } |
319 | |
320 | /*! |
321 | Returns true if this QJSValue is of the primitive type Number; |
322 | otherwise returns false. |
323 | |
324 | \sa toNumber() |
325 | */ |
326 | bool QJSValue::isNumber() const |
327 | { |
328 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
329 | if (val) |
330 | return val->isNumber(); |
331 | QVariant *variant = QJSValuePrivate::getVariant(jsval: this); |
332 | if (!variant) |
333 | return false; |
334 | |
335 | switch (variant->userType()) { |
336 | case QMetaType::Double: |
337 | case QMetaType::Int: |
338 | case QMetaType::UInt: |
339 | case QMetaType::Long: |
340 | case QMetaType::ULong: |
341 | case QMetaType::Short: |
342 | case QMetaType::UShort: |
343 | case QMetaType::LongLong: |
344 | case QMetaType::ULongLong: |
345 | return true; |
346 | default: |
347 | return false; |
348 | } |
349 | } |
350 | |
351 | /*! |
352 | Returns true if this QJSValue is of the primitive type Null; |
353 | otherwise returns false. |
354 | */ |
355 | bool QJSValue::isNull() const |
356 | { |
357 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
358 | if (val) |
359 | return val->isNull(); |
360 | QVariant *variant = QJSValuePrivate::getVariant(jsval: this); |
361 | if (!variant) |
362 | return false; |
363 | const int type = variant->userType(); |
364 | return type == QMetaType::Nullptr || type == QMetaType::VoidStar; |
365 | } |
366 | |
367 | /*! |
368 | Returns true if this QJSValue is of the primitive type String; |
369 | otherwise returns false. |
370 | |
371 | \sa toString() |
372 | */ |
373 | bool QJSValue::isString() const |
374 | { |
375 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
376 | if (val) |
377 | return val->isString(); |
378 | QVariant *variant = QJSValuePrivate::getVariant(jsval: this); |
379 | return variant && variant->userType() == QMetaType::QString; |
380 | } |
381 | |
382 | /*! |
383 | Returns true if this QJSValue is of the primitive type Undefined; |
384 | otherwise returns false. |
385 | */ |
386 | bool QJSValue::isUndefined() const |
387 | { |
388 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
389 | if (val) |
390 | return val->isUndefined(); |
391 | QVariant *variant = QJSValuePrivate::getVariant(jsval: this); |
392 | return !variant || variant->userType() == QMetaType::UnknownType || variant->userType() == QMetaType::Void; |
393 | } |
394 | |
395 | /*! |
396 | Returns true if this QJSValue is an object of the Error class; |
397 | otherwise returns false. |
398 | |
399 | \sa errorType(), {QJSEngine#Script Exceptions}{QJSEngine - Script Exceptions} |
400 | */ |
401 | bool QJSValue::isError() const |
402 | { |
403 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
404 | if (!val) |
405 | return false; |
406 | return val->as<ErrorObject>(); |
407 | } |
408 | |
409 | /*! |
410 | \since 5.12 |
411 | Returns the error type this QJSValue represents if it is an Error object. |
412 | Otherwise, returns \c NoError." |
413 | |
414 | \sa isError(), {QJSEngine#Script Exceptions}{QJSEngine - Script Exceptions} |
415 | */ |
416 | QJSValue::ErrorType QJSValue::errorType() const |
417 | { |
418 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
419 | if (!val) |
420 | return NoError; |
421 | QV4::ErrorObject *error = val->as<ErrorObject>(); |
422 | if (!error) |
423 | return NoError; |
424 | switch (error->d()->errorType) { |
425 | case QV4::Heap::ErrorObject::Error: |
426 | return GenericError; |
427 | case QV4::Heap::ErrorObject::EvalError: |
428 | return EvalError; |
429 | case QV4::Heap::ErrorObject::RangeError: |
430 | return RangeError; |
431 | case QV4::Heap::ErrorObject::ReferenceError: |
432 | return ReferenceError; |
433 | case QV4::Heap::ErrorObject::SyntaxError: |
434 | return SyntaxError; |
435 | case QV4::Heap::ErrorObject::TypeError: |
436 | return TypeError; |
437 | case QV4::Heap::ErrorObject::URIError: |
438 | return URIError; |
439 | } |
440 | Q_UNREACHABLE(); |
441 | return NoError; |
442 | } |
443 | |
444 | /*! |
445 | Returns true if this QJSValue is an object of the Array class; |
446 | otherwise returns false. |
447 | |
448 | \sa QJSEngine::newArray() |
449 | */ |
450 | bool QJSValue::isArray() const |
451 | { |
452 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
453 | if (!val) |
454 | return false; |
455 | return val->as<ArrayObject>(); |
456 | } |
457 | |
458 | /*! |
459 | Returns true if this QJSValue is of the Object type; otherwise |
460 | returns false. |
461 | |
462 | Note that function values, variant values, and QObject values are |
463 | objects, so this function returns true for such values. |
464 | |
465 | \sa QJSEngine::newObject() |
466 | */ |
467 | bool QJSValue::isObject() const |
468 | { |
469 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
470 | if (!val) |
471 | return false; |
472 | return val->as<QV4::Object>(); |
473 | } |
474 | |
475 | /*! |
476 | Returns true if this QJSValue is a function, otherwise |
477 | returns false. |
478 | |
479 | \sa call() |
480 | */ |
481 | bool QJSValue::isCallable() const |
482 | { |
483 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
484 | if (!val) |
485 | return false; |
486 | return val->as<FunctionObject>(); |
487 | } |
488 | |
489 | /*! |
490 | Returns true if this QJSValue is a variant value; |
491 | otherwise returns false. |
492 | |
493 | \sa toVariant() |
494 | */ |
495 | bool QJSValue::isVariant() const |
496 | { |
497 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
498 | if (!val) |
499 | return false; |
500 | return val->as<QV4::VariantObject>(); |
501 | } |
502 | |
503 | /*! |
504 | Returns the string value of this QJSValue, as defined in |
505 | \l{ECMA-262} section 9.8, "ToString". |
506 | |
507 | Note that if this QJSValue is an object, calling this function |
508 | has side effects on the script engine, since the engine will call |
509 | the object's toString() function (and possibly valueOf()) in an |
510 | attempt to convert the object to a primitive value (possibly |
511 | resulting in an uncaught script exception). |
512 | |
513 | \sa isString() |
514 | */ |
515 | QString QJSValue::toString() const |
516 | { |
517 | QV4::Value scratch; |
518 | QV4::Value *val = QJSValuePrivate::valueForData(jsval: this, scratch: &scratch); |
519 | |
520 | if (!val) { |
521 | QVariant *variant = QJSValuePrivate::getVariant(jsval: this); |
522 | Q_ASSERT(variant); |
523 | if (variant->userType() == QMetaType::QVariantMap) |
524 | return QStringLiteral("[object Object]" ); |
525 | else if (variant->userType() == QMetaType::QVariantList) { |
526 | const QVariantList list = variant->toList(); |
527 | QString result; |
528 | for (int i = 0; i < list.count(); ++i) { |
529 | if (i > 0) |
530 | result.append(c: QLatin1Char(',')); |
531 | result.append(s: list.at(i).toString()); |
532 | } |
533 | return result; |
534 | } |
535 | return variant->toString(); |
536 | } |
537 | return val->toQStringNoThrow(); |
538 | } |
539 | |
540 | /*! |
541 | Returns the number value of this QJSValue, as defined in |
542 | \l{ECMA-262} section 9.3, "ToNumber". |
543 | |
544 | Note that if this QJSValue is an object, calling this function |
545 | has side effects on the script engine, since the engine will call |
546 | the object's valueOf() function (and possibly toString()) in an |
547 | attempt to convert the object to a primitive value (possibly |
548 | resulting in an uncaught script exception). |
549 | |
550 | \sa isNumber(), toInt(), toUInt() |
551 | */ |
552 | double QJSValue::toNumber() const |
553 | { |
554 | QV4::Value scratch; |
555 | QV4::Value *val = QJSValuePrivate::valueForData(jsval: this, scratch: &scratch); |
556 | |
557 | if (!val) { |
558 | QVariant *variant = QJSValuePrivate::getVariant(jsval: this); |
559 | Q_ASSERT(variant); |
560 | |
561 | if (variant->userType() == QMetaType::QString) |
562 | return RuntimeHelpers::stringToNumber(s: variant->toString()); |
563 | else if (variant->canConvert<double>()) |
564 | return variant->value<double>(); |
565 | else |
566 | return std::numeric_limits<double>::quiet_NaN(); |
567 | } |
568 | |
569 | double dbl = val->toNumber(); |
570 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
571 | if (engine && engine->hasException) { |
572 | engine->catchException(); |
573 | return 0; |
574 | } |
575 | return dbl; |
576 | } |
577 | |
578 | /*! |
579 | Returns the boolean value of this QJSValue, using the conversion |
580 | rules described in \l{ECMA-262} section 9.2, "ToBoolean". |
581 | |
582 | Note that if this QJSValue is an object, calling this function |
583 | has side effects on the script engine, since the engine will call |
584 | the object's valueOf() function (and possibly toString()) in an |
585 | attempt to convert the object to a primitive value (possibly |
586 | resulting in an uncaught script exception). |
587 | |
588 | \sa isBool() |
589 | */ |
590 | bool QJSValue::toBool() const |
591 | { |
592 | QV4::Value scratch; |
593 | QV4::Value *val = QJSValuePrivate::valueForData(jsval: this, scratch: &scratch); |
594 | |
595 | if (!val) { |
596 | QVariant *variant = QJSValuePrivate::getVariant(jsval: this); |
597 | if (variant->userType() == QMetaType::QString) |
598 | return variant->toString().length() > 0; |
599 | else |
600 | return variant->toBool(); |
601 | } |
602 | |
603 | bool b = val->toBoolean(); |
604 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
605 | if (engine && engine->hasException) { |
606 | engine->catchException(); |
607 | return false; |
608 | } |
609 | return b; |
610 | } |
611 | |
612 | /*! |
613 | Returns the signed 32-bit integer value of this QJSValue, using |
614 | the conversion rules described in \l{ECMA-262} section 9.5, "ToInt32". |
615 | |
616 | Note that if this QJSValue is an object, calling this function |
617 | has side effects on the script engine, since the engine will call |
618 | the object's valueOf() function (and possibly toString()) in an |
619 | attempt to convert the object to a primitive value (possibly |
620 | resulting in an uncaught script exception). |
621 | |
622 | \sa toNumber(), toUInt() |
623 | */ |
624 | qint32 QJSValue::toInt() const |
625 | { |
626 | QV4::Value scratch; |
627 | QV4::Value *val = QJSValuePrivate::valueForData(jsval: this, scratch: &scratch); |
628 | |
629 | if (!val) { |
630 | QVariant *variant = QJSValuePrivate::getVariant(jsval: this); |
631 | if (variant->userType() == QMetaType::QString) |
632 | return QV4::Value::toInt32(d: RuntimeHelpers::stringToNumber(s: variant->toString())); |
633 | else |
634 | return variant->toInt(); |
635 | } |
636 | |
637 | qint32 i = val->toInt32(); |
638 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
639 | if (engine && engine->hasException) { |
640 | engine->catchException(); |
641 | return 0; |
642 | } |
643 | return i; |
644 | } |
645 | |
646 | /*! |
647 | Returns the unsigned 32-bit integer value of this QJSValue, using |
648 | the conversion rules described in \l{ECMA-262} section 9.6, "ToUint32". |
649 | |
650 | Note that if this QJSValue is an object, calling this function |
651 | has side effects on the script engine, since the engine will call |
652 | the object's valueOf() function (and possibly toString()) in an |
653 | attempt to convert the object to a primitive value (possibly |
654 | resulting in an uncaught script exception). |
655 | |
656 | \sa toNumber(), toInt() |
657 | */ |
658 | quint32 QJSValue::toUInt() const |
659 | { |
660 | QV4::Value scratch; |
661 | QV4::Value *val = QJSValuePrivate::valueForData(jsval: this, scratch: &scratch); |
662 | |
663 | if (!val) { |
664 | QVariant *variant = QJSValuePrivate::getVariant(jsval: this); |
665 | if (variant->userType() == QMetaType::QString) |
666 | return QV4::Value::toUInt32(d: RuntimeHelpers::stringToNumber(s: variant->toString())); |
667 | else |
668 | return variant->toUInt(); |
669 | } |
670 | |
671 | quint32 u = val->toUInt32(); |
672 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
673 | if (engine && engine->hasException) { |
674 | engine->catchException(); |
675 | return 0; |
676 | } |
677 | return u; |
678 | } |
679 | |
680 | /*! |
681 | Returns the QVariant value of this QJSValue, if it can be |
682 | converted to a QVariant; otherwise returns an invalid QVariant. |
683 | The conversion is performed according to the following table: |
684 | |
685 | \table |
686 | \header \li Input Type \li Result |
687 | \row \li Undefined \li An invalid QVariant. |
688 | \row \li Null \li A QVariant containing a null pointer (QMetaType::Nullptr). |
689 | \row \li Boolean \li A QVariant containing the value of the boolean. |
690 | \row \li Number \li A QVariant containing the value of the number. |
691 | \row \li String \li A QVariant containing the value of the string. |
692 | \row \li QVariant Object \li The result is the QVariant value of the object (no conversion). |
693 | \row \li QObject Object \li A QVariant containing a pointer to the QObject. |
694 | \row \li Date Object \li A QVariant containing the date value (toDateTime()). |
695 | \row \li RegExp Object \li A QVariant containing the regular expression value. |
696 | \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. |
697 | \row \li Object \li The object is converted to a QVariantMap. Each property is converted to a QVariant, recursively; cyclic references are not followed. |
698 | \endtable |
699 | |
700 | \sa isVariant() |
701 | */ |
702 | QVariant QJSValue::toVariant() const |
703 | { |
704 | QVariant *variant = QJSValuePrivate::getVariant(jsval: this); |
705 | if (variant) |
706 | return *variant; |
707 | |
708 | QV4::Value scratch; |
709 | QV4::Value *val = QJSValuePrivate::valueForData(jsval: this, scratch: &scratch); |
710 | Q_ASSERT(val); |
711 | |
712 | if (QV4::Object *o = val->as<QV4::Object>()) |
713 | return o->engine()->toVariant(value: *val, /*typeHint*/ -1, /*createJSValueForObjects*/ false); |
714 | |
715 | if (String *s = val->stringValue()) |
716 | return QVariant(s->toQString()); |
717 | if (val->isBoolean()) |
718 | return QVariant(val->booleanValue()); |
719 | if (val->isNumber()) { |
720 | if (val->isInt32()) |
721 | return QVariant(val->integerValue()); |
722 | return QVariant(val->asDouble()); |
723 | } |
724 | if (val->isNull()) |
725 | return QVariant(QMetaType::Nullptr, nullptr); |
726 | Q_ASSERT(val->isUndefined()); |
727 | return QVariant(); |
728 | } |
729 | |
730 | /*! |
731 | Calls this QJSValue as a function, passing \a args as arguments |
732 | to the function, and using the globalObject() as the "this"-object. |
733 | Returns the value returned from the function. |
734 | |
735 | If this QJSValue is not callable, call() does nothing and |
736 | returns an undefined QJSValue. |
737 | |
738 | Calling call() can cause an exception to occur in the script engine; |
739 | in that case, call() returns the value that was thrown (typically an |
740 | \c{Error} object). You can call isError() on the return value to |
741 | determine whether an exception occurred. |
742 | |
743 | \sa isCallable(), callWithInstance(), callAsConstructor() |
744 | */ |
745 | QJSValue QJSValue::call(const QJSValueList &args) |
746 | { |
747 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
748 | if (!val) |
749 | return QJSValue(); |
750 | |
751 | FunctionObject *f = val->as<FunctionObject>(); |
752 | if (!f) |
753 | return QJSValue(); |
754 | |
755 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
756 | Q_ASSERT(engine); |
757 | |
758 | Scope scope(engine); |
759 | JSCallData jsCallData(scope, args.length()); |
760 | *jsCallData->thisObject = engine->globalObject; |
761 | for (int i = 0; i < args.size(); ++i) { |
762 | if (!QJSValuePrivate::checkEngine(e: engine, jsval: args.at(i))) { |
763 | qWarning(msg: "QJSValue::call() failed: cannot call function with argument created in a different engine" ); |
764 | return QJSValue(); |
765 | } |
766 | jsCallData->args[i] = QJSValuePrivate::convertedToValue(e: engine, jsval: args.at(i)); |
767 | } |
768 | |
769 | ScopedValue result(scope, f->call(data: jsCallData)); |
770 | if (engine->hasException) |
771 | result = engine->catchException(); |
772 | if (engine->isInterrupted.loadAcquire()) |
773 | result = engine->newErrorObject(QStringLiteral("Interrupted" )); |
774 | |
775 | return QJSValue(engine, result->asReturnedValue()); |
776 | } |
777 | |
778 | /*! |
779 | Calls this QJSValue as a function, using \a instance as |
780 | the `this' object in the function call, and passing \a args |
781 | as arguments to the function. Returns the value returned from |
782 | the function. |
783 | |
784 | If this QJSValue is not a function, call() does nothing |
785 | and returns an undefined QJSValue. |
786 | |
787 | Note that if \a instance is not an object, the global object |
788 | (see \l{QJSEngine::globalObject()}) will be used as the |
789 | `this' object. |
790 | |
791 | Calling call() can cause an exception to occur in the script engine; |
792 | in that case, call() returns the value that was thrown (typically an |
793 | \c{Error} object). You can call isError() on the return value to |
794 | determine whether an exception occurred. |
795 | |
796 | \sa call() |
797 | */ |
798 | QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList &args) |
799 | { |
800 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
801 | if (!val) |
802 | return QJSValue(); |
803 | |
804 | FunctionObject *f = val->as<FunctionObject>(); |
805 | if (!f) |
806 | return QJSValue(); |
807 | |
808 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
809 | Q_ASSERT(engine); |
810 | Scope scope(engine); |
811 | |
812 | if (!QJSValuePrivate::checkEngine(e: engine, jsval: instance)) { |
813 | qWarning(msg: "QJSValue::call() failed: cannot call function with thisObject created in a different engine" ); |
814 | return QJSValue(); |
815 | } |
816 | |
817 | JSCallData jsCallData(scope, args.size()); |
818 | *jsCallData->thisObject = QJSValuePrivate::convertedToValue(e: engine, jsval: instance); |
819 | for (int i = 0; i < args.size(); ++i) { |
820 | if (!QJSValuePrivate::checkEngine(e: engine, jsval: args.at(i))) { |
821 | qWarning(msg: "QJSValue::call() failed: cannot call function with argument created in a different engine" ); |
822 | return QJSValue(); |
823 | } |
824 | jsCallData->args[i] = QJSValuePrivate::convertedToValue(e: engine, jsval: args.at(i)); |
825 | } |
826 | |
827 | ScopedValue result(scope, f->call(data: jsCallData)); |
828 | if (engine->hasException) |
829 | result = engine->catchException(); |
830 | if (engine->isInterrupted.loadAcquire()) |
831 | result = engine->newErrorObject(QStringLiteral("Interrupted" )); |
832 | |
833 | return QJSValue(engine, result->asReturnedValue()); |
834 | } |
835 | |
836 | /*! |
837 | Creates a new \c{Object} and calls this QJSValue as a |
838 | constructor, using the created object as the `this' object and |
839 | passing \a args as arguments. If the return value from the |
840 | constructor call is an object, then that object is returned; |
841 | otherwise the default constructed object is returned. |
842 | |
843 | If this QJSValue is not a function, callAsConstructor() does |
844 | nothing and returns an undefined QJSValue. |
845 | |
846 | Calling this function can cause an exception to occur in the |
847 | script engine; in that case, the value that was thrown |
848 | (typically an \c{Error} object) is returned. You can call |
849 | isError() on the return value to determine whether an |
850 | exception occurred. |
851 | |
852 | \sa call(), QJSEngine::newObject() |
853 | */ |
854 | QJSValue QJSValue::callAsConstructor(const QJSValueList &args) |
855 | { |
856 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
857 | if (!val) |
858 | return QJSValue(); |
859 | |
860 | FunctionObject *f = val->as<FunctionObject>(); |
861 | if (!f) |
862 | return QJSValue(); |
863 | |
864 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
865 | Q_ASSERT(engine); |
866 | |
867 | Scope scope(engine); |
868 | JSCallData jsCallData(scope, args.size()); |
869 | for (int i = 0; i < args.size(); ++i) { |
870 | if (!QJSValuePrivate::checkEngine(e: engine, jsval: args.at(i))) { |
871 | qWarning(msg: "QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine" ); |
872 | return QJSValue(); |
873 | } |
874 | jsCallData->args[i] = QJSValuePrivate::convertedToValue(e: engine, jsval: args.at(i)); |
875 | } |
876 | |
877 | ScopedValue result(scope, f->callAsConstructor(data: jsCallData)); |
878 | if (engine->hasException) |
879 | result = engine->catchException(); |
880 | if (engine->isInterrupted.loadAcquire()) |
881 | result = engine->newErrorObject(QStringLiteral("Interrupted" )); |
882 | |
883 | return QJSValue(engine, result->asReturnedValue()); |
884 | } |
885 | |
886 | #ifdef QT_DEPRECATED |
887 | |
888 | /*! |
889 | \obsolete |
890 | |
891 | Returns the QJSEngine that created this QJSValue, |
892 | or 0 if this QJSValue is invalid or the value is not |
893 | associated with a particular engine. |
894 | */ |
895 | QJSEngine* QJSValue::engine() const |
896 | { |
897 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
898 | if (engine) |
899 | return engine->jsEngine(); |
900 | return nullptr; |
901 | } |
902 | |
903 | #endif // QT_DEPRECATED |
904 | |
905 | /*! |
906 | If this QJSValue is an object, returns the internal prototype |
907 | (\c{__proto__} property) of this object; otherwise returns an |
908 | undefined QJSValue. |
909 | |
910 | \sa setPrototype(), isObject() |
911 | */ |
912 | QJSValue QJSValue::prototype() const |
913 | { |
914 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
915 | if (!engine) |
916 | return QJSValue(); |
917 | QV4::Scope scope(engine); |
918 | ScopedObject o(scope, QJSValuePrivate::getValue(jsval: this)->as<QV4::Object>()); |
919 | if (!o) |
920 | return QJSValue(); |
921 | ScopedObject p(scope, o->getPrototypeOf()); |
922 | if (!p) |
923 | return QJSValue(NullValue); |
924 | return QJSValue(o->internalClass()->engine, p.asReturnedValue()); |
925 | } |
926 | |
927 | /*! |
928 | If this QJSValue is an object, sets the internal prototype |
929 | (\c{__proto__} property) of this object to be \a prototype; |
930 | if the QJSValue is null, it sets the prototype to null; |
931 | otherwise does nothing. |
932 | |
933 | The internal prototype should not be confused with the public |
934 | property with name "prototype"; the public prototype is usually |
935 | only set on functions that act as constructors. |
936 | |
937 | \sa prototype(), isObject() |
938 | */ |
939 | void QJSValue::setPrototype(const QJSValue& prototype) |
940 | { |
941 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
942 | if (!engine) |
943 | return; |
944 | Scope scope(engine); |
945 | ScopedObject o(scope, QJSValuePrivate::getValue(jsval: this)); |
946 | if (!o) |
947 | return; |
948 | QV4::Value scratch; |
949 | QV4::Value *val = QJSValuePrivate::valueForData(jsval: &prototype, scratch: &scratch); |
950 | if (!val) |
951 | return; |
952 | if (val->isNull()) { |
953 | o->setPrototypeOf(nullptr); |
954 | return; |
955 | } |
956 | |
957 | ScopedObject p(scope, val); |
958 | if (!p) |
959 | return; |
960 | if (o->engine() != p->engine()) { |
961 | qWarning(msg: "QJSValue::setPrototype() failed: cannot set a prototype created in a different engine" ); |
962 | return; |
963 | } |
964 | if (!o->setPrototypeOf(p)) |
965 | qWarning(msg: "QJSValue::setPrototype() failed: cyclic prototype value" ); |
966 | } |
967 | |
968 | /*! |
969 | Assigns the \a other value to this QJSValue. |
970 | |
971 | Note that if \a other is an object (isObject() returns true), |
972 | only a reference to the underlying object will be assigned; |
973 | the object itself will not be copied. |
974 | */ |
975 | QJSValue& QJSValue::operator=(const QJSValue& other) |
976 | { |
977 | if (d == other.d) |
978 | return *this; |
979 | |
980 | QJSValuePrivate::free(jsval: this); |
981 | d = 0; |
982 | |
983 | QV4::Value *v = QJSValuePrivate::getValue(jsval: &other); |
984 | if (v) { |
985 | QJSValuePrivate::setValue(jsval: this, engine: QJSValuePrivate::engine(jsval: &other), v: *v); |
986 | } else if (QVariant *v = QJSValuePrivate::getVariant(jsval: &other)) { |
987 | QJSValuePrivate::setVariant(jsval: this, v: *v); |
988 | } |
989 | return *this; |
990 | } |
991 | |
992 | static bool js_equal(const QString &string, const QV4::Value &value) |
993 | { |
994 | if (String *s = value.stringValue()) |
995 | return string == s->toQString(); |
996 | if (value.isNumber()) |
997 | return RuntimeHelpers::stringToNumber(s: string) == value.asDouble(); |
998 | if (value.isBoolean()) |
999 | return RuntimeHelpers::stringToNumber(s: string) == double(value.booleanValue()); |
1000 | if (QV4::Object *o = value.objectValue()) { |
1001 | Scope scope(o->engine()); |
1002 | ScopedValue p(scope, RuntimeHelpers::toPrimitive(value, typeHint: PREFERREDTYPE_HINT)); |
1003 | return js_equal(string, value: p); |
1004 | } |
1005 | return false; |
1006 | } |
1007 | |
1008 | /*! |
1009 | Returns true if this QJSValue is equal to \a other, otherwise |
1010 | returns false. The comparison follows the behavior described in |
1011 | \l{ECMA-262} section 11.9.3, "The Abstract Equality Comparison |
1012 | Algorithm". |
1013 | |
1014 | This function can return true even if the type of this QJSValue |
1015 | is different from the type of the \a other value; i.e. the |
1016 | comparison is not strict. For example, comparing the number 9 to |
1017 | the string "9" returns true; comparing an undefined value to a null |
1018 | value returns true; comparing a \c{Number} object whose primitive |
1019 | value is 6 to a \c{String} object whose primitive value is "6" |
1020 | returns true; and comparing the number 1 to the boolean value |
1021 | \c{true} returns true. If you want to perform a comparison |
1022 | without such implicit value conversion, use strictlyEquals(). |
1023 | |
1024 | Note that if this QJSValue or the \a other value are objects, |
1025 | calling this function has side effects on the script engine, since |
1026 | the engine will call the object's valueOf() function (and possibly |
1027 | toString()) in an attempt to convert the object to a primitive value |
1028 | (possibly resulting in an uncaught script exception). |
1029 | |
1030 | \sa strictlyEquals() |
1031 | */ |
1032 | bool QJSValue::equals(const QJSValue& other) const |
1033 | { |
1034 | QV4::Value s1, s2; |
1035 | QV4::Value *v = QJSValuePrivate::valueForData(jsval: this, scratch: &s1); |
1036 | QV4::Value *ov = QJSValuePrivate::valueForData(jsval: &other, scratch: &s2); |
1037 | |
1038 | if (!v) { |
1039 | QVariant *variant = QJSValuePrivate::getVariant(jsval: this); |
1040 | Q_ASSERT(variant); |
1041 | if (!ov) |
1042 | return *variant == *QJSValuePrivate::getVariant(jsval: &other); |
1043 | if (variant->userType() == QMetaType::QVariantMap || variant->userType() == QMetaType::QVariantList) |
1044 | return false; |
1045 | return js_equal(string: variant->toString(), value: *ov); |
1046 | } |
1047 | if (!ov) |
1048 | return other.equals(other: *this); |
1049 | |
1050 | return Runtime::CompareEqual::call(*v, *ov); |
1051 | } |
1052 | |
1053 | /*! |
1054 | Returns true if this QJSValue is equal to \a other using strict |
1055 | comparison (no conversion), otherwise returns false. The comparison |
1056 | follows the behavior described in \l{ECMA-262} section 11.9.6, "The |
1057 | Strict Equality Comparison Algorithm". |
1058 | |
1059 | If the type of this QJSValue is different from the type of the |
1060 | \a other value, this function returns false. If the types are equal, |
1061 | the result depends on the type, as shown in the following table: |
1062 | |
1063 | \table |
1064 | \header \li Type \li Result |
1065 | \row \li Undefined \li true |
1066 | \row \li Null \li true |
1067 | \row \li Boolean \li true if both values are true, false otherwise |
1068 | \row \li Number \li false if either value is NaN (Not-a-Number); true if values are equal, false otherwise |
1069 | \row \li String \li true if both values are exactly the same sequence of characters, false otherwise |
1070 | \row \li Object \li true if both values refer to the same object, false otherwise |
1071 | \endtable |
1072 | |
1073 | \sa equals() |
1074 | */ |
1075 | bool QJSValue::strictlyEquals(const QJSValue& other) const |
1076 | { |
1077 | QV4::Value s1, s2; |
1078 | QV4::Value *v = QJSValuePrivate::valueForData(jsval: this, scratch: &s1); |
1079 | QV4::Value *ov = QJSValuePrivate::valueForData(jsval: &other, scratch: &s2); |
1080 | |
1081 | if (!v) { |
1082 | QVariant *variant = QJSValuePrivate::getVariant(jsval: this); |
1083 | Q_ASSERT(variant); |
1084 | if (!ov) |
1085 | return *variant == *QJSValuePrivate::getVariant(jsval: &other); |
1086 | if (variant->userType() == QMetaType::QVariantMap || variant->userType() == QMetaType::QVariantList) |
1087 | return false; |
1088 | if (String *s = ov->stringValue()) |
1089 | return variant->toString() == s->toQString(); |
1090 | return false; |
1091 | } |
1092 | if (!ov) |
1093 | return other.strictlyEquals(other: *this); |
1094 | |
1095 | return RuntimeHelpers::strictEqual(x: *v, y: *ov); |
1096 | } |
1097 | |
1098 | /*! |
1099 | Returns the value of this QJSValue's property with the given \a name. |
1100 | If no such property exists, an undefined QJSValue is returned. |
1101 | |
1102 | If the property is implemented using a getter function (i.e. has the |
1103 | PropertyGetter flag set), calling property() has side-effects on the |
1104 | script engine, since the getter function will be called (possibly |
1105 | resulting in an uncaught script exception). If an exception |
1106 | occurred, property() returns the value that was thrown (typically |
1107 | an \c{Error} object). |
1108 | |
1109 | To access array elements, use the |
1110 | \l {QJSValue::}{setProperty(quint32 arrayIndex, const QJSValue &value)} |
1111 | overload instead. |
1112 | |
1113 | \sa setProperty(), hasProperty(), QJSValueIterator |
1114 | */ |
1115 | QJSValue QJSValue::property(const QString& name) const |
1116 | { |
1117 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1118 | if (!engine) |
1119 | return QJSValue(); |
1120 | |
1121 | QV4::Scope scope(engine); |
1122 | ScopedObject o(scope, QJSValuePrivate::getValue(jsval: this)); |
1123 | if (!o) |
1124 | return QJSValue(); |
1125 | |
1126 | ScopedString s(scope, engine->newString(s: name)); |
1127 | QV4::ScopedValue result(scope, o->get(id: s->toPropertyKey())); |
1128 | if (engine->hasException) |
1129 | result = engine->catchException(); |
1130 | |
1131 | return QJSValue(engine, result->asReturnedValue()); |
1132 | } |
1133 | |
1134 | /*! |
1135 | \overload |
1136 | |
1137 | Returns the property at the given \a arrayIndex. |
1138 | |
1139 | It is possible to access elements in an array in two ways. The first is to |
1140 | use the array index as the property name: |
1141 | |
1142 | \code |
1143 | qDebug() << jsValueArray.property(QLatin1String("4")).toString(); |
1144 | \endcode |
1145 | |
1146 | The second is to use the overload that takes an index: |
1147 | |
1148 | \code |
1149 | qDebug() << jsValueArray.property(4).toString(); |
1150 | \endcode |
1151 | |
1152 | Both of these approaches achieve the same result, except that the latter: |
1153 | |
1154 | \list |
1155 | \li Is easier to use (can use an integer directly) |
1156 | \li Is faster (no conversion to integer) |
1157 | \endlist |
1158 | |
1159 | If this QJSValue is not an Array object, this function behaves |
1160 | as if property() was called with the string representation of \a |
1161 | arrayIndex. |
1162 | */ |
1163 | QJSValue QJSValue::property(quint32 arrayIndex) const |
1164 | { |
1165 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1166 | if (!engine) |
1167 | return QJSValue(); |
1168 | |
1169 | QV4::Scope scope(engine); |
1170 | ScopedObject o(scope, QJSValuePrivate::getValue(jsval: this)); |
1171 | if (!o) |
1172 | return QJSValue(); |
1173 | |
1174 | QV4::ScopedValue result(scope, arrayIndex == UINT_MAX ? o->get(name: engine->id_uintMax()) : o->get(idx: arrayIndex)); |
1175 | if (engine->hasException) |
1176 | engine->catchException(); |
1177 | return QJSValue(engine, result->asReturnedValue()); |
1178 | } |
1179 | |
1180 | /*! |
1181 | Sets the value of this QJSValue's property with the given \a name to |
1182 | the given \a value. |
1183 | |
1184 | If this QJSValue is not an object, this function does nothing. |
1185 | |
1186 | If this QJSValue does not already have a property with name \a name, |
1187 | a new property is created. |
1188 | |
1189 | To modify array elements, use the |
1190 | \l {QJSValue::}{setProperty(quint32 arrayIndex, const QJSValue &value)} |
1191 | overload instead. |
1192 | |
1193 | \sa property(), deleteProperty() |
1194 | */ |
1195 | void QJSValue::setProperty(const QString& name, const QJSValue& value) |
1196 | { |
1197 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1198 | if (!engine) |
1199 | return; |
1200 | Scope scope(engine); |
1201 | |
1202 | ScopedObject o(scope, QJSValuePrivate::getValue(jsval: this)); |
1203 | if (!o) |
1204 | return; |
1205 | |
1206 | if (!QJSValuePrivate::checkEngine(e: engine, jsval: value)) { |
1207 | qWarning(msg: "QJSValue::setProperty(%s) failed: cannot set value created in a different engine" , name.toUtf8().constData()); |
1208 | return; |
1209 | } |
1210 | |
1211 | ScopedString s(scope, engine->newString(s: name)); |
1212 | QV4::ScopedValue v(scope, QJSValuePrivate::convertedToValue(e: engine, jsval: value)); |
1213 | o->put(id: s->toPropertyKey(), v); |
1214 | if (engine->hasException) |
1215 | engine->catchException(); |
1216 | } |
1217 | |
1218 | /*! |
1219 | \overload |
1220 | |
1221 | Sets the property at the given \a arrayIndex to the given \a value. |
1222 | |
1223 | It is possible to modify elements in an array in two ways. The first is to |
1224 | use the array index as the property name: |
1225 | |
1226 | \code |
1227 | jsValueArray.setProperty(QLatin1String("4"), value); |
1228 | \endcode |
1229 | |
1230 | The second is to use the overload that takes an index: |
1231 | |
1232 | \code |
1233 | jsValueArray.setProperty(4, value); |
1234 | \endcode |
1235 | |
1236 | Both of these approaches achieve the same result, except that the latter: |
1237 | |
1238 | \list |
1239 | \li Is easier to use (can use an integer directly) |
1240 | \li Is faster (no conversion to integer) |
1241 | \endlist |
1242 | |
1243 | If this QJSValue is not an Array object, this function behaves |
1244 | as if setProperty() was called with the string representation of \a |
1245 | arrayIndex. |
1246 | |
1247 | \sa {QJSValue::}{property(quint32 arrayIndex)}, {Working With Arrays} |
1248 | */ |
1249 | void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value) |
1250 | { |
1251 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1252 | if (!engine) |
1253 | return; |
1254 | Scope scope(engine); |
1255 | |
1256 | ScopedObject o(scope, QJSValuePrivate::getValue(jsval: this)); |
1257 | if (!o) |
1258 | return; |
1259 | |
1260 | if (!QJSValuePrivate::checkEngine(e: engine, jsval: value)) { |
1261 | qWarning(msg: "QJSValue::setProperty(%d) failed: cannot set value created in a different engine" , arrayIndex); |
1262 | return; |
1263 | } |
1264 | |
1265 | QV4::ScopedValue v(scope, QJSValuePrivate::convertedToValue(e: engine, jsval: value)); |
1266 | PropertyKey id = arrayIndex != UINT_MAX ? PropertyKey::fromArrayIndex(idx: arrayIndex) : engine->id_uintMax()->propertyKey(); |
1267 | o->put(id, v); |
1268 | if (engine->hasException) |
1269 | engine->catchException(); |
1270 | } |
1271 | |
1272 | /*! |
1273 | Attempts to delete this object's property of the given \a name. |
1274 | Returns true if the property was deleted, otherwise returns false. |
1275 | |
1276 | The behavior of this function is consistent with the JavaScript |
1277 | delete operator. In particular: |
1278 | |
1279 | \list |
1280 | \li Non-configurable properties cannot be deleted. |
1281 | \li This function will return true even if this object doesn't |
1282 | have a property of the given \a name (i.e., non-existent |
1283 | properties are "trivially deletable"). |
1284 | \li If this object doesn't have an own property of the given |
1285 | \a name, but an object in the prototype() chain does, the |
1286 | prototype object's property is not deleted, and this function |
1287 | returns true. |
1288 | \endlist |
1289 | |
1290 | \sa setProperty(), hasOwnProperty() |
1291 | */ |
1292 | bool QJSValue::deleteProperty(const QString &name) |
1293 | { |
1294 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1295 | if (!engine) |
1296 | return false; |
1297 | |
1298 | Scope scope(engine); |
1299 | ScopedObject o(scope, QJSValuePrivate::getValue(jsval: this)); |
1300 | if (!o) |
1301 | return false; |
1302 | |
1303 | ScopedString s(scope, engine->newString(s: name)); |
1304 | return o->deleteProperty(id: s->toPropertyKey()); |
1305 | } |
1306 | |
1307 | /*! |
1308 | Returns true if this object has a property of the given \a name, |
1309 | otherwise returns false. |
1310 | |
1311 | \sa property(), hasOwnProperty() |
1312 | */ |
1313 | bool QJSValue::hasProperty(const QString &name) const |
1314 | { |
1315 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1316 | if (!engine) |
1317 | return false; |
1318 | |
1319 | Scope scope(engine); |
1320 | ScopedObject o(scope, QJSValuePrivate::getValue(jsval: this)); |
1321 | if (!o) |
1322 | return false; |
1323 | |
1324 | ScopedString s(scope, engine->newString(s: name)); |
1325 | return o->hasProperty(id: s->toPropertyKey()); |
1326 | } |
1327 | |
1328 | /*! |
1329 | Returns true if this object has an own (not prototype-inherited) |
1330 | property of the given \a name, otherwise returns false. |
1331 | |
1332 | \sa property(), hasProperty() |
1333 | */ |
1334 | bool QJSValue::hasOwnProperty(const QString &name) const |
1335 | { |
1336 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1337 | if (!engine) |
1338 | return false; |
1339 | |
1340 | Scope scope(engine); |
1341 | ScopedObject o(scope, QJSValuePrivate::getValue(jsval: this)); |
1342 | if (!o) |
1343 | return false; |
1344 | |
1345 | ScopedString s(scope, engine->newIdentifier(text: name)); |
1346 | return o->getOwnProperty(id: s->propertyKey()) != Attr_Invalid; |
1347 | } |
1348 | |
1349 | /*! |
1350 | * If this QJSValue is a QObject, returns the QObject pointer |
1351 | * that the QJSValue represents; otherwise, returns \nullptr. |
1352 | * |
1353 | * If the QObject that this QJSValue wraps has been deleted, |
1354 | * this function returns \nullptr (i.e. it is possible for toQObject() |
1355 | * to return \nullptr even when isQObject() returns true). |
1356 | * |
1357 | * \sa isQObject() |
1358 | */ |
1359 | QObject *QJSValue::toQObject() const |
1360 | { |
1361 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1362 | if (!engine) |
1363 | return nullptr; |
1364 | QV4::Scope scope(engine); |
1365 | QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, QJSValuePrivate::getValue(jsval: this)); |
1366 | if (!wrapper) |
1367 | return nullptr; |
1368 | |
1369 | return wrapper->object(); |
1370 | } |
1371 | |
1372 | /*! |
1373 | \since 5.8 |
1374 | |
1375 | * If this QJSValue is a QMetaObject, returns the QMetaObject pointer |
1376 | * that the QJSValue represents; otherwise, returns \nullptr. |
1377 | * |
1378 | * \sa isQMetaObject() |
1379 | */ |
1380 | const QMetaObject *QJSValue::toQMetaObject() const |
1381 | { |
1382 | QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this); |
1383 | if (!engine) |
1384 | return nullptr; |
1385 | QV4::Scope scope(engine); |
1386 | QV4::Scoped<QV4::QMetaObjectWrapper> wrapper(scope, QJSValuePrivate::getValue(jsval: this)); |
1387 | if (!wrapper) |
1388 | return nullptr; |
1389 | |
1390 | return wrapper->metaObject(); |
1391 | } |
1392 | |
1393 | |
1394 | /*! |
1395 | Returns a QDateTime representation of this value, in local time. |
1396 | If this QJSValue is not a date, or the value of the date is NaN |
1397 | (Not-a-Number), an invalid QDateTime is returned. |
1398 | |
1399 | \sa isDate() |
1400 | */ |
1401 | QDateTime QJSValue::toDateTime() const |
1402 | { |
1403 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
1404 | if (val) { |
1405 | QV4::DateObject *date = val->as<DateObject>(); |
1406 | if (date) |
1407 | return date->toQDateTime(); |
1408 | } |
1409 | return QDateTime(); |
1410 | } |
1411 | |
1412 | /*! |
1413 | Returns true if this QJSValue is an object of the Date class; |
1414 | otherwise returns false. |
1415 | */ |
1416 | bool QJSValue::isDate() const |
1417 | { |
1418 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
1419 | return val && val->as<DateObject>(); |
1420 | } |
1421 | |
1422 | /*! |
1423 | Returns true if this QJSValue is an object of the RegExp class; |
1424 | otherwise returns false. |
1425 | */ |
1426 | bool QJSValue::isRegExp() const |
1427 | { |
1428 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
1429 | return val && val->as<RegExpObject>(); |
1430 | } |
1431 | |
1432 | /*! |
1433 | Returns true if this QJSValue is a QObject; otherwise returns |
1434 | false. |
1435 | |
1436 | Note: This function returns true even if the QObject that this |
1437 | QJSValue wraps has been deleted. |
1438 | |
1439 | \sa toQObject(), QJSEngine::newQObject() |
1440 | */ |
1441 | bool QJSValue::isQObject() const |
1442 | { |
1443 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
1444 | return val && val->as<QV4::QObjectWrapper>() != nullptr; |
1445 | } |
1446 | |
1447 | /*! |
1448 | \since 5.8 |
1449 | |
1450 | Returns true if this QJSValue is a QMetaObject; otherwise returns |
1451 | false. |
1452 | |
1453 | \sa toQMetaObject(), QJSEngine::newQMetaObject() |
1454 | */ |
1455 | bool QJSValue::isQMetaObject() const |
1456 | { |
1457 | QV4::Value *val = QJSValuePrivate::getValue(jsval: this); |
1458 | return val && val->as<QV4::QMetaObjectWrapper>() != nullptr; |
1459 | } |
1460 | |
1461 | QT_END_NAMESPACE |
1462 | |