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

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

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 78.1 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::JSValue other = d->engine->scriptValueToJSCValue(prototype);
796
797 // check for cycle
798 JSC::JSValue nextPrototypeValue = other;
799 while (nextPrototypeValue && nextPrototypeValue.isObject()) {
800 JSC::JSObject *nextPrototype = JSC::asObject(nextPrototypeValue);
801 if (nextPrototype == JSC::asObject(d->jscValue)) {
802 qWarning("QScriptValue::setPrototype() failed: cyclic prototype value");
803 return;
804 }
805 nextPrototypeValue = nextPrototype->prototype();
806 }
807 JSC::asObject(d->jscValue)->setPrototype(other);
808}
809
810/*!
811 \internal
812*/
813QScriptValue QScriptValue::scope() const
814{
815 Q_D(const QScriptValue);
816 if (!d || !d->isObject())
817 return QScriptValue();
818 // ### make hidden property
819 return d->property(QLatin1String("__qt_scope__"), QScriptValue::ResolveLocal);
820}
821
822/*!
823 \internal
824*/
825void QScriptValue::setScope(const QScriptValue &scope)
826{
827 Q_D(QScriptValue);
828 if (!d || !d->isObject())
829 return;
830 if (scope.isValid() && QScriptValuePrivate::getEngine(scope)
831 && (QScriptValuePrivate::getEngine(scope) != d->engine)) {
832 qWarning("QScriptValue::setScope() failed: "
833 "cannot set a scope object created in "
834 "a different engine");
835 return;
836 }
837 JSC::JSValue other = d->engine->scriptValueToJSCValue(scope);
838 JSC::ExecState *exec = d->engine->currentFrame;
839 JSC::Identifier id = JSC::Identifier(exec, "__qt_scope__");
840 if (!scope.isValid()) {
841 JSC::asObject(d->jscValue)->removeDirect(id);
842 } else {
843 // ### make hidden property
844 JSC::asObject(d->jscValue)->putDirect(id, other);
845 }
846}
847
848/*!
849 Returns true if this QScriptValue is an instance of
850 \a other; otherwise returns false.
851
852 This QScriptValue is considered to be an instance of \a other if
853 \a other is a function and the value of the \c{prototype}
854 property of \a other is in the prototype chain of this
855 QScriptValue.
856*/
857bool QScriptValue::instanceOf(const QScriptValue &other) const
858{
859 Q_D(const QScriptValue);
860 if (!d || !d->isObject() || !other.isObject())
861 return false;
862 if (QScriptValuePrivate::getEngine(other) != d->engine) {
863 qWarning("QScriptValue::instanceof: "
864 "cannot perform operation on a value created in "
865 "a different engine");
866 return false;
867 }
868 JSC::JSValue jscProto = d->engine->scriptValueToJSCValue(other.property(QLatin1String("prototype")));
869 if (!jscProto)
870 jscProto = JSC::jsUndefined();
871 JSC::ExecState *exec = d->engine->currentFrame;
872 JSC::JSValue jscOther = d->engine->scriptValueToJSCValue(other);
873 return JSC::asObject(jscOther)->hasInstance(exec, d->jscValue, jscProto);
874}
875
876// ### move
877
878namespace QScript
879{
880
881enum Type {
882 Undefined,
883 Null,
884 Boolean,
885 String,
886 Number,
887 Object
888};
889
890static Type type(const QScriptValue &v)
891{
892 if (v.isUndefined())
893 return Undefined;
894 else if (v.isNull())
895 return Null;
896 else if (v.isBoolean())
897 return Boolean;
898 else if (v.isString())
899 return String;
900 else if (v.isNumber())
901 return Number;
902 Q_ASSERT(v.isObject());
903 return Object;
904}
905
906QScriptValue ToPrimitive(const QScriptValue &object, JSC::PreferredPrimitiveType hint = JSC::NoPreference)
907{
908 Q_ASSERT(object.isObject());
909 QScriptValuePrivate *pp = QScriptValuePrivate::get(object);
910 Q_ASSERT(pp->engine != 0);
911 JSC::ExecState *exec = pp->engine->currentFrame;
912 JSC::JSValue savedException;
913 QScriptValuePrivate::saveException(exec, &savedException);
914 JSC::JSValue result = JSC::asObject(pp->jscValue)->toPrimitive(exec, hint);
915 QScriptValuePrivate::restoreException(exec, savedException);
916 return pp->engine->scriptValueFromJSCValue(result);
917}
918
919static bool IsNumerical(const QScriptValue &value)
920{
921 return value.isNumber() || value.isBool();
922}
923
924static bool LessThan(QScriptValue lhs, QScriptValue rhs)
925{
926 if (type(lhs) == type(rhs)) {
927 switch (type(lhs)) {
928 case Undefined:
929 case Null:
930 return false;
931
932 case Number:
933#if defined Q_CC_MSVC && !defined Q_CC_MSVC_NET
934 if (qIsNaN(lhs.toNumber()) || qIsNaN(rhs.toNumber()))
935 return false;
936#endif
937 return lhs.toNumber() < rhs.toNumber();
938
939 case Boolean:
940 return lhs.toBool() < rhs.toBool();
941
942 case String:
943 return lhs.toString() < rhs.toString();
944
945 case Object:
946 break;
947 } // switch
948 }
949
950 if (lhs.isObject())
951 lhs = ToPrimitive(lhs, JSC::PreferNumber);
952
953 if (rhs.isObject())
954 rhs = ToPrimitive(rhs, JSC::PreferNumber);
955
956 if (lhs.isString() && rhs.isString())
957 return lhs.toString() < rhs.toString();
958
959 qsreal n1 = lhs.toNumber();
960 qsreal n2 = rhs.toNumber();
961#if defined Q_CC_MSVC && !defined Q_CC_MSVC_NET
962 if (qIsNaN(n1) || qIsNaN(n2))
963 return false;
964#endif
965 return n1 < n2;
966}
967
968static bool Equals(QScriptValue lhs, QScriptValue rhs)
969{
970 if (type(lhs) == type(rhs)) {
971 switch (type(lhs)) {
972 case QScript::Undefined:
973 case QScript::Null:
974 return true;
975
976 case QScript::Number:
977 return lhs.toNumber() == rhs.toNumber();
978
979 case QScript::Boolean:
980 return lhs.toBool() == rhs.toBool();
981
982 case QScript::String:
983 return lhs.toString() == rhs.toString();
984
985 case QScript::Object:
986 if (lhs.isVariant())
987 return lhs.strictlyEquals(rhs) || (lhs.toVariant() == rhs.toVariant());
988#ifndef QT_NO_QOBJECT
989 else if (lhs.isQObject())
990 return (lhs.strictlyEquals(rhs)) || (lhs.toQObject() == rhs.toQObject());
991#endif
992 else
993 return lhs.strictlyEquals(rhs);
994 }
995 }
996
997 if (lhs.isNull() && rhs.isUndefined())
998 return true;
999
1000 else if (lhs.isUndefined() && rhs.isNull())
1001 return true;
1002
1003 else if (IsNumerical(lhs) && rhs.isString())
1004 return lhs.toNumber() == rhs.toNumber();
1005
1006 else if (lhs.isString() && IsNumerical(rhs))
1007 return lhs.toNumber() == rhs.toNumber();
1008
1009 else if (lhs.isBool())
1010 return Equals(lhs.toNumber(), rhs);
1011
1012 else if (rhs.isBool())
1013 return Equals(lhs, rhs.toNumber());
1014
1015 else if (lhs.isObject() && !rhs.isNull()) {
1016 lhs = ToPrimitive(lhs);
1017
1018 if (lhs.isValid() && !lhs.isObject())
1019 return Equals(lhs, rhs);
1020 }
1021
1022 else if (rhs.isObject() && ! lhs.isNull()) {
1023 rhs = ToPrimitive(rhs);
1024 if (rhs.isValid() && !rhs.isObject())
1025 return Equals(lhs, rhs);
1026 }
1027
1028 return false;
1029}
1030
1031} // namespace QScript
1032
1033/*!
1034 Returns true if this QScriptValue is less than \a other, otherwise
1035 returns false. The comparison follows the behavior described in
1036 \l{ECMA-262} section 11.8.5, "The Abstract Relational Comparison
1037 Algorithm".
1038
1039 Note that if this QScriptValue or the \a other value are objects,
1040 calling this function has side effects on the script engine, since
1041 the engine will call the object's valueOf() function (and possibly
1042 toString()) in an attempt to convert the object to a primitive value
1043 (possibly resulting in an uncaught script exception).
1044
1045 \sa equals()
1046*/
1047bool QScriptValue::lessThan(const QScriptValue &other) const
1048{
1049 Q_D(const QScriptValue);
1050 // no equivalent function in JSC? There's a jsLess() in VM/Machine.cpp
1051 if (!isValid() || !other.isValid())
1052 return false;
1053 if (QScriptValuePrivate::getEngine(other) && d->engine
1054 && (QScriptValuePrivate::getEngine(other) != d->engine)) {
1055 qWarning("QScriptValue::lessThan: "
1056 "cannot compare to a value created in "
1057 "a different engine");
1058 return false;
1059 }
1060 return QScript::LessThan(*this, other);
1061}
1062
1063/*!
1064 Returns true if this QScriptValue is equal to \a other, otherwise
1065 returns false. The comparison follows the behavior described in
1066 \l{ECMA-262} section 11.9.3, "The Abstract Equality Comparison
1067 Algorithm".
1068
1069 This function can return true even if the type of this QScriptValue
1070 is different from the type of the \a other value; i.e. the
1071 comparison is not strict. For example, comparing the number 9 to
1072 the string "9" returns true; comparing an undefined value to a null
1073 value returns true; comparing a \c{Number} object whose primitive
1074 value is 6 to a \c{String} object whose primitive value is "6"
1075 returns true; and comparing the number 1 to the boolean value
1076 \c{true} returns true. If you want to perform a comparison
1077 without such implicit value conversion, use strictlyEquals().
1078
1079 Note that if this QScriptValue or the \a other value are objects,
1080 calling this function has side effects on the script engine, since
1081 the engine will call the object's valueOf() function (and possibly
1082 toString()) in an attempt to convert the object to a primitive value
1083 (possibly resulting in an uncaught script exception).
1084
1085 \sa strictlyEquals(), lessThan()
1086*/
1087bool QScriptValue::equals(const QScriptValue &other) const
1088{
1089 Q_D(const QScriptValue);
1090 if (!d || !other.d_ptr)
1091 return (d_ptr == other.d_ptr);
1092 if (QScriptValuePrivate::getEngine(other) && d->engine
1093 && (QScriptValuePrivate::getEngine(other) != d->engine)) {
1094 qWarning("QScriptValue::equals: "
1095 "cannot compare to a value created in "
1096 "a different engine");
1097 return false;
1098 }
1099 if (d->isJSC() && other.d_ptr->isJSC()) {
1100 QScriptEnginePrivate *eng_p = d->engine;
1101 if (!eng_p)
1102 eng_p = other.d_ptr->engine;
1103 if (eng_p) {
1104 JSC::ExecState *exec = eng_p->currentFrame;
1105 JSC::JSValue savedException;
1106 QScriptValuePrivate::saveException(exec, &savedException);
1107 bool result = JSC::JSValue::equal(exec, d->jscValue, other.d_ptr->jscValue);
1108 QScriptValuePrivate::restoreException(exec, savedException);
1109 return result;
1110 }
1111 }
1112 return QScript::Equals(*this, other);
1113}
1114
1115/*!
1116 Returns true if this QScriptValue is equal to \a other using strict
1117 comparison (no conversion), otherwise returns false. The comparison
1118 follows the behavior described in \l{ECMA-262} section 11.9.6, "The
1119 Strict Equality Comparison Algorithm".
1120
1121 If the type of this QScriptValue is different from the type of the
1122 \a other value, this function returns false. If the types are equal,
1123 the result depends on the type, as shown in the following table:
1124
1125 \table
1126 \header \o Type \o Result
1127 \row \o Undefined \o true
1128 \row \o Null \o true
1129 \row \o Boolean \o true if both values are true, false otherwise
1130 \row \o Number \o false if either value is NaN (Not-a-Number); true if values are equal, false otherwise
1131 \row \o String \o true if both values are exactly the same sequence of characters, false otherwise
1132 \row \o Object \o true if both values refer to the same object, false otherwise
1133 \endtable
1134
1135 \sa equals()
1136*/
1137bool QScriptValue::strictlyEquals(const QScriptValue &other) const
1138{
1139 Q_D(const QScriptValue);
1140 if (!d || !other.d_ptr)
1141 return (d_ptr == other.d_ptr);
1142 if (QScriptValuePrivate::getEngine(other) && d->engine
1143 && (QScriptValuePrivate::getEngine(other) != d->engine)) {
1144 qWarning("QScriptValue::strictlyEquals: "
1145 "cannot compare to a value created in "
1146 "a different engine");
1147 return false;
1148 }
1149
1150 if (d->type != other.d_ptr->type) {
1151 if (d->type == QScriptValuePrivate::JavaScriptCore)
1152 return JSC::JSValue::strictEqual(d->jscValue, d->engine->scriptValueToJSCValue(other));
1153 else if (other.d_ptr->type == QScriptValuePrivate::JavaScriptCore)
1154 return JSC::JSValue::strictEqual(other.d_ptr->engine->scriptValueToJSCValue(*this), other.d_ptr->jscValue);
1155
1156 return false;
1157 }
1158 switch (d->type) {
1159 case QScriptValuePrivate::JavaScriptCore:
1160 return JSC::JSValue::strictEqual(d->jscValue, other.d_ptr->jscValue);
1161 case QScriptValuePrivate::Number:
1162 return (d->numberValue == other.d_ptr->numberValue);
1163 case QScriptValuePrivate::String:
1164 return (d->stringValue == other.d_ptr->stringValue);
1165 }
1166 return false;
1167}
1168
1169/*!
1170 Returns the string value of this QScriptValue, as defined in
1171 \l{ECMA-262} section 9.8, "ToString".
1172
1173 Note that if this QScriptValue is an object, calling this function
1174 has side effects on the script engine, since the engine will call
1175 the object's toString() function (and possibly valueOf()) in an
1176 attempt to convert the object to a primitive value (possibly
1177 resulting in an uncaught script exception).
1178
1179 \sa isString()
1180*/
1181QString QScriptValue::toString() const
1182{
1183 Q_D(const QScriptValue);
1184 if (!d)
1185 return QString();
1186 switch (d->type) {
1187 case QScriptValuePrivate::JavaScriptCore: {
1188 JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
1189 JSC::JSValue savedException;
1190 QScriptValuePrivate::saveException(exec, &savedException);
1191 JSC::UString str = d->jscValue.toString(exec);
1192 if (exec && exec->hadException() && !str.size()) {
1193 JSC::JSValue savedException2;
1194 QScriptValuePrivate::saveException(exec, &savedException2);
1195 str = savedException2.toString(exec);
1196 QScriptValuePrivate::restoreException(exec, savedException2);
1197 }
1198 if (savedException)
1199 QScriptValuePrivate::restoreException(exec, savedException);
1200 return str;
1201 }
1202 case QScriptValuePrivate::Number:
1203 return JSC::UString::from(d->numberValue);
1204 case QScriptValuePrivate::String:
1205 return d->stringValue;
1206 }
1207 return QString();
1208}
1209
1210/*!
1211 Returns the number value of this QScriptValue, as defined in
1212 \l{ECMA-262} section 9.3, "ToNumber".
1213
1214 Note that if this QScriptValue is an object, calling this function
1215 has side effects on the script engine, since the engine will call
1216 the object's valueOf() function (and possibly toString()) in an
1217 attempt to convert the object to a primitive value (possibly
1218 resulting in an uncaught script exception).
1219
1220 \sa isNumber(), toInteger(), toInt32(), toUInt32(), toUInt16()
1221*/
1222qsreal QScriptValue::toNumber() const
1223{
1224 Q_D(const QScriptValue);
1225 if (!d)
1226 return 0;
1227 switch (d->type) {
1228 case QScriptValuePrivate::JavaScriptCore: {
1229 JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
1230 JSC::JSValue savedException;
1231 QScriptValuePrivate::saveException(exec, &savedException);
1232 qsreal result = d->jscValue.toNumber(exec);
1233 QScriptValuePrivate::restoreException(exec, savedException);
1234 return result;
1235 }
1236 case QScriptValuePrivate::Number:
1237 return d->numberValue;
1238 case QScriptValuePrivate::String:
1239 return ((JSC::UString)d->stringValue).toDouble();
1240 }
1241 return 0;
1242}
1243
1244/*!
1245 \obsolete
1246
1247 Use toBool() instead.
1248*/
1249bool QScriptValue::toBoolean() const
1250{
1251 Q_D(const QScriptValue);
1252 if (!d)
1253 return false;
1254 switch (d->type) {
1255 case QScriptValuePrivate::JavaScriptCore: {
1256 JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
1257 JSC::JSValue savedException;
1258 QScriptValuePrivate::saveException(exec, &savedException);
1259 bool result = d->jscValue.toBoolean(exec);
1260 QScriptValuePrivate::restoreException(exec, savedException);
1261 return result;
1262 }
1263 case QScriptValuePrivate::Number:
1264 return (d->numberValue != 0) && !qIsNaN(d->numberValue);
1265 case QScriptValuePrivate::String:
1266 return (!d->stringValue.isEmpty());
1267 }
1268 return false;
1269}
1270
1271/*!
1272 \since 4.5
1273
1274 Returns the boolean value of this QScriptValue, using the conversion
1275 rules described in \l{ECMA-262} section 9.2, "ToBoolean".
1276
1277 Note that if this QScriptValue is an object, calling this function
1278 has side effects on the script engine, since the engine will call
1279 the object's valueOf() function (and possibly toString()) in an
1280 attempt to convert the object to a primitive value (possibly
1281 resulting in an uncaught script exception).
1282
1283 \sa isBool()
1284*/
1285bool QScriptValue::toBool() const
1286{
1287 Q_D(const QScriptValue);
1288 if (!d)
1289 return false;
1290 switch (d->type) {
1291 case QScriptValuePrivate::JavaScriptCore: {
1292 JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
1293 JSC::JSValue savedException;
1294 QScriptValuePrivate::saveException(exec, &savedException);
1295 bool result = d->jscValue.toBoolean(exec);
1296 QScriptValuePrivate::restoreException(exec, savedException);
1297 return result;
1298 }
1299 case QScriptValuePrivate::Number:
1300 return (d->numberValue != 0) && !qIsNaN(d->numberValue);
1301 case QScriptValuePrivate::String:
1302 return (!d->stringValue.isEmpty());
1303 }
1304 return false;
1305}
1306
1307/*!
1308 Returns the signed 32-bit integer value of this QScriptValue, using
1309 the conversion rules described in \l{ECMA-262} section 9.5, "ToInt32".
1310
1311 Note that if this QScriptValue is an object, calling this function
1312 has side effects on the script engine, since the engine will call
1313 the object's valueOf() function (and possibly toString()) in an
1314 attempt to convert the object to a primitive value (possibly
1315 resulting in an uncaught script exception).
1316
1317 \sa toNumber(), toUInt32()
1318*/
1319qint32 QScriptValue::toInt32() const
1320{
1321 Q_D(const QScriptValue);
1322 if (!d)
1323 return 0;
1324 switch (d->type) {
1325 case QScriptValuePrivate::JavaScriptCore: {
1326 JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
1327 JSC::JSValue savedException;
1328 QScriptValuePrivate::saveException(exec, &savedException);
1329 qint32 result = d->jscValue.toInt32(exec);
1330 QScriptValuePrivate::restoreException(exec, savedException);
1331 return result;
1332 }
1333 case QScriptValuePrivate::Number:
1334 return QScript::ToInt32(d->numberValue);
1335 case QScriptValuePrivate::String:
1336 return QScript::ToInt32(((JSC::UString)d->stringValue).toDouble());
1337 }
1338 return 0;
1339}
1340
1341/*!
1342 Returns the unsigned 32-bit integer value of this QScriptValue, using
1343 the conversion rules described in \l{ECMA-262} section 9.6, "ToUint32".
1344
1345 Note that if this QScriptValue is an object, calling this function
1346 has side effects on the script engine, since the engine will call
1347 the object's valueOf() function (and possibly toString()) in an
1348 attempt to convert the object to a primitive value (possibly
1349 resulting in an uncaught script exception).
1350
1351 \sa toNumber(), toInt32()
1352*/
1353quint32 QScriptValue::toUInt32() const
1354{
1355 Q_D(const QScriptValue);
1356 if (!d)
1357 return 0;
1358 switch (d->type) {
1359 case QScriptValuePrivate::JavaScriptCore: {
1360 JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
1361 JSC::JSValue savedException;
1362 QScriptValuePrivate::saveException(exec, &savedException);
1363 quint32 result = d->jscValue.toUInt32(exec);
1364 QScriptValuePrivate::restoreException(exec, savedException);
1365 return result;
1366 }
1367 case QScriptValuePrivate::Number:
1368 return QScript::ToUint32(d->numberValue);
1369 case QScriptValuePrivate::String:
1370 return QScript::ToUint32(((JSC::UString)d->stringValue).toDouble());
1371 }
1372 return 0;
1373}
1374
1375/*!
1376 Returns the unsigned 16-bit integer value of this QScriptValue, using
1377 the conversion rules described in \l{ECMA-262} section 9.7, "ToUint16".
1378
1379 Note that if this QScriptValue is an object, calling this function
1380 has side effects on the script engine, since the engine will call
1381 the object's valueOf() function (and possibly toString()) in an
1382 attempt to convert the object to a primitive value (possibly
1383 resulting in an uncaught script exception).
1384
1385 \sa toNumber()
1386*/
1387quint16 QScriptValue::toUInt16() const
1388{
1389 Q_D(const QScriptValue);
1390 if (!d)
1391 return 0;
1392 switch (d->type) {
1393 case QScriptValuePrivate::JavaScriptCore: {
1394 // ### no equivalent function in JSC
1395 return QScript::ToUint16(toNumber());
1396 }
1397 case QScriptValuePrivate::Number:
1398 return QScript::ToUint16(d->numberValue);
1399 case QScriptValuePrivate::String:
1400 return QScript::ToUint16(((JSC::UString)d->stringValue).toDouble());
1401 }
1402 return 0;
1403}
1404
1405/*!
1406 Returns the integer value of this QScriptValue, using the conversion
1407 rules described in \l{ECMA-262} section 9.4, "ToInteger".
1408
1409 Note that if this QScriptValue is an object, calling this function
1410 has side effects on the script engine, since the engine will call
1411 the object's valueOf() function (and possibly toString()) in an
1412 attempt to convert the object to a primitive value (possibly
1413 resulting in an uncaught script exception).
1414
1415 \sa toNumber()
1416*/
1417qsreal QScriptValue::toInteger() const
1418{
1419 Q_D(const QScriptValue);
1420 if (!d)
1421 return 0;
1422 switch (d->type) {
1423 case QScriptValuePrivate::JavaScriptCore: {
1424 JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
1425 JSC::JSValue savedException;
1426 QScriptValuePrivate::saveException(exec, &savedException);
1427 qsreal result = d->jscValue.toInteger(exec);
1428 QScriptValuePrivate::restoreException(exec, savedException);
1429 return result;
1430 }
1431 case QScriptValuePrivate::Number:
1432 return QScript::ToInteger(d->numberValue);
1433 case QScriptValuePrivate::String:
1434 return QScript::ToInteger(((JSC::UString)d->stringValue).toDouble());
1435 }
1436 return 0;
1437}
1438
1439/*!
1440 Returns the QVariant value of this QScriptValue, if it can be
1441 converted to a QVariant; otherwise returns an invalid QVariant.
1442 The conversion is performed according to the following table:
1443
1444 \table
1445 \header \o Input Type \o Result
1446 \row \o Undefined \o An invalid QVariant.
1447 \row \o Null \o An invalid QVariant.
1448 \row \o Boolean \o A QVariant containing the value of the boolean.
1449 \row \o Number \o A QVariant containing the value of the number.
1450 \row \o String \o A QVariant containing the value of the string.
1451 \row \o QVariant Object \o The result is the QVariant value of the object (no conversion).
1452 \row \o QObject Object \o A QVariant containing a pointer to the QObject.
1453 \row \o Date Object \o A QVariant containing the date value (toDateTime()).
1454 \row \o RegExp Object \o A QVariant containing the regular expression value (toRegExp()).
1455 \row \o Array Object \o The array is converted to a QVariantList.
1456 \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.
1457 \endtable
1458
1459 \sa isVariant()
1460*/
1461QVariant QScriptValue::toVariant() const
1462{
1463 Q_D(const QScriptValue);
1464 if (!d)
1465 return QVariant();
1466 switch (d->type) {
1467 case QScriptValuePrivate::JavaScriptCore:
1468 if (isObject()) {
1469 if (isVariant())
1470 return d->variantValue();
1471#ifndef QT_NO_QOBJECT
1472 else if (isQObject())
1473 return qVariantFromValue(toQObject());
1474#endif
1475 else if (isDate())
1476 return QVariant(toDateTime());
1477#ifndef QT_NO_REGEXP
1478 else if (isRegExp())
1479 return QVariant(toRegExp());
1480#endif
1481 else if (isArray())
1482 return QScriptEnginePrivate::variantListFromArray(*this);
1483 else if (QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(*this))
1484 return dc->toVariant(QScriptDeclarativeClass::object(*this));
1485 // try to convert to primitive
1486 JSC::ExecState *exec = d->engine->currentFrame;
1487 JSC::JSValue savedException;
1488 QScriptValuePrivate::saveException(exec, &savedException);
1489 JSC::JSValue prim = d->jscValue.toPrimitive(exec);
1490 QScriptValuePrivate::restoreException(exec, savedException);
1491 if (!prim.isObject())
1492 return d->engine->scriptValueFromJSCValue(prim).toVariant();
1493 } else if (isNumber()) {
1494 return QVariant(toNumber());
1495 } else if (isString()) {
1496 return QVariant(toString());
1497 } else if (isBool()) {
1498 return QVariant(toBool());
1499 }
1500 return QVariant();
1501 case QScriptValuePrivate::Number:
1502 return QVariant(d->numberValue);
1503 case QScriptValuePrivate::String:
1504 return QVariant(d->stringValue);
1505 }
1506 return QVariant();
1507}
1508
1509/*!
1510 \obsolete
1511
1512 This function is obsolete; use QScriptEngine::toObject() instead.
1513*/
1514QScriptValue QScriptValue::toObject() const
1515{
1516 Q_D(const QScriptValue);
1517 if (!d || !d->engine)
1518 return QScriptValue();
1519 return engine()->toObject(*this);
1520}
1521
1522/*!
1523 Returns a QDateTime representation of this value, in local time.
1524 If this QScriptValue is not a date, or the value of the date is NaN
1525 (Not-a-Number), an invalid QDateTime is returned.
1526
1527 \sa isDate()
1528*/
1529QDateTime QScriptValue::toDateTime() const
1530{
1531 Q_D(const QScriptValue);
1532 if (!isDate())
1533 return QDateTime();
1534 qsreal t = static_cast<JSC::DateInstance*>(JSC::asObject(d->jscValue))->internalNumber();
1535 return QScript::ToDateTime(t, Qt::LocalTime);
1536}
1537
1538#ifndef QT_NO_REGEXP
1539/*!
1540 Returns the QRegExp representation of this value.
1541 If this QScriptValue is not a regular expression, an empty
1542 QRegExp is returned.
1543
1544 \sa isRegExp()
1545*/
1546QRegExp QScriptValue::toRegExp() const
1547{
1548 Q_D(const QScriptValue);
1549 if (!isRegExp())
1550 return QRegExp();
1551 QString pattern = d->property(QLatin1String("source"), QScriptValue::ResolvePrototype).toString();
1552 Qt::CaseSensitivity kase = Qt::CaseSensitive;
1553 if (d->property(QLatin1String("ignoreCase"), QScriptValue::ResolvePrototype).toBool())
1554 kase = Qt::CaseInsensitive;
1555 return QRegExp(pattern, kase, QRegExp::RegExp2);
1556}
1557#endif // QT_NO_REGEXP
1558
1559/*!
1560 If this QScriptValue is a QObject, returns the QObject pointer
1561 that the QScriptValue represents; otherwise, returns 0.
1562
1563 If the QObject that this QScriptValue wraps has been deleted,
1564 this function returns 0 (i.e. it is possible for toQObject()
1565 to return 0 even when isQObject() returns true).
1566
1567 \sa isQObject()
1568*/
1569QObject *QScriptValue::toQObject() const
1570{
1571 Q_D(const QScriptValue);
1572 if (isQObject()) {
1573 QScriptObject *object = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
1574 QScriptObjectDelegate *delegate = object->delegate();
1575 if (delegate->type() == QScriptObjectDelegate::DeclarativeClassObject)
1576 return static_cast<QScript::DeclarativeObjectDelegate*>(delegate)->scriptClass()->toQObject(QScriptDeclarativeClass::object(*this));
1577 return static_cast<QScript::QObjectDelegate*>(delegate)->value();
1578 } else if (isVariant()) {
1579 QVariant var = toVariant();
1580 int type = var.userType();
1581 if ((type == QMetaType::QObjectStar) || (type == QMetaType::QWidgetStar))
1582 return *reinterpret_cast<QObject* const *>(var.constData());
1583 }
1584 return 0;
1585}
1586
1587/*!
1588 If this QScriptValue is a QMetaObject, returns the QMetaObject pointer
1589 that the QScriptValue represents; otherwise, returns 0.
1590
1591 \sa isQMetaObject()
1592*/
1593const QMetaObject *QScriptValue::toQMetaObject() const
1594{
1595 Q_D(const QScriptValue);
1596 if (isQMetaObject())
1597 return static_cast<QScript::QMetaObjectWrapperObject*>(JSC::asObject(d->jscValue))->value();
1598 return 0;
1599}
1600
1601/*!
1602 Sets the value of this QScriptValue's property with the given \a name to
1603 the given \a value.
1604
1605 If this QScriptValue is not an object, this function does nothing.
1606
1607 If this QScriptValue does not already have a property with name \a name,
1608 a new property is created; the given \a flags then specify how this
1609 property may be accessed by script code.
1610
1611 If \a value is invalid, the property is removed.
1612
1613 If the property is implemented using a setter function (i.e. has the
1614 PropertySetter flag set), calling setProperty() has side-effects on
1615 the script engine, since the setter function will be called with the
1616 given \a value as argument (possibly resulting in an uncaught script
1617 exception).
1618
1619 Note that you cannot specify custom getter or setter functions for
1620 built-in properties, such as the \c{length} property of Array objects
1621 or meta properties of QObject objects.
1622
1623 \sa property()
1624*/
1625
1626void QScriptValue::setProperty(const QString &name, const QScriptValue &value,
1627 const PropertyFlags &flags)
1628{
1629 Q_D(QScriptValue);
1630 if (!d || !d->isObject())
1631 return;
1632 JSC::ExecState *exec = d->engine->currentFrame;
1633 d->setProperty(JSC::Identifier(exec, name), value, flags);
1634}
1635
1636/*!
1637 Returns the value of this QScriptValue's property with the given \a name,
1638 using the given \a mode to resolve the property.
1639
1640 If no such property exists, an invalid QScriptValue is returned.
1641
1642 If the property is implemented using a getter function (i.e. has the
1643 PropertyGetter flag set), calling property() has side-effects on the
1644 script engine, since the getter function will be called (possibly
1645 resulting in an uncaught script exception). If an exception
1646 occurred, property() returns the value that was thrown (typically
1647 an \c{Error} object).
1648
1649 \sa setProperty(), propertyFlags(), QScriptValueIterator
1650*/
1651QScriptValue QScriptValue::property(const QString &name,
1652 const ResolveFlags &mode) const
1653{
1654 Q_D(const QScriptValue);
1655 if (!d || !d->isObject())
1656 return QScriptValue();
1657 return d->property(name, mode);
1658}
1659
1660/*!
1661 \overload
1662
1663 Returns the property at the given \a arrayIndex, using the given \a
1664 mode to resolve the property.
1665
1666 This function is provided for convenience and performance when
1667 working with array objects.
1668
1669 If this QScriptValue is not an Array object, this function behaves
1670 as if property() was called with the string representation of \a
1671 arrayIndex.
1672*/
1673QScriptValue QScriptValue::property(quint32 arrayIndex,
1674 const ResolveFlags &mode) const
1675{
1676 Q_D(const QScriptValue);
1677 if (!d || !d->isObject())
1678 return QScriptValue();
1679 return d->property(arrayIndex, mode);
1680}
1681
1682/*!
1683 \overload
1684
1685 Sets the property at the given \a arrayIndex to the given \a value.
1686
1687 This function is provided for convenience and performance when
1688 working with array objects.
1689
1690 If this QScriptValue is not an Array object, this function behaves
1691 as if setProperty() was called with the string representation of \a
1692 arrayIndex.
1693*/
1694void QScriptValue::setProperty(quint32 arrayIndex, const QScriptValue &value,
1695 const PropertyFlags &flags)
1696{
1697 Q_D(QScriptValue);
1698 if (!d || !d->isObject())
1699 return;
1700 if (QScriptValuePrivate::getEngine(value)
1701 && (QScriptValuePrivate::getEngine(value) != d->engine)) {
1702 qWarning("QScriptValue::setProperty() failed: "
1703 "cannot set value created in a different engine");
1704 return;
1705 }
1706 JSC::ExecState *exec = d->engine->currentFrame;
1707 JSC::JSValue jscValue = d->engine->scriptValueToJSCValue(value);
1708 if (!jscValue) {
1709 JSC::asObject(d->jscValue)->deleteProperty(exec, arrayIndex, /*checkDontDelete=*/false);
1710 } else {
1711 if ((flags & QScriptValue::PropertyGetter) || (flags & QScriptValue::PropertySetter)) {
1712 // fall back to string-based setProperty(), since there is no
1713 // JSC::JSObject::defineGetter(unsigned)
1714 d->setProperty(JSC::Identifier::from(exec, arrayIndex), value, flags);
1715 } else {
1716 if (flags != QScriptValue::KeepExistingFlags) {
1717// if (JSC::asObject(d->jscValue)->hasOwnProperty(exec, arrayIndex))
1718// JSC::asObject(d->jscValue)->deleteProperty(exec, arrayIndex);
1719 unsigned attribs = 0;
1720 if (flags & QScriptValue::ReadOnly)
1721 attribs |= JSC::ReadOnly;
1722 if (flags & QScriptValue::SkipInEnumeration)
1723 attribs |= JSC::DontEnum;
1724 if (flags & QScriptValue::Undeletable)
1725 attribs |= JSC::DontDelete;
1726 attribs |= flags & QScriptValue::UserRange;
1727 JSC::asObject(d->jscValue)->putWithAttributes(exec, arrayIndex, jscValue, attribs);
1728 } else {
1729 JSC::asObject(d->jscValue)->put(exec, arrayIndex, jscValue);
1730 }
1731 }
1732 }
1733}
1734
1735/*!
1736 \since 4.4
1737
1738 Returns the value of this QScriptValue's property with the given \a name,
1739 using the given \a mode to resolve the property.
1740
1741 This overload of property() is useful when you need to look up the
1742 same property repeatedly, since the lookup can be performed faster
1743 when the name is represented as an interned string.
1744
1745 \sa QScriptEngine::toStringHandle(), setProperty()
1746*/
1747QScriptValue QScriptValue::property(const QScriptString &name,
1748 const ResolveFlags &mode) const
1749{
1750 Q_D(const QScriptValue);
1751 if (!d || !d->isObject() || !QScriptStringPrivate::isValid(name))
1752 return QScriptValue();
1753 return d->property(name.d_ptr->identifier, mode);
1754}
1755
1756/*!
1757 \since 4.4
1758
1759 Sets the value of this QScriptValue's property with the given \a
1760 name to the given \a value. The given \a flags specify how this
1761 property may be accessed by script code.
1762
1763 This overload of setProperty() is useful when you need to set the
1764 same property repeatedly, since the operation can be performed
1765 faster when the name is represented as an interned string.
1766
1767 \sa QScriptEngine::toStringHandle()
1768*/
1769void QScriptValue::setProperty(const QScriptString &name,
1770 const QScriptValue &value,
1771 const PropertyFlags &flags)
1772{
1773 Q_D(QScriptValue);
1774 if (!d || !d->isObject() || !QScriptStringPrivate::isValid(name))
1775 return;
1776 d->setProperty(name.d_ptr->identifier, value, flags);
1777}
1778
1779/*!
1780 Returns the flags of the property with the given \a name, using the
1781 given \a mode to resolve the property.
1782
1783 \sa property()
1784*/
1785QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QString &name,
1786 const ResolveFlags &mode) const
1787{
1788 Q_D(const QScriptValue);
1789 if (!d || !d->isObject())
1790 return 0;
1791 JSC::ExecState *exec = d->engine->currentFrame;
1792 return d->propertyFlags(JSC::Identifier(exec, name), mode);
1793
1794}
1795
1796/*!
1797 \since 4.4
1798
1799 Returns the flags of the property with the given \a name, using the
1800 given \a mode to resolve the property.
1801
1802 \sa property()
1803*/
1804QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QScriptString &name,
1805 const ResolveFlags &mode) const
1806{
1807 Q_D(const QScriptValue);
1808 if (!d || !d->isObject() || !QScriptStringPrivate::isValid(name))
1809 return 0;
1810 return d->propertyFlags(name.d_ptr->identifier, mode);
1811}
1812
1813/*!
1814 Calls this QScriptValue as a function, using \a thisObject as
1815 the `this' object in the function call, and passing \a args
1816 as arguments to the function. Returns the value returned from
1817 the function.
1818
1819 If this QScriptValue is not a function, call() does nothing
1820 and returns an invalid QScriptValue.
1821
1822 Note that if \a thisObject is not an object, the global object
1823 (see \l{QScriptEngine::globalObject()}) will be used as the
1824 `this' object.
1825
1826 Calling call() can cause an exception to occur in the script engine;
1827 in that case, call() returns the value that was thrown (typically an
1828 \c{Error} object). You can call
1829 QScriptEngine::hasUncaughtException() to determine if an exception
1830 occurred.
1831
1832 \snippet doc/src/snippets/code/src_script_qscriptvalue.cpp 2
1833
1834 \sa construct()
1835*/
1836QScriptValue QScriptValue::call(const QScriptValue &thisObject,
1837 const QScriptValueList &args)
1838{
1839 Q_D(const QScriptValue);
1840 if (!d || !d->isJSC())
1841 return QScriptValue();
1842 JSC::JSValue callee = d->jscValue;
1843 JSC::CallData callData;
1844 JSC::CallType callType = callee.getCallData(callData);
1845 if (callType == JSC::CallTypeNone)
1846 return QScriptValue();
1847
1848 if (QScriptValuePrivate::getEngine(thisObject)
1849 && (QScriptValuePrivate::getEngine(thisObject) != d->engine)) {
1850 qWarning("QScriptValue::call() failed: "
1851 "cannot call function with thisObject created in "
1852 "a different engine");
1853 return QScriptValue();
1854 }
1855
1856 JSC::ExecState *exec = d->engine->currentFrame;
1857
1858 JSC::JSValue jscThisObject = d->engine->scriptValueToJSCValue(thisObject);
1859 if (!jscThisObject || !jscThisObject.isObject())
1860 jscThisObject = d->engine->globalObject();
1861
1862 QVarLengthArray<JSC::JSValue, 8> argsVector(args.size());
1863 for (int i = 0; i < args.size(); ++i) {
1864 const QScriptValue &arg = args.at(i);
1865 if (!arg.isValid()) {
1866 argsVector[i] = JSC::jsUndefined();
1867 } else if (QScriptValuePrivate::getEngine(arg)
1868 && (QScriptValuePrivate::getEngine(arg) != d->engine)) {
1869 qWarning("QScriptValue::call() failed: "
1870 "cannot call function with argument created in "
1871 "a different engine");
1872 return QScriptValue();
1873 } else {
1874 argsVector[i] = d->engine->scriptValueToJSCValue(arg);
1875 }
1876 }
1877 JSC::ArgList jscArgs(argsVector.data(), argsVector.size());
1878
1879 JSC::JSValue savedException;
1880 QScriptValuePrivate::saveException(exec, &savedException);
1881 JSC::JSValue result = JSC::call(exec, callee, callType, callData, jscThisObject, jscArgs);
1882 if (exec->hadException()) {
1883 result = exec->exception();
1884 } else {
1885 QScriptValuePrivate::restoreException(exec, savedException);
1886 }
1887 return d->engine->scriptValueFromJSCValue(result);
1888}
1889
1890/*!
1891 Calls this QScriptValue as a function, using \a thisObject as
1892 the `this' object in the function call, and passing \a arguments
1893 as arguments to the function. Returns the value returned from
1894 the function.
1895
1896 If this QScriptValue is not a function, call() does nothing
1897 and returns an invalid QScriptValue.
1898
1899 \a arguments can be an arguments object, an array, null or
1900 undefined; any other type will cause a TypeError to be thrown.
1901
1902 Note that if \a thisObject is not an object, the global object
1903 (see \l{QScriptEngine::globalObject()}) will be used as the
1904 `this' object.
1905
1906 One common usage of this function is to forward native function
1907 calls to another function:
1908
1909 \snippet doc/src/snippets/code/src_script_qscriptvalue.cpp 3
1910
1911 \sa construct(), QScriptContext::argumentsObject()
1912*/
1913QScriptValue QScriptValue::call(const QScriptValue &thisObject,
1914 const QScriptValue &arguments)
1915{
1916 Q_D(QScriptValue);
1917 if (!d || !d->isJSC())
1918 return QScriptValue();
1919 JSC::JSValue callee = d->jscValue;
1920 JSC::CallData callData;
1921 JSC::CallType callType = callee.getCallData(callData);
1922 if (callType == JSC::CallTypeNone)
1923 return QScriptValue();
1924
1925 if (QScriptValuePrivate::getEngine(thisObject)
1926 && (QScriptValuePrivate::getEngine(thisObject) != d->engine)) {
1927 qWarning("QScriptValue::call() failed: "
1928 "cannot call function with thisObject created in "
1929 "a different engine");
1930 return QScriptValue();
1931 }
1932
1933 JSC::ExecState *exec = d->engine->currentFrame;
1934
1935 JSC::JSValue jscThisObject = d->engine->scriptValueToJSCValue(thisObject);
1936 if (!jscThisObject || !jscThisObject.isObject())
1937 jscThisObject = d->engine->globalObject();
1938
1939 JSC::JSValue array = d->engine->scriptValueToJSCValue(arguments);
1940 // copied from runtime/FunctionPrototype.cpp, functionProtoFuncApply()
1941 JSC::MarkedArgumentBuffer applyArgs;
1942 if (!array.isUndefinedOrNull()) {
1943 if (!array.isObject()) {
1944 return d->engine->scriptValueFromJSCValue(JSC::throwError(exec, JSC::TypeError));
1945 }
1946 if (JSC::asObject(array)->classInfo() == &JSC::Arguments::info)
1947 JSC::asArguments(array)->fillArgList(exec, applyArgs);
1948 else if (JSC::isJSArray(&exec->globalData(), array))
1949 JSC::asArray(array)->fillArgList(exec, applyArgs);
1950 else if (JSC::asObject(array)->inherits(&JSC::JSArray::info)) {
1951 unsigned length = JSC::asArray(array)->get(exec, exec->propertyNames().length).toUInt32(exec);
1952 for (unsigned i = 0; i < length; ++i)
1953 applyArgs.append(JSC::asArray(array)->get(exec, i));
1954 } else {
1955 Q_ASSERT_X(false, Q_FUNC_INFO, "implement me");
1956// return JSC::throwError(exec, JSC::TypeError);
1957 }
1958 }
1959
1960 JSC::JSValue savedException;
1961 QScriptValuePrivate::saveException(exec, &savedException);
1962 JSC::JSValue result = JSC::call(exec, callee, callType, callData, jscThisObject, applyArgs);
1963 if (exec->hadException()) {
1964 result = exec->exception();
1965 } else {
1966 QScriptValuePrivate::restoreException(exec, savedException);
1967 }
1968 return d->engine->scriptValueFromJSCValue(result);
1969}
1970
1971/*!
1972 Creates a new \c{Object} and calls this QScriptValue as a
1973 constructor, using the created object as the `this' object and
1974 passing \a args as arguments. If the return value from the
1975 constructor call is an object, then that object is returned;
1976 otherwise the default constructed object is returned.
1977
1978 If this QScriptValue is not a function, construct() does nothing
1979 and returns an invalid QScriptValue.
1980
1981 Calling construct() can cause an exception to occur in the script
1982 engine; in that case, construct() returns the value that was thrown
1983 (typically an \c{Error} object). You can call
1984 QScriptEngine::hasUncaughtException() to determine if an exception
1985 occurred.
1986
1987 \sa call(), QScriptEngine::newObject()
1988*/
1989QScriptValue QScriptValue::construct(const QScriptValueList &args)
1990{
1991 Q_D(const QScriptValue);
1992 if (!d || !d->isJSC())
1993 return QScriptValue();
1994 JSC::JSValue callee = d->jscValue;
1995 JSC::ConstructData constructData;
1996 JSC::ConstructType constructType = callee.getConstructData(constructData);
1997 if (constructType == JSC::ConstructTypeNone)
1998 return QScriptValue();
1999
2000 JSC::ExecState *exec = d->engine->currentFrame;
2001
2002 QVarLengthArray<JSC::JSValue, 8> argsVector(args.size());
2003 for (int i = 0; i < args.size(); ++i) {
2004 if (!args.at(i).isValid())
2005 argsVector[i] = JSC::jsUndefined();
2006 else
2007 argsVector[i] = d->engine->scriptValueToJSCValue(args.at(i));
2008 }
2009
2010 JSC::ArgList jscArgs(argsVector.data(), argsVector.size());
2011
2012 JSC::JSValue savedException;
2013 QScriptValuePrivate::saveException(exec, &savedException);
2014 JSC::JSObject *result = JSC::construct(exec, callee, constructType, constructData, jscArgs);
2015 if (exec->hadException()) {
2016 result = JSC::asObject(exec->exception());
2017 } else {
2018 QScriptValuePrivate::restoreException(exec, savedException);
2019 }
2020 return d->engine->scriptValueFromJSCValue(result);
2021}
2022
2023/*!
2024 Creates a new \c{Object} and calls this QScriptValue as a
2025 constructor, using the created object as the `this' object and
2026 passing \a arguments as arguments. If the return value from the
2027 constructor call is an object, then that object is returned;
2028 otherwise the default constructed object is returned.
2029
2030 If this QScriptValue is not a function, construct() does nothing
2031 and returns an invalid QScriptValue.
2032
2033 \a arguments can be an arguments object, an array, null or
2034 undefined. Any other type will cause a TypeError to be thrown.
2035
2036 \sa call(), QScriptEngine::newObject(), QScriptContext::argumentsObject()
2037*/
2038QScriptValue QScriptValue::construct(const QScriptValue &arguments)
2039{
2040 Q_D(QScriptValue);
2041 if (!d || !d->isJSC())
2042 return QScriptValue();
2043 JSC::JSValue callee = d->jscValue;
2044 JSC::ConstructData constructData;
2045 JSC::ConstructType constructType = callee.getConstructData(constructData);
2046 if (constructType == JSC::ConstructTypeNone)
2047 return QScriptValue();
2048
2049 JSC::ExecState *exec = d->engine->currentFrame;
2050
2051 JSC::JSValue array = d->engine->scriptValueToJSCValue(arguments);
2052 // copied from runtime/FunctionPrototype.cpp, functionProtoFuncApply()
2053 JSC::MarkedArgumentBuffer applyArgs;
2054 if (!array.isUndefinedOrNull()) {
2055 if (!array.isObject()) {
2056 return d->engine->scriptValueFromJSCValue(JSC::throwError(exec, JSC::TypeError, "Arguments must be an array"));
2057 }
2058 if (JSC::asObject(array)->classInfo() == &JSC::Arguments::info)
2059 JSC::asArguments(array)->fillArgList(exec, applyArgs);
2060 else if (JSC::isJSArray(&exec->globalData(), array))
2061 JSC::asArray(array)->fillArgList(exec, applyArgs);
2062 else if (JSC::asObject(array)->inherits(&JSC::JSArray::info)) {
2063 unsigned length = JSC::asArray(array)->get(exec, exec->propertyNames().length).toUInt32(exec);
2064 for (unsigned i = 0; i < length; ++i)
2065 applyArgs.append(JSC::asArray(array)->get(exec, i));
2066 } else {
2067 return d->engine->scriptValueFromJSCValue(JSC::throwError(exec, JSC::TypeError, "Arguments must be an array"));
2068 }
2069 }
2070
2071 JSC::JSValue savedException;
2072 QScriptValuePrivate::saveException(exec, &savedException);
2073 JSC::JSObject *result = JSC::construct(exec, callee, constructType, constructData, applyArgs);
2074 if (exec->hadException()) {
2075 if (exec->exception().isObject())
2076 result = JSC::asObject(exec->exception());
2077 } else {
2078 QScriptValuePrivate::restoreException(exec, savedException);
2079 }
2080 return d->engine->scriptValueFromJSCValue(result);
2081}
2082
2083/*!
2084 Returns the QScriptEngine that created this QScriptValue,
2085 or 0 if this QScriptValue is invalid or the value is not
2086 associated with a particular engine.
2087*/
2088QScriptEngine *QScriptValue::engine() const
2089{
2090 Q_D(const QScriptValue);
2091 if (!d)
2092 return 0;
2093 return QScriptEnginePrivate::get(d->engine);
2094}
2095
2096/*!
2097 \obsolete
2098
2099 Use isBool() instead.
2100*/
2101bool QScriptValue::isBoolean() const
2102{
2103 Q_D(const QScriptValue);
2104 return d && d->isJSC() && d->jscValue.isBoolean();
2105}
2106
2107/*!
2108 \since 4.5
2109
2110 Returns true if this QScriptValue is of the primitive type Boolean;
2111 otherwise returns false.
2112
2113 \sa toBool()
2114*/
2115bool QScriptValue::isBool() const
2116{
2117 Q_D(const QScriptValue);
2118 return d && d->isJSC() && d->jscValue.isBoolean();
2119}
2120
2121/*!
2122 Returns true if this QScriptValue is of the primitive type Number;
2123 otherwise returns false.
2124
2125 \sa toNumber()
2126*/
2127bool QScriptValue::isNumber() const
2128{
2129 Q_D(const QScriptValue);
2130 if (!d)
2131 return false;
2132 switch (d->type) {
2133 case QScriptValuePrivate::JavaScriptCore:
2134 return d->jscValue.isNumber();
2135 case QScriptValuePrivate::Number:
2136 return true;
2137 case QScriptValuePrivate::String:
2138 return false;
2139 }
2140 return false;
2141}
2142
2143/*!
2144 Returns true if this QScriptValue is of the primitive type String;
2145 otherwise returns false.
2146
2147 \sa toString()
2148*/
2149bool QScriptValue::isString() const
2150{
2151 Q_D(const QScriptValue);
2152 if (!d)
2153 return false;
2154 switch (d->type) {
2155 case QScriptValuePrivate::JavaScriptCore:
2156 return d->jscValue.isString();
2157 case QScriptValuePrivate::Number:
2158 return false;
2159 case QScriptValuePrivate::String:
2160 return true;
2161 }
2162 return false;
2163}
2164
2165/*!
2166 Returns true if this QScriptValue is a function; otherwise returns
2167 false.
2168
2169 \sa call()
2170*/
2171bool QScriptValue::isFunction() const
2172{
2173 Q_D(const QScriptValue);
2174 if (!d || !d->isJSC())
2175 return false;
2176 return QScript::isFunction(d->jscValue);
2177}
2178
2179/*!
2180 Returns true if this QScriptValue is of the primitive type Null;
2181 otherwise returns false.
2182
2183 \sa QScriptEngine::nullValue()
2184*/
2185bool QScriptValue::isNull() const
2186{
2187 Q_D(const QScriptValue);
2188 return d && d->isJSC() && d->jscValue.isNull();
2189}
2190
2191/*!
2192 Returns true if this QScriptValue is of the primitive type Undefined;
2193 otherwise returns false.
2194
2195 \sa QScriptEngine::undefinedValue()
2196*/
2197bool QScriptValue::isUndefined() const
2198{
2199 Q_D(const QScriptValue);
2200 return d && d->isJSC() && d->jscValue.isUndefined();
2201}
2202
2203/*!
2204 Returns true if this QScriptValue is of the Object type; otherwise
2205 returns false.
2206
2207 Note that function values, variant values, and QObject values are
2208 objects, so this function returns true for such values.
2209
2210 \sa toObject(), QScriptEngine::newObject()
2211*/
2212bool QScriptValue::isObject() const
2213{
2214 Q_D(const QScriptValue);
2215 return d && d->isObject();
2216}
2217
2218/*!
2219 Returns true if this QScriptValue is a variant value;
2220 otherwise returns false.
2221
2222 \sa toVariant(), QScriptEngine::newVariant()
2223*/
2224bool QScriptValue::isVariant() const
2225{
2226 Q_D(const QScriptValue);
2227 if (!d || !d->isJSC() || !d->jscValue.inherits(&QScriptObject::info))
2228 return false;
2229 QScriptObject *object = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
2230 QScriptObjectDelegate *delegate = object->delegate();
2231 return (delegate && (delegate->type() == QScriptObjectDelegate::Variant));
2232}
2233
2234/*!
2235 Returns true if this QScriptValue is a QObject; otherwise returns
2236 false.
2237
2238 Note: This function returns true even if the QObject that this
2239 QScriptValue wraps has been deleted.
2240
2241 \sa toQObject(), QScriptEngine::newQObject()
2242*/
2243bool QScriptValue::isQObject() const
2244{
2245 Q_D(const QScriptValue);
2246 if (!d || !d->isJSC() || !d->jscValue.inherits(&QScriptObject::info))
2247 return false;
2248 QScriptObject *object = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
2249 QScriptObjectDelegate *delegate = object->delegate();
2250 return (delegate && (delegate->type() == QScriptObjectDelegate::QtObject ||
2251 (delegate->type() == QScriptObjectDelegate::DeclarativeClassObject &&
2252 static_cast<QScript::DeclarativeObjectDelegate*>(delegate)->scriptClass()->isQObject())));
2253}
2254
2255/*!
2256 Returns true if this QScriptValue is a QMetaObject; otherwise returns
2257 false.
2258
2259 \sa toQMetaObject(), QScriptEngine::newQMetaObject()
2260*/
2261bool QScriptValue::isQMetaObject() const
2262{
2263 Q_D(const QScriptValue);
2264 if (!d || !d->isObject())
2265 return false;
2266 return JSC::asObject(d->jscValue)->inherits(&QScript::QMetaObjectWrapperObject::info);
2267}
2268
2269/*!
2270 Returns true if this QScriptValue is valid; otherwise returns
2271 false.
2272*/
2273bool QScriptValue::isValid() const
2274{
2275 Q_D(const QScriptValue);
2276 return d && (!d->isJSC() || !!d->jscValue);
2277}
2278
2279/*!
2280 \since 4.4
2281
2282 Returns the internal data of this QScriptValue object. QtScript uses
2283 this property to store the primitive value of Date, String, Number
2284 and Boolean objects. For other types of object, custom data may be
2285 stored using setData().
2286*/
2287QScriptValue QScriptValue::data() const
2288{
2289 Q_D(const QScriptValue);
2290 if (!d || !d->isObject())
2291 return QScriptValue();
2292 if (d->jscValue.inherits(&QScriptObject::info)) {
2293 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
2294 return d->engine->scriptValueFromJSCValue(scriptObject->data());
2295 } else {
2296 // ### make hidden property
2297 return d->property(QLatin1String("__qt_data__"), QScriptValue::ResolveLocal);
2298 }
2299}
2300
2301/*!
2302 \since 4.4
2303
2304 Sets the internal \a data of this QScriptValue object. You can use
2305 this function to set object-specific data that won't be directly
2306 accessible to scripts, but may be retrieved in C++ using the data()
2307 function.
2308*/
2309void QScriptValue::setData(const QScriptValue &data)
2310{
2311 Q_D(QScriptValue);
2312 if (!d || !d->isObject())
2313 return;
2314 JSC::JSValue other = d->engine->scriptValueToJSCValue(data);
2315 if (d->jscValue.inherits(&QScriptObject::info)) {
2316 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
2317 scriptObject->setData(other);
2318 } else {
2319 JSC::ExecState *exec = d->engine->currentFrame;
2320 JSC::Identifier id = JSC::Identifier(exec, "__qt_data__");
2321 if (!data.isValid()) {
2322 JSC::asObject(d->jscValue)->removeDirect(id);
2323 } else {
2324 // ### make hidden property
2325 JSC::asObject(d->jscValue)->putDirect(id, other);
2326 }
2327 }
2328}
2329
2330/*!
2331 \since 4.4
2332
2333 Returns the custom script class that this script object is an
2334 instance of, or 0 if the object is not of a custom class.
2335
2336 \sa setScriptClass()
2337*/
2338QScriptClass *QScriptValue::scriptClass() const
2339{
2340 Q_D(const QScriptValue);
2341 if (!d || !d->isJSC() || !d->jscValue.inherits(&QScriptObject::info))
2342 return 0;
2343 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
2344 QScriptObjectDelegate *delegate = scriptObject->delegate();
2345 if (!delegate || (delegate->type() != QScriptObjectDelegate::ClassObject))
2346 return 0;
2347 return static_cast<QScript::ClassObjectDelegate*>(delegate)->scriptClass();
2348}
2349
2350/*!
2351 \since 4.4
2352
2353 Sets the custom script class of this script object to \a scriptClass.
2354 This can be used to "promote" a plain script object (e.g. created
2355 by the "new" operator in a script, or by QScriptEngine::newObject() in C++)
2356 to an object of a custom type.
2357
2358 If \a scriptClass is 0, the object will be demoted to a plain
2359 script object.
2360
2361 \sa scriptClass(), setData()
2362*/
2363void QScriptValue::setScriptClass(QScriptClass *scriptClass)
2364{
2365 Q_D(QScriptValue);
2366 if (!d || !d->isObject())
2367 return;
2368 if (!d->jscValue.inherits(&QScriptObject::info)) {
2369 qWarning("QScriptValue::setScriptClass() failed: "
2370 "cannot change class of non-QScriptObject");
2371 return;
2372 }
2373 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
2374 if (!scriptClass) {
2375 scriptObject->setDelegate(0);
2376 } else {
2377 QScriptObjectDelegate *delegate = scriptObject->delegate();
2378 if (!delegate || (delegate->type() != QScriptObjectDelegate::ClassObject)) {
2379 delegate = new QScript::ClassObjectDelegate(scriptClass);
2380 scriptObject->setDelegate(delegate);
2381 }
2382 static_cast<QScript::ClassObjectDelegate*>(delegate)->setScriptClass(scriptClass);
2383 }
2384}
2385
2386/*!
2387 \internal
2388
2389 Returns the ID of this object, or -1 if this QScriptValue is not an
2390 object.
2391
2392 \sa QScriptEngine::objectById()
2393*/
2394qint64 QScriptValue::objectId() const
2395{
2396 return d_ptr?d_ptr->objectId():-1;
2397}
2398QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.