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