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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtdeclarative/src/qml/jsapi/qjsvalue.cpp