2 Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
20 #ifndef qscriptvalue_p_h
21 #define qscriptvalue_p_h
23 #include "qscriptconverter_p.h"
24 #include "qscriptengine_p.h"
25 #include "qscriptvalue.h"
26 #include <JavaScriptCore/JavaScript.h>
27 #include <JavaScriptCore/JSRetainPtr.h>
28 #include <JSObjectRefPrivate.h>
29 #include <QtCore/qdatetime.h>
30 #include <QtCore/qmath.h>
31 #include <QtCore/qnumeric.h>
32 #include <QtCore/qshareddata.h>
33 #include <QtCore/qvarlengtharray.h>
40 \class QScriptValuePrivate
42 Implementation of QScriptValue.
43 The implementation is based on a state machine. The states names are included in
44 QScriptValuePrivate::State. Each method should check for the current state and then perform a
48 Invalid -> QSVP is invalid, no assumptions should be made about class members (apart from m_value).
49 CString -> QSVP is created from QString or const char* and no JSC engine has been associated yet.
50 Current value is kept in m_string,
51 CNumber -> QSVP is created from int, uint, double... and no JSC engine has been bind yet. Current
52 value is kept in m_number
53 CBool -> QSVP is created from bool and no JSC engine has been associated yet. Current value is kept
55 CNull -> QSVP is null, but a JSC engine hasn't been associated yet.
56 CUndefined -> QSVP is undefined, but a JSC engine hasn't been associated yet.
57 JSValue -> QSVP is associated with engine, but there is no information about real type, the state
58 have really short live cycle. Normally it is created as a function call result.
59 JSPrimitive -> QSVP is associated with engine, and it is sure that it isn't a JavaScript object.
60 JSObject -> QSVP is associated with engine, and it is sure that it is a JavaScript object.
62 Each state keep all necessary information to invoke all methods, if not it should be changed to
63 a proper state. Changed state shouldn't be reverted.
65 The QScriptValuePrivate use the JSC C API directly. The QSVP type is equal to combination of
66 the JSValueRef and the JSObjectRef, and it could be automatically casted to these types by cast
70 class QScriptValuePrivate
: public QSharedData
{
72 inline static QScriptValuePrivate
* get(const QScriptValue
& q
);
73 inline static QScriptValue
get(const QScriptValuePrivate
* d
);
74 inline static QScriptValue
get(QScriptValuePrivate
* d
);
76 inline ~QScriptValuePrivate();
78 inline QScriptValuePrivate();
79 inline QScriptValuePrivate(const QString
& string
);
80 inline QScriptValuePrivate(bool value
);
81 inline QScriptValuePrivate(int number
);
82 inline QScriptValuePrivate(uint number
);
83 inline QScriptValuePrivate(qsreal number
);
84 inline QScriptValuePrivate(QScriptValue::SpecialValue value
);
86 inline QScriptValuePrivate(const QScriptEnginePrivate
* engine
, bool value
);
87 inline QScriptValuePrivate(const QScriptEnginePrivate
* engine
, int value
);
88 inline QScriptValuePrivate(const QScriptEnginePrivate
* engine
, uint value
);
89 inline QScriptValuePrivate(const QScriptEnginePrivate
* engine
, qsreal value
);
90 inline QScriptValuePrivate(const QScriptEnginePrivate
* engine
, const QString
& value
);
91 inline QScriptValuePrivate(const QScriptEnginePrivate
* engine
, QScriptValue::SpecialValue value
);
93 inline QScriptValuePrivate(const QScriptEnginePrivate
* engine
, JSValueRef value
);
94 inline QScriptValuePrivate(const QScriptEnginePrivate
* engine
, JSObjectRef object
);
96 inline bool isValid() const;
98 inline bool isNumber();
100 inline bool isString();
101 inline bool isUndefined();
102 inline bool isError();
103 inline bool isObject();
104 inline bool isFunction();
105 inline bool isArray();
106 inline bool isDate();
108 inline QString
toString() const;
109 inline qsreal
toNumber() const;
110 inline bool toBool() const;
111 inline qsreal
toInteger() const;
112 inline qint32
toInt32() const;
113 inline quint32
toUInt32() const;
114 inline quint16
toUInt16() const;
116 inline QScriptValuePrivate
* toObject(QScriptEnginePrivate
* engine
);
117 inline QScriptValuePrivate
* toObject();
118 inline QDateTime
toDateTime();
119 inline QScriptValuePrivate
* prototype();
120 inline void setPrototype(QScriptValuePrivate
* prototype
);
122 inline bool equals(QScriptValuePrivate
* other
);
123 inline bool strictlyEquals(QScriptValuePrivate
* other
);
124 inline bool instanceOf(QScriptValuePrivate
* other
);
125 inline bool assignEngine(QScriptEnginePrivate
* engine
);
127 inline QScriptValuePrivate
* property(const QString
& name
, const QScriptValue::ResolveFlags
& mode
);
128 inline QScriptValuePrivate
* property(const QScriptStringPrivate
* name
, const QScriptValue::ResolveFlags
& mode
);
129 inline QScriptValuePrivate
* property(quint32 arrayIndex
, const QScriptValue::ResolveFlags
& mode
);
130 inline JSValueRef
property(quint32 property
, JSValueRef
* exception
);
131 inline JSValueRef
property(JSStringRef property
, JSValueRef
* exception
);
132 inline bool hasOwnProperty(quint32 property
);
133 inline bool hasOwnProperty(JSStringRef property
);
135 inline QScriptValuePrivate
* property(T name
, const QScriptValue::ResolveFlags
& mode
);
137 inline void setProperty(const QString
& name
, QScriptValuePrivate
* value
, const QScriptValue::PropertyFlags
& flags
);
138 inline void setProperty(const QScriptStringPrivate
* name
, QScriptValuePrivate
* value
, const QScriptValue::PropertyFlags
& flags
);
139 inline void setProperty(const quint32 indexArray
, QScriptValuePrivate
* value
, const QScriptValue::PropertyFlags
& flags
);
140 inline void setProperty(quint32 property
, JSValueRef value
, JSPropertyAttributes flags
, JSValueRef
* exception
);
141 inline void setProperty(JSStringRef property
, JSValueRef value
, JSPropertyAttributes flags
, JSValueRef
* exception
);
142 inline void deleteProperty(quint32 property
, JSValueRef
* exception
);
143 inline void deleteProperty(JSStringRef property
, JSValueRef
* exception
);
145 inline void setProperty(T name
, QScriptValuePrivate
* value
, const QScriptValue::PropertyFlags
& flags
);
147 QScriptValue::PropertyFlags
propertyFlags(const QString
& name
, const QScriptValue::ResolveFlags
& mode
);
148 QScriptValue::PropertyFlags
propertyFlags(const QScriptStringPrivate
* name
, const QScriptValue::ResolveFlags
& mode
);
149 QScriptValue::PropertyFlags
propertyFlags(const JSStringRef name
, const QScriptValue::ResolveFlags
& mode
);
151 inline QScriptValuePrivate
* call(const QScriptValuePrivate
* , const QScriptValueList
& args
);
153 inline operator JSValueRef() const;
154 inline operator JSObjectRef() const;
156 inline QScriptEnginePrivate
* engine() const;
159 // Please, update class documentation when you change the enum.
167 JSValue
= 0x2000, // JS values are equal or higher then this value.
171 QScriptEnginePtr m_engine
;
177 JSObjectRef m_object
;
180 Value() : m_number(0) {}
181 Value(bool value
) : m_bool(value
) {}
182 Value(int number
) : m_number(number
) {}
183 Value(uint number
) : m_number(number
) {}
184 Value(qsreal number
) : m_number(number
) {}
185 Value(JSValueRef value
) : m_value(value
) {}
186 Value(JSObjectRef object
) : m_object(object
) {}
187 Value(QString
* string
) : m_string(string
) {}
190 inline State
refinedJSValue();
192 inline bool isJSBased() const;
193 inline bool isNumberBased() const;
194 inline bool isStringBased() const;
197 QScriptValuePrivate
* QScriptValuePrivate::get(const QScriptValue
& q
) { return q
.d_ptr
.data(); }
199 QScriptValue
QScriptValuePrivate::get(const QScriptValuePrivate
* d
)
201 return QScriptValue(const_cast<QScriptValuePrivate
*>(d
));
204 QScriptValue
QScriptValuePrivate::get(QScriptValuePrivate
* d
)
206 return QScriptValue(d
);
209 QScriptValuePrivate::~QScriptValuePrivate()
212 JSValueUnprotect(*m_engine
, u
.m_value
);
213 else if (isStringBased())
217 QScriptValuePrivate::QScriptValuePrivate()
222 QScriptValuePrivate::QScriptValuePrivate(const QString
& string
)
224 , u(new QString(string
))
228 QScriptValuePrivate::QScriptValuePrivate(bool value
)
234 QScriptValuePrivate::QScriptValuePrivate(int number
)
240 QScriptValuePrivate::QScriptValuePrivate(uint number
)
246 QScriptValuePrivate::QScriptValuePrivate(qsreal number
)
252 QScriptValuePrivate::QScriptValuePrivate(QScriptValue::SpecialValue value
)
253 : m_state(value
== QScriptValue::NullValue
? CNull
: CUndefined
)
257 QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate
* engine
, bool value
)
258 : m_state(JSPrimitive
)
259 , m_engine(const_cast<QScriptEnginePrivate
*>(engine
))
260 , u(engine
->makeJSValue(value
))
263 JSValueProtect(*m_engine
, u
.m_value
);
266 QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate
* engine
, int value
)
267 : m_state(JSPrimitive
)
268 , m_engine(const_cast<QScriptEnginePrivate
*>(engine
))
269 , u(m_engine
->makeJSValue(value
))
272 JSValueProtect(*m_engine
, u
.m_value
);
275 QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate
* engine
, uint value
)
276 : m_state(JSPrimitive
)
277 , m_engine(const_cast<QScriptEnginePrivate
*>(engine
))
278 , u(m_engine
->makeJSValue(value
))
281 JSValueProtect(*m_engine
, u
.m_value
);
284 QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate
* engine
, qsreal value
)
285 : m_state(JSPrimitive
)
286 , m_engine(const_cast<QScriptEnginePrivate
*>(engine
))
287 , u(m_engine
->makeJSValue(value
))
290 JSValueProtect(*m_engine
, u
.m_value
);
293 QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate
* engine
, const QString
& value
)
294 : m_state(JSPrimitive
)
295 , m_engine(const_cast<QScriptEnginePrivate
*>(engine
))
296 , u(m_engine
->makeJSValue(value
))
299 JSValueProtect(*m_engine
, u
.m_value
);
302 QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate
* engine
, QScriptValue::SpecialValue value
)
303 : m_state(JSPrimitive
)
304 , m_engine(const_cast<QScriptEnginePrivate
*>(engine
))
305 , u(m_engine
->makeJSValue(value
))
308 JSValueProtect(*m_engine
, u
.m_value
);
311 QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate
* engine
, JSValueRef value
)
313 , m_engine(const_cast<QScriptEnginePrivate
*>(engine
))
318 JSValueProtect(*m_engine
, u
.m_value
);
321 QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate
* engine
, JSObjectRef object
)
323 , m_engine(const_cast<QScriptEnginePrivate
*>(engine
))
328 JSValueProtect(*m_engine
, object
);
331 bool QScriptValuePrivate::isValid() const { return m_state
!= Invalid
; }
333 bool QScriptValuePrivate::isBool()
339 if (refinedJSValue() != JSPrimitive
)
343 return JSValueIsBoolean(*m_engine
, *this);
349 bool QScriptValuePrivate::isNumber()
355 if (refinedJSValue() != JSPrimitive
)
359 return JSValueIsNumber(*m_engine
, *this);
365 bool QScriptValuePrivate::isNull()
371 if (refinedJSValue() != JSPrimitive
)
375 return JSValueIsNull(*m_engine
, *this);
381 bool QScriptValuePrivate::isString()
387 if (refinedJSValue() != JSPrimitive
)
391 return JSValueIsString(*m_engine
, *this);
397 bool QScriptValuePrivate::isUndefined()
403 if (refinedJSValue() != JSPrimitive
)
407 return JSValueIsUndefined(*m_engine
, *this);
413 bool QScriptValuePrivate::isError()
417 if (refinedJSValue() != JSObject
)
421 return m_engine
->isError(*this);
427 bool QScriptValuePrivate::isObject()
431 return refinedJSValue() == JSObject
;
440 bool QScriptValuePrivate::isFunction()
444 if (refinedJSValue() != JSObject
)
448 return JSObjectIsFunction(*m_engine
, *this);
454 bool QScriptValuePrivate::isArray()
458 if (refinedJSValue() != JSObject
)
462 return m_engine
->isArray(*this);
468 bool QScriptValuePrivate::isDate()
472 if (refinedJSValue() != JSObject
)
476 return m_engine
->isDate(*this);
482 QString
QScriptValuePrivate::toString() const
488 return u
.m_bool
? QString::fromLatin1("true") : QString::fromLatin1("false");
492 return QScriptConverter::toString(u
.m_number
);
494 return QString::fromLatin1("null");
496 return QString::fromLatin1("undefined");
500 JSValueRef exception
= 0;
501 JSRetainPtr
<JSStringRef
> ptr(Adopt
, JSValueToStringCopy(*m_engine
, *this, &exception
));
502 m_engine
->setException(exception
);
503 return QScriptConverter::toString(ptr
.get());
506 Q_ASSERT_X(false, "toString()", "Not all states are included in the previous switch statement.");
507 return QString(); // Avoid compiler warning.
510 qsreal
QScriptValuePrivate::toNumber() const
517 JSValueRef exception
= 0;
518 qsreal result
= JSValueToNumber(*m_engine
, *this, &exception
);
519 m_engine
->setException(exception
);
525 return u
.m_bool
? 1 : 0;
533 qsreal result
= u
.m_string
->toDouble(&ok
);
536 result
= u
.m_string
->toInt(&ok
, 0); // Try other bases.
539 if (*u
.m_string
== "Infinity" || *u
.m_string
== "-Infinity")
541 return u
.m_string
->length() ? qQNaN() : 0;
544 Q_ASSERT_X(false, "toNumber()", "Not all states are included in the previous switch statement.");
545 return 0; // Avoid compiler warning.
548 bool QScriptValuePrivate::toBool() const
553 return JSValueToBoolean(*m_engine
, *this);
557 return !(qIsNaN(u
.m_number
) || !u
.m_number
);
565 return u
.m_string
->length();
568 Q_ASSERT_X(false, "toBool()", "Not all states are included in the previous switch statement.");
569 return false; // Avoid compiler warning.
572 qsreal
QScriptValuePrivate::toInteger() const
574 qsreal result
= toNumber();
579 return (result
> 0) ? qFloor(result
) : -1 * qFloor(-result
);
582 qint32
QScriptValuePrivate::toInt32() const
584 qsreal result
= toInteger();
585 // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but
586 // some of these operation are invoked in toInteger subcall.
592 quint32
QScriptValuePrivate::toUInt32() const
594 qsreal result
= toInteger();
595 // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but
596 // some of these operation are invoked in toInteger subcall.
602 quint16
QScriptValuePrivate::toUInt16() const
608 Creates a copy of this value and converts it to an object. If this value is an object
609 then pointer to this value will be returned.
610 \attention it should not happen but if this value is bounded to a different engine that the given, the first
614 QScriptValuePrivate
* QScriptValuePrivate::toObject(QScriptEnginePrivate
* engine
)
620 return new QScriptValuePrivate
;
623 // Exception can't occur here.
624 JSObjectRef object
= JSValueToObject(*engine
, engine
->makeJSValue(*u
.m_string
), /* exception */ 0);
626 return new QScriptValuePrivate(engine
, object
);
630 // Exception can't occur here.
631 JSObjectRef object
= JSValueToObject(*engine
, engine
->makeJSValue(u
.m_number
), /* exception */ 0);
633 return new QScriptValuePrivate(engine
, object
);
637 // Exception can't occure here.
638 JSObjectRef object
= JSValueToObject(*engine
, engine
->makeJSValue(u
.m_bool
), /* exception */ 0);
640 return new QScriptValuePrivate(engine
, object
);
643 if (refinedJSValue() != JSPrimitive
)
648 if (engine
!= this->engine())
649 qWarning("QScriptEngine::toObject: cannot convert value created in a different engine");
650 JSValueRef exception
= 0;
651 JSObjectRef object
= JSValueToObject(*m_engine
, *this, &exception
);
653 return new QScriptValuePrivate(m_engine
.constData(), object
);
655 m_engine
->setException(exception
, QScriptEnginePrivate::NotNullException
);
658 return new QScriptValuePrivate
;
663 if (engine
!= this->engine())
664 qWarning("QScriptEngine::toObject: cannot convert value created in a different engine");
665 Q_ASSERT(m_state
== JSObject
);
670 This method is created only for QScriptValue::toObject() purpose which is obsolete.
673 QScriptValuePrivate
* QScriptValuePrivate::toObject()
676 return toObject(m_engine
.data());
678 // Without an engine there is not much we can do.
679 return new QScriptValuePrivate
;
682 QDateTime
QScriptValuePrivate::toDateTime()
687 JSValueRef exception
= 0;
688 qsreal t
= JSValueToNumber(*m_engine
, *this, &exception
);
691 m_engine
->setException(exception
, QScriptEnginePrivate::NotNullException
);
696 result
.setMSecsSinceEpoch(qint64(t
));
700 inline QScriptValuePrivate
* QScriptValuePrivate::prototype()
703 JSValueRef prototype
= JSObjectGetPrototype(*m_engine
, *this);
704 if (JSValueIsNull(*m_engine
, prototype
))
705 return new QScriptValuePrivate(engine(), prototype
);
706 // The prototype could be either a null or a JSObject, so it is safe to cast the prototype
707 // to the JSObjectRef here.
708 return new QScriptValuePrivate(engine(), const_cast<JSObjectRef
>(prototype
));
710 return new QScriptValuePrivate
;
713 inline void QScriptValuePrivate::setPrototype(QScriptValuePrivate
* prototype
)
715 if (isObject() && prototype
->isValid() && (prototype
->isObject() || prototype
->isNull())) {
716 if (engine() != prototype
->engine()) {
717 qWarning("QScriptValue::setPrototype() failed: cannot set a prototype created in a different engine");
720 // FIXME: This could be replaced by a new, faster API
721 // look at https://bugs.webkit.org/show_bug.cgi?id=40060
722 JSObjectSetPrototype(*m_engine
, *this, *prototype
);
723 JSValueRef proto
= JSObjectGetPrototype(*m_engine
, *this);
724 if (!JSValueIsStrictEqual(*m_engine
, proto
, *prototype
))
725 qWarning("QScriptValue::setPrototype() failed: cyclic prototype value");
729 bool QScriptValuePrivate::equals(QScriptValuePrivate
* other
)
732 return !other
->isValid();
734 if (!other
->isValid())
737 if (!isJSBased() && !other
->isJSBased()) {
741 return other
->isUndefined() || other
->isNull();
743 switch (other
->m_state
) {
746 return u
.m_number
== other
->toNumber();
748 return u
.m_number
== other
->u
.m_number
;
753 switch (other
->m_state
) {
755 return u
.m_bool
== other
->u
.m_bool
;
757 return toNumber() == other
->u
.m_number
;
759 return toNumber() == other
->toNumber();
764 switch (other
->m_state
) {
766 return toNumber() == other
->toNumber();
768 return toNumber() == other
->u
.m_number
;
770 return *u
.m_string
== *other
->u
.m_string
;
775 Q_ASSERT_X(false, "equals()", "Not all states are included in the previous switch statement.");
779 if (isJSBased() && !other
->isJSBased()) {
780 if (!other
->assignEngine(engine())) {
781 qWarning("equals(): Cannot compare to a value created in a different engine");
784 } else if (!isJSBased() && other
->isJSBased()) {
785 if (!assignEngine(other
->engine())) {
786 qWarning("equals(): Cannot compare to a value created in a different engine");
791 JSValueRef exception
= 0;
792 bool result
= JSValueIsEqual(*m_engine
, *this, *other
, &exception
);
793 m_engine
->setException(exception
);
797 bool QScriptValuePrivate::strictlyEquals(QScriptValuePrivate
* other
)
800 // We can't compare these two values without binding to the same engine.
801 if (!other
->isJSBased()) {
802 if (other
->assignEngine(engine()))
803 return JSValueIsStrictEqual(*m_engine
, *this, *other
);
806 if (other
->engine() != engine()) {
807 qWarning("strictlyEquals(): Cannot compare to a value created in a different engine");
810 return JSValueIsStrictEqual(*m_engine
, *this, *other
);
812 if (isStringBased()) {
813 if (other
->isStringBased())
814 return *u
.m_string
== *(other
->u
.m_string
);
815 if (other
->isJSBased()) {
816 assignEngine(other
->engine());
817 return JSValueIsStrictEqual(*m_engine
, *this, *other
);
820 if (isNumberBased()) {
821 if (other
->isNumberBased())
822 return u
.m_number
== other
->u
.m_number
;
823 if (other
->isJSBased()) {
824 assignEngine(other
->engine());
825 return JSValueIsStrictEqual(*m_engine
, *this, *other
);
828 if (!isValid() && !other
->isValid())
834 inline bool QScriptValuePrivate::instanceOf(QScriptValuePrivate
* other
)
836 if (!isJSBased() || !other
->isObject())
838 JSValueRef exception
= 0;
839 bool result
= JSValueIsInstanceOfConstructor(*m_engine
, *this, *other
, &exception
);
840 m_engine
->setException(exception
);
845 Tries to assign \a engine to this value. Returns true on success; otherwise returns false.
847 bool QScriptValuePrivate::assignEngine(QScriptEnginePrivate
* engine
)
853 value
= engine
->makeJSValue(u
.m_bool
);
856 value
= engine
->makeJSValue(*u
.m_string
);
860 value
= engine
->makeJSValue(u
.m_number
);
863 value
= engine
->makeJSValue(QScriptValue::NullValue
);
866 value
= engine
->makeJSValue(QScriptValue::UndefinedValue
);
870 Q_ASSERT_X(!isJSBased(), "assignEngine()", "Not all states are included in the previous switch statement.");
872 qWarning("JSValue can't be rassigned to an another engine.");
876 m_state
= JSPrimitive
;
878 JSValueProtect(*m_engine
, value
);
882 inline QScriptValuePrivate
* QScriptValuePrivate::property(const QString
& name
, const QScriptValue::ResolveFlags
& mode
)
884 JSRetainPtr
<JSStringRef
> propertyName(Adopt
, QScriptConverter::toString(name
));
885 return property
<JSStringRef
>(propertyName
.get(), mode
);
888 inline QScriptValuePrivate
* QScriptValuePrivate::property(const QScriptStringPrivate
* name
, const QScriptValue::ResolveFlags
& mode
)
890 return property
<JSStringRef
>(*name
, mode
);
893 inline QScriptValuePrivate
* QScriptValuePrivate::property(quint32 arrayIndex
, const QScriptValue::ResolveFlags
& mode
)
895 return property
<quint32
>(arrayIndex
, mode
);
900 This method was created to unify access to the JSObjectGetPropertyAtIndex and the JSObjectGetProperty.
902 inline JSValueRef
QScriptValuePrivate::property(quint32 property
, JSValueRef
* exception
)
904 return JSObjectGetPropertyAtIndex(*m_engine
, *this, property
, exception
);
909 This method was created to unify access to the JSObjectGetPropertyAtIndex and the JSObjectGetProperty.
911 inline JSValueRef
QScriptValuePrivate::property(JSStringRef property
, JSValueRef
* exception
)
913 return JSObjectGetProperty(*m_engine
, *this, property
, exception
);
918 This method was created to unify acccess to hasOwnProperty, same function for an array index
919 and a property name access.
921 inline bool QScriptValuePrivate::hasOwnProperty(quint32 property
)
923 Q_ASSERT(isObject());
924 // FIXME it could be faster, but JSC C API doesn't expose needed functionality.
925 JSRetainPtr
<JSStringRef
> propertyName(Adopt
, QScriptConverter::toString(QString::number(property
)));
926 return hasOwnProperty(propertyName
.get());
931 This method was created to unify acccess to hasOwnProperty, same function for an array index
932 and a property name access.
934 inline bool QScriptValuePrivate::hasOwnProperty(JSStringRef property
)
936 Q_ASSERT(isObject());
937 return m_engine
->objectHasOwnProperty(*this, property
);
942 This function gets property of an object.
943 \arg propertyName could be type of quint32 (an array index) or JSStringRef (a property name).
946 inline QScriptValuePrivate
* QScriptValuePrivate::property(T propertyName
, const QScriptValue::ResolveFlags
& mode
)
949 return new QScriptValuePrivate();
951 if ((mode
== QScriptValue::ResolveLocal
) && (!hasOwnProperty(propertyName
)))
952 return new QScriptValuePrivate();
954 JSValueRef exception
= 0;
955 JSValueRef value
= property(propertyName
, &exception
);
958 m_engine
->setException(exception
, QScriptEnginePrivate::NotNullException
);
959 return new QScriptValuePrivate(engine(), exception
);
961 if (JSValueIsUndefined(*m_engine
, value
))
962 return new QScriptValuePrivate
;
963 return new QScriptValuePrivate(engine(), value
);
966 inline void QScriptValuePrivate::setProperty(const QString
& name
, QScriptValuePrivate
* value
, const QScriptValue::PropertyFlags
& flags
)
968 JSRetainPtr
<JSStringRef
> propertyName(Adopt
, QScriptConverter::toString(name
));
969 setProperty
<JSStringRef
>(propertyName
.get(), value
, flags
);
972 inline void QScriptValuePrivate::setProperty(quint32 arrayIndex
, QScriptValuePrivate
* value
, const QScriptValue::PropertyFlags
& flags
)
974 setProperty
<quint32
>(arrayIndex
, value
, flags
);
977 inline void QScriptValuePrivate::setProperty(const QScriptStringPrivate
* name
, QScriptValuePrivate
* value
, const QScriptValue::PropertyFlags
& flags
)
979 setProperty
<JSStringRef
>(*name
, value
, flags
);
984 This method was created to unify access to the JSObjectSetPropertyAtIndex and the JSObjectSetProperty.
986 inline void QScriptValuePrivate::setProperty(quint32 property
, JSValueRef value
, JSPropertyAttributes flags
, JSValueRef
* exception
)
988 Q_ASSERT(isObject());
990 // FIXME This could be better, but JSC C API doesn't expose needed functionality. It is
991 // not possible to create / modify a property attribute via an array index.
992 JSRetainPtr
<JSStringRef
> propertyName(Adopt
, QScriptConverter::toString(QString::number(property
)));
993 JSObjectSetProperty(*m_engine
, *this, propertyName
.get(), value
, flags
, exception
);
996 JSObjectSetPropertyAtIndex(*m_engine
, *this, property
, value
, exception
);
1001 This method was created to unify access to the JSObjectSetPropertyAtIndex and the JSObjectSetProperty.
1003 inline void QScriptValuePrivate::setProperty(JSStringRef property
, JSValueRef value
, JSPropertyAttributes flags
, JSValueRef
* exception
)
1005 Q_ASSERT(isObject());
1006 JSObjectSetProperty(*m_engine
, *this, property
, value
, flags
, exception
);
1011 This method was created to unify access to the JSObjectDeleteProperty and a teoretical JSObjectDeletePropertyAtIndex
1012 which doesn't exist now.
1014 inline void QScriptValuePrivate::deleteProperty(quint32 property
, JSValueRef
* exception
)
1016 // FIXME It could be faster, we need a JSC C API for deleting array index properties.
1017 JSRetainPtr
<JSStringRef
> propertyName(Adopt
, QScriptConverter::toString(QString::number(property
)));
1018 JSObjectDeleteProperty(*m_engine
, *this, propertyName
.get(), exception
);
1023 This method was created to unify access to the JSObjectDeleteProperty and a teoretical JSObjectDeletePropertyAtIndex.
1025 inline void QScriptValuePrivate::deleteProperty(JSStringRef property
, JSValueRef
* exception
)
1027 Q_ASSERT(isObject());
1028 JSObjectDeleteProperty(*m_engine
, *this, property
, exception
);
1031 template<typename T
>
1032 inline void QScriptValuePrivate::setProperty(T name
, QScriptValuePrivate
* value
, const QScriptValue::PropertyFlags
& flags
)
1037 if (!value
->isJSBased())
1038 value
->assignEngine(engine());
1040 JSValueRef exception
= 0;
1041 if (!value
->isValid()) {
1042 // Remove the property.
1043 deleteProperty(name
, &exception
);
1044 m_engine
->setException(exception
);
1047 if (m_engine
!= value
->m_engine
) {
1048 qWarning("QScriptValue::setProperty() failed: cannot set value created in a different engine");
1052 setProperty(name
, *value
, QScriptConverter::toPropertyFlags(flags
), &exception
);
1053 m_engine
->setException(exception
);
1056 inline QScriptValue::PropertyFlags
QScriptValuePrivate::propertyFlags(const QString
& name
, const QScriptValue::ResolveFlags
& mode
)
1058 JSRetainPtr
<JSStringRef
> propertyName(Adopt
, QScriptConverter::toString(name
));
1059 return propertyFlags(propertyName
.get(), mode
);
1062 inline QScriptValue::PropertyFlags
QScriptValuePrivate::propertyFlags(const QScriptStringPrivate
* name
, const QScriptValue::ResolveFlags
& mode
)
1064 return propertyFlags(*name
, mode
);
1067 inline QScriptValue::PropertyFlags
QScriptValuePrivate::propertyFlags(JSStringRef name
, const QScriptValue::ResolveFlags
& mode
)
1071 return QScriptValue::PropertyFlags(flags
);
1073 // FIXME It could be faster and nicer, but new JSC C API should be created.
1074 static JSStringRef objectName
= QScriptConverter::toString("Object");
1075 static JSStringRef propertyDescriptorName
= QScriptConverter::toString("getOwnPropertyDescriptor");
1077 // FIXME This is dangerous if global object was modified (bug 41839).
1078 JSValueRef exception
= 0;
1079 JSObjectRef globalObject
= JSContextGetGlobalObject(*m_engine
);
1080 JSValueRef objectConstructor
= JSObjectGetProperty(*m_engine
, globalObject
, objectName
, &exception
);
1081 Q_ASSERT(JSValueIsObject(*m_engine
, objectConstructor
));
1082 JSValueRef propertyDescriptorGetter
= JSObjectGetProperty(*m_engine
, const_cast<JSObjectRef
>(objectConstructor
), propertyDescriptorName
, &exception
);
1083 Q_ASSERT(JSValueIsObject(*m_engine
, propertyDescriptorGetter
));
1085 JSValueRef arguments
[] = { *this, JSValueMakeString(*m_engine
, name
) };
1086 JSObjectRef propertyDescriptor
1087 = const_cast<JSObjectRef
>(JSObjectCallAsFunction(*m_engine
,
1088 const_cast<JSObjectRef
>(propertyDescriptorGetter
),
1090 /* argumentCount */ 2,
1094 // Invalid property.
1095 return QScriptValue::PropertyFlags(flags
);
1098 if (!JSValueIsObject(*m_engine
, propertyDescriptor
)) {
1099 // Property isn't owned by this object.
1101 if (mode
== QScriptValue::ResolveLocal
1102 || ((proto
= const_cast<JSObjectRef
>(JSObjectGetPrototype(*m_engine
, *this))) && JSValueIsNull(*m_engine
, proto
))) {
1103 return QScriptValue::PropertyFlags(flags
);
1105 QScriptValuePrivate
p(engine(), proto
);
1106 return p
.propertyFlags(name
, QScriptValue::ResolvePrototype
);
1109 static JSStringRef writableName
= QScriptConverter::toString("writable");
1110 static JSStringRef configurableName
= QScriptConverter::toString("configurable");
1111 static JSStringRef enumerableName
= QScriptConverter::toString("enumerable");
1113 bool readOnly
= !JSValueToBoolean(*m_engine
, JSObjectGetProperty(*m_engine
, propertyDescriptor
, writableName
, &exception
));
1114 if (!exception
&& readOnly
)
1115 flags
|= QScriptValue::ReadOnly
;
1116 bool undeletable
= !JSValueToBoolean(*m_engine
, JSObjectGetProperty(*m_engine
, propertyDescriptor
, configurableName
, &exception
));
1117 if (!exception
&& undeletable
)
1118 flags
|= QScriptValue::Undeletable
;
1119 bool skipInEnum
= !JSValueToBoolean(*m_engine
, JSObjectGetProperty(*m_engine
, propertyDescriptor
, enumerableName
, &exception
));
1120 if (!exception
&& skipInEnum
)
1121 flags
|= QScriptValue::SkipInEnumeration
;
1123 return QScriptValue::PropertyFlags(flags
);
1126 QScriptValuePrivate
* QScriptValuePrivate::call(const QScriptValuePrivate
*, const QScriptValueList
& args
)
1130 if (refinedJSValue() != JSObject
)
1131 return new QScriptValuePrivate
;
1135 // Convert all arguments and bind to the engine.
1136 int argc
= args
.size();
1137 QVarLengthArray
<JSValueRef
, 8> argv(argc
);
1138 QScriptValueList::const_iterator i
= args
.constBegin();
1139 for (int j
= 0; i
!= args
.constEnd(); j
++, i
++) {
1140 QScriptValuePrivate
* value
= QScriptValuePrivate::get(*i
);
1141 if (!value
->assignEngine(engine())) {
1142 qWarning("QScriptValue::call() failed: cannot call function with values created in a different engine");
1143 return new QScriptValuePrivate
;
1149 JSValueRef exception
= 0;
1150 JSValueRef result
= JSObjectCallAsFunction(*m_engine
, *this, /* thisObject */ 0, argc
, argv
.constData(), &exception
);
1151 if (!result
&& exception
) {
1152 m_engine
->setException(exception
);
1153 return new QScriptValuePrivate(engine(), exception
);
1155 if (result
&& !exception
)
1156 return new QScriptValuePrivate(engine(), result
);
1158 // this QSV is not a function <-- !result && !exception. Fall-through.
1160 return new QScriptValuePrivate
;
1164 QScriptEnginePrivate
* QScriptValuePrivate::engine() const
1166 // As long as m_engine is an autoinitializated pointer we can safely return it without
1167 // checking current state.
1168 return m_engine
.data();
1171 QScriptValuePrivate::operator JSValueRef() const
1173 Q_ASSERT(isJSBased());
1174 Q_ASSERT(u
.m_value
);
1178 QScriptValuePrivate::operator JSObjectRef() const
1180 Q_ASSERT(m_state
== JSObject
);
1181 Q_ASSERT(u
.m_object
);
1187 Refines the state of this QScriptValuePrivate. Returns the new state.
1189 QScriptValuePrivate::State
QScriptValuePrivate::refinedJSValue()
1191 Q_ASSERT(m_state
== JSValue
);
1192 if (!JSValueIsObject(*m_engine
, *this)) {
1193 m_state
= JSPrimitive
;
1195 // Difference between JSValueRef and JSObjectRef is only in their type, binarywise it is the same.
1196 // As m_value and m_object are stored in the u union, it is enough to change the m_state only.
1204 Returns true if QSV have an engine associated.
1206 bool QScriptValuePrivate::isJSBased() const { return m_state
>= JSValue
; }
1210 Returns true if current value of QSV is placed in m_number.
1212 bool QScriptValuePrivate::isNumberBased() const { return m_state
== CNumber
|| m_state
== CBool
; }
1216 Returns true if current value of QSV is placed in m_string.
1218 bool QScriptValuePrivate::isStringBased() const { return m_state
== CString
; }
1220 #endif // qscriptvalue_p_h