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 <QtCore/qshareddata.h>
28 #include <QtCore/qvarlengtharray.h>
35 \class QScriptValuePrivate
37 Implementation of QScriptValue.
38 The implementation is based on a state machine. The states names are included in
39 QScriptValuePrivate::States. Each method should check for the current state and then perform a
43 Invalid -> QSVP is invalid, no assumptions should be made about class members (apart from m_value).
44 CString -> QSVP is created from QString or const char* and no JSC engine has been associated yet.
45 Current value is kept in m_string,
46 CNumber -> QSVP is created from int, uint, double... and no JSC engine has been bind yet. Current
47 value is kept in m_number
48 CBool -> QSVP is created from bool and no JSC engine has been associated yet. Current value is kept
50 CSpecial -> QSVP is Undefined or Null, but a JSC engine hasn't been associated yet, current value
51 is kept in m_number (cast of QScriptValue::SpecialValue)
52 JSValue -> QSVP is associated with engine, but there is no information about real type, the state
53 have really short live cycle. Normally it is created as a function call result.
54 JSNative -> QSVP is associated with engine, and it is sure that it isn't a JavaScript object.
55 JSObject -> QSVP is associated with engine, and it is sure that it is a JavaScript object.
57 Each state keep all necessary information to invoke all methods, if not it should be changed to
58 a proper state. Changed state shouldn't be reverted.
61 class QScriptValuePrivate
: public QSharedData
{
63 inline static QScriptValuePrivate
* get(const QScriptValue
& q
);
64 inline static QScriptValue
get(const QScriptValuePrivate
* d
);
65 inline static QScriptValue
get(QScriptValuePrivate
* d
);
67 inline ~QScriptValuePrivate();
69 inline QScriptValuePrivate();
70 inline QScriptValuePrivate(const QString
& string
);
71 inline QScriptValuePrivate(bool value
);
72 inline QScriptValuePrivate(int number
);
73 inline QScriptValuePrivate(uint number
);
74 inline QScriptValuePrivate(qsreal number
);
75 inline QScriptValuePrivate(QScriptValue::SpecialValue value
);
77 inline QScriptValuePrivate(const QScriptEngine
* engine
, bool value
);
78 inline QScriptValuePrivate(const QScriptEngine
* engine
, int value
);
79 inline QScriptValuePrivate(const QScriptEngine
* engine
, uint value
);
80 inline QScriptValuePrivate(const QScriptEngine
* engine
, qsreal value
);
81 inline QScriptValuePrivate(const QScriptEngine
* engine
, const QString
& value
);
82 inline QScriptValuePrivate(const QScriptEngine
* engine
, QScriptValue::SpecialValue value
);
84 inline QScriptValuePrivate(const QScriptEnginePrivate
* engine
, JSValueRef value
);
85 inline QScriptValuePrivate(const QScriptEnginePrivate
* engine
, JSValueRef value
, JSObjectRef object
);
87 inline bool isValid() const;
89 inline bool isNumber();
91 inline bool isString();
92 inline bool isUndefined();
93 inline bool isError();
94 inline bool isObject();
95 inline bool isFunction();
97 inline QString
toString() const;
98 inline qsreal
toNumber() const;
99 inline bool toBool() const;
100 inline qsreal
toInteger() const;
101 inline qint32
toInt32() const;
102 inline quint32
toUInt32() const;
103 inline quint16
toUInt16() const;
105 inline bool equals(QScriptValuePrivate
* other
);
106 inline bool strictlyEquals(const QScriptValuePrivate
* other
) const;
107 inline bool assignEngine(QScriptEnginePrivate
* engine
);
109 inline QScriptValuePrivate
* call(const QScriptValuePrivate
* , const QScriptValueList
& args
);
111 inline JSGlobalContextRef
context() const;
112 inline JSValueRef
value() const;
113 inline JSObjectRef
object() const;
114 inline QScriptEnginePrivate
* engine() const;
117 // Please, update class documentation when you change the enum.
124 JSValue
= 0x2000, // JS values are equal or higher then this value.
128 QScriptEnginePtr m_engine
;
132 JSObjectRef m_object
;
134 inline void setValue(JSValueRef
);
136 inline bool inherits(const char*);
138 inline bool isJSBased() const;
139 inline bool isNumberBased() const;
140 inline bool isStringBased() const;
143 QScriptValuePrivate
* QScriptValuePrivate::get(const QScriptValue
& q
) { return q
.d_ptr
.data(); }
145 QScriptValue
QScriptValuePrivate::get(const QScriptValuePrivate
* d
)
147 return QScriptValue(const_cast<QScriptValuePrivate
*>(d
));
150 QScriptValue
QScriptValuePrivate::get(QScriptValuePrivate
* d
)
152 return QScriptValue(d
);
155 QScriptValuePrivate::~QScriptValuePrivate()
158 JSValueUnprotect(context(), m_value
);
161 QScriptValuePrivate::QScriptValuePrivate()
167 QScriptValuePrivate::QScriptValuePrivate(const QString
& string
)
174 QScriptValuePrivate::QScriptValuePrivate(bool value
)
181 QScriptValuePrivate::QScriptValuePrivate(int number
)
188 QScriptValuePrivate::QScriptValuePrivate(uint number
)
195 QScriptValuePrivate::QScriptValuePrivate(qsreal number
)
202 QScriptValuePrivate::QScriptValuePrivate(QScriptValue::SpecialValue value
)
209 QScriptValuePrivate::QScriptValuePrivate(const QScriptEngine
* engine
, bool value
)
213 // slower path reinitialization
218 m_engine
= QScriptEnginePrivate::get(engine
);
219 m_value
= m_engine
->makeJSValue(value
);
220 JSValueProtect(context(), m_value
);
224 QScriptValuePrivate::QScriptValuePrivate(const QScriptEngine
* engine
, int value
)
228 // slower path reinitialization
233 m_engine
= QScriptEnginePrivate::get(engine
);
234 m_value
= m_engine
->makeJSValue(value
);
235 JSValueProtect(context(), m_value
);
239 QScriptValuePrivate::QScriptValuePrivate(const QScriptEngine
* engine
, uint value
)
243 // slower path reinitialization
248 m_engine
= QScriptEnginePrivate::get(engine
);
249 m_value
= m_engine
->makeJSValue(value
);
250 JSValueProtect(context(), m_value
);
254 QScriptValuePrivate::QScriptValuePrivate(const QScriptEngine
* engine
, qsreal value
)
258 // slower path reinitialization
263 m_engine
= QScriptEnginePrivate::get(engine
);
264 m_value
= m_engine
->makeJSValue(value
);
265 JSValueProtect(context(), m_value
);
269 QScriptValuePrivate::QScriptValuePrivate(const QScriptEngine
* engine
, const QString
& value
)
273 // slower path reinitialization
278 m_engine
= QScriptEnginePrivate::get(engine
);
279 m_value
= m_engine
->makeJSValue(value
);
280 JSValueProtect(context(), m_value
);
284 QScriptValuePrivate::QScriptValuePrivate(const QScriptEngine
* engine
, QScriptValue::SpecialValue value
)
288 // slower path reinitialization
293 m_engine
= QScriptEnginePrivate::get(engine
);
294 m_value
= m_engine
->makeJSValue(value
);
295 JSValueProtect(context(), m_value
);
299 QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate
* engine
, JSValueRef value
)
301 , m_engine(const_cast<QScriptEnginePrivate
*>(engine
))
305 JSValueProtect(context(), m_value
);
308 QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate
* engine
, JSValueRef value
, JSObjectRef object
)
310 , m_engine(const_cast<QScriptEnginePrivate
*>(engine
))
315 JSValueProtect(context(), m_value
);
318 bool QScriptValuePrivate::isValid() const { return m_state
!= Invalid
; }
320 bool QScriptValuePrivate::isBool()
330 return JSValueIsBoolean(context(), value());
336 bool QScriptValuePrivate::isNumber()
346 return JSValueIsNumber(context(), value());
352 bool QScriptValuePrivate::isNull()
356 return m_number
== static_cast<int>(QScriptValue::NullValue
);
362 return JSValueIsNull(context(), value());
368 bool QScriptValuePrivate::isString()
378 return JSValueIsString(context(), value());
384 bool QScriptValuePrivate::isUndefined()
388 return m_number
== static_cast<int>(QScriptValue::UndefinedValue
);
394 return JSValueIsUndefined(context(), value());
400 bool QScriptValuePrivate::isError()
408 return inherits("Error");
414 bool QScriptValuePrivate::isObject()
420 m_object
= JSValueToObject(context(), value(), /* exception */ 0);
430 bool QScriptValuePrivate::isFunction()
434 m_object
= JSValueToObject(context(), value(), /* exception */ 0);
440 return JSObjectIsFunction(context(), object());
446 QString
QScriptValuePrivate::toString() const
452 return m_number
? QString::fromLatin1("true") : QString::fromLatin1("false");
456 return QString::number(m_number
);
458 return m_number
== QScriptValue::NullValue
? QString::fromLatin1("null") : QString::fromLatin1("undefined");
462 return QScriptConverter::toString(JSValueToStringCopy(context(), value(), /* exception */ 0));
465 Q_ASSERT_X(false, "toString()", "Not all states are included in the previous switch statement.");
466 return QString(); // Avoid compiler warning.
469 qsreal
QScriptValuePrivate::toNumber() const
476 return JSValueToNumber(context(), value(), /* exception */ 0);
484 return m_string
.isEmpty();
487 Q_ASSERT_X(false, "toNumber()", "Not all states are included in the previous switch statement.");
488 return 0; // Avoid compiler warning.
491 bool QScriptValuePrivate::toBool() const
497 return JSValueToBoolean(context(), value());
505 return m_string
.isEmpty();
508 Q_ASSERT_X(false, "toBool()", "Not all states are included in the previous switch statement.");
509 return false; // Avoid compiler warning.
512 qsreal
QScriptValuePrivate::toInteger() const
514 // TODO it is not true implementation!
518 qint32
QScriptValuePrivate::toInt32() const
520 // TODO it is not true implementation!
524 quint32
QScriptValuePrivate::toUInt32() const
526 // TODO it is not true implementation!
530 quint16
QScriptValuePrivate::toUInt16() const
532 // TODO it is not true implementation!
537 bool QScriptValuePrivate::equals(QScriptValuePrivate
* other
)
539 if (!isValid() || !other
->isValid())
542 if ((m_state
== other
->m_state
) && !isJSBased()) {
544 return m_number
== other
->m_number
;
545 return m_string
== other
->m_string
;
548 if (isJSBased() && !other
->isJSBased()) {
549 if (!other
->assignEngine(engine())) {
550 qWarning("equals(): Cannot compare to a value created in a different engine");
553 } else if (!isJSBased() && other
->isJSBased()) {
554 if (!other
->assignEngine(other
->engine())) {
555 qWarning("equals(): Cannot compare to a value created in a different engine");
560 return JSValueIsEqual(context(), value(), other
->value(), /* exception */ 0);
563 bool QScriptValuePrivate::strictlyEquals(const QScriptValuePrivate
* other
) const
565 if (m_state
!= other
->m_state
)
568 if (other
->engine() != engine()) {
569 qWarning("strictlyEquals(): Cannot compare to a value created in a different engine");
572 return JSValueIsStrictEqual(context(), value(), other
->value());
575 return m_string
== other
->m_string
;
577 return m_number
== other
->m_number
;
579 return false; // Invalid state.
583 Tries to assign \a engine to this value. Returns true on success; otherwise returns false.
585 bool QScriptValuePrivate::assignEngine(QScriptEnginePrivate
* engine
)
590 value
= engine
->makeJSValue(static_cast<bool>(m_number
));
593 value
= engine
->makeJSValue(m_string
);
596 value
= engine
->makeJSValue(m_number
);
599 value
= engine
->makeJSValue(static_cast<QScriptValue::SpecialValue
>(m_number
));
603 Q_ASSERT_X(!isJSBased(), "assignEngine()", "Not all states are included in the previous switch statement.");
605 qWarning("JSValue can't be rassigned to an another engine.");
614 QScriptValuePrivate
* QScriptValuePrivate::call(const QScriptValuePrivate
*, const QScriptValueList
& args
)
618 m_object
= JSValueToObject(context(), value(), /* exception */ 0);
621 return new QScriptValuePrivate
;
627 // Convert all arguments and bind to the engine.
628 int argc
= args
.size();
629 QVarLengthArray
<JSValueRef
, 8> argv(argc
);
630 QScriptValueList::const_iterator i
= args
.constBegin();
631 for (int j
= 0; i
!= args
.constEnd(); j
++, i
++) {
632 QScriptValuePrivate
* value
= QScriptValuePrivate::get(*i
);
633 if (!value
->assignEngine(engine())) {
634 qWarning("QScriptValue::call() failed: cannot call function with values created in a different engine");
635 return new QScriptValuePrivate
;
637 argv
[j
] = value
->value();
641 JSValueRef exception
= 0;
642 JSValueRef result
= JSObjectCallAsFunction(context(), object(), /* thisObject */ 0, argc
, argv
.constData(), &exception
);
643 if (!result
&& exception
)
644 return new QScriptValuePrivate(engine(), exception
);
645 if (result
&& !exception
)
646 return new QScriptValuePrivate(engine(), result
);
648 // this QSV is not a function <-- !result && !exception. Fall-through.
650 return new QScriptValuePrivate
;
654 QScriptEnginePrivate
* QScriptValuePrivate::engine() const
656 // As long as m_engine is an autoinitializated pointer we can safely return it without
657 // checking current state.
658 return m_engine
.data();
661 JSGlobalContextRef
QScriptValuePrivate::context() const
663 Q_ASSERT(isJSBased());
664 return m_engine
->context();
667 JSValueRef
QScriptValuePrivate::value() const
669 Q_ASSERT(isJSBased());
673 JSObjectRef
QScriptValuePrivate::object() const
675 Q_ASSERT(m_state
== JSObject
);
679 void QScriptValuePrivate::setValue(JSValueRef value
)
682 JSValueUnprotect(context(), m_value
);
684 JSValueProtect(context(), value
);
690 Returns true if QSV is created from constructor with the given \a name, it has to be a
693 bool QScriptValuePrivate::inherits(const char* name
)
695 Q_ASSERT(isJSBased());
696 JSObjectRef globalObject
= JSContextGetGlobalObject(context());
697 JSValueRef error
= JSObjectGetProperty(context(), globalObject
, QScriptConverter::toString(name
), 0);
698 return JSValueIsInstanceOfConstructor(context(), value(), JSValueToObject(context(), error
, /* exception */ 0), /* exception */ 0);
703 Returns true if QSV have an engine associated.
705 bool QScriptValuePrivate::isJSBased() const { return m_state
>= JSValue
; }
709 Returns true if current value of QSV is placed in m_number.
711 bool QScriptValuePrivate::isNumberBased() const { return !isJSBased() && !isStringBased() && m_state
!= Invalid
; }
715 Returns true if current value of QSV is placed in m_string.
717 bool QScriptValuePrivate::isStringBased() const { return m_state
== CString
; }
719 #endif // qscriptvalue_p_h