source: trunk/src/script/api/qscriptvalue.cpp@ 769

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

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