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

source code of qtscript/src/script/api/qscriptvalue.cpp