util/src/script/api/qscriptvalue.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     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 
       
   188 QT_BEGIN_NAMESPACE
       
   189 
       
   190 namespace QScript
       
   191 {
       
   192 
       
   193 static const qsreal D32 = 4294967296.0;
       
   194 
       
   195 qint32 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 
       
   215 quint32 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 
       
   231 quint16 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 
       
   249 qsreal 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 
       
   263 QScriptValue 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 
       
   283 QScriptValue 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 
       
   297 void 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 
       
   375 QScriptValue::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 
       
   409 QVariant &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 
       
   417 void 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 
       
   425 void QScriptValuePrivate::detachFromEngine()
       
   426 {
       
   427     if (isJSC())
       
   428         jscValue = JSC::JSValue();
       
   429     engine = 0;
       
   430 }
       
   431 
       
   432 /*!
       
   433   \internal
       
   434 */
       
   435 QScriptValue::QScriptValue(QScriptValuePrivate *d)
       
   436     : d_ptr(d)
       
   437 {
       
   438 }
       
   439 
       
   440 /*!
       
   441   Constructs an invalid QScriptValue.
       
   442 */
       
   443 QScriptValue::QScriptValue()
       
   444     : d_ptr(0)
       
   445 {
       
   446 }
       
   447 
       
   448 /*!
       
   449   Destroys this QScriptValue.
       
   450 */
       
   451 QScriptValue::~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 */
       
   462 QScriptValue::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 */
       
   473 QScriptValue::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 */
       
   494 QScriptValue::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 */
       
   507 QScriptValue::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  */
       
   524 QScriptValue::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 */
       
   541 QScriptValue::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 */
       
   558 QScriptValue::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
       
   578 QScriptValue::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 */
       
   595 QScriptValue::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 */
       
   613 QScriptValue::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 */
       
   624 QScriptValue::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 */
       
   635 QScriptValue::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 */
       
   646 QScriptValue::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 */
       
   657 QScriptValue::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 */
       
   668 QScriptValue::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
       
   681 QScriptValue::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 */
       
   695 QScriptValue &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 */
       
   707 bool 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 */
       
   721 bool 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 */
       
   735 bool 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 */
       
   749 bool 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 */
       
   764 QScriptValue 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 */
       
   783 void 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 */
       
   813 QScriptValue 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 */
       
   825 void 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 */
       
   857 bool 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 
       
   878 namespace QScript
       
   879 {
       
   880 
       
   881 enum Type {
       
   882     Undefined,
       
   883     Null,
       
   884     Boolean,
       
   885     String,
       
   886     Number,
       
   887     Object
       
   888 };
       
   889 
       
   890 static 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 
       
   906 QScriptValue 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 
       
   919 static bool IsNumerical(const QScriptValue &value)
       
   920 {
       
   921     return value.isNumber() || value.isBool();
       
   922 }
       
   923 
       
   924 static 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 
       
   968 static 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 */
       
  1047 bool 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 */
       
  1087 bool 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 */
       
  1137 bool 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             QScriptEnginePrivate *eng_p = d->engine ? d->engine : other.d_ptr->engine;
       
  1153             if (eng_p)
       
  1154                 return JSC::JSValue::strictEqual(d->jscValue, eng_p->scriptValueToJSCValue(other));
       
  1155         } else if (other.d_ptr->type == QScriptValuePrivate::JavaScriptCore) {
       
  1156             QScriptEnginePrivate *eng_p = other.d_ptr->engine ? other.d_ptr->engine : d->engine;
       
  1157             if (eng_p)
       
  1158                 return JSC::JSValue::strictEqual(eng_p->scriptValueToJSCValue(*this), other.d_ptr->jscValue);
       
  1159         }
       
  1160 
       
  1161         return false;
       
  1162     }
       
  1163     switch (d->type) {
       
  1164     case QScriptValuePrivate::JavaScriptCore:
       
  1165         return JSC::JSValue::strictEqual(d->jscValue, other.d_ptr->jscValue);
       
  1166     case QScriptValuePrivate::Number:
       
  1167         return (d->numberValue == other.d_ptr->numberValue);
       
  1168     case QScriptValuePrivate::String:
       
  1169         return (d->stringValue == other.d_ptr->stringValue);
       
  1170     }
       
  1171     return false;
       
  1172 }
       
  1173 
       
  1174 /*!
       
  1175   Returns the string value of this QScriptValue, as defined in
       
  1176   \l{ECMA-262} section 9.8, "ToString".
       
  1177 
       
  1178   Note that if this QScriptValue is an object, calling this function
       
  1179   has side effects on the script engine, since the engine will call
       
  1180   the object's toString() function (and possibly valueOf()) in an
       
  1181   attempt to convert the object to a primitive value (possibly
       
  1182   resulting in an uncaught script exception).
       
  1183 
       
  1184   \sa isString()
       
  1185 */
       
  1186 QString QScriptValue::toString() const
       
  1187 {
       
  1188     Q_D(const QScriptValue);
       
  1189     if (!d)
       
  1190         return QString();
       
  1191     switch (d->type) {
       
  1192     case QScriptValuePrivate::JavaScriptCore: {
       
  1193         JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
       
  1194         JSC::JSValue savedException;
       
  1195         QScriptValuePrivate::saveException(exec, &savedException);
       
  1196         JSC::UString str = d->jscValue.toString(exec);
       
  1197         if (exec && exec->hadException() && !str.size()) {
       
  1198             JSC::JSValue savedException2;
       
  1199             QScriptValuePrivate::saveException(exec, &savedException2);
       
  1200             str = savedException2.toString(exec);
       
  1201             QScriptValuePrivate::restoreException(exec, savedException2);
       
  1202         }
       
  1203         if (savedException)
       
  1204             QScriptValuePrivate::restoreException(exec, savedException);
       
  1205         return str;
       
  1206     }
       
  1207     case QScriptValuePrivate::Number:
       
  1208         return JSC::UString::from(d->numberValue);
       
  1209     case QScriptValuePrivate::String:
       
  1210         return d->stringValue;
       
  1211     }
       
  1212     return QString();
       
  1213 }
       
  1214 
       
  1215 /*!
       
  1216   Returns the number value of this QScriptValue, as defined in
       
  1217   \l{ECMA-262} section 9.3, "ToNumber".
       
  1218 
       
  1219   Note that if this QScriptValue is an object, calling this function
       
  1220   has side effects on the script engine, since the engine will call
       
  1221   the object's valueOf() function (and possibly toString()) in an
       
  1222   attempt to convert the object to a primitive value (possibly
       
  1223   resulting in an uncaught script exception).
       
  1224 
       
  1225   \sa isNumber(), toInteger(), toInt32(), toUInt32(), toUInt16()
       
  1226 */
       
  1227 qsreal QScriptValue::toNumber() const
       
  1228 {
       
  1229     Q_D(const QScriptValue);
       
  1230     if (!d)
       
  1231         return 0;
       
  1232     switch (d->type) {
       
  1233     case QScriptValuePrivate::JavaScriptCore: {
       
  1234         JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
       
  1235         JSC::JSValue savedException;
       
  1236         QScriptValuePrivate::saveException(exec, &savedException);
       
  1237         qsreal result = d->jscValue.toNumber(exec);
       
  1238         QScriptValuePrivate::restoreException(exec, savedException);
       
  1239         return result;
       
  1240     }
       
  1241     case QScriptValuePrivate::Number:
       
  1242         return d->numberValue;
       
  1243     case QScriptValuePrivate::String:
       
  1244         return ((JSC::UString)d->stringValue).toDouble();
       
  1245     }
       
  1246     return 0;
       
  1247 }
       
  1248 
       
  1249 /*!
       
  1250   \obsolete
       
  1251 
       
  1252   Use toBool() instead.
       
  1253 */
       
  1254 bool QScriptValue::toBoolean() const
       
  1255 {
       
  1256     Q_D(const QScriptValue);
       
  1257     if (!d)
       
  1258         return false;
       
  1259     switch (d->type) {
       
  1260     case QScriptValuePrivate::JavaScriptCore: {
       
  1261         JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
       
  1262         JSC::JSValue savedException;
       
  1263         QScriptValuePrivate::saveException(exec, &savedException);
       
  1264         bool result = d->jscValue.toBoolean(exec);
       
  1265         QScriptValuePrivate::restoreException(exec, savedException);
       
  1266         return result;
       
  1267     }
       
  1268     case QScriptValuePrivate::Number:
       
  1269         return (d->numberValue != 0) && !qIsNaN(d->numberValue);
       
  1270     case QScriptValuePrivate::String:
       
  1271         return (!d->stringValue.isEmpty());
       
  1272     }
       
  1273     return false;
       
  1274 }
       
  1275 
       
  1276 /*!
       
  1277   \since 4.5
       
  1278 
       
  1279   Returns the boolean value of this QScriptValue, using the conversion
       
  1280   rules described in \l{ECMA-262} section 9.2, "ToBoolean".
       
  1281 
       
  1282   Note that if this QScriptValue is an object, calling this function
       
  1283   has side effects on the script engine, since the engine will call
       
  1284   the object's valueOf() function (and possibly toString()) in an
       
  1285   attempt to convert the object to a primitive value (possibly
       
  1286   resulting in an uncaught script exception).
       
  1287 
       
  1288   \sa isBool()
       
  1289 */
       
  1290 bool QScriptValue::toBool() const
       
  1291 {
       
  1292     Q_D(const QScriptValue);
       
  1293     if (!d)
       
  1294         return false;
       
  1295     switch (d->type) {
       
  1296     case QScriptValuePrivate::JavaScriptCore: {
       
  1297         JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
       
  1298         JSC::JSValue savedException;
       
  1299         QScriptValuePrivate::saveException(exec, &savedException);
       
  1300         bool result = d->jscValue.toBoolean(exec);
       
  1301         QScriptValuePrivate::restoreException(exec, savedException);
       
  1302         return result;
       
  1303     }
       
  1304     case QScriptValuePrivate::Number:
       
  1305         return (d->numberValue != 0) && !qIsNaN(d->numberValue);
       
  1306     case QScriptValuePrivate::String:
       
  1307         return (!d->stringValue.isEmpty());
       
  1308     }
       
  1309     return false;
       
  1310 }
       
  1311 
       
  1312 /*!
       
  1313   Returns the signed 32-bit integer value of this QScriptValue, using
       
  1314   the conversion rules described in \l{ECMA-262} section 9.5, "ToInt32".
       
  1315 
       
  1316   Note that if this QScriptValue is an object, calling this function
       
  1317   has side effects on the script engine, since the engine will call
       
  1318   the object's valueOf() function (and possibly toString()) in an
       
  1319   attempt to convert the object to a primitive value (possibly
       
  1320   resulting in an uncaught script exception).
       
  1321 
       
  1322   \sa toNumber(), toUInt32()
       
  1323 */
       
  1324 qint32 QScriptValue::toInt32() const
       
  1325 {
       
  1326     Q_D(const QScriptValue);
       
  1327     if (!d)
       
  1328         return 0;
       
  1329     switch (d->type) {
       
  1330     case QScriptValuePrivate::JavaScriptCore: {
       
  1331         JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
       
  1332         JSC::JSValue savedException;
       
  1333         QScriptValuePrivate::saveException(exec, &savedException);
       
  1334         qint32 result = d->jscValue.toInt32(exec);
       
  1335         QScriptValuePrivate::restoreException(exec, savedException);
       
  1336         return result;
       
  1337     }
       
  1338     case QScriptValuePrivate::Number:
       
  1339         return QScript::ToInt32(d->numberValue);
       
  1340     case QScriptValuePrivate::String:
       
  1341         return QScript::ToInt32(((JSC::UString)d->stringValue).toDouble());
       
  1342     }
       
  1343     return 0;
       
  1344 }
       
  1345 
       
  1346 /*!
       
  1347   Returns the unsigned 32-bit integer value of this QScriptValue, using
       
  1348   the conversion rules described in \l{ECMA-262} section 9.6, "ToUint32".
       
  1349 
       
  1350   Note that if this QScriptValue is an object, calling this function
       
  1351   has side effects on the script engine, since the engine will call
       
  1352   the object's valueOf() function (and possibly toString()) in an
       
  1353   attempt to convert the object to a primitive value (possibly
       
  1354   resulting in an uncaught script exception).
       
  1355 
       
  1356   \sa toNumber(), toInt32()
       
  1357 */
       
  1358 quint32 QScriptValue::toUInt32() const
       
  1359 {
       
  1360     Q_D(const QScriptValue);
       
  1361     if (!d)
       
  1362         return 0;
       
  1363     switch (d->type) {
       
  1364     case QScriptValuePrivate::JavaScriptCore: {
       
  1365         JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
       
  1366         JSC::JSValue savedException;
       
  1367         QScriptValuePrivate::saveException(exec, &savedException);
       
  1368         quint32 result = d->jscValue.toUInt32(exec);
       
  1369         QScriptValuePrivate::restoreException(exec, savedException);
       
  1370         return result;
       
  1371     }
       
  1372     case QScriptValuePrivate::Number:
       
  1373         return QScript::ToUint32(d->numberValue);
       
  1374     case QScriptValuePrivate::String:
       
  1375         return QScript::ToUint32(((JSC::UString)d->stringValue).toDouble());
       
  1376     }
       
  1377     return 0;
       
  1378 }
       
  1379 
       
  1380 /*!
       
  1381   Returns the unsigned 16-bit integer value of this QScriptValue, using
       
  1382   the conversion rules described in \l{ECMA-262} section 9.7, "ToUint16".
       
  1383 
       
  1384   Note that if this QScriptValue is an object, calling this function
       
  1385   has side effects on the script engine, since the engine will call
       
  1386   the object's valueOf() function (and possibly toString()) in an
       
  1387   attempt to convert the object to a primitive value (possibly
       
  1388   resulting in an uncaught script exception).
       
  1389 
       
  1390   \sa toNumber()
       
  1391 */
       
  1392 quint16 QScriptValue::toUInt16() const
       
  1393 {
       
  1394     Q_D(const QScriptValue);
       
  1395     if (!d)
       
  1396         return 0;
       
  1397     switch (d->type) {
       
  1398     case QScriptValuePrivate::JavaScriptCore: {
       
  1399         // ### no equivalent function in JSC
       
  1400         return QScript::ToUint16(toNumber());
       
  1401     }
       
  1402     case QScriptValuePrivate::Number:
       
  1403         return QScript::ToUint16(d->numberValue);
       
  1404     case QScriptValuePrivate::String:
       
  1405         return QScript::ToUint16(((JSC::UString)d->stringValue).toDouble());
       
  1406     }
       
  1407     return 0;
       
  1408 }
       
  1409 
       
  1410 /*!
       
  1411   Returns the integer value of this QScriptValue, using the conversion
       
  1412   rules described in \l{ECMA-262} section 9.4, "ToInteger".
       
  1413 
       
  1414   Note that if this QScriptValue is an object, calling this function
       
  1415   has side effects on the script engine, since the engine will call
       
  1416   the object's valueOf() function (and possibly toString()) in an
       
  1417   attempt to convert the object to a primitive value (possibly
       
  1418   resulting in an uncaught script exception).
       
  1419 
       
  1420   \sa toNumber()
       
  1421 */
       
  1422 qsreal QScriptValue::toInteger() const
       
  1423 {
       
  1424     Q_D(const QScriptValue);
       
  1425     if (!d)
       
  1426         return 0;
       
  1427     switch (d->type) {
       
  1428     case QScriptValuePrivate::JavaScriptCore: {
       
  1429         JSC::ExecState *exec = d->engine ? d->engine->currentFrame : 0;
       
  1430         JSC::JSValue savedException;
       
  1431         QScriptValuePrivate::saveException(exec, &savedException);
       
  1432         qsreal result = d->jscValue.toInteger(exec);
       
  1433         QScriptValuePrivate::restoreException(exec, savedException);
       
  1434         return result;
       
  1435     }
       
  1436     case QScriptValuePrivate::Number:
       
  1437         return QScript::ToInteger(d->numberValue);
       
  1438     case QScriptValuePrivate::String:
       
  1439         return QScript::ToInteger(((JSC::UString)d->stringValue).toDouble());
       
  1440     }
       
  1441     return 0;
       
  1442 }
       
  1443 
       
  1444 /*!
       
  1445   Returns the QVariant value of this QScriptValue, if it can be
       
  1446   converted to a QVariant; otherwise returns an invalid QVariant.
       
  1447   The conversion is performed according to the following table:
       
  1448 
       
  1449     \table
       
  1450     \header \o Input Type \o Result
       
  1451     \row    \o Undefined  \o An invalid QVariant.
       
  1452     \row    \o Null       \o An invalid QVariant.
       
  1453     \row    \o Boolean    \o A QVariant containing the value of the boolean.
       
  1454     \row    \o Number     \o A QVariant containing the value of the number.
       
  1455     \row    \o String     \o A QVariant containing the value of the string.
       
  1456     \row    \o QVariant Object \o The result is the QVariant value of the object (no conversion).
       
  1457     \row    \o QObject Object \o A QVariant containing a pointer to the QObject.
       
  1458     \row    \o Date Object \o A QVariant containing the date value (toDateTime()).
       
  1459     \row    \o RegExp Object \o A QVariant containing the regular expression value (toRegExp()).
       
  1460     \row    \o Array Object \o The array is converted to a QVariantList.
       
  1461     \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.
       
  1462     \endtable
       
  1463 
       
  1464   \sa isVariant()
       
  1465 */
       
  1466 QVariant QScriptValue::toVariant() const
       
  1467 {
       
  1468     Q_D(const QScriptValue);
       
  1469     if (!d)
       
  1470         return QVariant();
       
  1471     switch (d->type) {
       
  1472     case QScriptValuePrivate::JavaScriptCore:
       
  1473         if (isObject()) {
       
  1474             if (isVariant())
       
  1475                 return d->variantValue();
       
  1476 #ifndef QT_NO_QOBJECT
       
  1477             else if (isQObject())
       
  1478                 return qVariantFromValue(toQObject());
       
  1479 #endif
       
  1480             else if (isDate())
       
  1481                 return QVariant(toDateTime());
       
  1482 #ifndef QT_NO_REGEXP
       
  1483             else if (isRegExp())
       
  1484                 return QVariant(toRegExp());
       
  1485 #endif
       
  1486             else if (isArray())
       
  1487                 return QScriptEnginePrivate::variantListFromArray(*this);
       
  1488             else if (QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(*this))
       
  1489                 return dc->toVariant(QScriptDeclarativeClass::object(*this));
       
  1490             // try to convert to primitive
       
  1491             JSC::ExecState *exec = d->engine->currentFrame;
       
  1492             JSC::JSValue savedException;
       
  1493             QScriptValuePrivate::saveException(exec, &savedException);
       
  1494             JSC::JSValue prim = d->jscValue.toPrimitive(exec);
       
  1495             QScriptValuePrivate::restoreException(exec, savedException);
       
  1496             if (!prim.isObject())
       
  1497                 return d->engine->scriptValueFromJSCValue(prim).toVariant();
       
  1498         } else if (isNumber()) {
       
  1499             return QVariant(toNumber());
       
  1500         } else if (isString()) {
       
  1501             return QVariant(toString());
       
  1502         } else if (isBool()) {
       
  1503             return QVariant(toBool());
       
  1504         }
       
  1505         return QVariant();
       
  1506     case QScriptValuePrivate::Number:
       
  1507         return QVariant(d->numberValue);
       
  1508     case QScriptValuePrivate::String:
       
  1509         return QVariant(d->stringValue);
       
  1510     }
       
  1511     return QVariant();
       
  1512 }
       
  1513 
       
  1514 /*!
       
  1515   \obsolete
       
  1516 
       
  1517   This function is obsolete; use QScriptEngine::toObject() instead.
       
  1518 */
       
  1519 QScriptValue QScriptValue::toObject() const
       
  1520 {
       
  1521     Q_D(const QScriptValue);
       
  1522     if (!d || !d->engine)
       
  1523         return QScriptValue();
       
  1524     return engine()->toObject(*this);
       
  1525 }
       
  1526 
       
  1527 /*!
       
  1528   Returns a QDateTime representation of this value, in local time.
       
  1529   If this QScriptValue is not a date, or the value of the date is NaN
       
  1530   (Not-a-Number), an invalid QDateTime is returned.
       
  1531 
       
  1532   \sa isDate()
       
  1533 */
       
  1534 QDateTime QScriptValue::toDateTime() const
       
  1535 {
       
  1536     Q_D(const QScriptValue);
       
  1537     if (!isDate())
       
  1538         return QDateTime();
       
  1539     qsreal t = static_cast<JSC::DateInstance*>(JSC::asObject(d->jscValue))->internalNumber();
       
  1540     return QScript::ToDateTime(t, Qt::LocalTime);
       
  1541 }
       
  1542 
       
  1543 #ifndef QT_NO_REGEXP
       
  1544 /*!
       
  1545   Returns the QRegExp representation of this value.
       
  1546   If this QScriptValue is not a regular expression, an empty
       
  1547   QRegExp is returned.
       
  1548 
       
  1549   \sa isRegExp()
       
  1550 */
       
  1551 QRegExp QScriptValue::toRegExp() const
       
  1552 {
       
  1553     Q_D(const QScriptValue);
       
  1554     if (!isRegExp())
       
  1555         return QRegExp();
       
  1556     QString pattern = d->property(QLatin1String("source"), QScriptValue::ResolvePrototype).toString();
       
  1557     Qt::CaseSensitivity kase = Qt::CaseSensitive;
       
  1558     if (d->property(QLatin1String("ignoreCase"), QScriptValue::ResolvePrototype).toBool())
       
  1559         kase = Qt::CaseInsensitive;
       
  1560     return QRegExp(pattern, kase, QRegExp::RegExp2);
       
  1561 }
       
  1562 #endif // QT_NO_REGEXP
       
  1563 
       
  1564 /*!
       
  1565   If this QScriptValue is a QObject, returns the QObject pointer
       
  1566   that the QScriptValue represents; otherwise, returns 0.
       
  1567 
       
  1568   If the QObject that this QScriptValue wraps has been deleted,
       
  1569   this function returns 0 (i.e. it is possible for toQObject()
       
  1570   to return 0 even when isQObject() returns true).
       
  1571 
       
  1572   \sa isQObject()
       
  1573 */
       
  1574 QObject *QScriptValue::toQObject() const
       
  1575 {
       
  1576     Q_D(const QScriptValue);
       
  1577     if (isQObject()) {
       
  1578         QScriptObject *object = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
       
  1579         QScriptObjectDelegate *delegate = object->delegate();
       
  1580         if (delegate->type() == QScriptObjectDelegate::DeclarativeClassObject)
       
  1581             return static_cast<QScript::DeclarativeObjectDelegate*>(delegate)->scriptClass()->toQObject(QScriptDeclarativeClass::object(*this));
       
  1582         return static_cast<QScript::QObjectDelegate*>(delegate)->value();
       
  1583     } else if (isVariant()) {
       
  1584         QVariant var = toVariant();
       
  1585         int type = var.userType();
       
  1586         if ((type == QMetaType::QObjectStar) || (type == QMetaType::QWidgetStar))
       
  1587             return *reinterpret_cast<QObject* const *>(var.constData());
       
  1588     }
       
  1589     return 0;
       
  1590 }
       
  1591 
       
  1592 /*!
       
  1593   If this QScriptValue is a QMetaObject, returns the QMetaObject pointer
       
  1594   that the QScriptValue represents; otherwise, returns 0.
       
  1595 
       
  1596   \sa isQMetaObject()
       
  1597 */
       
  1598 const QMetaObject *QScriptValue::toQMetaObject() const
       
  1599 {
       
  1600     Q_D(const QScriptValue);
       
  1601     if (isQMetaObject())
       
  1602         return static_cast<QScript::QMetaObjectWrapperObject*>(JSC::asObject(d->jscValue))->value();
       
  1603     return 0;
       
  1604 }
       
  1605 
       
  1606 /*!
       
  1607   Sets the value of this QScriptValue's property with the given \a name to
       
  1608   the given \a value.
       
  1609 
       
  1610   If this QScriptValue is not an object, this function does nothing.
       
  1611 
       
  1612   If this QScriptValue does not already have a property with name \a name,
       
  1613   a new property is created; the given \a flags then specify how this
       
  1614   property may be accessed by script code.
       
  1615 
       
  1616   If \a value is invalid, the property is removed.
       
  1617 
       
  1618   If the property is implemented using a setter function (i.e. has the
       
  1619   PropertySetter flag set), calling setProperty() has side-effects on
       
  1620   the script engine, since the setter function will be called with the
       
  1621   given \a value as argument (possibly resulting in an uncaught script
       
  1622   exception).
       
  1623 
       
  1624   Note that you cannot specify custom getter or setter functions for
       
  1625   built-in properties, such as the \c{length} property of Array objects
       
  1626   or meta properties of QObject objects.
       
  1627 
       
  1628   \sa property()
       
  1629 */
       
  1630 
       
  1631 void QScriptValue::setProperty(const QString &name, const QScriptValue &value,
       
  1632                                const PropertyFlags &flags)
       
  1633 {
       
  1634     Q_D(QScriptValue);
       
  1635     if (!d || !d->isObject())
       
  1636         return;
       
  1637     JSC::ExecState *exec = d->engine->currentFrame;
       
  1638     d->setProperty(JSC::Identifier(exec, name), value, flags);
       
  1639 }
       
  1640 
       
  1641 /*!
       
  1642   Returns the value of this QScriptValue's property with the given \a name,
       
  1643   using the given \a mode to resolve the property.
       
  1644 
       
  1645   If no such property exists, an invalid QScriptValue is returned.
       
  1646 
       
  1647   If the property is implemented using a getter function (i.e. has the
       
  1648   PropertyGetter flag set), calling property() has side-effects on the
       
  1649   script engine, since the getter function will be called (possibly
       
  1650   resulting in an uncaught script exception). If an exception
       
  1651   occurred, property() returns the value that was thrown (typically
       
  1652   an \c{Error} object).
       
  1653 
       
  1654   \sa setProperty(), propertyFlags(), QScriptValueIterator
       
  1655 */
       
  1656 QScriptValue QScriptValue::property(const QString &name,
       
  1657                                     const ResolveFlags &mode) const
       
  1658 {
       
  1659     Q_D(const QScriptValue);
       
  1660     if (!d || !d->isObject())
       
  1661         return QScriptValue();
       
  1662     return d->property(name, mode);
       
  1663 }
       
  1664 
       
  1665 /*!
       
  1666   \overload
       
  1667 
       
  1668   Returns the property at the given \a arrayIndex, using the given \a
       
  1669   mode to resolve the property.
       
  1670 
       
  1671   This function is provided for convenience and performance when
       
  1672   working with array objects.
       
  1673 
       
  1674   If this QScriptValue is not an Array object, this function behaves
       
  1675   as if property() was called with the string representation of \a
       
  1676   arrayIndex.
       
  1677 */
       
  1678 QScriptValue QScriptValue::property(quint32 arrayIndex,
       
  1679                                     const ResolveFlags &mode) const
       
  1680 {
       
  1681     Q_D(const QScriptValue);
       
  1682     if (!d || !d->isObject())
       
  1683         return QScriptValue();
       
  1684     return d->property(arrayIndex, mode);
       
  1685 }
       
  1686 
       
  1687 /*!
       
  1688   \overload
       
  1689 
       
  1690   Sets the property at the given \a arrayIndex to the given \a value.
       
  1691 
       
  1692   This function is provided for convenience and performance when
       
  1693   working with array objects.
       
  1694 
       
  1695   If this QScriptValue is not an Array object, this function behaves
       
  1696   as if setProperty() was called with the string representation of \a
       
  1697   arrayIndex.
       
  1698 */
       
  1699 void QScriptValue::setProperty(quint32 arrayIndex, const QScriptValue &value,
       
  1700                                const PropertyFlags &flags)
       
  1701 {
       
  1702     Q_D(QScriptValue);
       
  1703     if (!d || !d->isObject())
       
  1704         return;
       
  1705     if (QScriptValuePrivate::getEngine(value)
       
  1706         && (QScriptValuePrivate::getEngine(value) != d->engine)) {
       
  1707         qWarning("QScriptValue::setProperty() failed: "
       
  1708                  "cannot set value created in a different engine");
       
  1709         return;
       
  1710     }
       
  1711     JSC::ExecState *exec = d->engine->currentFrame;
       
  1712     JSC::JSValue jscValue = d->engine->scriptValueToJSCValue(value);
       
  1713     if (!jscValue) {
       
  1714         JSC::asObject(d->jscValue)->deleteProperty(exec, arrayIndex, /*checkDontDelete=*/false);
       
  1715     } else {
       
  1716         if ((flags & QScriptValue::PropertyGetter) || (flags & QScriptValue::PropertySetter)) {
       
  1717             // fall back to string-based setProperty(), since there is no
       
  1718             // JSC::JSObject::defineGetter(unsigned)
       
  1719             d->setProperty(JSC::Identifier::from(exec, arrayIndex), value, flags);
       
  1720         } else {
       
  1721             if (flags != QScriptValue::KeepExistingFlags) {
       
  1722 //                if (JSC::asObject(d->jscValue)->hasOwnProperty(exec, arrayIndex))
       
  1723 //                    JSC::asObject(d->jscValue)->deleteProperty(exec, arrayIndex);
       
  1724                 unsigned attribs = 0;
       
  1725                 if (flags & QScriptValue::ReadOnly)
       
  1726                     attribs |= JSC::ReadOnly;
       
  1727                 if (flags & QScriptValue::SkipInEnumeration)
       
  1728                     attribs |= JSC::DontEnum;
       
  1729                 if (flags & QScriptValue::Undeletable)
       
  1730                     attribs |= JSC::DontDelete;
       
  1731                 attribs |= flags & QScriptValue::UserRange;
       
  1732                 JSC::asObject(d->jscValue)->putWithAttributes(exec, arrayIndex, jscValue, attribs);
       
  1733             } else {
       
  1734                 JSC::asObject(d->jscValue)->put(exec, arrayIndex, jscValue);
       
  1735             }
       
  1736         }
       
  1737     }
       
  1738 }
       
  1739 
       
  1740 /*!
       
  1741   \since 4.4
       
  1742 
       
  1743   Returns the value of this QScriptValue's property with the given \a name,
       
  1744   using the given \a mode to resolve the property.
       
  1745 
       
  1746   This overload of property() is useful when you need to look up the
       
  1747   same property repeatedly, since the lookup can be performed faster
       
  1748   when the name is represented as an interned string.
       
  1749 
       
  1750   \sa QScriptEngine::toStringHandle(), setProperty()
       
  1751 */
       
  1752 QScriptValue QScriptValue::property(const QScriptString &name,
       
  1753                                     const ResolveFlags &mode) const
       
  1754 {
       
  1755     Q_D(const QScriptValue);
       
  1756     if (!d || !d->isObject() || !QScriptStringPrivate::isValid(name))
       
  1757         return QScriptValue();
       
  1758     return d->property(name.d_ptr->identifier, mode);
       
  1759 }
       
  1760 
       
  1761 /*!
       
  1762   \since 4.4
       
  1763 
       
  1764   Sets the value of this QScriptValue's property with the given \a
       
  1765   name to the given \a value. The given \a flags specify how this
       
  1766   property may be accessed by script code.
       
  1767 
       
  1768   This overload of setProperty() is useful when you need to set the
       
  1769   same property repeatedly, since the operation can be performed
       
  1770   faster when the name is represented as an interned string.
       
  1771 
       
  1772   \sa QScriptEngine::toStringHandle()
       
  1773 */
       
  1774 void QScriptValue::setProperty(const QScriptString &name,
       
  1775                                const QScriptValue &value,
       
  1776                                const PropertyFlags &flags)
       
  1777 {
       
  1778     Q_D(QScriptValue);
       
  1779     if (!d || !d->isObject() || !QScriptStringPrivate::isValid(name))
       
  1780         return;
       
  1781     d->setProperty(name.d_ptr->identifier, value, flags);
       
  1782 }
       
  1783 
       
  1784 /*!
       
  1785   Returns the flags of the property with the given \a name, using the
       
  1786   given \a mode to resolve the property.
       
  1787 
       
  1788   \sa property()
       
  1789 */
       
  1790 QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QString &name,
       
  1791                                                         const ResolveFlags &mode) const
       
  1792 {
       
  1793     Q_D(const QScriptValue);
       
  1794     if (!d || !d->isObject())
       
  1795         return 0;
       
  1796     JSC::ExecState *exec = d->engine->currentFrame;
       
  1797     return d->propertyFlags(JSC::Identifier(exec, name), mode);
       
  1798 
       
  1799 }
       
  1800 
       
  1801 /*!
       
  1802   \since 4.4
       
  1803 
       
  1804   Returns the flags of the property with the given \a name, using the
       
  1805   given \a mode to resolve the property.
       
  1806 
       
  1807   \sa property()
       
  1808 */
       
  1809 QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QScriptString &name,
       
  1810                                                         const ResolveFlags &mode) const
       
  1811 {
       
  1812     Q_D(const QScriptValue);
       
  1813     if (!d || !d->isObject() || !QScriptStringPrivate::isValid(name))
       
  1814         return 0;
       
  1815     return d->propertyFlags(name.d_ptr->identifier, mode);
       
  1816 }
       
  1817 
       
  1818 /*!
       
  1819   Calls this QScriptValue as a function, using \a thisObject as
       
  1820   the `this' object in the function call, and passing \a args
       
  1821   as arguments to the function. Returns the value returned from
       
  1822   the function.
       
  1823 
       
  1824   If this QScriptValue is not a function, call() does nothing
       
  1825   and returns an invalid QScriptValue.
       
  1826 
       
  1827   Note that if \a thisObject is not an object, the global object
       
  1828   (see \l{QScriptEngine::globalObject()}) will be used as the
       
  1829   `this' object.
       
  1830 
       
  1831   Calling call() can cause an exception to occur in the script engine;
       
  1832   in that case, call() returns the value that was thrown (typically an
       
  1833   \c{Error} object). You can call
       
  1834   QScriptEngine::hasUncaughtException() to determine if an exception
       
  1835   occurred.
       
  1836 
       
  1837   \snippet doc/src/snippets/code/src_script_qscriptvalue.cpp 2
       
  1838 
       
  1839   \sa construct()
       
  1840 */
       
  1841 QScriptValue QScriptValue::call(const QScriptValue &thisObject,
       
  1842                                 const QScriptValueList &args)
       
  1843 {
       
  1844     Q_D(const QScriptValue);
       
  1845     if (!d || !d->isJSC())
       
  1846         return QScriptValue();
       
  1847     JSC::JSValue callee = d->jscValue;
       
  1848     JSC::CallData callData;
       
  1849     JSC::CallType callType = callee.getCallData(callData);
       
  1850     if (callType == JSC::CallTypeNone)
       
  1851         return QScriptValue();
       
  1852 
       
  1853     if (QScriptValuePrivate::getEngine(thisObject)
       
  1854         && (QScriptValuePrivate::getEngine(thisObject) != d->engine)) {
       
  1855         qWarning("QScriptValue::call() failed: "
       
  1856                  "cannot call function with thisObject created in "
       
  1857                  "a different engine");
       
  1858         return QScriptValue();
       
  1859     }
       
  1860 
       
  1861     JSC::ExecState *exec = d->engine->currentFrame;
       
  1862 
       
  1863     JSC::JSValue jscThisObject = d->engine->scriptValueToJSCValue(thisObject);
       
  1864     if (!jscThisObject || !jscThisObject.isObject())
       
  1865         jscThisObject = d->engine->globalObject();
       
  1866 
       
  1867     QVarLengthArray<JSC::JSValue, 8> argsVector(args.size());
       
  1868     for (int i = 0; i < args.size(); ++i) {
       
  1869         const QScriptValue &arg = args.at(i);
       
  1870         if (!arg.isValid()) {
       
  1871             argsVector[i] = JSC::jsUndefined();
       
  1872         } else if (QScriptValuePrivate::getEngine(arg)
       
  1873                    && (QScriptValuePrivate::getEngine(arg) != d->engine)) {
       
  1874             qWarning("QScriptValue::call() failed: "
       
  1875                      "cannot call function with argument created in "
       
  1876                      "a different engine");
       
  1877             return QScriptValue();
       
  1878         } else {
       
  1879             argsVector[i] = d->engine->scriptValueToJSCValue(arg);
       
  1880         }
       
  1881     }
       
  1882     JSC::ArgList jscArgs(argsVector.data(), argsVector.size());
       
  1883 
       
  1884     JSC::JSValue savedException;
       
  1885     QScriptValuePrivate::saveException(exec, &savedException);
       
  1886     JSC::JSValue result = JSC::call(exec, callee, callType, callData, jscThisObject, jscArgs);
       
  1887     if (exec->hadException()) {
       
  1888         result = exec->exception();
       
  1889     } else {
       
  1890         QScriptValuePrivate::restoreException(exec, savedException);
       
  1891     }
       
  1892     return d->engine->scriptValueFromJSCValue(result);
       
  1893 }
       
  1894 
       
  1895 /*!
       
  1896   Calls this QScriptValue as a function, using \a thisObject as
       
  1897   the `this' object in the function call, and passing \a arguments
       
  1898   as arguments to the function. Returns the value returned from
       
  1899   the function.
       
  1900 
       
  1901   If this QScriptValue is not a function, call() does nothing
       
  1902   and returns an invalid QScriptValue.
       
  1903 
       
  1904   \a arguments can be an arguments object, an array, null or
       
  1905   undefined; any other type will cause a TypeError to be thrown.
       
  1906 
       
  1907   Note that if \a thisObject is not an object, the global object
       
  1908   (see \l{QScriptEngine::globalObject()}) will be used as the
       
  1909   `this' object.
       
  1910 
       
  1911   One common usage of this function is to forward native function
       
  1912   calls to another function:
       
  1913 
       
  1914   \snippet doc/src/snippets/code/src_script_qscriptvalue.cpp 3
       
  1915 
       
  1916   \sa construct(), QScriptContext::argumentsObject()
       
  1917 */
       
  1918 QScriptValue QScriptValue::call(const QScriptValue &thisObject,
       
  1919                                 const QScriptValue &arguments)
       
  1920 {
       
  1921     Q_D(QScriptValue);
       
  1922     if (!d || !d->isJSC())
       
  1923         return QScriptValue();
       
  1924     JSC::JSValue callee = d->jscValue;
       
  1925     JSC::CallData callData;
       
  1926     JSC::CallType callType = callee.getCallData(callData);
       
  1927     if (callType == JSC::CallTypeNone)
       
  1928         return QScriptValue();
       
  1929 
       
  1930     if (QScriptValuePrivate::getEngine(thisObject)
       
  1931         && (QScriptValuePrivate::getEngine(thisObject) != d->engine)) {
       
  1932         qWarning("QScriptValue::call() failed: "
       
  1933                  "cannot call function with thisObject created in "
       
  1934                  "a different engine");
       
  1935         return QScriptValue();
       
  1936     }
       
  1937 
       
  1938     JSC::ExecState *exec = d->engine->currentFrame;
       
  1939 
       
  1940     JSC::JSValue jscThisObject = d->engine->scriptValueToJSCValue(thisObject);
       
  1941     if (!jscThisObject || !jscThisObject.isObject())
       
  1942         jscThisObject = d->engine->globalObject();
       
  1943 
       
  1944     JSC::JSValue array = d->engine->scriptValueToJSCValue(arguments);
       
  1945     // copied from runtime/FunctionPrototype.cpp, functionProtoFuncApply()
       
  1946     JSC::MarkedArgumentBuffer applyArgs;
       
  1947     if (!array.isUndefinedOrNull()) {
       
  1948         if (!array.isObject()) {
       
  1949             return d->engine->scriptValueFromJSCValue(JSC::throwError(exec, JSC::TypeError, "Arguments must be an array"));
       
  1950         }
       
  1951         if (JSC::asObject(array)->classInfo() == &JSC::Arguments::info)
       
  1952             JSC::asArguments(array)->fillArgList(exec, applyArgs);
       
  1953         else if (JSC::isJSArray(&exec->globalData(), array))
       
  1954             JSC::asArray(array)->fillArgList(exec, applyArgs);
       
  1955         else if (JSC::asObject(array)->inherits(&JSC::JSArray::info)) {
       
  1956             unsigned length = JSC::asArray(array)->get(exec, exec->propertyNames().length).toUInt32(exec);
       
  1957             for (unsigned i = 0; i < length; ++i)
       
  1958                 applyArgs.append(JSC::asArray(array)->get(exec, i));
       
  1959         } else {
       
  1960             return d->engine->scriptValueFromJSCValue(JSC::throwError(exec, JSC::TypeError, "Arguments must be an array"));
       
  1961         }
       
  1962     }
       
  1963 
       
  1964     JSC::JSValue savedException;
       
  1965     QScriptValuePrivate::saveException(exec, &savedException);
       
  1966     JSC::JSValue result = JSC::call(exec, callee, callType, callData, jscThisObject, applyArgs);
       
  1967     if (exec->hadException()) {
       
  1968         result = exec->exception();
       
  1969     } else {
       
  1970         QScriptValuePrivate::restoreException(exec, savedException);
       
  1971     }
       
  1972     return d->engine->scriptValueFromJSCValue(result);
       
  1973 }
       
  1974 
       
  1975 /*!
       
  1976   Creates a new \c{Object} and calls this QScriptValue as a
       
  1977   constructor, using the created object as the `this' object and
       
  1978   passing \a args as arguments. If the return value from the
       
  1979   constructor call is an object, then that object is returned;
       
  1980   otherwise the default constructed object is returned.
       
  1981 
       
  1982   If this QScriptValue is not a function, construct() does nothing
       
  1983   and returns an invalid QScriptValue.
       
  1984 
       
  1985   Calling construct() can cause an exception to occur in the script
       
  1986   engine; in that case, construct() returns the value that was thrown
       
  1987   (typically an \c{Error} object). You can call
       
  1988   QScriptEngine::hasUncaughtException() to determine if an exception
       
  1989   occurred.
       
  1990 
       
  1991   \sa call(), QScriptEngine::newObject()
       
  1992 */
       
  1993 QScriptValue QScriptValue::construct(const QScriptValueList &args)
       
  1994 {
       
  1995     Q_D(const QScriptValue);
       
  1996     if (!d || !d->isJSC())
       
  1997         return QScriptValue();
       
  1998     JSC::JSValue callee = d->jscValue;
       
  1999     JSC::ConstructData constructData;
       
  2000     JSC::ConstructType constructType = callee.getConstructData(constructData);
       
  2001     if (constructType == JSC::ConstructTypeNone)
       
  2002         return QScriptValue();
       
  2003 
       
  2004     JSC::ExecState *exec = d->engine->currentFrame;
       
  2005 
       
  2006     QVarLengthArray<JSC::JSValue, 8> argsVector(args.size());
       
  2007     for (int i = 0; i < args.size(); ++i) {
       
  2008         if (!args.at(i).isValid())
       
  2009             argsVector[i] = JSC::jsUndefined();
       
  2010         else
       
  2011             argsVector[i] = d->engine->scriptValueToJSCValue(args.at(i));
       
  2012     }
       
  2013 
       
  2014     JSC::ArgList jscArgs(argsVector.data(), argsVector.size());
       
  2015 
       
  2016     JSC::JSValue savedException;
       
  2017     QScriptValuePrivate::saveException(exec, &savedException);
       
  2018     JSC::JSObject *result = JSC::construct(exec, callee, constructType, constructData, jscArgs);
       
  2019     if (exec->hadException()) {
       
  2020         result = JSC::asObject(exec->exception());
       
  2021     } else {
       
  2022         QScriptValuePrivate::restoreException(exec, savedException);
       
  2023     }
       
  2024     return d->engine->scriptValueFromJSCValue(result);
       
  2025 }
       
  2026 
       
  2027 /*!
       
  2028   Creates a new \c{Object} and calls this QScriptValue as a
       
  2029   constructor, using the created object as the `this' object and
       
  2030   passing \a arguments as arguments. If the return value from the
       
  2031   constructor call is an object, then that object is returned;
       
  2032   otherwise the default constructed object is returned.
       
  2033 
       
  2034   If this QScriptValue is not a function, construct() does nothing
       
  2035   and returns an invalid QScriptValue.
       
  2036 
       
  2037   \a arguments can be an arguments object, an array, null or
       
  2038   undefined. Any other type will cause a TypeError to be thrown.
       
  2039 
       
  2040   \sa call(), QScriptEngine::newObject(), QScriptContext::argumentsObject()
       
  2041 */
       
  2042 QScriptValue QScriptValue::construct(const QScriptValue &arguments)
       
  2043 {
       
  2044     Q_D(QScriptValue);
       
  2045     if (!d || !d->isJSC())
       
  2046         return QScriptValue();
       
  2047     JSC::JSValue callee = d->jscValue;
       
  2048     JSC::ConstructData constructData;
       
  2049     JSC::ConstructType constructType = callee.getConstructData(constructData);
       
  2050     if (constructType == JSC::ConstructTypeNone)
       
  2051         return QScriptValue();
       
  2052 
       
  2053     JSC::ExecState *exec = d->engine->currentFrame;
       
  2054 
       
  2055     JSC::JSValue array = d->engine->scriptValueToJSCValue(arguments);
       
  2056     // copied from runtime/FunctionPrototype.cpp, functionProtoFuncApply()
       
  2057     JSC::MarkedArgumentBuffer applyArgs;
       
  2058     if (!array.isUndefinedOrNull()) {
       
  2059         if (!array.isObject()) {
       
  2060             return d->engine->scriptValueFromJSCValue(JSC::throwError(exec, JSC::TypeError, "Arguments must be an array"));
       
  2061         }
       
  2062         if (JSC::asObject(array)->classInfo() == &JSC::Arguments::info)
       
  2063             JSC::asArguments(array)->fillArgList(exec, applyArgs);
       
  2064         else if (JSC::isJSArray(&exec->globalData(), array))
       
  2065             JSC::asArray(array)->fillArgList(exec, applyArgs);
       
  2066         else if (JSC::asObject(array)->inherits(&JSC::JSArray::info)) {
       
  2067             unsigned length = JSC::asArray(array)->get(exec, exec->propertyNames().length).toUInt32(exec);
       
  2068             for (unsigned i = 0; i < length; ++i)
       
  2069                 applyArgs.append(JSC::asArray(array)->get(exec, i));
       
  2070         } else {
       
  2071             return d->engine->scriptValueFromJSCValue(JSC::throwError(exec, JSC::TypeError, "Arguments must be an array"));
       
  2072         }
       
  2073     }
       
  2074 
       
  2075     JSC::JSValue savedException;
       
  2076     QScriptValuePrivate::saveException(exec, &savedException);
       
  2077     JSC::JSObject *result = JSC::construct(exec, callee, constructType, constructData, applyArgs);
       
  2078     if (exec->hadException()) {
       
  2079         if (exec->exception().isObject())
       
  2080             result = JSC::asObject(exec->exception());
       
  2081     } else {
       
  2082         QScriptValuePrivate::restoreException(exec, savedException);
       
  2083     }
       
  2084     return d->engine->scriptValueFromJSCValue(result);
       
  2085 }
       
  2086 
       
  2087 /*!
       
  2088   Returns the QScriptEngine that created this QScriptValue,
       
  2089   or 0 if this QScriptValue is invalid or the value is not
       
  2090   associated with a particular engine.
       
  2091 */
       
  2092 QScriptEngine *QScriptValue::engine() const
       
  2093 {
       
  2094     Q_D(const QScriptValue);
       
  2095     if (!d)
       
  2096         return 0;
       
  2097     return QScriptEnginePrivate::get(d->engine);
       
  2098 }
       
  2099 
       
  2100 /*!
       
  2101   \obsolete
       
  2102 
       
  2103   Use isBool() instead.
       
  2104 */
       
  2105 bool QScriptValue::isBoolean() const
       
  2106 {
       
  2107     Q_D(const QScriptValue);
       
  2108     return d && d->isJSC() && d->jscValue.isBoolean();
       
  2109 }
       
  2110 
       
  2111 /*!
       
  2112   \since 4.5
       
  2113 
       
  2114   Returns true if this QScriptValue is of the primitive type Boolean;
       
  2115   otherwise returns false.
       
  2116 
       
  2117   \sa toBool()
       
  2118 */
       
  2119 bool QScriptValue::isBool() const
       
  2120 {
       
  2121     Q_D(const QScriptValue);
       
  2122     return d && d->isJSC() && d->jscValue.isBoolean();
       
  2123 }
       
  2124 
       
  2125 /*!
       
  2126   Returns true if this QScriptValue is of the primitive type Number;
       
  2127   otherwise returns false.
       
  2128 
       
  2129   \sa toNumber()
       
  2130 */
       
  2131 bool QScriptValue::isNumber() const
       
  2132 {
       
  2133     Q_D(const QScriptValue);
       
  2134     if (!d)
       
  2135         return false;
       
  2136     switch (d->type) {
       
  2137     case QScriptValuePrivate::JavaScriptCore:
       
  2138         return d->jscValue.isNumber();
       
  2139     case QScriptValuePrivate::Number:
       
  2140         return true;
       
  2141     case QScriptValuePrivate::String:
       
  2142         return false;
       
  2143     }
       
  2144     return false;
       
  2145 }
       
  2146 
       
  2147 /*!
       
  2148   Returns true if this QScriptValue is of the primitive type String;
       
  2149   otherwise returns false.
       
  2150 
       
  2151   \sa toString()
       
  2152 */
       
  2153 bool QScriptValue::isString() const
       
  2154 {
       
  2155     Q_D(const QScriptValue);
       
  2156     if (!d)
       
  2157         return false;
       
  2158     switch (d->type) {
       
  2159     case QScriptValuePrivate::JavaScriptCore:
       
  2160         return d->jscValue.isString();
       
  2161     case QScriptValuePrivate::Number:
       
  2162         return false;
       
  2163     case QScriptValuePrivate::String:
       
  2164         return true;
       
  2165     }
       
  2166     return false;
       
  2167 }
       
  2168 
       
  2169 /*!
       
  2170   Returns true if this QScriptValue is a function; otherwise returns
       
  2171   false.
       
  2172 
       
  2173   \sa call()
       
  2174 */
       
  2175 bool QScriptValue::isFunction() const
       
  2176 {
       
  2177     Q_D(const QScriptValue);
       
  2178     if (!d || !d->isJSC())
       
  2179         return false;
       
  2180     return QScript::isFunction(d->jscValue);
       
  2181 }
       
  2182 
       
  2183 /*!
       
  2184   Returns true if this QScriptValue is of the primitive type Null;
       
  2185   otherwise returns false.
       
  2186 
       
  2187   \sa QScriptEngine::nullValue()
       
  2188 */
       
  2189 bool QScriptValue::isNull() const
       
  2190 {
       
  2191     Q_D(const QScriptValue);
       
  2192     return d && d->isJSC() && d->jscValue.isNull();
       
  2193 }
       
  2194 
       
  2195 /*!
       
  2196   Returns true if this QScriptValue is of the primitive type Undefined;
       
  2197   otherwise returns false.
       
  2198 
       
  2199   \sa QScriptEngine::undefinedValue()
       
  2200 */
       
  2201 bool QScriptValue::isUndefined() const
       
  2202 {
       
  2203     Q_D(const QScriptValue);
       
  2204     return d && d->isJSC() && d->jscValue.isUndefined();
       
  2205 }
       
  2206 
       
  2207 /*!
       
  2208   Returns true if this QScriptValue is of the Object type; otherwise
       
  2209   returns false.
       
  2210 
       
  2211   Note that function values, variant values, and QObject values are
       
  2212   objects, so this function returns true for such values.
       
  2213 
       
  2214   \sa toObject(), QScriptEngine::newObject()
       
  2215 */
       
  2216 bool QScriptValue::isObject() const
       
  2217 {
       
  2218     Q_D(const QScriptValue);
       
  2219     return d && d->isObject();
       
  2220 }
       
  2221 
       
  2222 /*!
       
  2223   Returns true if this QScriptValue is a variant value;
       
  2224   otherwise returns false.
       
  2225 
       
  2226   \sa toVariant(), QScriptEngine::newVariant()
       
  2227 */
       
  2228 bool QScriptValue::isVariant() const
       
  2229 {
       
  2230     Q_D(const QScriptValue);
       
  2231     if (!d || !d->isJSC() || !d->jscValue.inherits(&QScriptObject::info))
       
  2232         return false;
       
  2233     QScriptObject *object = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
       
  2234     QScriptObjectDelegate *delegate = object->delegate();
       
  2235     return (delegate && (delegate->type() == QScriptObjectDelegate::Variant));
       
  2236 }
       
  2237 
       
  2238 /*!
       
  2239   Returns true if this QScriptValue is a QObject; otherwise returns
       
  2240   false.
       
  2241 
       
  2242   Note: This function returns true even if the QObject that this
       
  2243   QScriptValue wraps has been deleted.
       
  2244 
       
  2245   \sa toQObject(), QScriptEngine::newQObject()
       
  2246 */
       
  2247 bool QScriptValue::isQObject() const
       
  2248 {
       
  2249     Q_D(const QScriptValue);
       
  2250     if (!d || !d->isJSC() || !d->jscValue.inherits(&QScriptObject::info))
       
  2251         return false;
       
  2252     QScriptObject *object = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
       
  2253     QScriptObjectDelegate *delegate = object->delegate();
       
  2254     return (delegate && (delegate->type() == QScriptObjectDelegate::QtObject ||
       
  2255                          (delegate->type() == QScriptObjectDelegate::DeclarativeClassObject &&
       
  2256                           static_cast<QScript::DeclarativeObjectDelegate*>(delegate)->scriptClass()->isQObject())));
       
  2257 }
       
  2258 
       
  2259 /*!
       
  2260   Returns true if this QScriptValue is a QMetaObject; otherwise returns
       
  2261   false.
       
  2262 
       
  2263   \sa toQMetaObject(), QScriptEngine::newQMetaObject()
       
  2264 */
       
  2265 bool QScriptValue::isQMetaObject() const
       
  2266 {
       
  2267     Q_D(const QScriptValue);
       
  2268     if (!d || !d->isObject())
       
  2269         return false;
       
  2270     return JSC::asObject(d->jscValue)->inherits(&QScript::QMetaObjectWrapperObject::info);
       
  2271 }
       
  2272 
       
  2273 /*!
       
  2274   Returns true if this QScriptValue is valid; otherwise returns
       
  2275   false.
       
  2276 */
       
  2277 bool QScriptValue::isValid() const
       
  2278 {
       
  2279     Q_D(const QScriptValue);
       
  2280     return d && (!d->isJSC() || !!d->jscValue);
       
  2281 }
       
  2282 
       
  2283 /*!
       
  2284   \since 4.4
       
  2285 
       
  2286   Returns the internal data of this QScriptValue object. QtScript uses
       
  2287   this property to store the primitive value of Date, String, Number
       
  2288   and Boolean objects. For other types of object, custom data may be
       
  2289   stored using setData().
       
  2290 */
       
  2291 QScriptValue QScriptValue::data() const
       
  2292 {
       
  2293     Q_D(const QScriptValue);
       
  2294     if (!d || !d->isObject())
       
  2295         return QScriptValue();
       
  2296     if (d->jscValue.inherits(&QScriptObject::info)) {
       
  2297         QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
       
  2298         return d->engine->scriptValueFromJSCValue(scriptObject->data());
       
  2299     } else {
       
  2300         // ### make hidden property
       
  2301         return d->property(QLatin1String("__qt_data__"), QScriptValue::ResolveLocal);
       
  2302     }
       
  2303 }
       
  2304 
       
  2305 /*!
       
  2306   \since 4.4
       
  2307 
       
  2308   Sets the internal \a data of this QScriptValue object. You can use
       
  2309   this function to set object-specific data that won't be directly
       
  2310   accessible to scripts, but may be retrieved in C++ using the data()
       
  2311   function.
       
  2312 */
       
  2313 void QScriptValue::setData(const QScriptValue &data)
       
  2314 {
       
  2315     Q_D(QScriptValue);
       
  2316     if (!d || !d->isObject())
       
  2317         return;
       
  2318     JSC::JSValue other = d->engine->scriptValueToJSCValue(data);
       
  2319     if (d->jscValue.inherits(&QScriptObject::info)) {
       
  2320         QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
       
  2321         scriptObject->setData(other);
       
  2322     } else {
       
  2323         JSC::ExecState *exec = d->engine->currentFrame;
       
  2324         JSC::Identifier id = JSC::Identifier(exec, "__qt_data__");
       
  2325         if (!data.isValid()) {
       
  2326             JSC::asObject(d->jscValue)->removeDirect(id);
       
  2327         } else {
       
  2328             // ### make hidden property
       
  2329             JSC::asObject(d->jscValue)->putDirect(id, other);
       
  2330         }
       
  2331     }
       
  2332 }
       
  2333 
       
  2334 /*!
       
  2335   \since 4.4
       
  2336 
       
  2337   Returns the custom script class that this script object is an
       
  2338   instance of, or 0 if the object is not of a custom class.
       
  2339 
       
  2340   \sa setScriptClass()
       
  2341 */
       
  2342 QScriptClass *QScriptValue::scriptClass() const
       
  2343 {
       
  2344     Q_D(const QScriptValue);
       
  2345     if (!d || !d->isJSC() || !d->jscValue.inherits(&QScriptObject::info))
       
  2346         return 0;
       
  2347     QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
       
  2348     QScriptObjectDelegate *delegate = scriptObject->delegate();
       
  2349     if (!delegate || (delegate->type() != QScriptObjectDelegate::ClassObject))
       
  2350         return 0;
       
  2351     return static_cast<QScript::ClassObjectDelegate*>(delegate)->scriptClass();
       
  2352 }
       
  2353 
       
  2354 /*!
       
  2355   \since 4.4
       
  2356 
       
  2357   Sets the custom script class of this script object to \a scriptClass.
       
  2358   This can be used to "promote" a plain script object (e.g. created
       
  2359   by the "new" operator in a script, or by QScriptEngine::newObject() in C++)
       
  2360   to an object of a custom type.
       
  2361 
       
  2362   If \a scriptClass is 0, the object will be demoted to a plain
       
  2363   script object.
       
  2364 
       
  2365   \sa scriptClass(), setData()
       
  2366 */
       
  2367 void QScriptValue::setScriptClass(QScriptClass *scriptClass)
       
  2368 {
       
  2369     Q_D(QScriptValue);
       
  2370     if (!d || !d->isObject())
       
  2371         return;
       
  2372     if (!d->jscValue.inherits(&QScriptObject::info)) {
       
  2373         qWarning("QScriptValue::setScriptClass() failed: "
       
  2374                  "cannot change class of non-QScriptObject");
       
  2375         return;
       
  2376     }
       
  2377     QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
       
  2378     if (!scriptClass) {
       
  2379         scriptObject->setDelegate(0);
       
  2380     } else {
       
  2381         QScriptObjectDelegate *delegate = scriptObject->delegate();
       
  2382         if (!delegate || (delegate->type() != QScriptObjectDelegate::ClassObject)) {
       
  2383             delegate = new QScript::ClassObjectDelegate(scriptClass);
       
  2384             scriptObject->setDelegate(delegate);
       
  2385         }
       
  2386         static_cast<QScript::ClassObjectDelegate*>(delegate)->setScriptClass(scriptClass);
       
  2387     }
       
  2388 }
       
  2389 
       
  2390 /*!
       
  2391   \internal
       
  2392 
       
  2393   Returns the ID of this object, or -1 if this QScriptValue is not an
       
  2394   object.
       
  2395 
       
  2396   \sa QScriptEngine::objectById()
       
  2397 */
       
  2398 qint64 QScriptValue::objectId() const
       
  2399 {
       
  2400     return d_ptr?d_ptr->objectId():-1;
       
  2401 }
       
  2402 QT_END_NAMESPACE